<commit_before>var keystone	= require('keystone'),
	_			= require('underscore'),
	async		= require('async'),
	middleware	= require('./middleware'),
	Child		= keystone.list('Child');

exports.getAllChildren = function getAllChildren(req, res, done) {

	var locals = res.locals;

	Child.model.find()
				.populate('gender')
				.populate('race')
				.populate('language')
				.populate('disabilities')
				.populate('otherConsiderations')
				.populate('recommendedFamilyConstellation')
				.populate('otherFamilyConstellationConsideration')
				.populate('status')
				.populate('legalStatus')
				.exec()
				.then(function (children) {
					// Filter out all children who don't have a status of 'active'
					children = _.filter(children, function(child) {
						return child.status.childStatus === 'active'
					});

					_.each(children, function(child) {
						// adjust the image to the blank male/female image if needed
						exports.setNoChildImage(req, res, child);
						// set extra information needed for rendering the child to the page
						child.age						= middleware.getAge(child.birthDate);
			    		child.ageConverted				= middleware.convertDate(child.birthDate);
			    		child.registrationDateConverted	= middleware.convertDate(child.registrationDate);
					});

					locals.children = children;
					// execute done function if async is used to continue the flow of execution
					done()

				}, function(err) {

					console.log(err);
					// execute done function if async is used to continue the flow of execution
					done();

				});
};

exports.getUnrestrictedChildren = function getUnrestrictedChildren(req, res, done) {

	var locals = res.locals;

	Child.model.find()
				.where('siteVisibility', 'everyone')
				.populate('gender')
				.populate('race')
				.populate('language')
				.populate('disabilities')
				.populate('otherConsiderations')
				.populate('recommendedFamilyConstellation')
				.populate('otherFamilyConstellationConsideration')
				.populate('status')
				.populate('legalStatus')
				.exec()
				.then(function (children) {
					// Filter out all children who don't have a status of 'active'
					children = _.filter(children, function(child) {
						return child.status.childStatus === 'active'
					});

					_.each(children, function(child) {
						// adjust the image to the blank male/female image if needed
						exports.setNoChildImage(req, res, child);
						// set extra information needed for rendering the child to the page
						child.age						= middleware.getAge(child.birthDate);
			    		child.ageConverted				= middleware.convertDate(child.birthDate);
			    		child.registrationDateConverted	= middleware.convertDate(child.registrationDate);

					});

					locals.children = children;
					// execute done function if async is used to continue the flow of execution
					done()

				}, function(err) {

					console.log(err);
					// execute done function if async is used to continue the flow of execution
					done();

				});
};

/* Sets the images for display in the gallery to a blank male/female face in the following cases:
 *	1. No image was uploaded for the child
 *	2. The child has been identified as legal risk
 */
exports.setNoChildImage = function setNoChildImage(req, res, child) {
	// Constant definitions.  TODO: Change these to const instead of var once support for ES2015 improves
	var NO_IMAGE_MALE_GALLERY = 'images/no-image-male_gallery.png',
		NO_IMAGE_MALE_DETAILS = 'images/no-image-male_detail.png',
		NO_IMAGE_FEMALE_GALLERY = 'images/no-image-female_gallery.png',
		NO_IMAGE_FEMALE_DETAILS = 'images/no-image-female_detail.png';
	// If there's no image or if the child has been identified as legal risk set the correct picture for males/females

	if(child.image.url === undefined || child.legalStatus.legalStatus === 'legal risk') {

		if(child.gender.gender === 'male') {

			child.detailImage = NO_IMAGE_MALE_DETAILS;
			child.galleryImage = NO_IMAGE_MALE_GALLERY;

		} else if(child.gender.gender === 'female') {

			child.detailImage = NO_IMAGE_FEMALE_DETAILS;
			child.galleryImage = NO_IMAGE_FEMALE_GALLERY;

		}
	}
};

exports.getChildByRegistrationNumber = function getChildByRegistrationNumber(req, res, done, registrationNumber) {

	var locals				= res.locals,
		registrationNumber	= parseInt(registrationNumber);

		Child.model.find()
				.where('registrationNumber', registrationNumber)
				.exec()
				.then(function (child) {

					locals.child = child[0];
					// execute done function if async is used to continue the flow of execution
	 				// TODO: if this is used in non-async middleware, done or next should be passed into options and the appropriate one should be executed
					done();

				}, function(err) {

					console.log(err);
					done();

				});

};

/* Expose the child data for the gallery view to the front-end via an API call */
exports.getGalleryData = function getGalleryData(req, res, next) {

	var locals = res.locals;
	// Set local variables
	locals.publicChildrenData = [];
	locals.userType	= req.user ? req.user.get('userType') : 'anonymous';
	locals.targetChildren = locals.userType === 'anonymous' || locals.userType === 'site visitor' ? 'unrestricted' : 'all';

	async.series([
		function(done) {

			if(locals.targetChildren === 'all') {
				exports.getAllChildren(req, res, done);
			} else {
				exports.getUnrestrictedChildren(req, res, done);
			}

		}

	], function() {

		var needsMap = {
			'none'		: 0,
			'mild'		: 1,
			'moderate'	: 2,
			'severe'	: 3
		}
		// Full child records have been fetched and stored on res.locals
		_.each(locals.children, function(child) {

			var relevantData = {
	    		name									: child.name.first,
	    		age										: middleware.getAge(child.birthDate),
	    		ageConverted							: middleware.convertDate(child.birthDate),
	    		registrationNumber						: child.registrationNumber,
	    		registrationDateConverted				: middleware.convertDate(child.registrationDate),
				gender									: child.gender.gender,
	    		race									: _.pluck(child.race, 'race'),
				siblingContactsCount					: child.siblingContacts.length,
	    		language								: _.pluck(child.language, 'language'),
	    		legalStatus								: child.legalStatus.legalStatus,
	    		hasContactWithBiologicalSiblings		: child.hasContactWithSiblings || false,
	    		hasContactWithBiologicalParents			: child.hasContactWithBirthFamily || false,
	    		physicalNeeds							: needsMap[child.physicalNeeds],
	    		emotionalNeeds							: needsMap[child.emotionalNeeds],
	    		intellectualNeeds						: needsMap[child.intellectualNeeds],
	    		disabilities							: _.pluck(child.disabilities, 'disability'),
	    		otherConsiderations						: _.pluck(child.otherConsiderations, 'otherConsideration'),
	    		recommendedFamilyConstellation			: _.pluck(child.recommendedFamilyConstellation, 'familyConstellation'),
	    		otherFamilyConstellationConsideration	: _.pluck(child.otherFamilyConstellationConsideration, 'otherFamilyConstellationConsideration'),
	    		galleryImage							: child.galleryImage,
	    		detailImage								: child.detailImage,
	    		hasVideo								: child.video && child.video.length > 0 ? true : false,
	    		wednesdaysChild							: child.wednesdaysChild,
	    		numberOfSiblings						: child.siblingContacts.length,
				updatedAt								: child.updatedAt
	    	};

	    	locals.publicChildrenData.push(relevantData);

		});

		res.send(locals.publicChildrenData);

	});
};

// TODO: include an error message for this and other functions in middleware if applicable
exports.getChildDetails = function(req, res, next) {

	var childData = req.body,
		registrationNumber = childData['registrationNumber'];

	/* TODO: Fetch only the needed fields instead of grabbing everything */
	Child.model.find()
        .where('registrationNumber', registrationNumber)
        .populate('gender')
        .exec()
        .then(function (child) {

        	var child = child[0];

        	var relevantData = {
        		profilePart1		: child.profile.part1,
        		profilePart2		: child.profile.part2,
        		profilePart3		: child.profile.part3,
        		hasImage			: _.isEmpty(child.image) && child.image.url.length > 0,
        		video				: child.video && child.video.length > 0 ? child.video.replace('watch?v=', 'embed/') : undefined,
        	};

        	res.send(relevantData);
        });
};
<commit_msg>#1 | update child service to pull other family constellation considerations in a cleaner way<commit_after>var keystone	= require('keystone'),
	_			= require('underscore'),
	async		= require('async'),
	middleware	= require('./middleware'),
	Child		= keystone.list('Child');

exports.getAllChildren = function getAllChildren(req, res, done) {

	var locals = res.locals;

	Child.model.find()
				.populate('gender')
				.populate('race')
				.populate('language')
				.populate('disabilities')
				.populate('otherConsiderations')
				.populate('recommendedFamilyConstellation')
				.populate('otherFamilyConstellationConsideration')
				.populate('status')
				.populate('legalStatus')
				.exec()
				.then(function (children) {
					// Filter out all children who don't have a status of 'active'
					children = _.filter(children, function(child) {
						return child.status.childStatus === 'active'
					});

					_.each(children, function(child) {
						// adjust the image to the blank male/female image if needed
						exports.setNoChildImage(req, res, child);
						// set extra information needed for rendering the child to the page
						child.age						= middleware.getAge(child.birthDate);
			    		child.ageConverted				= middleware.convertDate(child.birthDate);
			    		child.registrationDateConverted	= middleware.convertDate(child.registrationDate);
					});

					locals.children = children;
					// execute done function if async is used to continue the flow of execution
					done()

				}, function(err) {

					console.log(err);
					// execute done function if async is used to continue the flow of execution
					done();

				});
};

exports.getUnrestrictedChildren = function getUnrestrictedChildren(req, res, done) {

	var locals = res.locals;

	Child.model.find()
				.where('siteVisibility', 'everyone')
				.populate('gender')
				.populate('race')
				.populate('language')
				.populate('disabilities')
				.populate('otherConsiderations')
				.populate('recommendedFamilyConstellation')
				.populate('otherFamilyConstellationConsideration')
				.populate('status')
				.populate('legalStatus')
				.exec()
				.then(function (children) {
					// Filter out all children who don't have a status of 'active'
					children = _.filter(children, function(child) {
						return child.status.childStatus === 'active'
					});

					_.each(children, function(child) {
						// adjust the image to the blank male/female image if needed
						exports.setNoChildImage(req, res, child);
						// set extra information needed for rendering the child to the page
						child.age						= middleware.getAge(child.birthDate);
			    		child.ageConverted				= middleware.convertDate(child.birthDate);
			    		child.registrationDateConverted	= middleware.convertDate(child.registrationDate);

					});

					locals.children = children;
					// execute done function if async is used to continue the flow of execution
					done()

				}, function(err) {

					console.log(err);
					// execute done function if async is used to continue the flow of execution
					done();

				});
};

/* Sets the images for display in the gallery to a blank male/female face in the following cases:
 *	1. No image was uploaded for the child
 *	2. The child has been identified as legal risk
 */
exports.setNoChildImage = function setNoChildImage(req, res, child) {
	// Constant definitions.  TODO: Change these to const instead of var once support for ES2015 improves
	var NO_IMAGE_MALE_GALLERY = 'images/no-image-male_gallery.png',
		NO_IMAGE_MALE_DETAILS = 'images/no-image-male_detail.png',
		NO_IMAGE_FEMALE_GALLERY = 'images/no-image-female_gallery.png',
		NO_IMAGE_FEMALE_DETAILS = 'images/no-image-female_detail.png';
	// If there's no image or if the child has been identified as legal risk set the correct picture for males/females

	if(child.image.url === undefined || child.legalStatus.legalStatus === 'legal risk') {

		if(child.gender.gender === 'male') {

			child.detailImage = NO_IMAGE_MALE_DETAILS;
			child.galleryImage = NO_IMAGE_MALE_GALLERY;

		} else if(child.gender.gender === 'female') {

			child.detailImage = NO_IMAGE_FEMALE_DETAILS;
			child.galleryImage = NO_IMAGE_FEMALE_GALLERY;

		}
	}
};

