<commit_before>/**
 * Client-side script for manipulating the debug panel on Rhymix.
 *
 * @file debug.js
 * @author Kijin Sung <kijin@kijinsung.com>
 */
$(function() {

	"use strict";

	// Find debug panel elements.
	var panel = $("#rhymix_debug_panel");
	var button = $("#rhymix_debug_button");

	// Initialize the debug button.
	$('').text("DEBUG").appendTo(button).click(function(event) {
		event.preventDefault();
		panel.css({ width: 0 }).show().animate({ width: 640 }, 200, function() {
			$(window).scrollTop(0);
		});
		button.hide();
	});

	// Initialize the debug panel.
	var header = $('

').appendTo(panel);
	header.append('
RHYMIX DEBUG
');
	header.append($('+').click(function(event) {
		panel.animate({ width: "95%" }, 300);
	}));
	header.append($('×').click(function(event) {
		event.preventDefault();
		panel.animate({ width: 0 }, 200, function() {
			panel.hide();
			button.show();
		});
	}));

	// Define a function for adding debug data to the panel.
	window.rhymix_debug_add_data = function(data, open) {

		// Define loop variables.
		var i, j, entry, num, backtrace, description;

		// New pages are open by default.
		if (open !== true && open !== false)
		{
			open = true;
		}

		// Create the page.
		var page = $('

').appendTo(panel);
		var page_body = $('

').appendTo(page);
		if (!open)
		{
			page_body.hide();
		}

		// Create the page header.
		var page_header = $('

').prependTo(page);
		page_header.append($('

').text(data.page_title).attr("title", data.url));
		page_header.append($('').text(open ? "▲" : "▼").click(function(event) {
			event.preventDefault();
			if (page_body.is(":visible")) {
				page_body.slideUp(200);
				$(this).text("▼");
			} else {
				page_body.slideDown(200);
				$(this).text("▲");
			}
		}));

		// Add general information.
		page_body.append($('

').text('General Information'));
		page_body.append($('

').text(
			'Request: ' + data.request.method + ' (' + data.request.size + ' bytes)' + "\n" +
			'Response: ' + data.response.method + ' (' + data.response.size + ' bytes)' + "\n" +
			'Time: ' + data.timing.total));

		// Add debug entries.
		if (data.entries && data.entries.length) {
			page_body.append($('

').text('Debug Entries (' + data.entries.length + ')'));
			for (i in data.entries) {
				entry = $('

').appendTo(page_body);
				num = parseInt(i) + 1; if (num < 10) num = "0" + num;
				backtrace = "";
				for (j in data.entries[i].backtrace) {
					if (data.entries[i].backtrace[j].file) {
						backtrace += "\n- " + data.entries[i].backtrace[j].file + ":" + data.entries[i].backtrace[j].line;
					}
				}
				entry.text(num + ". " + data.entries[i].message + backtrace);
			}
		}

		// Add errors.
		if (data.errors && data.errors.length) {
			page_body.append($('

').text('Errors (' + data.errors.length + ')'));
			for (i in data.errors) {
				entry = $('

').appendTo(page_body);
				num = parseInt(i) + 1; if (num < 10) num = "0" + num;
				backtrace = "";
				for (j in data.errors[i].backtrace) {
					if (data.errors[i].backtrace[j].file) {
						backtrace += "\n- " + data.errors[i].backtrace[j].file + ":" + data.errors[i].backtrace[j].line;
					}
				}
				entry.text(num + ". " + data.errors[i].type + ": " + data.errors[i].message + backtrace);
			}
		}

		// Add queries.
		if (data.queries && data.queries.length) {
			page_body.append($('

').text('Queries (' + data.queries.length + ')'));
			for (i in data.queries) {
				entry = $('

').appendTo(page_body);
				num = parseInt(i) + 1; if (num < 10) num = "0" + num;
				description = "";
				if (data.queries[i].query_connection) {
					description += "\n- Caller: " + data.queries[i].file + ":" + data.queries[i].line + " (" + data.queries[i].method + ")";
					description += "\n- Connection: " + data.queries[i].query_connection;
					description += "\n- Query Time: " + (data.queries[i].query_time ? (data.queries[i].query_time.toFixed(4) + " sec") : "");
				}
				description += "\n- Result: " + ((data.queries[i].message === "success" || !data.queries[i].message) ? "success" : ("error " + data.queries[i].error_code + " " + data.queries[i].message));
				entry.text(num + ". " + data.queries[i].query_string + description);
			}
		}
	};

	// Add debug data from the previous request.
	if (window.rhymix_debug_previous) {
		window.rhymix_debug_previous.page_title = 'PREVIOUS POST: ' + window.rhymix_debug_previous.ajax_module + "." + window.rhymix_debug_previous.ajax_act;
		rhymix_debug_add_data(window.rhymix_debug_previous, false);
	}

	// Add debug data from the current request.
	if (window.rhymix_debug_content) {
		window.rhymix_debug_content.page_title = 'MAIN PAGE';
		rhymix_debug_add_data(window.rhymix_debug_content, true);
	}

	// Add debug data from pending AJAX requests.
	if (window.rhymix_debug_pending_data) {
		while (window.rhymix_debug_pending_data.length) {
			rhymix_debug_add_data(window.rhymix_debug_pending_data.shift());
		}
	}
});
<commit_msg>Replace hyphen with bullet point<commit_after>/**
 * Client-side script for manipulating the debug panel on Rhymix.
 *
 * @file debug.js
 * @author Kijin Sung <kijin@kijinsung.com>
 */
$(function() {

	"use strict";

	// Find debug panel elements.
	var panel = $("#rhymix_debug_panel");
	var button = $("#rhymix_debug_button");

	// Initialize the debug button.
	$('').text("DEBUG").appendTo(button).click(function(event) {
		event.preventDefault();
		panel.css({ width: 0 }).show().animate({ width: 640 }, 200, function() {
			$(window).scrollTop(0);
		});
		button.hide();
	});

	// Initialize the debug panel.
	var header = $('

').appendTo(panel);
	header.append('
RHYMIX DEBUG
');
	header.append($('+').click(function(event) {
		panel.animate({ width: "95%" }, 300);
	}));
	header.append($('×').click(function(event) {
		event.preventDefault();
		panel.animate({ width: 0 }, 200, function() {
			panel.hide();
			button.show();
		});
	}));

	// Define a function for adding debug data to the panel.
	window.rhymix_debug_add_data = function(data, open) {

		// Define loop variables.
		var i, j, entry, num, backtrace, description;

		// New pages are open by default.
		if (open !== true && open !== false)
		{
			open = true;
		}

		// Create the page.
		var page = $('

').appendTo(panel);
		var page_body = $('

').appendTo(page);
		if (!open)
		{
			page_body.hide();
		}

		// Create the page header.
		var page_header = $('

').prependTo(page);
		page_header.append($('

').text(data.page_title).attr("title", data.url));
		page_header.append($('').text(open ? "▲" : "▼").click(function(event) {
			event.preventDefault();
			if (page_body.is(":visible")) {
				page_body.slideUp(200);
				$(this).text("▼");
			} else {
				page_body.slideDown(200);
				$(this).text("▲");
			}
		}));

		// Add general information.
		page_body.append($('

').text('General Information'));
		page_body.append($('

').text(
			'Request: ' + data.request.method + ' (' + data.request.size + ' bytes)' + "\n" +
			'Response: ' + data.response.method + ' (' + data.response.size + ' bytes)' + "\n" +
			'Time: ' + data.timing.total));

		// Add debug entries.
		if (data.entries && data.entries.length) {
			page_body.append($('

').text('Debug Entries (' + data.entries.length + ')'));
			for (i in data.entries) {
				entry = $('

').appendTo(page_body);
				num = parseInt(i) + 1; if (num < 10) num = "0" + num;
				backtrace = "";
				for (j in data.entries[i].backtrace) {
					if (data.entries[i].backtrace[j].file) {
						backtrace += "\n• " + data.entries[i].backtrace[j].file + ":" + data.entries[i].backtrace[j].line;
					}
				}
				entry.text(num + ". " + data.entries[i].message + backtrace);
			}
		}

		// Add errors.
		if (data.errors && data.errors.length) {
			page_body.append($('

').text('Errors (' + data.errors.length + ')'));
			for (i in data.errors) {
				entry = $('

').appendTo(page_body);
				num = parseInt(i) + 1; if (num < 10) num = "0" + num;
				backtrace = "";
				for (j in data.errors[i].backtrace) {
					if (data.errors[i].backtrace[j].file) {
						backtrace += "\n• " + data.errors[i].backtrace[j].file + ":" + data.errors[i].backtrace[j].line;
					}
				}
				entry.text(num + ". " + data.errors[i].type + ": " + data.errors[i].message + backtrace);
			}
		}

		// Add queries.
		if (data.queries && data.queries.length) {
			page_body.append($('

').text('Queries (' + data.queries.length + ')'));
			for (i in data.queries) {
				entry = $('

').appendTo(page_body);
				num = parseInt(i) + 1; if (num < 10) num = "0" + num;
				description = "";
				if (data.queries[i].query_connection) {
					description += "\n• Caller: " + data.queries[i].file + ":" + data.queries[i].line + " (" + data.queries[i].method + ")";
					description += "\n• Connection: " + data.queries[i].query_connection;
					description += "\n• Query Time: " + (data.queries[i].query_time ? (data.queries[i].query_time.toFixed(4) + " sec") : "");
				}
				description += "\n• Result: " + ((data.queries[i].message === "success" || !data.queries[i].message) ? "success" : ("error " + data.queries[i].error_code + " " + data.queries[i].message));
				entry.text(num + ". " + data.queries[i].query_string + description);
			}
		}
	};

	// Add debug data from the previous request.
	if (window.rhymix_debug_previous) {
		window.rhymix_debug_previous.page_title = 'PREVIOUS POST: ' + window.rhymix_debug_previous.ajax_module + "." + window.rhymix_debug_previous.ajax_act;
		rhymix_debug_add_data(window.rhymix_debug_previous, false);
	}

	// Add debug data from the current request.
	if (window.rhymix_debug_content) {
		window.rhymix_debug_content.page_title = 'MAIN PAGE';
		rhymix_debug_add_data(window.rhymix_debug_content, true);
	}

	// Add debug data from pending AJAX requests.
	if (window.rhymix_debug_pending_data) {
		while (window.rhymix_debug_pending_data.length) {
			rhymix_debug_add_data(window.rhymix_debug_pending_data.shift());
		}
	}
});
<|endoftext|>


<commit_before><commit_msg>implemented absence of whitespace directive<commit_after><|endoftext|>


<commit_before>/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'src-frontend',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    ENV.APP.API_HOST = 'http://localhost:8000';
    ENV.APP.API_NAMESPACE = 'api';
    ENV.APP.LOG_RESOLVER = true;
    ENV.APP.LOG_ACTIVE_GENERATION = true;
    ENV.APP.LOG_TRANSITIONS = true;
    ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {
    ENV.APP.API_HOST = 'https://sanaprotocolbuilder.me';
    ENV.APP.API_NAMESPACE = 'api';
  }

  return ENV;
};
<commit_msg>Turn off verbose logging<commit_after>/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'src-frontend',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    ENV.APP.API_HOST = 'http://localhost:8000';
    ENV.APP.API_NAMESPACE = 'api';
    ENV.APP.LOG_RESOLVER = false;
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_TRANSITIONS = false;
    ENV.APP.LOG_TRANSITIONS_INTERNAL = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {
    ENV.APP.API_HOST = 'https://sanaprotocolbuilder.me';
    ENV.APP.API_NAMESPACE = 'api';
  }

  return ENV;
};
<|endoftext|>


<commit_before>'use strict';
/* global google */

function cdEditDojoCtrl($scope, $window, $location, cdDojoService, cdCountriesService, alertService, Geocoder, gmap, auth, $state, $q, $translate, $sanitize, utilsService, currentUser, cdUsersService) {
  $scope.dojo = {};
  $scope.model = {};
  $scope.markers = [];
  $scope.buttonText = $translate.instant('Update Dojo');
  $scope.hideUserSelect = true;

  $scope.isCDFAdmin = currentUser && currentUser.data && _.contains(currentUser.data.roles, 'cdf-admin');

  var DEFAULT_COORDS = '53.3478,6.2597';

  auth.get_loggedin_user(function(user) {
    $scope.user = user;
  });

  cdDojoService.getDojoConfig(function(json){
    $scope.dojoConfig = json;
    $scope.dojoStages = json.dojoStages;
    $scope.dojoStates = json.verificationStates;
  });

  $scope.noop = angular.noop;

  $scope.toggleUserSelect = function(event){
    $scope.hideUserSelect = !$scope.hideUserSelect;
  };

  $scope.scrollToInvalid = function(form){
    $scope.getLocationFromAddress($scope.dojo);
    $scope.dojo.coordinates = $scope.dojo.place.latitude + ', ' + $scope.dojo.place.longitude;

    if(form.$invalid){
      angular.element('form[name=' + form.$name + '] .ng-invalid')[0].scrollIntoView();
    }
  };

  async.waterfall([function(done){
    var dojoId = $state.params.id;

    cdDojoService.load(dojoId, function(response) {
      if(!_.isEmpty(response)) {
        return done(null,response);
      } else {
        return done($translate.instant('Failed to load Dojo'));
      }
    });
  }, function(dojo, done){
    var query = {};

    query.dojoId = dojo.id;

    query.owner = 1;

    cdDojoService.getUsersDojos(query, function(response){

      return done(null, dojo, response[0]);
      }, function(){
        return done($translate.instant('Failed to load Dojo'));
      });

  }, function(dojo, prevFounder , done){

    if(_.isEmpty(prevFounder)){
      return done(null, dojo);
    }

    cdUsersService.load(prevFounder.userId, function(response){
      prevFounder.email = response.email;
      prevFounder.name = response.name;

      return done(null, dojo, prevFounder);
    }, function(err){
      return done(err);
    });
  }], function(err, dojo, prevFounder){
    if(err){
      alertService.showError(err);
      return;
    }

    $scope.dojo = dojo;
    $scope.prevFounder = prevFounder;
    $scope.founder  = angular.copy(prevFounder);
    loadDojoMap();
  });

  $scope.getUsersByEmails = function(email){
    if(!email || !email.length || email.length < 3) {
      $scope.users = [];
      return;
    }

    var win = function(users){
      $scope.users = users;
    };

    var fail = function(){
      alertService.showError($translate.instant('An error has occurred while loading Dojos'));
    };

    cdUsersService.getUsersByEmails(email, win, fail);
  };

  $scope.setFounder = function(founder){
    if(founder){
      $scope.founder = founder;
      $scope.founder.previousFounderId = $scope.prevFounder.userId;
      $scope.founder.dojoId = $scope.dojo.id;
    }
  }

  function loadDojoMap() {
    $scope.$watch('model.map', function(map){
      if(map) {
        var marker = new google.maps.Marker({
          map: $scope.model.map,
          position: new google.maps.LatLng(latitude, longitude)
        });
        $scope.markers.push(marker);
      }
    });

    if(gmap) {
      $scope.mapLoaded = true;

      var coordsStr = $scope.dojo.coordinates;

      if(!coordsStr){
        coordsStr = DEFAULT_COORDS;
      }

      var coordinates = coordsStr.split(',');
      var latitude  = coordinates[0];
      var longitude = coordinates[1];

      $scope.mapOptions = {
        center: new google.maps.LatLng(latitude, longitude),
        zoom: 15,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      };

    }
    $scope.dojoPageReady = true;
  }

  cdCountriesService.listCountries(function(countries) {
    $scope.countries = countries;
  });

  $scope.getPlaces = function (countryCode, $select) {
    return utilsService.getPlaces(countryCode, $select).then(function (data) {
      $scope.places = data;
    }, function (err) {
      $scope.places = [];
      console.error(err);
    });
  }

  $scope.setCountry = function(dojo, country) {
    dojo.countryName = country.countryName;
    dojo.countryNumber = country.countryNumber;
    dojo.continent = country.continent;
    dojo.alpha2 = country.alpha2;
    dojo.alpha3 = country.alpha3;
  };

  $scope.setPlace = function(dojo, place) {
    dojo.placeName = place.name;
    dojo.placeGeonameId = place.geonameId;
    dojo.county = {};
    dojo.state = {};
    dojo.city = {};
    for (var adminidx=1; adminidx<=4; adminidx++) {
      dojo['admin'+ adminidx + 'Code'] = place['admin'+ adminidx + 'Code'];
      dojo['admin'+ adminidx + 'Name'] = place['admin'+ adminidx + 'Name'];
    }
  };

  var sanitizeCdForms = {
    editDojo: ["address1","email","googleGroup","name","needMentors","notes","supporterImage","time","twitter","website"]
  }

  $scope.save = function(dojo) {
    canUpdateDojo().then(function (isDojoAdmin) {
      if(isDojoAdmin) {
        _.each(sanitizeCdForms.editDojo, function(item, i) {
          if(_.has(dojo, item)) {
            dojo[item] = $sanitize(dojo[item]);
          }
        });

        cdDojoService.save(dojo, function(response) {
          if(($scope.founder.id !== ($scope.prevFounder && $scope.prevFounder.id))){
            cdDojoService.updateFounder($scope.founder, function(response){
              alertService.showAlert($translate.instant("Your Dojo has been successfully saved"), function() {
                $state.go('my-dojos');
                $scope.$apply();
              });
            }, function(err){
              alertService.showError($translate.instant('An error has occurred while saving'));
            });
          } else {
            alertService.showAlert($translate.instant("Your Dojo has been successfully saved"), function() {
              $state.go('my-dojos');
              $scope.$apply();
            });
          }

        }, function(err) {
          alertService.showError(
            $translate.instant('An error has occurred while saving') + ':
 '+
            (err.error || JSON.stringify(err))
          );
        });
      } else {
        alertService.showAlert($translate.instant('You do not have permission to update this Dojo.'));
      }
    });
  }

  $scope.addMarker = function($event, $params, dojo) {
    angular.forEach($scope.markers, function(marker) {
      marker.setMap(null);
    });
    $scope.markers.push(new google.maps.Marker({
      map: $scope.model.map,
      position: $params[0].latLng
    }));
    dojo.coordinates = $params[0].latLng.lat() + ', ' + $params[0].latLng.lng();
  };

  $scope.getLocationFromAddress = function(dojo) {
    if(dojo) {
      if(!dojo.address1) dojo.address1 = '';
      if(!dojo.address2) dojo.address2 = '';
      if(!dojo.city) dojo.city = '';
      if(!dojo.county) dojo.county = '';
      if(!dojo.state) dojo.state = '';
      if(!dojo.country)  dojo.country  = '';
      var address = dojo.city.toponymName + ', ' + dojo.county.toponymName + ', ' + dojo.state.toponymName + ', ' + dojo.country.countryName;
      Geocoder.latLngForAddress(address).then(function (data) {
        $scope.mapOptions.center = new google.maps.LatLng(data.lat, data.lng);
        $scope.model.map.panTo($scope.mapOptions.center);
      });
    }
  }

  function canUpdateDojo() {
    var deferred = $q.defer();
    var query = {userId: currentUser.data.id, dojoId: $state.params.id};
    cdDojoService.getUsersDojos(query, function (userDojo) {
      var isDojoAdmin = _.find(userDojo[0].userPermissions, function (userPermission) {
        return userPermission.name === 'dojo-admin';
      });
      deferred.resolve(isDojoAdmin);
    }, function (err) {
      deferred.reject(err);
    });
    return deferred.promise;
  }

  $scope.editorOptions = {
    language: 'en',
    uiColor: '#000000',
    height:'200px'
  };

}

angular.module('cpZenPlatform')
  .controller('edit-dojo-controller', ['$scope', '$window', '$location', 'cdDojoService', 'cdCountriesService', 'alertService', 'Geocoder', 'gmap', 'auth', '$state', '$q', '$translate', '$sanitize', 'utilsService', 'currentUser', 'cdUsersService', cdEditDojoCtrl]);

<commit_msg>allow cdf admins to edit dojos<commit_after>'use strict';
/* global google */

function cdEditDojoCtrl($scope, $window, $location, cdDojoService, cdCountriesService, alertService, Geocoder, gmap, auth, $state, $q, $translate, $sanitize, utilsService, currentUser, cdUsersService) {
  $scope.dojo = {};
  $scope.model = {};
  $scope.markers = [];
  $scope.buttonText = $translate.instant('Update Dojo');
  $scope.hideUserSelect = true;

  $scope.isCDFAdmin = currentUser && currentUser.data && _.contains(currentUser.data.roles, 'cdf-admin');

  var DEFAULT_COORDS = '53.3478,6.2597';

  auth.get_loggedin_user(function(user) {
    $scope.user = user;
  });

  cdDojoService.getDojoConfig(function(json){
    $scope.dojoConfig = json;
    $scope.dojoStages = json.dojoStages;
    $scope.dojoStates = json.verificationStates;
  });

  $scope.noop = angular.noop;

  $scope.toggleUserSelect = function(event){
    $scope.hideUserSelect = !$scope.hideUserSelect;
  };

  $scope.scrollToInvalid = function(form){
    $scope.getLocationFromAddress($scope.dojo);
    $scope.dojo.coordinates = $scope.dojo.place.latitude + ', ' + $scope.dojo.place.longitude;

    if(form.$invalid){
      angular.element('form[name=' + form.$name + '] .ng-invalid')[0].scrollIntoView();
    }
  };

  async.waterfall([function(done){
    var dojoId = $state.params.id;

    cdDojoService.load(dojoId, function(response) {
      if(!_.isEmpty(response)) {
        return done(null,response);
      } else {
        return done($translate.instant('Failed to load Dojo'));
      }
    });
  }, function(dojo, done){
    var query = {};

    query.dojoId = dojo.id;

    query.owner = 1;

    cdDojoService.getUsersDojos(query, function(response){

      return done(null, dojo, response[0]);
      }, function(){
        return done($translate.instant('Failed to load Dojo'));
      });

  }, function(dojo, prevFounder , done){

    if(_.isEmpty(prevFounder)){
      return done(null, dojo);
    }

    cdUsersService.load(prevFounder.userId, function(response){
      prevFounder.email = response.email;
      prevFounder.name = response.name;

      return done(null, dojo, prevFounder);
    }, function(err){
      return done(err);
    });
  }], function(err, dojo, prevFounder){
    if(err){
      alertService.showError(err);
      return;
    }

    $scope.dojo = dojo;
    $scope.prevFounder = prevFounder;
    $scope.founder  = angular.copy(prevFounder);
    loadDojoMap();
  });

  $scope.getUsersByEmails = function(email){
    if(!email || !email.length || email.length < 3) {
      $scope.users = [];
      return;
    }

    var win = function(users){
      $scope.users = users;
    };

    var fail = function(){
      alertService.showError($translate.instant('An error has occurred while loading Dojos'));
    };

    cdUsersService.getUsersByEmails(email, win, fail);
  };

  $scope.setFounder = function(founder){
    if(founder){
      $scope.founder = founder;
      $scope.founder.previousFounderId = $scope.prevFounder.userId;
      $scope.founder.dojoId = $scope.dojo.id;
    }
  }

  function loadDojoMap() {
    $scope.$watch('model.map', function(map){
      if(map) {
        var marker = new google.maps.Marker({
          map: $scope.model.map,
          position: new google.maps.LatLng(latitude, longitude)
        });
        $scope.markers.push(marker);
      }
    });

    if(gmap) {
      $scope.mapLoaded = true;

      var coordsStr = $scope.dojo.coordinates;

      if(!coordsStr){
        coordsStr = DEFAULT_COORDS;
      }

      var coordinates = coordsStr.split(',');
      var latitude  = coordinates[0];
      var longitude = coordinates[1];

      $scope.mapOptions = {
        center: new google.maps.LatLng(latitude, longitude),
        zoom: 15,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      };

    }
    $scope.dojoPageReady = true;
  }

  cdCountriesService.listCountries(function(countries) {
    $scope.countries = countries;
  });

  $scope.getPlaces = function (countryCode, $select) {
    return utilsService.getPlaces(countryCode, $select).then(function (data) {
      $scope.places = data;
    }, function (err) {
      $scope.places = [];
      console.error(err);
    });
  }

  $scope.setCountry = function(dojo, country) {
    dojo.countryName = country.countryName;
    dojo.countryNumber = country.countryNumber;
    dojo.continent = country.continent;
    dojo.alpha2 = country.alpha2;
    dojo.alpha3 = country.alpha3;
  };

  $scope.setPlace = function(dojo, place) {
    dojo.placeName = place.name;
    dojo.placeGeonameId = place.geonameId;
    dojo.county = {};
    dojo.state = {};
    dojo.city = {};
    for (var adminidx=1; adminidx<=4; adminidx++) {
      dojo['admin'+ adminidx + 'Code'] = place['admin'+ adminidx + 'Code'];
      dojo['admin'+ adminidx + 'Name'] = place['admin'+ adminidx + 'Name'];
    }
  };

  var sanitizeCdForms = {
    editDojo: ["address1","email","googleGroup","name","needMentors","notes","supporterImage","time","twitter","website"]
  }

  $scope.save = function(dojo) {
    canUpdateDojo().then(function (isDojoAdmin) {
      if(isDojoAdmin) {
        _.each(sanitizeCdForms.editDojo, function(item, i) {
          if(_.has(dojo, item)) {
            dojo[item] = $sanitize(dojo[item]);
          }
        });

        cdDojoService.save(dojo, function(response) {
          if(($scope.founder.id !== ($scope.prevFounder && $scope.prevFounder.id))){
            cdDojoService.updateFounder($scope.founder, function(response){
              alertService.showAlert($translate.instant("Your Dojo has been successfully saved"), function() {
                $state.go('my-dojos');
                $scope.$apply();
              });
            }, function(err){
              alertService.showError($translate.instant('An error has occurred while saving'));
            });
          } else {
            alertService.showAlert($translate.instant("Your Dojo has been successfully saved"), function() {
              $state.go('my-dojos');
              $scope.$apply();
            });
          }

        }, function(err) {
          alertService.showError(
            $translate.instant('An error has occurred while saving') + ':
 '+
            (err.error || JSON.stringify(err))
          );
        });
      } else {
        alertService.showAlert($translate.instant('You do not have permission to update this Dojo.'));
      }
    });
  }

  $scope.addMarker = function($event, $params, dojo) {
    angular.forEach($scope.markers, function(marker) {
      marker.setMap(null);
    });
    $scope.markers.push(new google.maps.Marker({
      map: $scope.model.map,
      position: $params[0].latLng
    }));
    dojo.coordinates = $params[0].latLng.lat() + ', ' + $params[0].latLng.lng();
  };

  $scope.getLocationFromAddress = function(dojo) {
    if(dojo) {
      if(!dojo.address1) dojo.address1 = '';
      if(!dojo.address2) dojo.address2 = '';
      if(!dojo.city) dojo.city = '';
      if(!dojo.county) dojo.county = '';
      if(!dojo.state) dojo.state = '';
      if(!dojo.country)  dojo.country  = '';
      var address = dojo.city.toponymName + ', ' + dojo.county.toponymName + ', ' + dojo.state.toponymName + ', ' + dojo.country.countryName;
      Geocoder.latLngForAddress(address).then(function (data) {
        $scope.mapOptions.center = new google.maps.LatLng(data.lat, data.lng);
        $scope.model.map.panTo($scope.mapOptions.center);
      });
    }
  }

  function canUpdateDojo() {
    var deferred = $q.defer();
    var query = {userId: currentUser.data.id, dojoId: $state.params.id};
    var isCDFAdmin = _.contains(currentUser.data.roles, 'cdf-admin');
    if(isCDFAdmin) {
      deferred.resolve(isCDFAdmin);
    } else {
      cdDojoService.getUsersDojos(query, function (userDojo) {
        var isDojoAdmin = _.find(userDojo[0].userPermissions, function (userPermission) {
          return userPermission.name === 'dojo-admin';
        });
        deferred.resolve(isDojoAdmin);
      }, function (err) {
        deferred.reject(err);
      });
    }
    return deferred.promise;
  }

  $scope.editorOptions = {
    language: 'en',
    uiColor: '#000000',
    height:'200px'
  };

}

angular.module('cpZenPlatform')
  .controller('edit-dojo-controller', ['$scope', '$window', '$location', 'cdDojoService', 'cdCountriesService', 'alertService', 'Geocoder', 'gmap', 'auth', '$state', '$q', '$translate', '$sanitize', 'utilsService', 'currentUser', 'cdUsersService', cdEditDojoCtrl]);

<|endoftext|>


<commit_before><commit_msg>fixing AI<commit_after><|endoftext|>


<commit_before>define('datagramas', ['d3', 'legend', 'd3-tip'], function(d3, legend, tip) {
    "use strict";

    var datagramas = {};

    // we wrap d3-legend and d3-tip
    datagramas.legend = legend;
    datagramas.tip = tip;

    datagramas.add_css = function(url) {
        d3.select('head').append('link').attr({rel: 'stylesheet', href: url});
    };

    datagramas.move_to_front = function(selection) {
        /**
         * Makes all elements in the selection to be on front (over) other elements in the same group.
         *
         * Source: https://gist.github.com/trtg/3922684
         */
        selection.each(function(){
            this.parentNode.appendChild(this);
        });
    };

    datagramas.prepare_graph = function(graph) {
        /**
         * Sets the expected structure by d3.js on a NetworkX graph.
         */
        if (graph.hasOwnProperty('__datagramas_prepared__') && graph['__datagramas_prepared__'] == true) {
            return;
        }

        var node_map = d3.map();

        graph.nodes.forEach(function(d) {
            node_map.set(d.id, d);
        });

        graph.nodes.forEach(function(d) {
            if (d.parent != null) {
                d.parent = node_map.get(d.parent);
            }
        });

        graph.links.forEach(function(d) {
            d.source = graph.nodes[d.source];
            d.target = graph.nodes[d.target];
        });

        // graph attributes
        if (graph.hasOwnProperty('graph') && Array.isArray(graph.graph)) {
            graph.graph.forEach(function (d) {
                graph[d[0]] = d[1];
            });
        }

        graph['__datagramas_prepared__'] = true;
        console.log('prepared graph', graph);
    };

    datagramas.scale = function(name) {
        /**
         * Helper function to build scales.
         * In this way, in python we can define scales by name ('linear', 'sqrt', 'log') or exponent (e.g., 0.5).
         */
        if (d3.scale.hasOwnProperty(name)) {
            return d3.scale[name]();
        }

        return d3.scale.pow().exponent(name);
    };

    datagramas.fit_projection = function(width, height, bounding_box) {
        /**
         * Given width and height, and a bounding box, returns the projection parameters to fit the box into the screen.
         * Based on http://bl.ocks.org/mbostock/4573883
         */
        var b = bounding_box;
        var s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height);
        var t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
        return [s, t];
    };

    datagramas.get = function(obj, path) {
        /**
         * Given a path to an object member (e.g., 'parent.name'), return the object if it exists, null otherwise.
         */
        if (path === null) {
            return null;
        }

        if (typeof(path) === 'number') {
            return obj[path];
        }

        var current = obj;
        var properties = path.split('.');

        for (var i = 0; i < properties.length; i++) {
            var property = properties[i];
            if (!current.hasOwnProperty(property)) {
                current = null;
                break;
            }

            current = current[property];
        }
        return current;
    };

    datagramas.text_color = function(color) {
        /**
         * Given a color, return a suitable text color.
         * Function extracted from the D3 Plus library at http://d3plus.org/
         */
        var b, g, r, rgbColor, yiq;
        rgbColor = d3.rgb(color);
        r = rgbColor.r;
        g = rgbColor.g;
        b = rgbColor.b;
        yiq = (r * 299 + g * 587 + b * 114) / 1000;
        if (yiq >= 128) {
            return "#444444";
        } else {
            return "#f7f7f7";
        }
    };

    datagramas.to_time_string = function(timedelta) {
        /**
         * Given a timedelta serialized as the number of seconds, returns a string with 'HH:MM:SS' format.
         */
        var duration = moment.duration(timedelta, 'seconds');
        var hours = '' + duration.hours();
        if (hours.length == 1) {
            hours = '0' + hours;
        }
        var minutes = '' + duration.minutes();
        if (minutes.length == 1) {
            minutes = '0' + minutes;
        }

        var seconds = '' + duration.seconds();
        if (seconds.length == 1) {
            seconds = '0' + seconds;
        }
        return hours + ':' + minutes + ':' + seconds;
    };

    datagramas.generate_uuid = function() {
        /**
         * Generates a random unique string.
         *
         * Source: http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript/8809472#8809472
         */
        var d = new Date().getTime();
        if (window.performance && typeof window.performance.now === "function") {
            d += performance.now(); //use high-precision timer if available
        }
        var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
        });
        return uuid;
    };

    return datagramas;
});<commit_msg>datagramas.get can receive a function now<commit_after>define('datagramas', ['d3', 'legend', 'd3-tip'], function(d3, legend, tip) {
    "use strict";

    var datagramas = {};

    // we wrap d3-legend and d3-tip
    datagramas.legend = legend;
    datagramas.tip = tip;

    datagramas.add_css = function(url) {
        d3.select('head').append('link').attr({rel: 'stylesheet', href: url});
    };

    datagramas.move_to_front = function(selection) {
        /**
         * Makes all elements in the selection to be on front (over) other elements in the same group.
         *
         * Source: https://gist.github.com/trtg/3922684
         */
        selection.each(function(){
            this.parentNode.appendChild(this);
        });
    };

    datagramas.prepare_graph = function(graph) {
        /**
         * Sets the expected structure by d3.js on a NetworkX graph.
         */
        if (graph.hasOwnProperty('__datagramas_prepared__') && graph['__datagramas_prepared__'] == true) {
            return;
        }

        var node_map = d3.map();

        graph.nodes.forEach(function(d) {
            node_map.set(d.id, d);
        });

        graph.nodes.forEach(function(d) {
            if (d.parent != null) {
                d.parent = node_map.get(d.parent);
            }
        });

        graph.links.forEach(function(d) {
            d.source = graph.nodes[d.source];
            d.target = graph.nodes[d.target];
        });

        // graph attributes
        if (graph.hasOwnProperty('graph') && Array.isArray(graph.graph)) {
            graph.graph.forEach(function (d) {
                graph[d[0]] = d[1];
            });
        }

        graph['__datagramas_prepared__'] = true;
        console.log('prepared graph', graph);
    };

    datagramas.scale = function(name) {
        /**
         * Helper function to build scales.
         * In this way, in python we can define scales by name ('linear', 'sqrt', 'log') or exponent (e.g., 0.5).
         */
        if (d3.scale.hasOwnProperty(name)) {
            return d3.scale[name]();
        }

        return d3.scale.pow().exponent(name);
    };

    datagramas.fit_projection = function(width, height, bounding_box) {
        /**
         * Given width and height, and a bounding box, returns the projection parameters to fit the box into the screen.
         * Based on http://bl.ocks.org/mbostock/4573883
         */
        var b = bounding_box;
        var s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height);
        var t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];
        return [s, t];
    };

    datagramas.get = function(obj, path_or_function) {
        /**
         * Given a path to an object member (e.g., 'parent.name'), return the object if it exists, null otherwise.
         * Otherwise, if it is a function, call it with the object as argument.
         */
        if (path_or_function === null) {
            return null;
        }

        if (typeof(path_or_function) === 'function') {
            return path_or_function(obj);
        }

        if (typeof(path_or_function) === 'number') {
            return obj[path_or_function];
        }

        var current = obj;
        var properties = path_or_function.split('.');

        for (var i = 0; i < properties.length; i++) {
            var property = properties[i];
            if (!current.hasOwnProperty(property)) {
                current = null;
                break;
            }

            current = current[property];
        }
        return current;
    };

    datagramas.text_color = function(color) {
        /**
         * Given a color, return a suitable text color.
         * Function extracted from the D3 Plus library at http://d3plus.org/
         */
        var b, g, r, rgbColor, yiq;
        rgbColor = d3.rgb(color);
        r = rgbColor.r;
        g = rgbColor.g;
        b = rgbColor.b;
        yiq = (r * 299 + g * 587 + b * 114) / 1000;
        if (yiq >= 128) {
            return "#444444";
        } else {
            return "#f7f7f7";
        }
    };

    datagramas.to_time_string = function(timedelta) {
        /**
         * Given a timedelta serialized as the number of seconds, returns a string with 'HH:MM:SS' format.
         */
        var duration = moment.duration(timedelta, 'seconds');
        var hours = '' + duration.hours();
        if (hours.length == 1) {
            hours = '0' + hours;
        }
        var minutes = '' + duration.minutes();
        if (minutes.length == 1) {
            minutes = '0' + minutes;
        }

        var seconds = '' + duration.seconds();
        if (seconds.length == 1) {
            seconds = '0' + seconds;
        }
        return hours + ':' + minutes + ':' + seconds;
    };

    datagramas.generate_uuid = function() {
        /**
         * Generates a random unique string.
         *
         * Source: http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript/8809472#8809472
         */
        var d = new Date().getTime();
        if (window.performance && typeof window.performance.now === "function") {
            d += performance.now(); //use high-precision timer if available
        }
        var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
        });
        return uuid;
    };

    return datagramas;
});<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

'use strict';

var async = require('async');
var HKDF = require('hkdf');
var uuid = require('node-uuid');
var request = require('request');

var decrypt = require('../encrypt').decrypt;
var encrypt = require('../encrypt').encrypt;
var errors = require('../errno.json');
var getUserAccount = require('../utils').getUserAccount;
var sendError = require('../utils').sendError;
var tokenlib = require('../tokenlib');

var hmac = require('../hmac');

module.exports = function (apiRouter, conf, logError, storage, auth,
                           validators, tokBox) {

  var roomsConf = conf.get("rooms");

  /**
   * Returns the maximum number of allowed participants, between a list of
   * participants and the maximum size of a room.
   *
   * @param {Array} participants, the list of participants. Each participant
   *                object should contain a "clientMaxSize" property.
   * @param {Number} roomMaxSize, the maximum size of the room.
   **/
  function getClientMaxSize(participants, roomMaxSize) {
    var clientMaxSize = Math.min.apply(Math, participants.map(
      function(participant) {
        return participant.clientMaxSize;
      }));
    return Math.min(clientMaxSize, roomMaxSize);
  }

  /**
   * Ping the room Owner simplePush rooms endpoints.
   *
   * @param {String} roomOwnerHmac, the hmac-ed owner,
   * @param {Number} version, the version to pass in the request,
   * @param {Function} callback(err), called when notification is complete.
   **/
  function notifyOwner(roomOwnerHmac, version, callback) {
    storage.getUserSimplePushURLs(roomOwnerHmac,
      function(err, simplePushURLsMapping) {
        if (err) {
          callback(err);
          return;
        }
        simplePushURLsMapping.rooms.forEach(function(simplePushUrl) {
          request.put({
            url: simplePushUrl,
            form: { version: version }
          }, function() {
            // Catch errors.
          });
        });
        callback(null);
      });
  }

  /**
   * Update room data and emit an event if needed so the owner is aware.
   *
   * @param roomToken The roomToken
   * @param userIdHmac The roomOwnerHmac
   * @param callback The action to do next
   **/
  function emitRoomEvent(roomToken, roomOwnerHmac, callback) {
    storage.touchRoomData(roomToken, function(err, version) {
      if (err) {
        callback(err);
        return;
      }
      notifyOwner(roomOwnerHmac, version, callback);
    });
  }

  /**
   * Encrypt an account name with the roomID and a secret known only by
   * the server. This is useful as we don't want to store PII on our databases.
   *
   * @param {String} roomToken, the token of the room
   * @param {String} account the account information to encrypt
   * @param {Function} callback which will receive the encrypted account info.
   **/
  function encryptAccountName(roomToken, account, callback) {
    if (account === undefined) {
      callback();
      return;
    }
    var hkdf = new HKDF('sha256', roomsConf.HKDFSalt, roomToken);
    hkdf.derive('account-name', 32, function(key) {
      callback(encrypt(key.toString('hex'), account));
    });
  }
  /**
   * Decrypts an encrypted account information using the roomID and a
   * secret known only by the server.
   *
   * @param {String} roomToken, the token of the room
   * @param {String} encrypted account information to decrypt.
   * @param {Function} callback which will receive the decrypted account info.
   **/
  function decryptAccountName(roomToken, encryptedAccount, callback) {
    if (encryptedAccount === undefined) {
      callback();
      return;
    }
    var hkdf = new HKDF('sha256', roomsConf.HKDFSalt, roomToken);
    hkdf.derive('account-name', 32, function(key) {
      callback(decrypt(key.toString('hex'), encryptedAccount));
    });
  }

  /**
   * Create a new room with the given information
   **/
  apiRouter.post('/rooms', auth.requireHawkSession,
    validators.requireParams('roomName', 'roomOwner', 'maxSize'),
    validators.validateRoomUrlParams, function(req, res) {

      var roomData = req.roomRequestData;
      var token = tokenlib.generateToken(roomsConf.tokenSize);
      var now = parseInt(Date.now() / 1000, 10);
      roomData.creationTime = now;
      roomData.updateTime = now;
      roomData.expiresAt = now + roomData.expiresIn * tokenlib.ONE_HOUR;
      roomData.roomOwnerHmac = req.user;

      tokBox.getSession(function(err, session, opentok) {
        if (res.serverError(err)) return;

        roomData.sessionId = session.sessionId;
        roomData.apiKey = opentok.apiKey;

        storage.setUserRoomData(req.user, token, roomData, function(err) {
          if (res.serverError(err)) return;
          notifyOwner(req.user, roomData.updateTime, function(err) {
            if (res.serverError(err)) return;
            res.status(201).json({
              roomToken: token,
              roomUrl: roomsConf.webAppUrl.replace('{token}', token),
              expiresAt: roomData.expiresAt
            });
          });
        });
      });
    });

  /**
   * Updates information about a room.
   **/
  apiRouter.patch('/rooms/:token', auth.requireHawkSession,
    validators.validateRoomToken, validators.validateRoomUrlParams,
    validators.isRoomOwner, function(req, res) {
      var now = parseInt(Date.now() / 1000, 10);
      var roomData = req.roomStorageData;

      roomData.updateTime = now;

      // Update the roomData object with new data from the request.
      Object.keys(req.roomRequestData).map(function(key) {
        roomData[key] = req.roomRequestData[key];
      });

      roomData.expiresAt = now + roomData.expiresIn * tokenlib.ONE_HOUR;

      storage.setUserRoomData(req.user, req.token, roomData, function(err) {
        if (res.serverError(err)) return;
        notifyOwner(req.user, now, function(err) {
          if (res.serverError(err)) return;
          res.status(200).json({
            expiresAt: roomData.expiresAt
          });
        });
      });
    });

  /**
   * Deletes a room.
   * This only works if you're the owner of this room.
   **/
  apiRouter.delete('/rooms/:token', auth.requireHawkSession,
    validators.validateRoomToken, validators.isRoomOwner,
    function(req, res) {
      storage.deleteRoomData(req.token, function(err) {
        if (res.serverError(err)) return;
        var now = parseInt(Date.now() / 1000, 10);
        notifyOwner(req.user, now, function(err) {
          if (res.serverError(err)) return;
          res.status(204).json({});
        });
      });
    });

  /**
   * Retrieves information about a specific room.
   **/
  apiRouter.get('/rooms/:token', auth.requireHawkSession,
    validators.validateRoomToken, validators.isRoomParticipant,
    function(req, res) {
      var clientMaxSize = getClientMaxSize(
        req.roomStorageData.participants,
        req.roomStorageData.maxSize
      );

      // Since the participant information is stored encrypted,
      // there is a need to decrypt it using async.map as it is an async
      // operation.
      async.map(req.roomStorageData.participants,
        function(participant, callback) {
          decryptAccountName(req.token, participant.account, function(account) {
            participant.account = account;
            callback(null, participant);
          });
        }, function(err, participants) {
          if (res.serverError(err)) return;
          res.status(200).json({
            roomUrl: roomsConf.webAppUrl.replace('{token}', req.token),
            roomName: req.roomStorageData.roomName,
            roomOwner: req.roomStorageData.roomOwner,
            maxSize: req.roomStorageData.maxSize,
            clientMaxSize: clientMaxSize,
            creationTime: req.roomStorageData.creationTime,
            expiresAt: req.roomStorageData.expiresAt,
            ctime: req.roomStorageData.updateTime,
            participants: participants
          });
        });
    });

  /**
   * Do an action on a room.
   *
   * Actions are "join", "leave", "refresh".
   **/
  apiRouter.post('/rooms/:token', validators.validateRoomToken, auth.authenticateWithHawkOrToken,
    function(req, res) {
      var participantHmac = req.hawkIdHmac || req.participantTokenHmac;
      var ROOM_ACTIONS = ["join", "refresh", "leave"];
      var action = req.body.action;
      var code;

      if (ROOM_ACTIONS.indexOf(action) === -1) {
        if (req.body.hasOwnProperty('action')) {
          code = errors.INVALID_PARAMETERS;
        } else {
          code = errors.MISSING_PARAMETERS;
        }
        sendError(res, 400, code,
                  "action should be one of " + ROOM_ACTIONS.join(", "));
        return;
      }

      // If the action is not join, they should be authenticated.
      if (participantHmac === "undefined" && action !== "join") {
        var header = 'Token, Hawk';
        res.set('WWW-Authenticate', header);
        sendError(res, 401, errors.INVALID_AUTH_TOKEN, "Unauthorized");
        return;
      }

      var handlers = {
        handleJoin: function(req, res) {
          validators.requireParams('displayName', 'clientMaxSize')(
            req, res, function() {
              var requestMaxSize = parseInt(req.body.clientMaxSize, 10);
              if (isNaN(requestMaxSize)) {
                sendError(res, 400, errors.INVALID_PARAMETERS,
                          "clientMaxSize should be a number.");
                return;
              }
              var ttl = roomsConf.participantTTL;
              var sessionToken = tokBox.getSessionToken(
                req.roomStorageData.sessionId
              );

              function next(err) {
                storage.getRoomParticipants(req.token, function(err,
                  participants) {
                    if (res.serverError(err)) return;
                    var clientMaxSize = getClientMaxSize(
                      participants,
                      req.roomStorageData.maxSize
                    );

                    if (clientMaxSize <= participants.length) {
                      // The room is already full.
                      sendError(res, 400, errors.ROOM_FULL,
                                "The room is full.");
                      return;
                    } else if (requestMaxSize <= participants.length) {
                      // You cannot handle the number of actual participants.
                      sendError(res, 400, errors.CLIENT_REACHED_CAPACITY,
                        "Too many participants in the room for you to handle.");
                      return;
                    }

                    getUserAccount(storage, req, function(err, acc) {
                      encryptAccountName(req.token, acc, function(account) {
                        if (res.serverError(err)) return;
                        storage.addRoomParticipant(req.token, participantHmac, {
                          id: uuid.v4(),
                          displayName: req.body.displayName,
                          clientMaxSize: requestMaxSize,
                          userIdHmac: req.user,
                          account: account
                        }, ttl, function(err) {
                          if (res.serverError(err)) return;
                          emitRoomEvent(req.token,
                            req.roomStorageData.roomOwnerHmac, function(err) {
                              if (res.serverError(err)) return;
                              res.status(200).json({
                                apiKey: req.roomStorageData.apiKey,
                                sessionId: req.roomStorageData.sessionId,
                                sessionToken: sessionToken,
                                expires: ttl
                              });
                            });
                        });
                      });
                    });
                });
              }
              if (participantHmac === undefined) {
                participantHmac = hmac(sessionToken, conf.get('userMacSecret'));
                storage.setRoomToken(req.token, participantHmac, ttl, next);
                return;
              }
              next();
            });
        },
        handleRefresh: function(req, res) {
          var ttl = roomsConf.participantTTL;
          storage.touchRoomParticipant(req.token, participantHmac, ttl,
            function(err, success) {
              if (res.serverError(err)) return;
              if (success !== true) {
                sendError(res, 410, errors.EXPIRED, "Participation has expired.");
                return;
              }
              res.status(200).json({
                expires: ttl
              });
            });
        },
        handleLeave: function(req, res) {
          storage.deleteRoomParticipant(req.token, participantHmac,
            function(err) {
              if (res.serverError(err)) return;
              emitRoomEvent(req.token, req.roomStorageData.roomOwnerHmac,
                function(err) {
                  if (res.serverError(err)) return;
                  res.status(204).json();
                });
            });
        }
      };

      if (action === "join") {
        handlers.handleJoin(req, res);
      } else if (action === "refresh") {
        handlers.handleRefresh(req, res);
      } else if (action === "leave") {
        handlers.handleLeave(req, res);
      }
    });

  /**
   * List all the rooms for the connected user.
   **/

  apiRouter.get('/rooms', auth.requireHawkSession, function(req, res) {
    var version = req.query.version;
    storage.getUserRooms(req.user, function(err, rooms) {
      if (res.serverError(err)) return;
      var roomsData = rooms.map(function(room) {
        if (version && room.updateTime < version) {
          return null;
        }
        return {
          roomToken: room.roomToken,
          roomUrl: roomsConf.webAppUrl.replace('{token}', room.roomToken),
          roomName: room.roomName,
          maxSize: room.maxSize,
          currSize: room.currSize,
          ctime: room.updateTime
        };
      }).filter(function(room) {
        return room !== null;
      });
      res.status(200).json(roomsData);
    });
  });
};
<commit_msg>Don't forget to handle errors.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

'use strict';

var async = require('async');
var HKDF = require('hkdf');
var uuid = require('node-uuid');
var request = require('request');

var decrypt = require('../encrypt').decrypt;
var encrypt = require('../encrypt').encrypt;
var errors = require('../errno.json');
var getUserAccount = require('../utils').getUserAccount;
var sendError = require('../utils').sendError;
var tokenlib = require('../tokenlib');

var hmac = require('../hmac');

module.exports = function (apiRouter, conf, logError, storage, auth,
                           validators, tokBox) {

  var roomsConf = conf.get("rooms");

  /**
   * Returns the maximum number of allowed participants, between a list of
   * participants and the maximum size of a room.
   *
   * @param {Array} participants, the list of participants. Each participant
   *                object should contain a "clientMaxSize" property.
   * @param {Number} roomMaxSize, the maximum size of the room.
   **/
  function getClientMaxSize(participants, roomMaxSize) {
    var clientMaxSize = Math.min.apply(Math, participants.map(
      function(participant) {
        return participant.clientMaxSize;
      }));
    return Math.min(clientMaxSize, roomMaxSize);
  }

  /**
   * Ping the room Owner simplePush rooms endpoints.
   *
   * @param {String} roomOwnerHmac, the hmac-ed owner,
   * @param {Number} version, the version to pass in the request,
   * @param {Function} callback(err), called when notification is complete.
   **/
  function notifyOwner(roomOwnerHmac, version, callback) {
    storage.getUserSimplePushURLs(roomOwnerHmac,
      function(err, simplePushURLsMapping) {
        if (err) {
          callback(err);
          return;
        }
        simplePushURLsMapping.rooms.forEach(function(simplePushUrl) {
          request.put({
            url: simplePushUrl,
            form: { version: version }
          }, function() {
            // Catch errors.
          });
        });
        callback(null);
      });
  }

  /**
   * Update room data and emit an event if needed so the owner is aware.
   *
   * @param roomToken The roomToken
   * @param userIdHmac The roomOwnerHmac
   * @param callback The action to do next
   **/
  function emitRoomEvent(roomToken, roomOwnerHmac, callback) {
    storage.touchRoomData(roomToken, function(err, version) {
      if (err) {
        callback(err);
        return;
      }
      notifyOwner(roomOwnerHmac, version, callback);
    });
  }

  /**
   * Encrypt an account name with the roomID and a secret known only by
   * the server. This is useful as we don't want to store PII on our databases.
   *
   * @param {String} roomToken, the token of the room
   * @param {String} account the account information to encrypt
   * @param {Function} callback which will receive the encrypted account info.
   **/
  function encryptAccountName(roomToken, account, callback) {
    if (account === undefined) {
      callback();
      return;
    }
    var hkdf = new HKDF('sha256', roomsConf.HKDFSalt, roomToken);
    hkdf.derive('account-name', 32, function(key) {
      callback(encrypt(key.toString('hex'), account));
    });
  }
  /**
   * Decrypts an encrypted account information using the roomID and a
   * secret known only by the server.
   *
   * @param {String} roomToken, the token of the room
   * @param {String} encrypted account information to decrypt.
   * @param {Function} callback which will receive the decrypted account info.
   **/
  function decryptAccountName(roomToken, encryptedAccount, callback) {
    if (encryptedAccount === undefined) {
      callback();
      return;
    }
    var hkdf = new HKDF('sha256', roomsConf.HKDFSalt, roomToken);
    hkdf.derive('account-name', 32, function(key) {
      callback(decrypt(key.toString('hex'), encryptedAccount));
    });
  }

  /**
   * Create a new room with the given information
   **/
  apiRouter.post('/rooms', auth.requireHawkSession,
    validators.requireParams('roomName', 'roomOwner', 'maxSize'),
    validators.validateRoomUrlParams, function(req, res) {

      var roomData = req.roomRequestData;
      var token = tokenlib.generateToken(roomsConf.tokenSize);
      var now = parseInt(Date.now() / 1000, 10);
      roomData.creationTime = now;
      roomData.updateTime = now;
      roomData.expiresAt = now + roomData.expiresIn * tokenlib.ONE_HOUR;
      roomData.roomOwnerHmac = req.user;

      tokBox.getSession(function(err, session, opentok) {
        if (res.serverError(err)) return;

        roomData.sessionId = session.sessionId;
        roomData.apiKey = opentok.apiKey;

        storage.setUserRoomData(req.user, token, roomData, function(err) {
          if (res.serverError(err)) return;
          notifyOwner(req.user, roomData.updateTime, function(err) {
            if (res.serverError(err)) return;
            res.status(201).json({
              roomToken: token,
              roomUrl: roomsConf.webAppUrl.replace('{token}', token),
              expiresAt: roomData.expiresAt
            });
          });
        });
      });
    });

  /**
   * Updates information about a room.
   **/
  apiRouter.patch('/rooms/:token', auth.requireHawkSession,
    validators.validateRoomToken, validators.validateRoomUrlParams,
    validators.isRoomOwner, function(req, res) {
      var now = parseInt(Date.now() / 1000, 10);
      var roomData = req.roomStorageData;

      roomData.updateTime = now;

      // Update the roomData object with new data from the request.
      Object.keys(req.roomRequestData).map(function(key) {
        roomData[key] = req.roomRequestData[key];
      });

      roomData.expiresAt = now + roomData.expiresIn * tokenlib.ONE_HOUR;

      storage.setUserRoomData(req.user, req.token, roomData, function(err) {
        if (res.serverError(err)) return;
        notifyOwner(req.user, now, function(err) {
          if (res.serverError(err)) return;
          res.status(200).json({
            expiresAt: roomData.expiresAt
          });
        });
      });
    });

  /**
   * Deletes a room.
   * This only works if you're the owner of this room.
   **/
  apiRouter.delete('/rooms/:token', auth.requireHawkSession,
    validators.validateRoomToken, validators.isRoomOwner,
    function(req, res) {
      storage.deleteRoomData(req.token, function(err) {
        if (res.serverError(err)) return;
        var now = parseInt(Date.now() / 1000, 10);
        notifyOwner(req.user, now, function(err) {
          if (res.serverError(err)) return;
          res.status(204).json({});
        });
      });
    });

  /**
   * Retrieves information about a specific room.
   **/
  apiRouter.get('/rooms/:token', auth.requireHawkSession,
    validators.validateRoomToken, validators.isRoomParticipant,
    function(req, res) {
      var clientMaxSize = getClientMaxSize(
        req.roomStorageData.participants,
        req.roomStorageData.maxSize
      );

      // Since the participant information is stored encrypted,
      // there is a need to decrypt it using async.map as it is an async
      // operation.
      async.map(req.roomStorageData.participants,
        function(participant, callback) {
          decryptAccountName(req.token, participant.account, function(account) {
            participant.account = account;
            callback(null, participant);
          });
        }, function(err, participants) {
          if (res.serverError(err)) return;
          res.status(200).json({
            roomUrl: roomsConf.webAppUrl.replace('{token}', req.token),
            roomName: req.roomStorageData.roomName,
            roomOwner: req.roomStorageData.roomOwner,
            maxSize: req.roomStorageData.maxSize,
            clientMaxSize: clientMaxSize,
            creationTime: req.roomStorageData.creationTime,
            expiresAt: req.roomStorageData.expiresAt,
            ctime: req.roomStorageData.updateTime,
            participants: participants
          });
        });
    });

  /**
   * Do an action on a room.
   *
   * Actions are "join", "leave", "refresh".
   **/
  apiRouter.post('/rooms/:token', validators.validateRoomToken, auth.authenticateWithHawkOrToken,
    function(req, res) {
      var participantHmac = req.hawkIdHmac || req.participantTokenHmac;
      var ROOM_ACTIONS = ["join", "refresh", "leave"];
      var action = req.body.action;
      var code;

      if (ROOM_ACTIONS.indexOf(action) === -1) {
        if (req.body.hasOwnProperty('action')) {
          code = errors.INVALID_PARAMETERS;
        } else {
          code = errors.MISSING_PARAMETERS;
        }
        sendError(res, 400, code,
                  "action should be one of " + ROOM_ACTIONS.join(", "));
        return;
      }

      // If the action is not join, they should be authenticated.
      if (participantHmac === "undefined" && action !== "join") {
        var header = 'Token, Hawk';
        res.set('WWW-Authenticate', header);
        sendError(res, 401, errors.INVALID_AUTH_TOKEN, "Unauthorized");
        return;
      }

      var handlers = {
        handleJoin: function(req, res) {
          validators.requireParams('displayName', 'clientMaxSize')(
            req, res, function() {
              var requestMaxSize = parseInt(req.body.clientMaxSize, 10);
              if (isNaN(requestMaxSize)) {
                sendError(res, 400, errors.INVALID_PARAMETERS,
                          "clientMaxSize should be a number.");
                return;
              }
              var ttl = roomsConf.participantTTL;
              var sessionToken = tokBox.getSessionToken(
                req.roomStorageData.sessionId
              );

              function next(err) {
                if (res.serverError(err)) return;
                storage.getRoomParticipants(req.token, function(err,
                  participants) {
                    if (res.serverError(err)) return;
                    var clientMaxSize = getClientMaxSize(
                      participants,
                      req.roomStorageData.maxSize
                    );

                    if (clientMaxSize <= participants.length) {
                      // The room is already full.
                      sendError(res, 400, errors.ROOM_FULL,
                                "The room is full.");
                      return;
                    } else if (requestMaxSize <= participants.length) {
                      // You cannot handle the number of actual participants.
                      sendError(res, 400, errors.CLIENT_REACHED_CAPACITY,
                        "Too many participants in the room for you to handle.");
                      return;
                    }

                    getUserAccount(storage, req, function(err, acc) {
                      if (res.serverError(err)) return;
                      encryptAccountName(req.token, acc, function(account) {
                        storage.addRoomParticipant(req.token, participantHmac, {
                          id: uuid.v4(),
                          displayName: req.body.displayName,
                          clientMaxSize: requestMaxSize,
                          userIdHmac: req.user,
                          account: account
                        }, ttl, function(err) {
                          if (res.serverError(err)) return;
                          emitRoomEvent(req.token,
                            req.roomStorageData.roomOwnerHmac, function(err) {
                              if (res.serverError(err)) return;
                              res.status(200).json({
                                apiKey: req.roomStorageData.apiKey,
                                sessionId: req.roomStorageData.sessionId,
                                sessionToken: sessionToken,
                                expires: ttl
                              });
                            });
                        });
                      });
                    });
                });
              }
              if (participantHmac === undefined) {
                participantHmac = hmac(sessionToken, conf.get('userMacSecret'));
                storage.setRoomToken(req.token, participantHmac, ttl, next);
                return;
              }
              next();
            });
        },
        handleRefresh: function(req, res) {
          var ttl = roomsConf.participantTTL;
          storage.touchRoomParticipant(req.token, participantHmac, ttl,
            function(err, success) {
              if (res.serverError(err)) return;
              if (success !== true) {
                sendError(res, 410, errors.EXPIRED, "Participation has expired.");
                return;
              }
              res.status(200).json({
                expires: ttl
              });
            });
        },
        handleLeave: function(req, res) {
          storage.deleteRoomParticipant(req.token, participantHmac,
            function(err) {
              if (res.serverError(err)) return;
              emitRoomEvent(req.token, req.roomStorageData.roomOwnerHmac,
                function(err) {
                  if (res.serverError(err)) return;
                  res.status(204).json();
                });
            });
        }
      };

      if (action === "join") {
        handlers.handleJoin(req, res);
      } else if (action === "refresh") {
        handlers.handleRefresh(req, res);
      } else if (action === "leave") {
        handlers.handleLeave(req, res);
      }
    });

  /**
   * List all the rooms for the connected user.
   **/

  apiRouter.get('/rooms', auth.requireHawkSession, function(req, res) {
    var version = req.query.version;
    storage.getUserRooms(req.user, function(err, rooms) {
      if (res.serverError(err)) return;
      var roomsData = rooms.map(function(room) {
        if (version && room.updateTime < version) {
          return null;
        }
        return {
          roomToken: room.roomToken,
          roomUrl: roomsConf.webAppUrl.replace('{token}', room.roomToken),
          roomName: room.roomName,
          maxSize: room.maxSize,
          currSize: room.currSize,
          ctime: room.updateTime
        };
      }).filter(function(room) {
        return room !== null;
      });
      res.status(200).json(roomsData);
    });
  });
};
<|endoftext|>


<commit_before>-ace.define("ace/mode/verilog_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function(e, t, n) {
    "use strict";
    var r = e("../lib/oop"),
        i = e("./text_highlight_rules").TextHighlightRules,
        s = function() {
            var e = "if|endif",
                t = "use",
                n = "near|with|around|mention",
                r = this.createKeywordMapper({
                    "support.function": n,
                    keyword: e,
                    "constant.language": t
                }, "identifier", !0);
            this.$rules = {
                start: [{
                    token: "comment",
                    regex: "//.*$"
                }, {
                    token: "comment.start",
                    regex: "/\\*",
                    next: [{
                        token: "comment.end",
                        regex: "\\*/",
                        next: "start"
                    }, {
                        defaultToken: "comment"
                    }]
                }, {
                    token: "string",
                    regex: '".*?"'
                }, {
                    token: "string",
                    regex: "'.*?'"
                }, {
                    token: "constant.numeric",
                    regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
                }, {
                    token: r,
                    regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
                }, {
                    token: "keyword.operator",
                    regex: "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="
                }, {
                    token: "paren.lparen",
                    regex: "[\\(]"
                }, {
                    token: "paren.rparen",
                    regex: "[\\)]"
                }, {
                    token: "text",
                    regex: "\\s+"
                }, {
                    token: "if.start",
                    regex: "IF"
                }, {
                    token: "if.end",
                    regex: "ENDIF"
                }]
            }, this.normalizeRules()
        };
    r.inherits(s, i), t.VerilogHighlightRules = s
}), ace.define("ace/mode/verilog", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text", "ace/mode/verilog_highlight_rules", "ace/range"], function(e, t, n) {
    "use strict";
    var r = e("../lib/oop"),
        i = e("./text").Mode,
        s = e("./verilog_highlight_rules").VerilogHighlightRules,
        o = e("../range").Range,
        u = function() {
            this.HighlightRules = s, this.$behaviour = this.$defaultBehaviour
        };
    r.inherits(u, i),
        function() {
            this.lineCommentStart = "//", this.blockComment = {
                start: "/*",
                end: "*/"
            }, this.$id = "ace/mode/verilog"
        }.call(u.prototype), t.Mode = u
})
<commit_msg>Update mode-verilog.js<commit_after>-ace.define("ace/mode/verilog_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function(e, t, n) {
    "use strict";
    var r = e("../lib/oop"),
        i = e("./text_highlight_rules").TextHighlightRules,
        s = function() {
            var e = "if|endif|else if",
                t = "use",
                n = "near|with|around|mention",
                r = this.createKeywordMapper({
                    "support.function": n,
                    keyword: e,
                    "constant.language": t
                }, "identifier", !0);
            this.$rules = {
                start: [{
                    token: "comment",
                    regex: "//.*$"
                }, {
                    token: "comment.start",
                    regex: "/\\*",
                    next: [{
                        token: "comment.end",
                        regex: "\\*/",
                        next: "start"
                    }, {
                        defaultToken: "comment"
                    }]
                }, {
                    token: "string",
                    regex: '".*?"'
                }, {
                    token: "string",
                    regex: "'.*?'"
                }, {
                    token: "constant.numeric",
                    regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
                }, {
                    token: r,
                    regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
                }, {
                    token: "keyword.operator",
                    regex: "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=|or"
                }, {
                    token: "paren.lparen",
                    regex: "[\\(]"
                }, {
                    token: "paren.rparen",
                    regex: "[\\)]"
                }, {
                    token: "text",
                    regex: "\\s+"
                }, {
                    token: "if.start",
                    regex: "IF"
                }, {
                    token: "if.end",
                    regex: "ENDIF"
                }]
            }, this.normalizeRules()
        };
    r.inherits(s, i), t.VerilogHighlightRules = s
}), ace.define("ace/mode/verilog", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text", "ace/mode/verilog_highlight_rules", "ace/range"], function(e, t, n) {
    "use strict";
    var r = e("../lib/oop"),
        i = e("./text").Mode,
        s = e("./verilog_highlight_rules").VerilogHighlightRules,
        o = e("../range").Range,
        u = function() {
            this.HighlightRules = s, this.$behaviour = this.$defaultBehaviour
        };
    r.inherits(u, i),
        function() {
            this.lineCommentStart = "//", this.blockComment = {
                start: "/*",
                end: "*/"
            }, this.$id = "ace/mode/verilog"
        }.call(u.prototype), t.Mode = u
})
<|endoftext|>


<commit_before>var M = {};
M.loader = $('#ajax_wrap, #ajax_loader');
M.loadCount = 0;
M.loadCheck = function(){
	if ( this.loadCount > 0 ){
		this.loader.show();
	}
	else
	{
		this.loader.hide();
	}
}
M.init = function(){
	M.etsy.init();
	$('#etsy .more').tappable(function(){
		M.etsy.more();
	});

	M.write.get();
	$('#write .more').tappable(function(){
		M.write.get();
	});

	M.art.get();
	$('#art .more').tappable(function(){
		M.art.get();
	});

	$('.home').tappable(function(){
		M.nav.home();
	});

	if ( $('.mobNav').css('display') == 'block' ){
		if (History.getState().cleanUrl == "http://catandglove.com/"){
			router.navigate('/etsy');
		}
	}

	$('[show]:not(.prep)').addClass('prep').tappable(function(){
		var show = $(this).attr('show');
		router.navigate('/'+show);
		$('[show].act').removeClass('act');
		$('[show='+show+']').addClass('act');
	});
	router.checkRoutes(History.getState());
}

M.etsy = {};
M.etsy.items = {};
M.etsy.page = 0;
M.etsy.limit = 10;
M.etsy.isMore = true;
M.etsy.get = function(){
	if ( M.etsy.isMore ){
		limit = M.etsy.limit;
		var offset = M.etsy.page*limit;
		var url = 'http://openapi.etsy.com/v2/shops/catandglove/listings/active.js?callback=getData&api_key=3lrt6kdjs0ppzxvxj1ypo0m4&includes=Images&limit='+limit+'&order=date_desc&offset='+offset;
		M.loadCount++;
		M.loadCheck();
		$.ajax({
		url:url,
		dataType: 'jsonp'
		}).done(function(data){
			M.loadCount--;
			M.loadCheck();
			if (data.ok){
			M.etsy.page++;
			var count = 0;
				for (x in data.results)
				{
					count++;
					var result = data.results[x];
					if (M.etsy.items[result.listing_id] == undefined){
						M.etsy.items[result.listing_id] = result;
					}
				}
				if ( count < limit ) { M.etsy.isMore = false;}
				M.etsy.render();
			}
			else
			{

			}
		})
		.fail(function(){
		M.loadCount--;
		M.loadCheck();
		});
	}
}
M.etsy.hideMoreButton = function (){
	$('#etsy .more').hide();
}
M.etsy.showMoreButton = function (){
	$('#etsy .more').show();
}
M.etsy.render = function(){
	var itemTemp = '

{{{title}}}

';
	var etsyHTML = [];

	for (x in M.etsy.items){
		var result = M.etsy.items[x];
		if (result.rendered == undefined){
			result.image = result.Images[0]['url_570xN'];
			etsyHTML.push(Mustache.render(itemTemp, result));
			M.etsy.items[x]['rendered'] = true;
		}
	}

	var loadHTML = function(){
		if (etsyHTML.length > 0)
		{
			var $item = $(etsyHTML.pop());
			$('#etsy .items').append($item);
			$item.hide().fadeIn(1000);
			setTimeout(loadHTML, 100);
		}
		else
		{
			$('.etsyItem:not(prepped)').addClass('prepped').tappable(function(){
				var eid = $(this).attr('eid');
				router.navigate('/etsy/'+eid);
			});
			if ( M.etsy.isMore ){
				M.etsy.showMoreButton();
			}
			else
			{
				M.etsy.hideMoreButton();
			}
		}
	}
	loadHTML();
}
M.etsy.renderItem = function (data) {
M.nav.makeActive($('#etsy'));
var tmpl = '

{{{description}}}
<button class="button">View on etsy</button>

Price - {{price}} {{currency_code}}

Style - {{style_string}}

{{{image_list}}}

';
data.style_string = '';
var eid = data.listing_id;
for (x in data.style)
{
	data.style_string += data.style[x] +', ';
}
if (data.style_string.length > 0)
{
	data.style_string= data.style_string.substr(0, data.style_string.length-2);
}
data.description = data.description.replace(/\n/g,"
");

data.image_list = '';
var a = 0;
for (x in data.Images ){
	if (a == 0){
		data.image_list+='

';
		a++;
	} else
	{
		data.image_list+='

';
	}
}

var res = Mustache.render(tmpl, data);
$('[eid='+eid+']').after(res);
scrollTo(0, $('[eid='+eid+']').offset().top);
window.s = new Swipe($('.gal')[0]);
var myPhotoSwipe = $(".gal a").photoSwipe({ enableMouseWheel: false , enableKeyboard: true });
}

M.restoreItems = function (){
 $('.itemDetails').remove();
 $('.activeItem').removeClass('activeItem');
}
M.etsy.init = M.etsy.get;
M.etsy.more = M.etsy.get;

function WP(category){
	this.category = category;
	this.items = {};
	this.page = 1;
	this.limit = 10;
	this.isMore = true;
	this.get = function(){
		if ( this.isMore ){
			var wp = this;
			url = '/press?json=get_category_posts&category_slug='+this.category+'&count='+this.limit+'&page='+this.page;
			M.loadCount++;
			M.loadCheck();
			$.get(url).
			done( function( data ){
				M.loadCount--;
				M.loadCheck();
				if ( data.status == 'ok' ){
					wp.page++;
					var count = 0;
					for ( x in data.posts ){
						count++;
						var result = data.posts[x];
						wp.items[result['slug']] = result;
					}
					if ( count < wp.limit ) { wp.isMore = false;}
				}
				wp.render();
			})
			.fail(function(){
			M.loadCount--;
			M.loadCheck();
			});
		}
	}
}

M.write = new WP('write');
M.write.showMoreButton = function(){
	$('#write .more').show();
};
M.write.hideMoreButton = function(){
	$('#write .more').hide();
};
M.write.render = function(){
	var itemTemp = '

{{{title}}}
{{{content}}}

';
	var writeHTML = [];

	for (x in this.items){
		var result = this.items[x];
		if (result.rendered == undefined){
			//result.image = result.Images[0]['url_570xN'];
			writeHTML.push(Mustache.render(itemTemp, result));
			this.items[x]['rendered'] = true;
		}
	}

	var loadHTML = function(){
		if (writeHTML.length > 0)
		{
			var $item = $(writeHTML.pop());
			$('#write .items').append($item);
			$item.hide().fadeIn(1000);
			setTimeout(loadHTML, 100);
		}
		else
		{
			if ( M.write.isMore ){
				M.write.showMoreButton();
			}
			else
			{
				M.write.hideMoreButton();
			}
		}
	}
	loadHTML();
}

M.art = new WP('art');
M.art.render = function(){

	var itemTemp = 	'

{{{title}}}

';
	var artHTML = [];

	for ( x in this.items ){
		var result = this.items[x];
		if ( result.rendered == undefined ){
			//result.image = result.Images[0]['url_570xN'];
			artHTML.push(Mustache.render(itemTemp, result));
			this.items[x]['rendered'] = true;
		}
	}

	var loadHTML = function(){
		if (artHTML.length > 0)
		{
			var $item = $(artHTML.pop());
			$('#art .items').append($item);
			$item.hide().fadeIn(1000);
			setTimeout(loadHTML, 100);
		}
		else
		{
			if ( M.art.isMore ){
				M.art.showMoreButton();
			}
			else
			{
				M.art.hideMoreButton();
			}
		}
	}
	loadHTML();
}
M.art.showMoreButton = function(){
	$('#art .more').show();
};
M.art.hideMoreButton = function(){
	$('#art .more').hide();
};

M.nav = {};

M.nav.home = function () {
	router.navigate('/');
}
M.nav.makeActive = function ($id){
	if ( !$id.hasClass('eight') ){
		var id = $id.attr('id');
		$('[show]').removeClass('act');
		$('[show='+id+']').addClass('act');
		$('.content>.eight').removeClass('eight').removeClass('offset-by-two').addClass('four');
		$('.hidden').removeClass('hidden');
		$('#etsy, #write, #art').addClass('hidden');
		$id.removeClass('hidden').removeClass('four').addClass('eight').addClass('offset-by-two');
	}
}
M.nav.removeActive = function($id){
$('#etsy, #write, #art').removeClass('hidden');
$('.content>.eight').removeClass('eight').removeClass('offset-by-two').addClass('four');
}
M.nav.pageByID = function(type, id){

	if ( M[type]['items'][id] != undefined )
	{
		$('[eid='+id+']').addClass('activeItem');
		var data = M[type]['items'][id];
		M[type]['renderItem']( data );
		scrollTo(0, $('.activeItem').offset().top);
	}
	else
	{
		M[type]['getSingle'](id);

	}
}

var router = new Router();
router.route('/', function(){
	M.restoreItems();
	M.nav.removeActive();
});
router.route('/etsy', function(){
	M.restoreItems();
	M.nav.makeActive($('#etsy'));
});
router.route('/etsy/:id', function(id){
	M.restoreItems();
	M.nav.pageByID('etsy', id);
});
router.route('/write', function(){
	M.restoreItems();
	M.nav.makeActive($('#write'));
});
router.route('/write/:id', function(id){
	M.restoreItems();
	M.nav.pageByID('write', id);
});
router.route('/art', function(){
	M.restoreItems();
	M.nav.makeActive($('#art'));
});
router.route('/art/:id', function(id){
	M.restoreItems();
	M.nav.pageByID('art', id);
});

<commit_msg>remove link from images in writeItem<commit_after>var M = {};
M.loader = $('#ajax_wrap, #ajax_loader');
M.loadCount = 0;
M.loadCheck = function(){
	if ( this.loadCount > 0 ){
		this.loader.show();
	}
	else
	{
		this.loader.hide();
	}
}
M.init = function(){
	M.etsy.init();
	$('#etsy .more').tappable(function(){
		M.etsy.more();
	});

	M.write.get();
	$('#write .more').tappable(function(){
		M.write.get();
	});

	M.art.get();
	$('#art .more').tappable(function(){
		M.art.get();
	});

	$('.home').tappable(function(){
		M.nav.home();
	});

	if ( $('.mobNav').css('display') == 'block' ){
		if (History.getState().cleanUrl == "http://catandglove.com/"){
			router.navigate('/etsy');
		}
	}

	$('[show]:not(.prep)').addClass('prep').tappable(function(){
		var show = $(this).attr('show');
		router.navigate('/'+show);
		$('[show].act').removeClass('act');
		$('[show='+show+']').addClass('act');
	});
	router.checkRoutes(History.getState());
}

M.etsy = {};
M.etsy.items = {};
M.etsy.page = 0;
M.etsy.limit = 10;
M.etsy.isMore = true;
M.etsy.get = function(){
	if ( M.etsy.isMore ){
		limit = M.etsy.limit;
		var offset = M.etsy.page*limit;
		var url = 'http://openapi.etsy.com/v2/shops/catandglove/listings/active.js?callback=getData&api_key=3lrt6kdjs0ppzxvxj1ypo0m4&includes=Images&limit='+limit+'&order=date_desc&offset='+offset;
		M.loadCount++;
		M.loadCheck();
		$.ajax({
		url:url,
		dataType: 'jsonp'
		}).done(function(data){
			M.loadCount--;
			M.loadCheck();
			if (data.ok){
			M.etsy.page++;
			var count = 0;
				for (x in data.results)
				{
					count++;
					var result = data.results[x];
					if (M.etsy.items[result.listing_id] == undefined){
						M.etsy.items[result.listing_id] = result;
					}
				}
				if ( count < limit ) { M.etsy.isMore = false;}
				M.etsy.render();
			}
			else
			{

			}
		})
		.fail(function(){
		M.loadCount--;
		M.loadCheck();
		});
	}
}
M.etsy.hideMoreButton = function (){
	$('#etsy .more').hide();
}
M.etsy.showMoreButton = function (){
	$('#etsy .more').show();
}
M.etsy.render = function(){
	var itemTemp = '

{{{title}}}

';
	var etsyHTML = [];

	for (x in M.etsy.items){
		var result = M.etsy.items[x];
		if (result.rendered == undefined){
			result.image = result.Images[0]['url_570xN'];
			etsyHTML.push(Mustache.render(itemTemp, result));
			M.etsy.items[x]['rendered'] = true;
		}
	}

	var loadHTML = function(){
		if (etsyHTML.length > 0)
		{
			var $item = $(etsyHTML.pop());
			$('#etsy .items').append($item);
			$item.hide().fadeIn(1000);
			setTimeout(loadHTML, 100);
		}
		else
		{
			$('.etsyItem:not(prepped)').addClass('prepped').tappable(function(){
				var eid = $(this).attr('eid');
				router.navigate('/etsy/'+eid);
			});
			if ( M.etsy.isMore ){
				M.etsy.showMoreButton();
			}
			else
			{
				M.etsy.hideMoreButton();
			}
		}
	}
	loadHTML();
}
M.etsy.renderItem = function (data) {
M.nav.makeActive($('#etsy'));
var tmpl = '

{{{description}}}
<button class="button">View on etsy</button>

Price - {{price}} {{currency_code}}

Style - {{style_string}}

{{{image_list}}}

';
data.style_string = '';
var eid = data.listing_id;
for (x in data.style)
{
	data.style_string += data.style[x] +', ';
}
if (data.style_string.length > 0)
{
	data.style_string= data.style_string.substr(0, data.style_string.length-2);
}
data.description = data.description.replace(/\n/g,"
");

data.image_list = '';
var a = 0;
for (x in data.Images ){
	if (a == 0){
		data.image_list+='

';
		a++;
	} else
	{
		data.image_list+='

';
	}
}

var res = Mustache.render(tmpl, data);
$('[eid='+eid+']').after(res);
scrollTo(0, $('[eid='+eid+']').offset().top);
window.s = new Swipe($('.gal')[0]);
var myPhotoSwipe = $(".gal a").photoSwipe({ enableMouseWheel: false , enableKeyboard: true });
}

M.restoreItems = function (){
 $('.itemDetails').remove();
 $('.activeItem').removeClass('activeItem');
}
M.etsy.init = M.etsy.get;
M.etsy.more = M.etsy.get;

function WP(category){
	this.category = category;
	this.items = {};
	this.page = 1;
	this.limit = 10;
	this.isMore = true;
	this.get = function(){
		if ( this.isMore ){
			var wp = this;
			url = '/press?json=get_category_posts&category_slug='+this.category+'&count='+this.limit+'&page='+this.page;
			M.loadCount++;
			M.loadCheck();
			$.get(url).
			done( function( data ){
				M.loadCount--;
				M.loadCheck();
				if ( data.status == 'ok' ){
					wp.page++;
					var count = 0;
					for ( x in data.posts ){
						count++;
						var result = data.posts[x];
						wp.items[result['slug']] = result;
					}
					if ( count < wp.limit ) { wp.isMore = false;}
				}
				wp.render();
			})
			.fail(function(){
			M.loadCount--;
			M.loadCheck();
			});
		}
	}
}

M.write = new WP('write');
M.write.showMoreButton = function(){
	$('#write .more').show();
};
M.write.hideMoreButton = function(){
	$('#write .more').hide();
};
M.write.render = function(){
	var itemTemp = '

{{{title}}}
{{{content}}}

';
	var writeHTML = [];

	for (x in this.items){
		var result = this.items[x];
		if (result.rendered == undefined){
			//result.image = result.Images[0]['url_570xN'];
			writeHTML.push(Mustache.render(itemTemp, result));
			this.items[x]['rendered'] = true;
		}
	}

	var loadHTML = function(){
		if (writeHTML.length > 0)
		{
			var $item = $(writeHTML.pop());
			$('#write .items').append($item);
			$item.hide().fadeIn(1000);
			setTimeout(loadHTML, 100);
		}
		else
		{
			if ( M.write.isMore ){
				M.write.showMoreButton();
			}
			else
			{
				M.write.hideMoreButton();
			}
		}
	}
	loadHTML();
	$('.writeItem a img').each(function(){
	var image = $(this).html('img');
	var a = $(this).parent('a').before(image).remove();
	});
}

M.art = new WP('art');
M.art.render = function(){

	var itemTemp = 	'

{{{title}}}

';
	var artHTML = [];

	for ( x in this.items ){
		var result = this.items[x];
		if ( result.rendered == undefined ){
			//result.image = result.Images[0]['url_570xN'];
			artHTML.push(Mustache.render(itemTemp, result));
			this.items[x]['rendered'] = true;
		}
	}

	var loadHTML = function(){
		if (artHTML.length > 0)
		{
			var $item = $(artHTML.pop());
			$('#art .items').append($item);
			$item.hide().fadeIn(1000);
			setTimeout(loadHTML, 100);
		}
		else
		{
			if ( M.art.isMore ){
				M.art.showMoreButton();
			}
			else
			{
				M.art.hideMoreButton();
			}
		}
	}
	loadHTML();
}
M.art.showMoreButton = function(){
	$('#art .more').show();
};
M.art.hideMoreButton = function(){
	$('#art .more').hide();
};

M.nav = {};

M.nav.home = function () {
	router.navigate('/');
}
M.nav.makeActive = function ($id){
	if ( !$id.hasClass('eight') ){
		var id = $id.attr('id');
		$('[show]').removeClass('act');
		$('[show='+id+']').addClass('act');
		$('.content>.eight').removeClass('eight').removeClass('offset-by-two').addClass('four');
		$('.hidden').removeClass('hidden');
		$('#etsy, #write, #art').addClass('hidden');
		$id.removeClass('hidden').removeClass('four').addClass('eight').addClass('offset-by-two');
	}
}
M.nav.removeActive = function($id){
$('#etsy, #write, #art').removeClass('hidden');
$('.content>.eight').removeClass('eight').removeClass('offset-by-two').addClass('four');
}
M.nav.pageByID = function(type, id){

	if ( M[type]['items'][id] != undefined )
	{
		$('[eid='+id+']').addClass('activeItem');
		var data = M[type]['items'][id];
		M[type]['renderItem']( data );
		scrollTo(0, $('.activeItem').offset().top);
	}
	else
	{
		M[type]['getSingle'](id);

	}
}

var router = new Router();
router.route('/', function(){
	M.restoreItems();
	M.nav.removeActive();
});
router.route('/etsy', function(){
	M.restoreItems();
	M.nav.makeActive($('#etsy'));
});
router.route('/etsy/:id', function(id){
	M.restoreItems();
	M.nav.pageByID('etsy', id);
});
router.route('/write', function(){
	M.restoreItems();
	M.nav.makeActive($('#write'));
});
router.route('/write/:id', function(id){
	M.restoreItems();
	M.nav.pageByID('write', id);
});
router.route('/art', function(){
	M.restoreItems();
	M.nav.makeActive($('#art'));
});
router.route('/art/:id', function(id){
	M.restoreItems();
	M.nav.pageByID('art', id);
});

<|endoftext|>


<commit_before>/// <binding BeforeBuild='Run - Development' />
var webpack = require('webpack');
var path = require('path');

var buildDir = path.resolve(__dirname, 'wwwroot/scripts');
var scriptsDir = path.resolve(__dirname, 'wwwroot/tsxbuild');

var host = "localhost";
if(process.env.APIHOST)
    host = process.env.APIHOST;

console.log("APIHOST environment variable in webpack is set to '" + host + "'. This can be change from Dockerfile e.g. 'RUN APIHOST=${APIHOST} webpack'. Or if manually running webpack, e.g. 'APIHOST=localhost webpack'");
console.log("API full url is " + JSON.stringify("http://" + host + ":8001/"));

var config = {
    entry: {
        index: scriptsDir + '/Home' + '/Index',
        "sales/salesorder": scriptsDir + '/Sales/SalesOrder',
        "quotations/salesquotation": scriptsDir + '/Quotations/SalesQuotation',
        "sales/salesinvoice": scriptsDir + '/Sales/SalesInvoice',
        "purchasing/purchaseorder": scriptsDir + '/Purchasing/PurchaseOrder',
        "purchasing/purchaseinvoice": scriptsDir + '/Purchasing/PurchaseInvoice',
        "financials/journalentry": scriptsDir + '/Financials/JournalEntry',
        vendor: ['react', 'react-dom']
    },
    output: {
        path: buildDir,
        filename: '[name].chunk.js'
    },
    optimization: {
        splitChunks: {
            cacheGroups: {
                commons: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendor',
                    chunks: 'all'
                }
            }
        }
    },
    resolve: {
        extensions: ['.js', '.jsx', '.tsx']
    },
    devtool: 'source-map',
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
            'window.jQuery': 'jquery',
            Popper: ['popper.js', 'default']
        })
    ],
    externals: {
        'Config':  JSON.stringify({apiUrl : "http://" + host + ":8001/"})
    }
};

module.exports = config;<commit_msg>auto transpile tsx to js<commit_after>/// <binding BeforeBuild='Run - Development' />
var webpack = require('webpack');
var path = require('path');

var buildDir = path.resolve(__dirname, 'wwwroot/scripts');
var scriptsDir = path.resolve(__dirname, 'Scripts');

var host = "localhost";
if(process.env.APIHOST)
    host = process.env.APIHOST;

console.log("APIHOST environment variable in webpack is set to '" + host + "'. This can be change from Dockerfile e.g. 'RUN APIHOST=${APIHOST} webpack'. Or if manually running webpack, e.g. 'APIHOST=localhost webpack'");
console.log("API full url is " + JSON.stringify("http://" + host + ":8001/"));

var config = {
    entry: {
        index: scriptsDir + '/Home' + '/Index',
        "sales/salesorder": scriptsDir + '/Sales/SalesOrder',
        "quotations/salesquotation": scriptsDir + '/Quotations/SalesQuotation',
        "sales/salesinvoice": scriptsDir + '/Sales/SalesInvoice',
        "purchasing/purchaseorder": scriptsDir + '/Purchasing/PurchaseOrder',
        "purchasing/purchaseinvoice": scriptsDir + '/Purchasing/PurchaseInvoice',
        "financials/journalentry": scriptsDir + '/Financials/JournalEntry',
        vendor: ['react', 'react-dom']
    },
    module: {
        rules: [
          {
            test: /\.tsx?$/,
            loader: require.resolve('ts-loader'),
            exclude: /node_modules/
          }
        ]
    },
    output: {
        path: buildDir,
        filename: '[name].chunk.js'
    },
    optimization: {
        splitChunks: {
            cacheGroups: {
                commons: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendor',
                    chunks: 'all'
                }
            }
        }
    },
    resolve: {
        extensions: ['.js', '.jsx', '.tsx']
    },
    devtool: 'source-map',
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
            'window.jQuery': 'jquery',
            Popper: ['popper.js', 'default']
        })
    ],
    externals: {
        'Config':  JSON.stringify({apiUrl : "http://" + host + ":8001/"})
    }
};

module.exports = config;<|endoftext|>