exports.getChildByRegistrationNumber = function getChildByRegistrationNumber(req, res, done, registrationNumber) {

	var locals				= res.locals;

		Child.model.find()
				.where('registrationNumber', parseInt(registrationNumber, 10))
				.exec()
				.then(function (child) {

					locals.child = child[0];
					// execute done function if async is used to continue the flow of execution
	 				// TODO: if this is used in non-async middleware, done or next should be passed into options and the appropriate one should be executed
					done();

				}, function(err) {

					console.log(err);
					done();

				});

};

/* Expose the child data for the gallery view to the front-end via an API call */
exports.getGalleryData = function getGalleryData(req, res, next) {

	var locals = res.locals;
	// Set local variables
	locals.publicChildrenData = [];
	locals.userType	= req.user ? req.user.get('userType') : 'anonymous';
	locals.targetChildren = locals.userType === 'anonymous' || locals.userType === 'site visitor' ? 'unrestricted' : 'all';

	async.series([
		function(done) {

			if(locals.targetChildren === 'all') {
				exports.getAllChildren(req, res, done);
			} else {
				exports.getUnrestrictedChildren(req, res, done);
			}

		}

	], function() {

		var needsMap = {
			'none'		: 0,
			'mild'		: 1,
			'moderate'	: 2,
			'severe'	: 3
		}
		// Full child records have been fetched and stored on res.locals
		_.each(locals.children, function(child) {
			// Create a searchable array for dealing with other family constellation considerations
			var otherFamilyConstellationConsiderations = _.pluck(child.otherFamilyConstellationConsideration, 'otherFamilyConstellationConsideration');

			var relevantData = {
	    		name									: child.name.first,
	    		age										: middleware.getAge(child.birthDate),
	    		ageConverted							: middleware.convertDate(child.birthDate),
	    		registrationNumber						: child.registrationNumber,
	    		registrationDateConverted				: middleware.convertDate(child.registrationDate),
				gender									: child.gender.gender,
	    		race									: _.pluck(child.race, 'race'),
				siblingContactsCount					: child.siblingContacts.length,
	    		language								: _.pluck(child.language, 'language'),
	    		legalStatus								: child.legalStatus.legalStatus,
	    		hasContactWithBiologicalSiblings		: child.hasContactWithSiblings || false,
	    		hasContactWithBiologicalParents			: child.hasContactWithBirthFamily || false,
	    		physicalNeeds							: needsMap[child.physicalNeeds],
	    		emotionalNeeds							: needsMap[child.emotionalNeeds],
	    		intellectualNeeds						: needsMap[child.intellectualNeeds],
	    		disabilities							: _.pluck(child.disabilities, 'disability'),
	    		otherConsiderations						: _.pluck(child.otherConsiderations, 'otherConsideration'),
	    		recommendedFamilyConstellation			: _.pluck(child.recommendedFamilyConstellation, 'familyConstellation'),
				requiresSiblings						: otherFamilyConstellationConsiderations.indexOf('multi-child home') !== -1,
	    		requiresNoSiblings						: otherFamilyConstellationConsiderations.indexOf('childless home') !== -1,
				requiresYoungerSibling					: otherFamilyConstellationConsiderations.indexOf('requires younger children') !== -1,
				requiresOlderSibling					: otherFamilyConstellationConsiderations.indexOf('requires older children') !== -1,
				noPets									: otherFamilyConstellationConsiderations.indexOf('no pets') !== -1,
				galleryImage							: child.galleryImage,
	    		detailImage								: child.detailImage,
	    		hasVideo								: child.video && child.video.length > 0 ? true : false,
	    		wednesdaysChild							: child.wednesdaysChild,
	    		numberOfSiblings						: child.siblingContacts.length,
				updatedAt								: child.updatedAt
	    	};

	    	locals.publicChildrenData.push(relevantData);

		});

		res.send(locals.publicChildrenData);

	});
};

// TODO: include an error message for this and other functions in middleware if applicable
exports.getChildDetails = function(req, res, next) {

	var childData = req.body,
		registrationNumber = childData['registrationNumber'];

	/* TODO: Fetch only the needed fields instead of grabbing everything */
	Child.model.find()
        .where('registrationNumber', registrationNumber)
        .populate('gender')
        .exec()
        .then(function (child) {

        	var child = child[0];

        	var relevantData = {
        		profilePart1		: child.profile.part1,
        		profilePart2		: child.profile.part2,
        		profilePart3		: child.profile.part3,
        		hasImage			: _.isEmpty(child.image) && child.image.url.length > 0,
        		video				: child.video && child.video.length > 0 ? child.video.replace('watch?v=', 'embed/') : undefined,
        	};

        	res.send(relevantData);
        });
};
<|endoftext|>


<commit_before>(function() {

var checkVersion = Dagaz.Model.checkVersion;

Dagaz.Model.checkVersion = function(design, name, value) {
  if (name != "adiuh-checkers-goal") {
      checkVersion(design, name, value);
  }
}

Dagaz.AI.eval = function(design, params, board, player) {
  var r = 0;
  _.each(design.allPositions(), function(pos) {
      var piece = board.getPiece(pos);
      if (piece === null) return;
      var v = piece.getValue(0);
      if (v === null) {
          v = 1;
      } else {
          v++;
      }
      if (pos >= Dagaz.Model.BOARD_SIZE / 2) {
          v = -v;
      }
      if (player == 1) {
          r += v;
      } else {
          r -= v;
      }
      if (piece.player == player) {
          r++;
      } else {
          r--;
      }
  });
  return r;
}

var checkGoals = Dagaz.Model.checkGoals;

Dagaz.Model.checkGoals = function(design, board, player) {
  board.generate(design);
  if (board.moves.length == 0) {
      var w = 0; var b = 0;
      for (var pos = 0; pos < Dagaz.Model.BOARD_SIZE; pos++) {
           var piece = board.getPiece(pos);
           if (piece !== null) {
               var c = 1;
               var s = piece.getValue(0);
               if (s !== null) {
                   c += s.length;
               }
               if (pos < Dagaz.Model.BOARD_SIZE / 2) {
                   w += c;
               } else {
                   b += c;
               }
           }
      }
      var r = null;
      if (w == b) r = 0;
      if (w > b) {
          if (player == 1) {
              r = 1;
          } else {
              r = -1;
          }
      } else {
          if (player == 1) {
              r = -1;
          } else {
              r = 1;
          }
      }
      if (r !== null) return {
          message: ' (' + w + ':' + b + ')',
          result: r
      };
  }
  return checkGoals(design, board, player);
}

})();
<commit_msg>Shashki Adiyukh (goal fixed)<commit_after>(function() {

var checkVersion = Dagaz.Model.checkVersion;

Dagaz.Model.checkVersion = function(design, name, value) {
  if (name != "adiuh-checkers-goal") {
      checkVersion(design, name, value);
  }
}

Dagaz.AI.eval = function(design, params, board, player) {
  var r = 0;
  _.each(design.allPositions(), function(pos) {
      var piece = board.getPiece(pos);
      if (piece === null) return;
      var v = piece.getValue(0);
      if (v === null) {
          v = 1;
      } else {
          v++;
      }
      if (pos >= Dagaz.Model.BOARD_SIZE / 2) {
          v = -v;
      }
      if (player == 1) {
          r += v;
      } else {
          r -= v;
      }
      if (piece.player == player) {
          r++;
      } else {
          r--;
      }
  });
  return r;
}

var checkGoals = Dagaz.Model.checkGoals;

Dagaz.Model.checkGoals = function(design, board, player) {
  board.generate(design);
  if (board.moves.length == 0) {
      var w = 0; var b = 0;
      for (var pos = 0; pos < Dagaz.Model.BOARD_SIZE; pos++) {
           var piece = board.getPiece(pos);
           if (piece !== null) {
               var c = 1;
               var s = piece.getValue(0);
               if (s !== null) {
                   c += s.length;
               }
               if (pos < Dagaz.Model.BOARD_SIZE / 2) {
                   w += c;
               } else {
                   b += c;
               }
           }
      }
      var r = null;
      if (w == b) r = 0;
      if (w > b) {
          if (player == 1) {
              r = 1;
          } else {
              r = -1;
          }
      }
      if (w < b) {
          if (player == 1) {
              r = -1;
          } else {
              r = 1;
          }
      }
      if (r !== null) return {
          message: ' (' + w + ':' + b + ')',
          result: r
      };
  }
  return checkGoals(design, board, player);
}

})();
<|endoftext|>


<commit_before>window._config = {
  isDebug: ['localhost', 'dev.bootstrap-table.com'].indexOf(location.hostname) > -1
}

function loadUrl(url_) {
  var hash = ''
  if (location.search.slice(1) === 'is-debug') {
    hash = '#is-debug'
  }
  var url = 'template.html?v=VERSION&url=' + url_ + hash
  if (window._config.isDebug) {
    url = 'template.html?t=' + (+new Date()) + '&url=' + url_ + hash
  }
  if (url_.indexOf('view-source') > -1) {
    url = 'template.html?v=VERSION&view-source&url=' + url_ + hash
  }
  $('iframe').attr('src', url)
}

function initNavigation(href) {
  var $el = $('a[href="#' + href + '"]')
  var $parent = $el.parent()

  if (!$el.length) {
    return
  }

  $('#bd-docs-nav .active').removeClass('active')
  $parent.addClass('active')
  $el.parents('.bd-toc-item').addClass('active')
}

function autoScrollNavigation () {
  var $el = $('.bd-sidenav >li.active')
  $('#bd-docs-nav').scrollTop(0)
  if ($el.length && $el.offset().top > $(window).height() / 2) {
    $('#bd-docs-nav').scrollTop($el.offset().top - $(window).height() / 2)
  }
}

function doSearch() {
  var searchClient = window.algoliasearch('FXDJ517Z8G', '9b89c4a7048370f4809b0bc77b2564ac')

  var search = window.instantsearch({
    indexName: 'bootstrap-table-example',
    searchClient: searchClient,
    searchFunction: function (helper) {
      if (helper.state.query) {
        helper.search()
        $('#hits').show()
      } else {
        $('#hits').hide()
      }
    }
  })

  search.addWidget(
    window.instantsearch.widgets.searchBox({
      container: '#searchbox'
    })
  )

  search.addWidget(
    window.instantsearch.widgets.hits({
      container: '.hits-body',
      templates: {
        item: function (hit) {
          return [
            '
',
            '
',
            hit.anchor.split('/')[0].slice(1),
            '
',
            '
',
            hit.title,
            '
',
            '
',
            hit.description,
            '
',
            '
'
          ].join('')
        }
      }
    })
  )

  $(document).on('click', '.ais-Hits-item .link', function (e) {
    var href = $(e.currentTarget).data('href')
    if ($(e.target).is('a')) {
      return
    }
    location.href = href
    $('.ais-SearchBox-reset').click()
    $('.ais-SearchBox-input').blur()
    setTimeout(autoScrollNavigation, 200)
  })

  search.start()
}

$(function () {
  $('.bd-sidenav li').each(function () {
    $(this).attr('title', $.trim($(this).text()))
  })

  $('[data-toggle="tooltip"]').tooltip()

  $(window).hashchange(function () {
    var href = location.hash.substring(1)
    loadUrl(href)
    initNavigation(href)
  })

  var href = location.hash.substring(1) || 'welcome.html'
  loadUrl(href)
  initNavigation(href)
  autoScrollNavigation()
  doSearch()
})
<commit_msg>Fix index view-source bug<commit_after>window._config = {
  isDebug: ['localhost', 'dev.bootstrap-table.com'].indexOf(location.hostname) > -1
}

function loadUrl(url_) {
  var hash = ''
  if (location.search.slice(1) === 'is-debug') {
    hash = '#is-debug'
  }
  var url = 'template.html?v=VERSION&url=' + url_ + hash
  if (window._config.isDebug) {
    url = 'template.html?t=' + (+new Date()) + '&url=' + url_ + hash
  }
  if (url_.indexOf('view-source') > -1) {
    url = 'template.html?v=VERSION&view-source&url=' + url_ + hash
  }
  $('iframe').attr('src', url)
}

function initNavigation(href) {
  var $el = $('a[href="#' + href + '"]')
  var $parent = $el.parent()

  if (!$el.length) {
    return
  }

  $('#bd-docs-nav .active').removeClass('active')
  $parent.addClass('active')
  $el.parents('.bd-toc-item').addClass('active')
}

function autoScrollNavigation () {
  var $el = $('.bd-sidenav >li.active')
  $('#bd-docs-nav').scrollTop(0)
  if ($el.length && $el.offset().top > $(window).height() / 2) {
    $('#bd-docs-nav').scrollTop($el.offset().top - $(window).height() / 2)
  }
}

function doSearch() {
  var searchClient = window.algoliasearch('FXDJ517Z8G', '9b89c4a7048370f4809b0bc77b2564ac')

  var search = window.instantsearch({
    indexName: 'bootstrap-table-example',
    searchClient: searchClient,
    searchFunction: function (helper) {
      if (helper.state.query) {
        helper.search()
        $('#hits').show()
      } else {
        $('#hits').hide()
      }
    }
  })

  search.addWidget(
    window.instantsearch.widgets.searchBox({
      container: '#searchbox'
    })
  )

  search.addWidget(
    window.instantsearch.widgets.hits({
      container: '.hits-body',
      templates: {
        item: function (hit) {
          return [
            '
',
            '
',
            hit.anchor.split('/')[0].slice(1),
            '
',
            '
',
            hit.title,
            '
',
            '
',
            hit.description,
            '
',
            '
'
          ].join('')
        }
      }
    })
  )

  $(document).on('click', '.ais-Hits-item .link', function (e) {
    var href = $(e.currentTarget).data('href')
    if ($(e.target).is('a')) {
      return
    }
    location.href = href
    $('.ais-SearchBox-reset').click()
    $('.ais-SearchBox-input').blur()
    setTimeout(autoScrollNavigation, 200)
  })

  search.start()
}

$(function () {
  $('.bd-sidenav li').each(function () {
    $(this).attr('title', $.trim($(this).text()))
  })

  $('[data-toggle="tooltip"]').tooltip()

  $(window).hashchange(function () {
    var href = location.hash.substring(1)
    loadUrl(href)
    initNavigation(href)
  })

  var href = location.hash.substring(1) || 'welcome.html'
  if (href === 'view-source') {
    href = 'welcome.html#view-source'
  }
  loadUrl(href)
  initNavigation(href)
  autoScrollNavigation()
  doSearch()
})
<|endoftext|>


<commit_before>"use strict";

/**
 * Main JS file for GhostScroll behaviours
 */

var $sitehead = $('#site-head');

/* Globals jQuery, document */
(function ($) {
	$(document).ready(initialize);
	$(window).resize(onViewportChange);
	$(window).scroll(onViewportChange);

	function initialize() {
		setupJumpHandlers();
		fontAwesomeDecorators();
		fontAwesomeReplacement();

		function setupJumpHandlers() {
                    // FitVids for responsive videos
            $('.post-content').fitVids();
                    // Arrow top in fixed menu
            $('#totop-arrow').click(function () {
            smoothScroll($sitehead);
            });
			$('#header-arrow').click( function () {
				var $first = $(".post").first();
				smoothScroll($first);
			});

            $('.btn.first').click( function () {
			    var $first = $(".post").first();
				smoothScroll($first);
		    });

			$('.fn-item, .btn').click(function (evt) {
        var $this = $(this);
				var href = $this.attr("href");

        // We don't want to prevent a link from working if it is external.
        if (href.slice(0,1) === "#") {
          evt.preventDefault();
          var title = $(this).text();
          window.history.pushState(title, title, href);
          smoothScroll($(href))
        }
			});
		}

		function fontAwesomeDecorators() {
			$('ul > li').before('');
			$('blockquote p').prepend('');
			$('blockquote p').append('');
		}

		function fontAwesomeReplacement() {
			// // Matches
			// @fa-singleword@
			// @fa-dash-separated-words@
			// // Does *not* match
			// \@fa-escaped@
			// @fa-space separated@
			// @fa-Invalid-Case@
			// @fa-Invalid-(H^R@
			// @fa-will-match@@fa-will-not-match@
			//
			// Note: JS doesn't support negative lookbehinds. Thus to permit
			// escaped examples (\@fa-foo@) we capture the preceeding
			// character. This shouldn't pose a problem except in the event of
			// adjacent font-awesome characters (that are not space separated).
			// See last example above.
			var reg = /([^\\])@(fa-[-a-z]+)@/g;

			var $posts = $("#posts-wrapper")
			$posts.html($posts.html().replace(reg, "$1"));
		}
	}

	function onViewportChange() {
		conditionallyShowNav();
		highlightActiveSection();

		function conditionallyShowNav() {
      var isTooNarrow = $(window).width() < 500;
      var shouldDisplayNav = !isTooNarrow && !isElementInViewport($sitehead);
			var navOpacity = shouldDisplayNav ? 1 : 0;
			$(".fixed-nav").css("opacity", navOpacity);
		}

		function highlightActiveSection() {
			$(".post-holder").each(function () {
				var $this = $(this);
				var postId = $this.attr("id");
				var $thisNavLink = $(".fn-item[href='#" + postId + "']");
				var $previousArrow = $(this).prev('.post-holder').find('.post-after');

				if(isElementInViewport($this)) {
					$thisNavLink.addClass('active');
					$previousArrow.fadeOut('slow');
				} else {
					$thisNavLink.removeClass('active');
					$previousArrow.fadeIn('slow');
				}
			});
		}

		function isElementInViewport($element) {
			var scrollPosition = $(window).scrollTop();
			var topOfElement = $element.offset().top;
			var bottomOfElement = topOfElement + $element.height();

			var isAboveElement = topOfElement > scrollPosition;
			var isBelowElement = scrollPosition >= bottomOfElement;

			return (!isAboveElement && !isBelowElement);
		}
	}

	function smoothScroll ($element) {
		$('html, body').animate({
			scrollTop: $element.offset().top
		}, 400);
	}

}(jQuery));<commit_msg>Cache this<commit_after>"use strict";

/**
 * Main JS file for GhostScroll behaviours
 */

var $sitehead = $('#site-head');

/* Globals jQuery, document */
(function ($) {
	$(document).ready(initialize);
	$(window).resize(onViewportChange);
	$(window).scroll(onViewportChange);

	function initialize() {
		setupJumpHandlers();
		fontAwesomeDecorators();
		fontAwesomeReplacement();

		function setupJumpHandlers() {
                    // FitVids for responsive videos
            $('.post-content').fitVids();
                    // Arrow top in fixed menu
            $('#totop-arrow').click(function () {
            smoothScroll($sitehead);
            });
			$('#header-arrow').click( function () {
				var $first = $(".post").first();
				smoothScroll($first);
			});

            $('.btn.first').click( function () {
			    var $first = $(".post").first();
				smoothScroll($first);
		    });

			$('.fn-item, .btn').click(function (evt) {
        var $this = $(this);
				var href = $this.attr("href");

        // We don't want to prevent a link from working if it is external.
        if (href.slice(0,1) === "#") {
          evt.preventDefault();
          var title = $this.text();
          window.history.pushState(title, title, href);
          smoothScroll($(href))
        }
			});
		}

		function fontAwesomeDecorators() {
			$('ul > li').before('');
			$('blockquote p').prepend('');
			$('blockquote p').append('');
		}

		function fontAwesomeReplacement() {
			// // Matches
			// @fa-singleword@
			// @fa-dash-separated-words@
			// // Does *not* match
			// \@fa-escaped@
			// @fa-space separated@
			// @fa-Invalid-Case@
			// @fa-Invalid-(H^R@
			// @fa-will-match@@fa-will-not-match@
			//
			// Note: JS doesn't support negative lookbehinds. Thus to permit
			// escaped examples (\@fa-foo@) we capture the preceeding
			// character. This shouldn't pose a problem except in the event of
			// adjacent font-awesome characters (that are not space separated).
			// See last example above.
			var reg = /([^\\])@(fa-[-a-z]+)@/g;

			var $posts = $("#posts-wrapper")
			$posts.html($posts.html().replace(reg, "$1"));
		}
	}

	function onViewportChange() {
		conditionallyShowNav();
		highlightActiveSection();

		function conditionallyShowNav() {
      var isTooNarrow = $(window).width() < 500;
      var shouldDisplayNav = !isTooNarrow && !isElementInViewport($sitehead);
			var navOpacity = shouldDisplayNav ? 1 : 0;
			$(".fixed-nav").css("opacity", navOpacity);
		}

		function highlightActiveSection() {
			$(".post-holder").each(function () {
				var $this = $(this);
				var postId = $this.attr("id");
				var $thisNavLink = $(".fn-item[href='#" + postId + "']");
				var $previousArrow = $(this).prev('.post-holder').find('.post-after');

				if(isElementInViewport($this)) {
					$thisNavLink.addClass('active');
					$previousArrow.fadeOut('slow');
				} else {
					$thisNavLink.removeClass('active');
					$previousArrow.fadeIn('slow');
				}
			});
		}

		function isElementInViewport($element) {
			var scrollPosition = $(window).scrollTop();
			var topOfElement = $element.offset().top;
			var bottomOfElement = topOfElement + $element.height();

			var isAboveElement = topOfElement > scrollPosition;
			var isBelowElement = scrollPosition >= bottomOfElement;

			return (!isAboveElement && !isBelowElement);
		}
	}

	function smoothScroll ($element) {
		$('html, body').animate({
			scrollTop: $element.offset().top
		}, 400);
	}

}(jQuery));<|endoftext|>


<commit_before>jQuery(function($) {

	var body = $('body');
	var html = $('html');
	var viewport = $(window);

	/* ==========================================================================
	   Menu
	   ========================================================================== */

	function menu() {
		html.toggleClass('menu-active');
	};

	$('#menu').on({
		'click': function() {
			menu();
		}
	});

	$('.menu-button').on({
		'click': function() {
			menu();
		}
	});

	$('.hidden-close').on({
		'click': function() {
			menu();
		}
	});

	/* ==========================================================================
	   Parallax cover
	   ========================================================================== */

	var cover = $('.cover');
	var coverPosition = 0;

	function prlx() {
		if(cover.length >= 1) {
			var windowPosition = viewport.scrollTop();
			(windowPosition > 0) ? coverPosition = Math.floor(windowPosition * 0.25) : coverPosition = 0;
			cover.css({
				'transform' : 'translate(0, ' + coverPosition + 'px)'
			});
			(viewport.scrollTop() < cover.height()) ? body.addClass('cover-active') : body.removeClass('cover-active');
		}
	}
	prlx();

	viewport.on({
		'scroll': function() {
			prlx();
		},
		'resize': function() {
			prlx();
		},
		'orientationchange': function() {
			prlx();
		}
	});

	/* ==========================================================================
	   Reading Progress
	   ========================================================================== */

	var post = $('.post-content');

	function readingProgress() {
		if(post.length >= 1) {
			var postBottom = post.offset().top + post.height();
			var windowBottom = viewport.scrollTop() + viewport.height();
			var progress = 100 - (((postBottom - windowBottom) / (postBottom - viewport.height())) * 100);
			$('.progress-bar').css('width', progress + '%');
			(progress > 100) ? $('.progress-container').addClass('ready') : $('.progress-container').removeClass('ready');
		}
	}
	readingProgress();

	viewport.on({
		'scroll': function() {
			readingProgress();
		},
		'resize': function() {
			readingProgress();
		},
		'orientationchange': function() {
			readingProgress();
		}
	});

	/* ==========================================================================
	   Style code blocks with highlight and numbered lines
	   ========================================================================== */

	function codestyling() {
		$('pre code').each(function(i, e) {
			hljs.highlightBlock(e);
			var code = $(this);
			var lines = code.html().split(/\n/).length;
			var numbers = [];
			for (i = 1; i < lines; i++) {
				numbers += '' + i + '';
			}
			code.parent().append('
' + numbers + '
');
		});
	}
	codestyling();

	/* ==========================================================================
	   Responsive Videos with Fitvids
	   ========================================================================== */

	function video() {
		$('#wrapper').fitVids();
	}
	video();

	/* ==========================================================================
	   Initialize and load Disqus
	   ========================================================================== */

	if (typeof disqus === 'undefined') {
		$('.post-comments').css({
			'display' : 'none'
		});
	} else {
		$('#show-disqus').on('click', function() {
			$.ajax({
				type: "GET",
				url: "//" + disqus + ".disqus.com/embed.js",
				dataType: "script",
				cache: true
			});
			$(this).parent().addClass('activated');
		});
	}
});
<commit_msg>turned cover translate to translate3d<commit_after>jQuery(function($) {

	var body = $('body');
	var html = $('html');
	var viewport = $(window);

	/* ==========================================================================
	   Menu
	   ========================================================================== */

	function menu() {
		html.toggleClass('menu-active');
	};

	$('#menu').on({
		'click': function() {
			menu();
		}
	});

	$('.menu-button').on({
		'click': function() {
			menu();
		}
	});

	$('.hidden-close').on({
		'click': function() {
			menu();
		}
	});

	/* ==========================================================================
	   Parallax cover
	   ========================================================================== */

	var cover = $('.cover');
	var coverPosition = 0;

	function prlx() {
		if(cover.length >= 1) {
			var windowPosition = viewport.scrollTop();
			(windowPosition > 0) ? coverPosition = Math.floor(windowPosition * 0.25) : coverPosition = 0;
			cover.css({
				'-webkit-transform' : 'translate3d(0, ' + coverPosition + 'px, 0)',
				'transform' : 'translate3d(0, ' + coverPosition + 'px, 0)'
			});
			(viewport.scrollTop() < cover.height()) ? body.addClass('cover-active') : body.removeClass('cover-active');
		}
	}
	prlx();

	viewport.on({
		'scroll': function() {
			prlx();
		},
		'resize': function() {
			prlx();
		},
		'orientationchange': function() {
			prlx();
		}
	});

	/* ==========================================================================
	   Reading Progress
	   ========================================================================== */

	var post = $('.post-content');

	function readingProgress() {
		if(post.length >= 1) {
			var postBottom = post.offset().top + post.height();
			var windowBottom = viewport.scrollTop() + viewport.height();
			var progress = 100 - (((postBottom - windowBottom) / (postBottom - viewport.height())) * 100);
			$('.progress-bar').css('width', progress + '%');
			(progress > 100) ? $('.progress-container').addClass('ready') : $('.progress-container').removeClass('ready');
		}
	}
	readingProgress();

	viewport.on({
		'scroll': function() {
			readingProgress();
		},
		'resize': function() {
			readingProgress();
		},
		'orientationchange': function() {
			readingProgress();
		}
	});

	/* ==========================================================================
	   Style code blocks with highlight and numbered lines
	   ========================================================================== */

	function codestyling() {
		$('pre code').each(function(i, e) {
			hljs.highlightBlock(e);
			var code = $(this);
			var lines = code.html().split(/\n/).length;
			var numbers = [];
			for (i = 1; i < lines; i++) {
				numbers += '' + i + '';
			}
			code.parent().append('
' + numbers + '
');
		});
	}
	codestyling();

	/* ==========================================================================
	   Responsive Videos with Fitvids
	   ========================================================================== */

	function video() {
		$('#wrapper').fitVids();
	}
	video();

	/* ==========================================================================
	   Initialize and load Disqus
	   ========================================================================== */

	if (typeof disqus === 'undefined') {
		$('.post-comments').css({
			'display' : 'none'
		});
	} else {
		$('#show-disqus').on('click', function() {
			$.ajax({
				type: "GET",
				url: "//" + disqus + ".disqus.com/embed.js",
				dataType: "script",
				cache: true
			});
			$(this).parent().addClass('activated');
		});
	}
});
<|endoftext|>


<commit_before>import Cropper from 'cropperjs';

let details;

export default function initImageUpload(elm2js, js2elm) {
  elm2js.subscribe((detailsIn) => {
    details = detailsIn || {};
    const container = document.getElementById('image-upload');
    container.classList.add('image-upload--active')
    const imageInput =
          `Lataa kuva
      <input id="image-input" class="image-upload__file-input" type="file" onChange="imageUploadInit();"></input>` ;
    if (details.pictureUrl) {
      initEditor(details.pictureUrl, details);
    } else {
      container.innerHTML = containerHtml(imageInput);
    }

    function initEditor(fileName, data) {
      const imgTag = `<img src="/static/images/${fileName}" id="image-editor-image" class="image-upload__img" />`;
      const cropperDiv = `<div>${imgTag}</div>`;
      const editor = `${cropperDiv}

  <button onClick="imageUploadCancel();" class="btn btn-danger" style="margin-right: 25px;">Peru</button>
  <button onClick="imageUploadRemove();" class="btn btn-danger" style="margin-right: 25px;">Poista</button>
  <button onClick="imageUploadSave();" class="btn btn-primary" style="margin-right: 25px;">Valmis</button>

`;
      container.innerHTML = containerHtml(editor);
      const imgElement = document.getElementById('image-editor-image')
      const cropper = new Cropper(imgElement, {
        aspectRatio: 1,
        zoomable: false,
        croppable: true,
        scalable: false,
        rotatable: false,
        data,
        crop: function(e) {
          details.x = e.detail.x;
          details.y = e.detail.y;
          details.width = e.detail.width;
          details.height = e.detail.height;
        }
      });
    }

    window.imageUploadSave = () => {
      js2elm.send(details);
      container.classList.remove('image-upload--active')
    };

    window.imageUploadRemove = () => {
      js2elm.send({
        url: '',
        x: 0,
        y: 0,
        width: 0,
        height: 0
      });
      container.classList.remove('image-upload--active')
    };

    window.imageUploadCancel = () => {
      container.classList.remove('image-upload--active')
    };

    window.imageUploadClose = () => {
      container.classList.remove('image-upload--active');
    };

    window.imageUploadInit = () => {
      const input = document.getElementById("image-input");
      const formData = new FormData();
      const url = '/api/profiilit/oma/kuva';
      formData.append("image", input.files[0]);
      const request = new XMLHttpRequest();
      request.onreadystatechange = () => {
        if (request.readyState === XMLHttpRequest.DONE) {
          const fileName = request.responseText;
          details.pictureUrl = fileName;
          const data = {};
          initEditor(fileName, data);
        }
      };
      request.open("PUT", url);
      request.send(formData);
    }
  })
}

function containerHtml(content) {
  return `

${content}

`

}

<commit_msg>Remove and allow immediately replacing<commit_after>import Cropper from 'cropperjs';

let details;

const imageInput =
      `Lataa kuva
      <input id="image-input" class="image-upload__file-input" type="file" onChange="imageUploadInit();"></input>` ;

export default function initImageUpload(elm2js, js2elm) {
  elm2js.subscribe((detailsIn) => {
    details = detailsIn || {};
    const container = document.getElementById('image-upload');
    container.classList.add('image-upload--active')
    if (details.pictureUrl) {
      initEditor(details.pictureUrl, details);
    } else {
      container.innerHTML = containerHtml(imageInput);
    }

    function initEditor(fileName, data) {
      const imgTag = `<img src="/static/images/${fileName}" id="image-editor-image" class="image-upload__img" />`;
      const cropperDiv = `<div>${imgTag}</div>`;
      const editor = `${cropperDiv}

  <button onClick="imageUploadCancel();" class="btn btn-danger" style="margin-right: 25px;">Peru</button>
  <button onClick="imageUploadRemove();" class="btn btn-danger" style="margin-right: 25px;">Poista</button>
  <button onClick="imageUploadSave();" class="btn btn-primary" style="margin-right: 25px;">Valmis</button>

`;
      container.innerHTML = containerHtml(editor);
      const imgElement = document.getElementById('image-editor-image')
      const cropper = new Cropper(imgElement, {
        aspectRatio: 1,
        zoomable: false,
        croppable: true,
        scalable: false,
        rotatable: false,
        data,
        crop: function(e) {
          details.x = e.detail.x;
          details.y = e.detail.y;
          details.width = e.detail.width;
          details.height = e.detail.height;
        }
      });
    }

    window.imageUploadSave = () => {
      js2elm.send(details);
      container.classList.remove('image-upload--active')
    };

    window.imageUploadRemove = () => {
      details = {
        pictureUrl: '',
        x: 0,
        y: 0,
        width: 0,
        height: 0
      };
      js2elm.send(details);
      container.innerHTML = containerHtml(imageInput);
    };

    window.imageUploadCancel = () => {
      container.classList.remove('image-upload--active')
    };

    window.imageUploadClose = () => {
      container.classList.remove('image-upload--active');
    };

    window.imageUploadInit = () => {
      const input = document.getElementById("image-input");
      const formData = new FormData();
      const url = '/api/profiilit/oma/kuva';
      formData.append("image", input.files[0]);
      const request = new XMLHttpRequest();
      request.onreadystatechange = () => {
        if (request.readyState === XMLHttpRequest.DONE) {
          const fileName = request.responseText;
          details.pictureUrl = fileName;
          const data = {};
          initEditor(fileName, data);
        }
      };
      request.open("PUT", url);
      request.send(formData);
    }
  })
}

function containerHtml(content) {
  return `

${content}

`

}

<|endoftext|>


<commit_before>
var DESCRIPTIONS = Clubber.prototype.descriptions;

var descriptions = [];
var descriptionEl = document.querySelector("#descriptions");
function initDescriptions () {
  var el = descriptionEl;
  for(var i=0; i< 20; i++){
    var el2 = document.createElement("div");
    el2.setAttribute("title", "");
    el2.style.left = (100*i/20) + "vw";
    descriptions.push(el2);
    el.appendChild(el2);
  }
}

initDescriptions();

var bandIndex = 0;

function changeTemplate(el) {
  var t = templates[bandIndex];
  var a = ["Change data types for iMusic[" + bandIndex + "] vec4. String of indices. Available indices:\n"];
  DESCRIPTIONS.forEach(function (k,i){
    a.push(i + (t.match(i) ? " * " : " - ") + k);
  });
  var s = prompt(a.join("\n"),t);
  if(!s ) return;
  if(!s.match(/^[0-9]{4,4}$/)){
    alert("template must be exactly 4 characters long and consist of indices 0-9");
    return;
  }
  el.innerHTML = s;
  templates[bandIndex] = s;
  initClubber("?");
  updateDescriptions();
}

numinputs = document.querySelectorAll("#config input");
templateButton = document.querySelector("#config #template");
selectEl = document.querySelector("select");

function selectBand(idx) {
  bandIndex = idx;
  selectEl.selectedIndex = idx;
  selectEl.style.backgroundColor = ["rgb(255,220,220)", "rgb(220,255,220)","rgb(220,220,255)","rgb(232,232,232)"][idx];
  for(j=0;j<12;j++) {
    numinputs[j].value = [rangeArrays,smoothArrays,adaptArrays][Math.floor(j/4)][bandIndex][j&3];
  }
  templateButton.innerHTML = templates[bandIndex];
}

function updateBand() {
  for(j=0;j<12;j++) {
    [rangeArrays,smoothArrays,adaptArrays][Math.floor(j/4)][bandIndex][j&3] = parseFloat(numinputs[j].value);
  }
  localStorage.setItem("clubber-config-"+bandIndex, "?"+serialize(bandIndex, true));
  initClubber("?");
}

function updateDescriptions() {
  for(var i=0; i< 4; i++){
    for(var j=0; j< 4; j++){
      var el = descriptions[5*i + j];
      var t = templates[i][j];
      var h = "iMusic["+i+"]."+("xyzw"[j]);
      el.setAttribute("title", h + " = " + (t ? DESCRIPTIONS[parseInt(t)]:"Invalid index, using strongest note"));
    }
  }
}

var shaders = [null];
var info = document.getElementById("info");
var octaves = document.getElementById("octaves");
for(var i=0; i<11; i++){
  var el = document.createElement("div");
  el.classList.add("octave");
  el.innerHTML = 12*i;
  el.style.left = 0.33 + 100*i/10.66 + "vw";
  octaves.appendChild(el);
}

initClubber();

if (getParameterByName("reset")){
  localStorage.removeItem("soundcloud-track");
  for(var i=0; i<4; i++){
    localStorage.removeItem("clubber-config-"+i);
  }
} else {
  for(var i=0; i<4; i++){
    var s = localStorage.getItem("clubber-config-"+i);
    if(s) initClubber(s);
  }
}

selectBand(0);

var noteTexOptions = {
  src: clubber.notes, min: gl.LINEAR,
  width: 128, height:1, format: gl.LUMINANCE, internalFormat:gl.LUMINANCE
};

var uniforms = {
  iMusic: new Float32Array(16),
  iNotes: twgl.createTexture(gl, noteTexOptions),
  iBounds: new Float32Array(16)
};

["red", "green", "blue", "alpha"].forEach(function (s){
  var v = getParameterByName(s);
  v = v ? decodeURIComponent(v) : localStorage.getItem("clubber-tool-"+s);
  if (v) document.querySelector("div." + s + " input[type=text]").value = v;
});

var TRACK = getParameterByName("track");

function getChunk(s) {
  var v = document.querySelector("div." + s + " input[type=text]").value;
  var c = document.querySelector("div." + s + " input[type=checkbox]").checked;
  if ( v ) localStorage.setItem("clubber-tool-"+s, v); else localStorage.removeItem("clubber-tool-"+s);
  return v && c ? v : "0.0";
}

shaders.push(new Shader(gl, {
    source: load("../toy/shaders/debug.fs"),
    uniforms: uniforms,
    correct: false
  })
);

shaders.push(new Shader(gl, {
    source: load("../toy/shaders/spectrum.fs"),
    uniforms: uniforms,
    correct: false
  })
);

var ALT = null;
var ALTEXT = null;
var renderMods = true;

function loadShader(s) {
  s = s || prompt("Provide a shadertoy url.", ALT ? ALT: "");
  if(!s) return;
  shadertoy(s).then(function(t){ ALT=s; ALTEXT=t; reloadAll(); });
}

if(getParameterByName("shader")){
  loadShader(getParameterByName("shader"));
  document.getElementById("mods").onclick();
}
var altShader = null;

var debugMode = 0;

function toggleMods(el) {
  renderMods = !renderMods;
  if(renderMods){
    el.classList.remove("disabled");
  } else {
    el.classList.add("disabled");
  }
}

function bands(el) {
  debugMode = (++debugMode) % 3;
  octaves.classList.remove("show");
  descriptionEl.classList.remove("show");
  if(debugMode){
    if(debugMode == 2) {
      octaves.classList.add("show");
    } else if(debugMode == 1){
      descriptionEl.classList.add("show");
    }
    el.classList.remove("disabled");
  } else {
    el.classList.add("disabled");
  }
  el.innerHTML = ["1 views", "1 bands", "1 spectrum"][debugMode];
}

function stateLink(el){
  el.href = window.location.origin+window.location.pathname+"?"+genState();
}

function sourceLink(el){
  el.href = "//www.shadertoy.com/view/" + ALT.split("?")[0].split("/").pop();
}

function genState() {
  var a = ["tool=1"];
  for(var i=0;i<4;i++){
    a.push(serialize(i, true));
  }
  ["red", "green", "blue", "alpha"].forEach(function (s){
    var vs = localStorage.getItem("clubber-tool-"+s);
    if(vs) a.push(s+"="+encodeURIComponent(vs));
  });
  var v = localStorage.getItem("soundcloud-track");
  if(v) a.push("track="+encodeURIComponent(v));
  if(ALT) a.push("shader="+encodeURIComponent(ALT))
  return a.join("&");
}

function serialize(i,clean) {
  var s = "t" + i + "= " + templates[i];
  s += " &r" + i + "= " + rangeArrays[i].join(", ");
  s += " &s" + i + "= " + smoothArrays[i].join(", ");
  s += " &a" + i + "= " + adaptArrays[i].join(", ");
  return clean ? s.replace(/\s/g, '') : s;
}
function handleClick(e) {
  if (!debugMode) return;
  var i = false, x = e.clientX/this.clientWidth;
  if(debugMode === 1) {
    i = Math.floor(4 * x);
  } else {
    for (var j=0; j < 4; j++) {
      if( x > uniforms.iBounds[4 * j] && x < uniforms.iBounds[4 * j + 1]) {
        i = j;
        break;
      }
    }
  }
  if (i === false) return;
  selectBand(i);
}
canvas.addEventListener("click", handleClick);
descriptionEl.addEventListener("click", handleClick);

function reloadAll () {
  reload();
  if(ALTEXT) reload(ALTEXT);
}

function reload (alt) {

  var rtxt = getChunk("red");
  var gtxt = getChunk("green");
  var btxt = getChunk("blue");
  var atxt = getChunk("alpha");

  var defines = {
    "CLUBBER": "1",
    "CLUBBER_R": rtxt,
    "CLUBBER_G": gtxt,
    "CLUBBER_B": btxt,
    "CLUBBER_A": atxt
  };

  var txt = [
    "void mainImage(out vec4 color, vec2 fragCoord) {",
    " vec2 uv = fragCoord/iResolution.xy;",
    " vec4 fColor = vec4(0.);",
    " vec4 fields;",
    " fields.r = CLUBBER_R;",
    " fields.g = CLUBBER_G;",
    " fields.b = CLUBBER_B;",
    " fields.a = CLUBBER_A;",
    " fields *= 0.25;",
    " for(float i = 0.; i < 2.; i++) {",
    "   for(float j = 0.; j < 2.; j++) {",
    "     vec2 center = 0.25 + vec2(mod(i, 2.0), 1.0 - mod(j,2.0)) * 0.5;",
    "     float d = dot(abs(uv-center), vec2(1.0));",
    "     float f1 = 1.0 - smoothstep(fields.r - fwidth(d), fields.r, d);",
    "     float f2 = 1.0 - smoothstep(0.25 - fwidth(d), 0.25, d);",
    "     fColor.r = (0.01 * f2 + 0.99 * f1);",
    "     fColor.rgba = fColor.gbar;",
    "     fields.rgba = fields.gbar;",
    "   }",
    " }",
    " color.rgb = fColor.a > 0. ? vec3(fColor.a):  fColor.rgb;",
    " if(color.r + color.g + color.b > 0.) color.rgb += 0.33;",
    "}"
  ].join("\n");

  var s = new Shader(gl, {
    source: alt ?  alt: txt ,
    uniforms: uniforms,
    defines: defines,
    correct: needsCorrection,
    ondone: function (obj) {
      if(!obj.programInfo) return;
      if(alt){
        if (altShader) gl.deleteProgram(altShader.programInfo.program);
        altShader = obj;
      } else {
        if (shaders[0]) gl.deleteProgram(shaders[0].programInfo.program);
        shaders[0] = obj;
      }
    }
  });

  console.log(defines);

}

var buttons = document.querySelectorAll("button");
window.addEventListener("keydown", function (e){
  if (e.altKey && e.key != "Alt") {
    var k = e.key.toLowerCase();
    var i = parseInt(k);
    var keys = {
      "r": "red",
      "g": "green",
      "b": "blue"
    };
    var pkeys = {
      "p": 0,
      "k": -5,
      "l": 5,
      "n": -30,
      "m": 30
    }
    if(!isNaN(i) && buttons[i-1].onclick){
      buttons[i-1].onclick();
    } else if(k in keys) {
      var el = document.querySelector("div."+keys[k]+" input[type=checkbox]");
      el.checked = !el.checked;
      el.onchange();
    } else if(k in pkeys) {
      var v = pkeys[k];
      if(!v) {
        if(audio.paused){
          audio.play();
        }else {
          audio.pause();
        }
      } else {
        audio.currentTime += v;
      }
    }
  }
});

function  render(time) {
  currentTime = time;
  window.requestAnimationFrame(render);
  if(!shaders[0]) return;
  clubber.update(time);
  for(var i = 0; i< 4; i++){
    var obj = data.bands[i](uniforms.iMusic, 4*i);
    uniforms.iBounds[4 * i] = obj.from / 128;
    uniforms.iBounds[4 * i + 1] = obj.to / 128;
    uniforms.iBounds[4 * i + 2] = obj.low / 128;
    uniforms.iBounds[4 * i + 3] = obj.high / 128;
  }
  uniforms.iResolution = [gl.canvas.width, gl.canvas.height,0];
  twgl.setTextureFromArray(gl, uniforms.iNotes, clubber.notes, noteTexOptions);
  data.time = time/1000;
  gl.clear(gl.COLOR_BUFFER_BIT);
  twgl.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  shaders[0].transition = altShader ? 0.8 : 1;
  if(altShader) altShader.transition = renderMods || debugMode ? 0.4 : 1;
  if(debugMode) {
    shaders[0].transition = 0.66;
    shaders[debugMode].render(data, true);
  }

  if(renderMods) shaders[0].render(data, true);
  if(altShader) altShader.render(data,true);
}

reloadAll();
updateDescriptions();
soundcloud(TRACK || localStorage.getItem("soundcloud-track") || "https://soundcloud.com/draufunddran/drauf-und-dran-2eur");
render(0);<commit_msg>don't persist bands<commit_after>
var DESCRIPTIONS = Clubber.prototype.descriptions;

var descriptions = [];
var descriptionEl = document.querySelector("#descriptions");
function initDescriptions () {
  var el = descriptionEl;
  for(var i=0; i< 20; i++){
    var el2 = document.createElement("div");
    el2.setAttribute("title", "");
    el2.style.left = (100*i/20) + "vw";
    descriptions.push(el2);
    el.appendChild(el2);
  }
}

initDescriptions();

var bandIndex = 0;

function changeTemplate(el) {
  var t = templates[bandIndex];
  var a = ["Change data types for iMusic[" + bandIndex + "] vec4. String of indices. Available indices:\n"];
  DESCRIPTIONS.forEach(function (k,i){
    a.push(i + (t.match(i) ? " * " : " - ") + k);
  });
  var s = prompt(a.join("\n"),t);
  if(!s ) return;
  if(!s.match(/^[0-9]{4,4}$/)){
    alert("template must be exactly 4 characters long and consist of indices 0-9");
    return;
  }
  el.innerHTML = s;
  templates[bandIndex] = s;
  initClubber("?");
  updateDescriptions();
}

numinputs = document.querySelectorAll("#config input");
templateButton = document.querySelector("#config #template");
selectEl = document.querySelector("select");

function selectBand(idx) {
  bandIndex = idx;
  selectEl.selectedIndex = idx;
  selectEl.style.backgroundColor = ["rgb(255,220,220)", "rgb(220,255,220)","rgb(220,220,255)","rgb(232,232,232)"][idx];
  for(j=0;j<12;j++) {
    numinputs[j].value = [rangeArrays,smoothArrays,adaptArrays][Math.floor(j/4)][bandIndex][j&3];
  }
  templateButton.innerHTML = templates[bandIndex];
}

function updateBand() {
  for(j=0;j<12;j++) {
    [rangeArrays,smoothArrays,adaptArrays][Math.floor(j/4)][bandIndex][j&3] = parseFloat(numinputs[j].value);
  }
  localStorage.setItem("clubber-config-"+bandIndex, "?"+serialize(bandIndex, true));
  initClubber("?");
}

function updateDescriptions() {
  for(var i=0; i< 4; i++){
    for(var j=0; j< 4; j++){
      var el = descriptions[5*i + j];
      var t = templates[i][j];
      var h = "iMusic["+i+"]."+("xyzw"[j]);
      el.setAttribute("title", h + " = " + (t ? DESCRIPTIONS[parseInt(t)]:"Invalid index, using strongest note"));
    }
  }
}

var shaders = [null];
var info = document.getElementById("info");
var octaves = document.getElementById("octaves");
for(var i=0; i<11; i++){
  var el = document.createElement("div");
  el.classList.add("octave");
  el.innerHTML = 12*i;
  el.style.left = 0.33 + 100*i/10.66 + "vw";
  octaves.appendChild(el);
}

initClubber();

if (getParameterByName("reset")){
  localStorage.removeItem("soundcloud-track");
}

selectBand(0);

var noteTexOptions = {
  src: clubber.notes, min: gl.LINEAR,
  width: 128, height:1, format: gl.LUMINANCE, internalFormat:gl.LUMINANCE
};

var uniforms = {
  iMusic: new Float32Array(16),
  iNotes: twgl.createTexture(gl, noteTexOptions),
  iBounds: new Float32Array(16)
};

["red", "green", "blue", "alpha"].forEach(function (s){
  var v = getParameterByName(s);
  v = v ? decodeURIComponent(v) : localStorage.getItem("clubber-tool-"+s);
  if (v) document.querySelector("div." + s + " input[type=text]").value = v;
});

var TRACK = getParameterByName("track");

function getChunk(s) {
  var v = document.querySelector("div." + s + " input[type=text]").value;
  var c = document.querySelector("div." + s + " input[type=checkbox]").checked;
  if ( v ) localStorage.setItem("clubber-tool-"+s, v); else localStorage.removeItem("clubber-tool-"+s);
  return v && c ? v : "0.0";
}

shaders.push(new Shader(gl, {
    source: load("../toy/shaders/debug.fs"),
    uniforms: uniforms,
    correct: false
  })
);

shaders.push(new Shader(gl, {
    source: load("../toy/shaders/spectrum.fs"),
    uniforms: uniforms,
    correct: false
  })
);

var ALT = null;
var ALTEXT = null;
var renderMods = true;

function loadShader(s) {
  s = s || prompt("Provide a shadertoy url.", ALT ? ALT: "");
  if(!s) return;
  shadertoy(s).then(function(t){ ALT=s; ALTEXT=t; reloadAll(); });
}

if(getParameterByName("shader")){
  loadShader(getParameterByName("shader"));
  document.getElementById("mods").onclick();
}
var altShader = null;

var debugMode = 0;

function toggleMods(el) {
  renderMods = !renderMods;
  if(renderMods){
    el.classList.remove("disabled");
  } else {
    el.classList.add("disabled");
  }
}

function bands(el) {
  debugMode = (++debugMode) % 3;
  octaves.classList.remove("show");
  descriptionEl.classList.remove("show");
  if(debugMode){
    if(debugMode == 2) {
      octaves.classList.add("show");
    } else if(debugMode == 1){
      descriptionEl.classList.add("show");
    }
    el.classList.remove("disabled");
  } else {
    el.classList.add("disabled");
  }
  el.innerHTML = ["1 views", "1 bands", "1 spectrum"][debugMode];
}

function stateLink(el){
  el.href = window.location.origin+window.location.pathname+"?"+genState();
}

function sourceLink(el){
  el.href = "//www.shadertoy.com/view/" + ALT.split("?")[0].split("/").pop();
}

function genState() {
  var a = ["tool=1"];
  for(var i=0;i<4;i++){
    a.push(serialize(i, true));
  }
  ["red", "green", "blue", "alpha"].forEach(function (s){
    var vs = localStorage.getItem("clubber-tool-"+s);
    if(vs) a.push(s+"="+encodeURIComponent(vs));
  });
  var v = localStorage.getItem("soundcloud-track");
  if(v) a.push("track="+encodeURIComponent(v));
  if(ALT) a.push("shader="+encodeURIComponent(ALT))
  return a.join("&");
}

function serialize(i,clean) {
  var s = "t" + i + "= " + templates[i];
  s += " &r" + i + "= " + rangeArrays[i].join(", ");
  s += " &s" + i + "= " + smoothArrays[i].join(", ");
  s += " &a" + i + "= " + adaptArrays[i].join(", ");
  return clean ? s.replace(/\s/g, '') : s;
}
function handleClick(e) {
  if (!debugMode) return;
  var i = false, x = e.clientX/this.clientWidth;
  if(debugMode === 1) {
    i = Math.floor(4 * x);
  } else {
    for (var j=0; j < 4; j++) {
      if( x > uniforms.iBounds[4 * j] && x < uniforms.iBounds[4 * j + 1]) {
        i = j;
        break;
      }
    }
  }
  if (i === false) return;
  selectBand(i);
}
canvas.addEventListener("click", handleClick);
descriptionEl.addEventListener("click", handleClick);

function reloadAll () {
  reload();
  if(ALTEXT) reload(ALTEXT);
}

function reload (alt) {

  var rtxt = getChunk("red");
  var gtxt = getChunk("green");
  var btxt = getChunk("blue");
  var atxt = getChunk("alpha");

  var defines = {
    "CLUBBER": "1",
    "CLUBBER_R": rtxt,
    "CLUBBER_G": gtxt,
    "CLUBBER_B": btxt,
    "CLUBBER_A": atxt
  };

  var txt = [
    "void mainImage(out vec4 color, vec2 fragCoord) {",
    " vec2 uv = fragCoord/iResolution.xy;",
    " vec4 fColor = vec4(0.);",
    " vec4 fields;",
    " fields.r = CLUBBER_R;",
    " fields.g = CLUBBER_G;",
    " fields.b = CLUBBER_B;",
    " fields.a = CLUBBER_A;",
    " fields *= 0.25;",
    " for(float i = 0.; i < 2.; i++) {",
    "   for(float j = 0.; j < 2.; j++) {",
    "     vec2 center = 0.25 + vec2(mod(i, 2.0), 1.0 - mod(j,2.0)) * 0.5;",
    "     float d = dot(abs(uv-center), vec2(1.0));",
    "     float f1 = 1.0 - smoothstep(fields.r - fwidth(d), fields.r, d);",
    "     float f2 = 1.0 - smoothstep(0.25 - fwidth(d), 0.25, d);",
    "     fColor.r = (0.01 * f2 + 0.99 * f1);",
    "     fColor.rgba = fColor.gbar;",
    "     fields.rgba = fields.gbar;",
    "   }",
    " }",
    " color.rgb = fColor.a > 0. ? vec3(fColor.a):  fColor.rgb;",
    " if(color.r + color.g + color.b > 0.) color.rgb += 0.33;",
    "}"
  ].join("\n");

  var s = new Shader(gl, {
    source: alt ?  alt: txt ,
    uniforms: uniforms,
    defines: defines,
    correct: needsCorrection,
    ondone: function (obj) {
      if(!obj.programInfo) return;
      if(alt){
        if (altShader) gl.deleteProgram(altShader.programInfo.program);
        altShader = obj;
      } else {
        if (shaders[0]) gl.deleteProgram(shaders[0].programInfo.program);
        shaders[0] = obj;
      }
    }
  });

  console.log(defines);

}

var buttons = document.querySelectorAll("button");
window.addEventListener("keydown", function (e){
  if (e.altKey && e.key != "Alt") {
    var k = e.key.toLowerCase();
    var i = parseInt(k);
    var keys = {
      "r": "red",
      "g": "green",
      "b": "blue"
    };
    var pkeys = {
      "p": 0,
      "k": -5,
      "l": 5,
      "n": -30,
      "m": 30
    }
    if(!isNaN(i) && buttons[i-1].onclick){
      buttons[i-1].onclick();
    } else if(k in keys) {
      var el = document.querySelector("div."+keys[k]+" input[type=checkbox]");
      el.checked = !el.checked;
      el.onchange();
    } else if(k in pkeys) {
      var v = pkeys[k];
      if(!v) {
        if(audio.paused){
          audio.play();
        }else {
          audio.pause();
        }
      } else {
        audio.currentTime += v;
      }
    }
  }
});

function  render(time) {
  currentTime = time;
  window.requestAnimationFrame(render);
  if(!shaders[0]) return;
  clubber.update(time);
  for(var i = 0; i< 4; i++){
    var obj = data.bands[i](uniforms.iMusic, 4*i);
    uniforms.iBounds[4 * i] = obj.from / 128;
    uniforms.iBounds[4 * i + 1] = obj.to / 128;
    uniforms.iBounds[4 * i + 2] = obj.low / 128;
    uniforms.iBounds[4 * i + 3] = obj.high / 128;
  }
  uniforms.iResolution = [gl.canvas.width, gl.canvas.height,0];
  twgl.setTextureFromArray(gl, uniforms.iNotes, clubber.notes, noteTexOptions);
  data.time = time/1000;
  gl.clear(gl.COLOR_BUFFER_BIT);
  twgl.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  shaders[0].transition = altShader ? 0.8 : 1;
  if(altShader) altShader.transition = renderMods || debugMode ? 0.4 : 1;
  if(debugMode) {
    shaders[0].transition = 0.66;
    shaders[debugMode].render(data, true);
  }

  if(renderMods) shaders[0].render(data, true);
  if(altShader) altShader.render(data,true);
}

reloadAll();
updateDescriptions();
soundcloud(TRACK || localStorage.getItem("soundcloud-track") || "https://soundcloud.com/draufunddran/drauf-und-dran-2eur");
render(0);<|endoftext|>


<commit_before>/**
 * Created by Roger Jaggi on 22.10.2014.
 */

// Load the TCP Library
var net = require('net');
var atFormat = require('./atformat');
var debug = require('debug')('atformattcpsrv');
var S = require('string');
var Long = require("long");

// Start a TCP Server
module.exports = net.createServer(function (socket) {

    // Identify this client
    socket.isASCIIFormat = true;
    socket.trackerID = null;
    socket.commandQueue = [];
    socket.lastTransactionID = 0;
    socket.deviceType = null;
    socket.timeoutCount = 0;

    socket.sendCommand = function (newCommand) {

        if(newCommand) {
            if (newCommand.isValid()) {

                if (!socket.trackerID) {
                    // the Tracker sends a hearbeat after every connect
                    // if trackerID is null, then this heartbeat didn't get in until now
                    newCommand.finishAndCallCallback(socket, "No commands can be sent until initial tracker handshake is done");
                }

                socket.commandQueue.push(newCommand);
            }
            else {
                newCommand.finishAndCallCallback(socket, null);
            }
        }

        if (socket.commandQueue.length == 0) {
            // return on empty queue
            return;
        }

        var commandObject = socket.commandQueue[0];

        if (commandObject.sentTime) {
            // Currently a command is executing, wait until that command finishes
            return;
        }

        var timeoutInSeconds = 20;
        commandObject.setStatusSent(setTimeout(function(commandObj) {
            // if the result is still null, then we didn't get a response
            // in this case quit the command from the queue
            if(!commandObj.finishedTime) {
                socket.timeoutCount += 1;
                if(socket.timeoutCount > 2) {
                    debug("We got more than 2 timeouts, destroy the socket!");
                    socket.destroy();
                }

                for (var i = 0; i < socket.commandQueue.length; i++) {
                    if( socket.commandQueue[i] == commandObj ) {
                        socket._quitCommands(i, 1, "Timeout while waiting for data for command " + commandObj.command);
                        return;
                    }
                }
            }
        }, timeoutInSeconds * 1000, commandObject));

        if (socket.isASCIIFormat) {
            socket.write(commandObject.getCommandString());
            debug("Sent to tracker " + socket.trackerID, commandObject.getCommandString());
        }
        else {
            socket.write(atFormat.generateBinaryCommandRequest(socket.lastTransactionID + 1, commandObject.getCommandString()));
            debug("Sent to tracker " + socket.trackerID, commandObject.getCommandString());
        }
    };

    socket._setTrackerID = function(id) {
        var idString = S(id);

        if(!idString.isEmpty() && idString.isNumeric()) {
            var newId = idString.toString();
            var oldId = socket.trackerID;

            var sentConnectedMessage = socket.trackerID == 0 || socket.trackerID == null;
            var sentIdChangedMessage = !(oldId === newId);

            socket.trackerID = newId;

            if(sentConnectedMessage) module.exports.emit("trackerConnected", socket);
            if(sentIdChangedMessage && !sentConnectedMessage) module.exports.emit("trackerIdChanged", socket, oldId);
        }
        else {
            console.log("Connected device sent no or an invalid id, aborting connection...");
            socket.end();
        }
    };

    socket._quitCommands = function (startIndex, count, errorText) {
        // it it is not the first command, all commands before it failed. Remove then and call their callbacks
        var commands = socket.commandQueue.splice(startIndex, count);

        for (var i = 0; i < commands.length; i++) {
            commands[i].finishAndCallCallback(socket, errorText);
        }

        // send next command from the queue
        socket.sendCommand();
    };

    socket._processDataLine = function (line) {

        if (S(line).isEmpty()) return;

        if (socket.commandQueue.length > 0) {
            for (var i = 0; i < socket.commandQueue.length; i++) {
                switch (socket.commandQueue[0].parseLine(line)) {
                    case atFormat.ATCommandReturnCode.AWAIT_MORE_DATA:
                        return;

                    case atFormat.ATCommandReturnCode.SUCCESSFULLY_FINISHED:
                        socket._quitCommands(i, 1, null);
                        return;

                    case atFormat.ATCommandReturnCode.WRONG_COMMAND:
                        break;

                    case atFormat.ATCommandReturnCode.UNKNOWN_DATA: // Fall through default
                    default:
                        i = socket.commandQueue.length; // break the loop
                }
            }
        }

        // parse for async data
        var result;

        // async Data like GPS, etc.
        result = atFormat.parseASCII_TXT(line);
        if (result != null) {
            module.exports.emit('TxtDataReceived', socket, result);
            return;
        }

        result = atFormat.parseASCII_Garmin(line);
        if (result != null) {
            module.exports.emit('GarminDataReceived', socket, result);
            return;
        }

        result = atFormat.parseASCII_OBD(line);
        if (result != null) {
            module.exports.emit('OBDDataReceived', socket, result);
            return;
        }

        // GPS must be at the end, because GPS has no
        result = atFormat.parseASCII_GPS(line);
        if (result != null) {
            module.exports.emit('gpsDataReceived', socket, result);
            return;
        }

        debug('Unrecognised data: ' + line);
    };

    // Handle incoming messages from clients.
    socket.on('data', function(data) {

        socket.timeoutCount = 0;

        // check for ASCII Heartbeat Message
        if (data.readUInt16BE(0) == 0xfaf8) {
            // CareU1 Heartbeat
            try {

                var asciiAck = atFormat.atASCIIAcknowledge.parse(data);

                socket.deviceType = atFormat.DeviceTypes.CAREU1_TRACKER;
                socket.isASCIIFormat = true;

                socket._setTrackerID(asciiAck.modemID);

                // answer handshake
                socket.write(data);

                return;
            }
            catch (err) {
                debug(err, data);
            }
        }
        else if (data.readUInt16BE(0) == 0xfaf9) {
            // Netmodule Heartbeat
            try {
                var sequenceID = S(data.toString('ascii', 2, 4)).toInteger();
                var modemID = S(data.toString('ascii', 4)).toInteger();

                socket.deviceType = atFormat.DeviceTypes.NETMODULE;
                socket.isASCIIFormat = true;

                socket._setTrackerID(modemID);

                module.exports.emit('heartbeatReceived', socket, sequenceID);

                // answer handshake
                socket.write(data);

                return;
            }
            catch (err) {
                debug(err, data);
            }
        }

        // Check for Binary format
        try {
            var packet = atFormat.atBinaryResponsePacket.parse(data);

            debug("Received from tracker " + socket.trackerID, packet);

            // binary protocoll is only supported on CAREU1 Tracker
            socket.deviceType = atFormat.DeviceTypes.CAREU1_TRACKER;
            socket.isASCIIFormat = false;
            socket.lastTransactionID = packet.transactionID;
        }
        catch (err) {
            if (socket.isASCIIFormat = false) {
                console.log(err);
            }

            // Process ASCII Message
            socket.isASCIIFormat = true;
            debug("Received from tracker " + socket.trackerID, data.toString('ascii'));

            socket._processDataLine(data.toString('ascii'));
            return;
        }

        // Process Binary Message
        switch (packet.messageEncoding) {
            case 0x00: //atFormat.atAsyncStatusMessage,
                var modemIDOrIMEI = (new Long(packet.message.modemID2, packet.message.modemID1, true)).toString();

                if (packet.message.messageID == 0xAB) {
                    // heartbeat
                    socket._setTrackerID(modemIDOrIMEI);

                    module.exports.emit('heartbeatReceived', socket, packet.transactionID);
                }
                else {

                    // handle the annoying 24-bit signed integer for altitude
                    // convert to a 32 bit integer (signed / unsigned) and then divide last 8 bits away
                    var altitudeBuffer = new Buffer([packet.message.data.altitude1, packet.message.data.altitude2, packet.message.data.altitude3, 0x00]);
                    var altitude = altitudeBuffer.readInt32BE(0) / Math.pow(2, 8);

                    // GPS Position
                    var gpsObj = {
                        devicetime: atFormat.getMomentFromBinaryObject(packet.message.data.rtc).toDate(),
                        gpstime: atFormat.getMomentFromBinaryObject(packet.message.data.gps).toDate(),
                        latitude: packet.message.data.latitude / 100000,
                        longitude: packet.message.data.longitude / 100000,
                        altitude: altitude,
                        speed: packet.message.data.speed / 10,
                        direction: packet.message.data.direction / 10,
                        satelliteCount: packet.message.data.satelliteCount
                    };

                    module.exports.emit('gpsDataReceived', socket, gpsObj);
                }
                break;
            case 0x01: //atFormat.atCommandResponse,

                var lines = packet.message.messageData.toString().replace('\r\n', '\n').replace('\r', '\n').split("\n");

                for (var j = 0; j < lines.length; j++) {
                    socket._processDataLine(lines[j]);
                }
                break;

            case 0x02: //atFormat.atAsyncTextMessage, // Text

                module.exports.emit('TxtDataReceived', socket, {
                    textMessage: packet.message.textMessage,
                    deviceTime: atFormat.getMomentFromBinaryObject(packet.message.rtc).toDate(),
                    posSendingTime: atFormat.getMomentFromBinaryObject(packet.message.posSending).toDate()
                });
                return;

            case 0x03: //atFormat.atAsyncTextMessage, // Garmin

                module.exports.emit('GarminDataReceived', socket, {
                    textMessage: packet.message.textMessage,
                    deviceTime: atFormat.getMomentFromBinaryObject(packet.message.rtc).toDate(),
                    posSendingTime: atFormat.getMomentFromBinaryObject(packet.message.posSending).toDate()
                });
                return;

            case 0x04: //atFormat.atAsyncTextMessage  // OBD

                module.exports.emit('OBDDataReceived', socket, {
                    textMessage: packet.message.textMessage,
                    deviceTime: atFormat.getMomentFromBinaryObject(packet.message.rtc).toDate(),
                    posSendingTime: atFormat.getMomentFromBinaryObject(packet.message.posSending).toDate()
                });
                return;
        }

        // Acknowledge async messages
        if (packet.messageType == 0x02) {
            // answer async message with acknowledge
            socket.write(atFormat.generateBinaryAcknowledge(packet.transactionID, true));
        }
    });

    // Remove the client from the list when it leaves
    socket.on('end', function () {
        module.exports.clients.splice(module.exports.clients.indexOf(socket), 1);

        if(socket.trackerID) {
            module.exports.emit("trackerDisconnected", socket);
        }
    });

    /*
    socket.on('close', function(had_error) {
        module.exports.clients.splice(module.exports.clients.indexOf(socket), 1);
        module.exports.emit("trackerDisconnected", socket, had_error);
    });
    */

    // Put this new client in the list
    module.exports.clients.push(socket);
});

module.exports.onCommand = function(command, eventtype, callback) {
    var i;
    for(i = 0; i < atFormat.CommandList.length; i++) {
        if(atFormat.CommandList[i].isCommand(command)) {
            atFormat.CommandList[i].on(eventtype, callback);
            return atFormat.CommandList[i];
        }
    }
    return null;
};

module.exports.onCommand('MODID', 'onSuccess', function(tracker, commandObj) {
    if(!commandObj.isReadCommand() && !S(commandObj.newValue).isEmpty()) {
        tracker._setTrackerID(commandObj.newValue)
    }
});

module.exports.clients = [];

module.exports.AtCommand = atFormat.AtCommand;
module.exports.DeviceTypes = atFormat.DeviceTypes;

module.exports.sendCommand = function (trackerID, command, newValue, callback) {

    var newCommand = new atFormat.AtCommand(command, newValue, callback);

    var trackerIDString = S(trackerID);

    if(trackerIDString.isEmpty()) {
        newCommand.finishAndCallCallback(null, 'Tracker id is empty!');
        return;
    }

    if(!trackerIDString.isNumeric()) {
        newCommand.finishAndCallCallback(null, 'Tracker id ' + trackerID + ' is not numeric!');
        return;
    }

    trackerID = trackerIDString.toString();

    for (var i = 0; i < module.exports.clients.length; i++) {
        var client = module.exports.clients[i];
        if (client.trackerID && client.trackerID === trackerID) {
            client.sendCommand(newCommand);
            return;
        }
    }

    newCommand.finishAndCallCallback(null, 'Tracker id ' + trackerID + ' not found!');
};
<commit_msg>use close event<commit_after>/**
 * Created by Roger Jaggi on 22.10.2014.
 */

// Load the TCP Library
var net = require('net');
var atFormat = require('./atformat');
var debug = require('debug')('atformattcpsrv');
var S = require('string');
var Long = require("long");

// Start a TCP Server
module.exports = net.createServer(function (socket) {

    // Identify this client
    socket.isASCIIFormat = true;
    socket.trackerID = null;
    socket.commandQueue = [];
    socket.lastTransactionID = 0;
    socket.deviceType = null;
    socket.timeoutCount = 0;

    socket.sendCommand = function (newCommand) {

        if(newCommand) {
            if (newCommand.isValid()) {

                if (!socket.trackerID) {
                    // the Tracker sends a hearbeat after every connect
                    // if trackerID is null, then this heartbeat didn't get in until now
                    newCommand.finishAndCallCallback(socket, "No commands can be sent until initial tracker handshake is done");
                }

                socket.commandQueue.push(newCommand);
            }
            else {
                newCommand.finishAndCallCallback(socket, null);
            }
        }

        if (socket.commandQueue.length == 0) {
            // return on empty queue
            return;
        }

        var commandObject = socket.commandQueue[0];

        if (commandObject.sentTime) {
            // Currently a command is executing, wait until that command finishes
            return;
        }

        var timeoutInSeconds = 20;
        commandObject.setStatusSent(setTimeout(function(commandObj) {
            // if the result is still null, then we didn't get a response
            // in this case quit the command from the queue
            if(!commandObj.finishedTime) {
                socket.timeoutCount += 1;
                if(socket.timeoutCount > 2) {
                    debug("We got more than 2 timeouts, destroy the socket!");
                    socket.destroy();
                }

                for (var i = 0; i < socket.commandQueue.length; i++) {
                    if( socket.commandQueue[i] == commandObj ) {
                        socket._quitCommands(i, 1, "Timeout while waiting for data for command " + commandObj.command);
                        return;
                    }
                }
            }
        }, timeoutInSeconds * 1000, commandObject));

        if (socket.isASCIIFormat) {
            socket.write(commandObject.getCommandString());
            debug("Sent to tracker " + socket.trackerID, commandObject.getCommandString());
        }
        else {
            socket.write(atFormat.generateBinaryCommandRequest(socket.lastTransactionID + 1, commandObject.getCommandString()));
            debug("Sent to tracker " + socket.trackerID, commandObject.getCommandString());
        }
    };

    socket._setTrackerID = function(id) {
        var idString = S(id);

        if(!idString.isEmpty() && idString.isNumeric()) {
            var newId = idString.toString();
            var oldId = socket.trackerID;

            var sentConnectedMessage = socket.trackerID == 0 || socket.trackerID == null;
            var sentIdChangedMessage = !(oldId === newId);

            socket.trackerID = newId;

            if(sentConnectedMessage) module.exports.emit("trackerConnected", socket);
            if(sentIdChangedMessage && !sentConnectedMessage) module.exports.emit("trackerIdChanged", socket, oldId);
        }
        else {
            console.log("Connected device sent no or an invalid id, aborting connection...");
            socket.end();
        }
    };

    socket._quitCommands = function (startIndex, count, errorText) {
        // Remove the desired commands from the quie
        var commands = socket.commandQueue.splice(startIndex, count);

        for (var i = 0; i < commands.length; i++) {
            commands[i].finishAndCallCallback(socket, errorText);
        }

        // send next command from the queue
        socket.sendCommand();
    };

    socket._processDataLine = function (line) {

        if (S(line).isEmpty()) return;

        if (socket.commandQueue.length > 0) {
            for (var i = 0; i < socket.commandQueue.length; i++) {
                switch (socket.commandQueue[0].parseLine(line)) {
                    case atFormat.ATCommandReturnCode.AWAIT_MORE_DATA:
                        return;

                    case atFormat.ATCommandReturnCode.SUCCESSFULLY_FINISHED:
                        socket._quitCommands(i, 1, null);
                        return;

                    case atFormat.ATCommandReturnCode.WRONG_COMMAND:
                        break;

                    case atFormat.ATCommandReturnCode.UNKNOWN_DATA: // Fall through default
                    default:
                        i = socket.commandQueue.length; // break the loop
                }
            }
        }

        // parse for async data
        var result;

        // async Data like GPS, etc.
        result = atFormat.parseASCII_TXT(line);
        if (result != null) {
            module.exports.emit('TxtDataReceived', socket, result);
            return;
        }

        result = atFormat.parseASCII_Garmin(line);
        if (result != null) {
            module.exports.emit('GarminDataReceived', socket, result);
            return;
        }

        result = atFormat.parseASCII_OBD(line);
        if (result != null) {
            module.exports.emit('OBDDataReceived', socket, result);
            return;
        }

        // GPS must be at the end, because GPS has no
        result = atFormat.parseASCII_GPS(line);
        if (result != null) {
            module.exports.emit('gpsDataReceived', socket, result);
            return;
        }

        debug('Unrecognised data: ' + line);
    };

    // Handle incoming messages from clients.
    socket.on('data', function(data) {

        socket.timeoutCount = 0;

        // check for ASCII Heartbeat Message
        if (data.readUInt16BE(0) == 0xfaf8) {
            // CareU1 Heartbeat
            try {

                var asciiAck = atFormat.atASCIIAcknowledge.parse(data);

                socket.deviceType = atFormat.DeviceTypes.CAREU1_TRACKER;
                socket.isASCIIFormat = true;

                socket._setTrackerID(asciiAck.modemID);

                // answer handshake
                socket.write(data);

                return;
            }
            catch (err) {
                debug(err, data);
            }
        }
        else if (data.readUInt16BE(0) == 0xfaf9) {
            // Netmodule Heartbeat
            try {
                var sequenceID = S(data.toString('ascii', 2, 4)).toInteger();
                var modemID = S(data.toString('ascii', 4)).toInteger();

                socket.deviceType = atFormat.DeviceTypes.NETMODULE;
                socket.isASCIIFormat = true;

                socket._setTrackerID(modemID);

                module.exports.emit('heartbeatReceived', socket, sequenceID);

                // answer handshake
                socket.write(data);

                return;
            }
            catch (err) {
                debug(err, data);
            }
        }

        // Check for Binary format
        try {
            var packet = atFormat.atBinaryResponsePacket.parse(data);

            debug("Received from tracker " + socket.trackerID, packet);

            // binary protocoll is only supported on CAREU1 Tracker
            socket.deviceType = atFormat.DeviceTypes.CAREU1_TRACKER;
            socket.isASCIIFormat = false;
            socket.lastTransactionID = packet.transactionID;
        }
        catch (err) {
            if (socket.isASCIIFormat = false) {
                console.log(err);
            }

            // Process ASCII Message
            socket.isASCIIFormat = true;
            debug("Received from tracker " + socket.trackerID, data.toString('ascii'));

            socket._processDataLine(data.toString('ascii'));
            return;
        }

        // Process Binary Message
        switch (packet.messageEncoding) {
            case 0x00: //atFormat.atAsyncStatusMessage,
                var modemIDOrIMEI = (new Long(packet.message.modemID2, packet.message.modemID1, true)).toString();

                if (packet.message.messageID == 0xAB) {
                    // heartbeat
                    socket._setTrackerID(modemIDOrIMEI);

                    module.exports.emit('heartbeatReceived', socket, packet.transactionID);
                }
                else {

                    // handle the annoying 24-bit signed integer for altitude
                    // convert to a 32 bit integer (signed / unsigned) and then divide last 8 bits away
                    var altitudeBuffer = new Buffer([packet.message.data.altitude1, packet.message.data.altitude2, packet.message.data.altitude3, 0x00]);
                    var altitude = altitudeBuffer.readInt32BE(0) / Math.pow(2, 8);

                    // GPS Position
                    var gpsObj = {
                        devicetime: atFormat.getMomentFromBinaryObject(packet.message.data.rtc).toDate(),
                        gpstime: atFormat.getMomentFromBinaryObject(packet.message.data.gps).toDate(),
                        latitude: packet.message.data.latitude / 100000,
                        longitude: packet.message.data.longitude / 100000,
                        altitude: altitude,
                        speed: packet.message.data.speed / 10,
                        direction: packet.message.data.direction / 10,
                        satelliteCount: packet.message.data.satelliteCount
                    };

                    module.exports.emit('gpsDataReceived', socket, gpsObj);
                }
                break;
            case 0x01: //atFormat.atCommandResponse,

                var lines = packet.message.messageData.toString().replace('\r\n', '\n').replace('\r', '\n').split("\n");

                for (var j = 0; j < lines.length; j++) {
                    socket._processDataLine(lines[j]);
                }
                break;

            case 0x02: //atFormat.atAsyncTextMessage, // Text

                module.exports.emit('TxtDataReceived', socket, {
                    textMessage: packet.message.textMessage,
                    deviceTime: atFormat.getMomentFromBinaryObject(packet.message.rtc).toDate(),
                    posSendingTime: atFormat.getMomentFromBinaryObject(packet.message.posSending).toDate()
                });
                return;

            case 0x03: //atFormat.atAsyncTextMessage, // Garmin

                module.exports.emit('GarminDataReceived', socket, {
                    textMessage: packet.message.textMessage,
                    deviceTime: atFormat.getMomentFromBinaryObject(packet.message.rtc).toDate(),
                    posSendingTime: atFormat.getMomentFromBinaryObject(packet.message.posSending).toDate()
                });
                return;

            case 0x04: //atFormat.atAsyncTextMessage  // OBD

                module.exports.emit('OBDDataReceived', socket, {
                    textMessage: packet.message.textMessage,
                    deviceTime: atFormat.getMomentFromBinaryObject(packet.message.rtc).toDate(),
                    posSendingTime: atFormat.getMomentFromBinaryObject(packet.message.posSending).toDate()
                });
                return;
        }

        // Acknowledge async messages
        if (packet.messageType == 0x02) {
            // answer async message with acknowledge
            socket.write(atFormat.generateBinaryAcknowledge(packet.transactionID, true));
        }
    });

    // Remove the client from the list when it leaves
    socket.on('close', function(had_error) {

        debug("Close socket for device with IP " + socket.remoteAddress + " (Device-ID: " + socket.trackerID + ")" );
        socket._quitCommands(0, socket.commandQueue.length - 1, "Device disconnected");

        module.exports.clients.splice(module.exports.clients.indexOf(socket), 1);

        if(socket.trackerID) {
            module.exports.emit("trackerDisconnected", socket, had_error);
        }
    });

    /*
    socket.on('close', function(had_error) {
        module.exports.clients.splice(module.exports.clients.indexOf(socket), 1);
        module.exports.emit("trackerDisconnected", socket, had_error);
    });
    */

    // Put this new client in the list
    module.exports.clients.push(socket);
    debug("Device with remote IP " + socket.remoteAddress + " connected!");
});

module.exports.onCommand = function(command, eventtype, callback) {
    var i;
    for(i = 0; i < atFormat.CommandList.length; i++) {
        if(atFormat.CommandList[i].isCommand(command)) {
            atFormat.CommandList[i].on(eventtype, callback);
            return atFormat.CommandList[i];
        }
    }
    return null;
};

module.exports.onCommand('MODID', 'onSuccess', function(tracker, commandObj) {
    if(!commandObj.isReadCommand() && !S(commandObj.newValue).isEmpty()) {
        tracker._setTrackerID(commandObj.newValue)
    }
});

module.exports.clients = [];

module.exports.AtCommand = atFormat.AtCommand;
module.exports.DeviceTypes = atFormat.DeviceTypes;

module.exports.sendCommand = function (trackerID, command, newValue, callback) {

    var newCommand = new atFormat.AtCommand(command, newValue, callback);

    var trackerIDString = S(trackerID);

    if(trackerIDString.isEmpty()) {
        newCommand.finishAndCallCallback(null, 'Tracker id is empty!');
        return;
    }

    if(!trackerIDString.isNumeric()) {
        newCommand.finishAndCallCallback(null, 'Tracker id ' + trackerID + ' is not numeric!');
        return;
    }

    trackerID = trackerIDString.toString();

    for (var i = 0; i < module.exports.clients.length; i++) {
        var client = module.exports.clients[i];
        if (client.trackerID && client.trackerID === trackerID) {
            client.sendCommand(newCommand);
            return;
        }
    }

    newCommand.finishAndCallCallback(null, 'Tracker id ' + trackerID + ' not found!');
};
<|endoftext|>