<commit_before>function roundNumber(num, dec) {
	return Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
}

function getQueryString(con_con, con_sam, test_con, test_sam) {
	return 'conversions_control='+
		con_con+
		'&samples_control='+
		con_sam+
		'&conversions_experiment='+
		test_con+
		'&samples_experiment='+
		test_sam;
}

function getPermalink(con_con, con_sam, test_con, test_sam) {
	var queryString = getQueryString(con_con, con_sam, test_con, test_sam);
	return queryString.
		replace("conversions_control","cc").
		replace("samples_control","sc").
		replace("conversions_experiment","ce").
		replace("samples_experiment","se");
}

function displayPermalink(con_con, con_sam, test_con, test_sam) {
	var permalinkString = getPermalink(con_con, con_sam, test_con, test_sam);
	$('<input class="permalink" value="http://'+
		location.host+
		location.pathname+
		'?'+
		permalinkString+
		'" type="text">').
	prependTo("#action").focus();

	// Focus on click
	$("input[type=text].permalink").focus(function(){
		$(this).select();
	}).mouseup(function(e){
		e.preventDefault();
	});
}

function isPermalinkPage() {
	if(! getParameter("cc"))
		return false;
	if(! getParameter("sc"))
		return false;
	if(! getParameter("ce"))
		return false;
	if(! getParameter("se"))
		return false;

	return true;
}

function updateCharts(stat_results) {
	// Insert confidence charts
	var control_confidence = "

"+
		roundNumber(stat_results.confidence.results.control.low * 100,1)+
		" - "+
		roundNumber(stat_results.confidence.results.control.high * 100,1)+
		"%

Control performance

";

	var experiment_confidence = "

"+
		roundNumber(stat_results.confidence.results.experiment.low * 100,1)+
		" - "+
		roundNumber(stat_results.confidence.results.experiment.high * 100,1)+
		"%

Test performance

";

	$(control_confidence + experiment_confidence).appendTo(".column.left");

	// Insert significance and improvement charts
	var significance = "

"+
		roundNumber(stat_results.significance.results.experiment * 100,1)+
		"%

Chance of outperformance

";

	var improvement = "

"+
		roundNumber(stat_results.improvement.results.low * 100,1)+
		" - "+
		roundNumber(stat_results.improvement.results.high * 100,1)+
		"%

Likely improvement

";

	$(significance + improvement).appendTo(".column.right");
}

function cacheLastQuery(queryString) {
	cacheLastQuery.cache = queryString;
}

function getLastQuery() {
	if(typeof cacheLastQuery.cache == 'undefined')
		return false;

	return cacheLastQuery.cache;
}

function getResults(con_con, con_sam, test_con, test_sam) {
	var queryString = getQueryString(con_con, con_sam, test_con, test_sam);

	// Don't run the same query twice in a row
	if(queryString == getLastQuery())
		return false;

	cacheLastQuery(queryString);

	return queryAPI(con_con, con_sam, test_con, test_sam).done(function(stat_results) {
		$(".column").empty();

		// Check for errors
		if(stat_results.error)
			return false;

		updateCharts(stat_results);
		displayPermalink(con_con, con_sam, test_con, test_sam);
	});
}

function queryAPI(con_con, con_sam, test_con, test_sam) {
	var queryString = getQueryString(con_con, con_sam, test_con, test_sam);
	return $.getJSON("api?" + queryString);
}

function getParameter(paramName) {
	var searchString = window.location.search.substring(1),
		i, val, params = searchString.split("&");

	for (i=0;i<params.length;i++) {
		val = params[i].split("=");

		if (val[0] == paramName)
			return unescape(val[1]);
	}
	return null;
}

function isFormComplete() {
	if(! $("input#con_con").val())
		return false;
	if(! $("input#con_sam").val())
		return false;
	if(! $("input#test_con").val())
		return false;
	if(! $("input#test_sam").val())
		return false;

	return true;
}

$(function() {
	// Focus on the first input
	$("form :input:visible:first").first().focus();

	// Listen for form submit
	$("form").on('submit', function(event){
		event.preventDefault();

		// Don't submit incomplete forms
		if(! isFormComplete())
			return false;

		getResults(
			$("input#con_con").val(),
			$("input#con_sam").val(),
			$("input#test_con").val(),
			$("input#test_sam").val()
		);
	});

	// Auto-load results on permalink pages
	if(isPermalinkPage()){
		$("input#con_con").val(getParameter("cc"));
		$("input#con_sam").val(getParameter("sc"));
		$("input#test_con").val(getParameter("ce"));
		$("input#test_sam").val(getParameter("se"));

		getResults(
			getParameter("cc"),
			getParameter("sc"),
			getParameter("ce"),
			getParameter("se")
		);
	}

	// Auto-submit the form
	var keyup_timer;
	$("form input[type=text]").keyup(function(){
		clearTimeout(keyup_timer);
		keyup_timer = setTimeout(function(){
			$('form').submit();
		}, 800);
	});
});
<commit_msg>Replace lastQuery functions with lastQuery variable<commit_after>var lastQuery;

function roundNumber(num, dec) {
	return Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
}

function getQueryString(con_con, con_sam, test_con, test_sam) {
	return 'conversions_control='+
		con_con+
		'&samples_control='+
		con_sam+
		'&conversions_experiment='+
		test_con+
		'&samples_experiment='+
		test_sam;
}

function getPermalink(con_con, con_sam, test_con, test_sam) {
	var queryString = getQueryString(con_con, con_sam, test_con, test_sam);
	return queryString.
		replace("conversions_control","cc").
		replace("samples_control","sc").
		replace("conversions_experiment","ce").
		replace("samples_experiment","se");
}

function displayPermalink(con_con, con_sam, test_con, test_sam) {
	var permalinkString = getPermalink(con_con, con_sam, test_con, test_sam);
	$('<input class="permalink" value="http://'+
		location.host+
		location.pathname+
		'?'+
		permalinkString+
		'" type="text">').
	prependTo("#action").focus();

	// Focus on click
	$("input[type=text].permalink").focus(function(){
		$(this).select();
	}).mouseup(function(e){
		e.preventDefault();
	});
}

function isPermalinkPage() {
	if(! getParameter("cc"))
		return false;
	if(! getParameter("sc"))
		return false;
	if(! getParameter("ce"))
		return false;
	if(! getParameter("se"))
		return false;

	return true;
}

function updateCharts(stat_results) {
	// Insert confidence charts
	var control_confidence = "

"+
		roundNumber(stat_results.confidence.results.control.low * 100,1)+
		" - "+
		roundNumber(stat_results.confidence.results.control.high * 100,1)+
		"%

Control performance

";

	var experiment_confidence = "

"+
		roundNumber(stat_results.confidence.results.experiment.low * 100,1)+
		" - "+
		roundNumber(stat_results.confidence.results.experiment.high * 100,1)+
		"%

Test performance

";

	$(control_confidence + experiment_confidence).appendTo(".column.left");

	// Insert significance and improvement charts
	var significance = "

"+
		roundNumber(stat_results.significance.results.experiment * 100,1)+
		"%

Chance of outperformance

";

	var improvement = "

"+
		roundNumber(stat_results.improvement.results.low * 100,1)+
		" - "+
		roundNumber(stat_results.improvement.results.high * 100,1)+
		"%

Likely improvement

";

	$(significance + improvement).appendTo(".column.right");
}

function getResults(con_con, con_sam, test_con, test_sam) {
	var queryString = getQueryString(con_con, con_sam, test_con, test_sam);

	// Don't run the same query twice in a row
	if(queryString == lastQuery)
		return false;

	lastQuery = queryString;

	return queryAPI(con_con, con_sam, test_con, test_sam).done(function(stat_results) {
		$(".column").empty();

		// Check for errors
		if(stat_results.error)
			return false;

		updateCharts(stat_results);
		displayPermalink(con_con, con_sam, test_con, test_sam);
	});
}

function queryAPI(con_con, con_sam, test_con, test_sam) {
	var queryString = getQueryString(con_con, con_sam, test_con, test_sam);
	return $.getJSON("api?" + queryString);
}

function getParameter(paramName) {
	var searchString = window.location.search.substring(1),
		i, val, params = searchString.split("&");

	for (i=0;i<params.length;i++) {
		val = params[i].split("=");

		if (val[0] == paramName)
			return unescape(val[1]);
	}
	return null;
}

function isFormComplete() {
	if(! $("input#con_con").val())
		return false;
	if(! $("input#con_sam").val())
		return false;
	if(! $("input#test_con").val())
		return false;
	if(! $("input#test_sam").val())
		return false;

	return true;
}

$(function() {
	// Focus on the first input
	$("form :input:visible:first").first().focus();

	// Listen for form submit
	$("form").on('submit', function(event){
		event.preventDefault();

		// Don't submit incomplete forms
		if(! isFormComplete())
			return false;

		getResults(
			$("input#con_con").val(),
			$("input#con_sam").val(),
			$("input#test_con").val(),
			$("input#test_sam").val()
		);
	});

	// Auto-load results on permalink pages
	if(isPermalinkPage()){
		$("input#con_con").val(getParameter("cc"));
		$("input#con_sam").val(getParameter("sc"));
		$("input#test_con").val(getParameter("ce"));
		$("input#test_sam").val(getParameter("se"));

		getResults(
			getParameter("cc"),
			getParameter("sc"),
			getParameter("ce"),
			getParameter("se")
		);
	}

	// Auto-submit the form
	var keyup_timer;
	$("form input[type=text]").keyup(function(){
		clearTimeout(keyup_timer);
		keyup_timer = setTimeout(function(){
			$('form').submit();
		}, 800);
	});
});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

var classes = [
  'foam.core.Axiom',
  'foam.core.Serializable',
  'foam.core.Exception',
  'foam.core.Freezable',
  'foam.core.ContextAgent',
  'foam.core.Identifiable',
  'foam.core.AbstractFObject',
  'foam.mlang.predicate.Predicate',
  'foam.mlang.predicate.True',
  'foam.mlang.predicate.False',
  'foam.mlang.predicate.And',
  'foam.mlang.predicate.Gt',
  'foam.mlang.predicate.Or',
  'foam.mlang.predicate.AbstractPredicate',
  'foam.mlang.predicate.Nary',
  'foam.mlang.predicate.Unary',
  'foam.mlang.predicate.Binary',
  'foam.mlang.predicate.ArrayBinary',
  'foam.mlang.predicate.Contains',
  'foam.mlang.predicate.ContainsIC',
  'foam.mlang.predicate.StartsWith',
  'foam.mlang.predicate.StartsWithIC',
  'foam.mlang.predicate.Gt',
  'foam.mlang.predicate.Gte',
  'foam.mlang.predicate.Neq',
  'foam.mlang.predicate.Not',
  'foam.mlang.predicate.Lt',
  'foam.mlang.predicate.In',
  'foam.mlang.predicate.Lte',
  'foam.mlang.predicate.Has',
  'foam.mlang.predicate.Keyword',
  'foam.mlang.predicate.IsInstanceOf',
  'foam.mlang.sink.Count',
  'foam.mlang.sink.GroupBy',
  'foam.mlang.F',
  'foam.mlang.Expr',
  'foam.mlang.AbstractExpr',
  'foam.mlang.predicate.Eq',
  'foam.mlang.Constant',
  'foam.mlang.ArrayConstant',
  'foam.box.Box',
  'foam.box.Skeleton',
  'foam.box.AbstractSkeleton',
  'foam.box.ProxyBox',
  'foam.box.SubBox',
  'foam.box.Message',
  'foam.box.RegisterSelfMessage',
  'foam.box.SubBoxMessage',
  'foam.box.SubscribeMessage',
  'foam.box.NamedBox',
  'foam.box.HTTPBox',
  'foam.box.HTTPReplyBox',
  'foam.nanos.app.AppConfig',
  'foam.nanos.http.WebAgent',
  'com.google.foam.demos.heroes.Hero',
  'com.google.auth.TokenVerifier',
  'foam.box.RemoteException',
  'foam.box.RPCMessage',
  'foam.box.RPCReturnBox',
  'foam.box.RPCReturnMessage',
  'foam.box.RPCErrorMessage',
  'foam.box.BoxRegistry',
  'foam.box.NoSuchNameException',
  'foam.box.ReplyBox',
  'foam.box.LocalBoxRegistry',
  'foam.box.BoxRegistryBox',
  'foam.box.RawWebSocketBox',
  'foam.box.ReturnBox',
  'foam.box.BoxService',
  'foam.box.CheckAuthenticationBox',
  'foam.box.SessionReplyBox',
  'foam.box.SessionClientBox',
  'foam.dao.DAO',
  'foam.dao.java.JDAO',
  'foam.dao.FilteredDAO',
  'foam.dao.Journal',
  'foam.dao.AbstractJournal',
  'foam.dao.ProxyJournal',
  'foam.dao.CompositeJournal',
  'foam.dao.FileJournal',
  'foam.dao.RoutingJournal',
  'foam.dao.RoutingJournalTest',
  'foam.dao.RoutingJDAO',
  'foam.dao.WriteOnlyJDAO',
  'foam.dao.WriteOnlyFileJournal',
  'foam.dao.BaseClientDAO',
  'foam.dao.ClientDAO',
  'foam.dao.ClientSink',
  'foam.dao.ResetSink',
  'foam.dao.DAOSink',
  'foam.dao.MergedResetSink',
  'foam.dao.Sink',
  'foam.dao.ArraySink',
  'foam.dao.AbstractSink',
  'foam.mlang.sink.AbstractUnarySink',
  'foam.dao.PredicatedSink',
  'foam.dao.OrderedSink',
  'foam.dao.LimitedSink',
  'foam.dao.SkipSink',
  'foam.dao.DedupSink',
  'foam.dao.ReadOnlyDAO',
  'foam.dao.RelationshipDAO',
  'foam.dao.ManyToManyRelationship',
  'foam.dao.ManyToManyRelationshipImpl',
  'foam.dao.ManyToManyRelationshipDAO',
  'foam.dao.SQLStatement',
  'foam.dao.EasyDAO',
  'foam.dao.EnabledAwareDAO',
  'foam.dao.index.PersistedIndexTest',
  'foam.mlang.order.Comparator',
  'foam.mlang.order.Desc',
  'foam.mlang.sink.Count',
  'foam.mlang.sink.Max',
  'foam.mlang.sink.Min',
  'foam.mlang.sink.Sum',
  'foam.mlang.sink.Map',
  'foam.nanos.actioncommand.ActionCommand',
  'foam.nanos.NanoService',
  'foam.nanos.boot.NSpec',
  'foam.nanos.app.Mode',
  'foam.nanos.bench.Benchmark',
  'foam.nanos.auth.EnabledAware',
  'foam.nanos.auth.Group',
  'foam.nanos.auth.CreatedAware',
  'foam.nanos.auth.CreatedAwareDAO',
  'foam.nanos.auth.CreatedByAware',
  'foam.nanos.auth.CreatedByAwareDAO',
  'foam.nanos.auth.LastModifiedAware',
  'foam.nanos.auth.LastModifiedAwareDAO',
  'foam.nanos.auth.LastModifiedByAware',
  'foam.nanos.auth.LastModifiedByAwareDAO',
  'foam.nanos.auth.Permission',
  'foam.nanos.auth.DayOfWeek',
  'foam.nanos.auth.Hours',
  'foam.nanos.auth.Address',
  'foam.nanos.auth.Phone',
  'foam.nanos.auth.HumanNameTrait',
  'foam.nanos.auth.User',
  'foam.nanos.auth.Country',
  'foam.nanos.auth.AuthService',
  'foam.nanos.auth.UserUserJunction',
  'foam.nanos.auth.ClientAuthService',
  'foam.nanos.auth.AgentAuthService',
  'foam.nanos.auth.ClientAgentAuthService',
  'foam.nanos.auth.HtmlDoc',
  'foam.nanos.auth.PasswordExpiryAuthService',
  'foam.nanos.auth.token.Token',
  'foam.nanos.auth.token.TokenService',
  'foam.nanos.auth.token.ClientTokenService',
  'foam.nanos.auth.token.AbstractTokenService',
  'foam.nanos.auth.email.EmailTokenService',
  'foam.nanos.auth.email.EmailDocService',
  'foam.nanos.auth.email.EmailDocInterface',
  'foam.nanos.auth.email.ClientEmailDocService',
  'foam.nanos.auth.resetPassword.ResetPasswordTokenService',
  'foam.nanos.auth.PreventDuplicateEmailDAO',
  'foam.nanos.auth.ServiceProvider',
  'foam.nanos.auth.twofactor.OTPAuthService',
  'foam.nanos.auth.twofactor.AbstractOTPAuthService',
  'foam.nanos.auth.twofactor.AbstractTOTPAuthService',
  'foam.nanos.auth.twofactor.ClientOTPAuthService',
  'foam.nanos.auth.twofactor.GoogleTOTPAuthService',
  'foam.nanos.http.HttpParameters',
  'foam.nanos.http.DefaultHttpParameters',
  'foam.nanos.session.Session',
  'foam.nanos.pool.AbstractFixedThreadPool',
  'foam.nanos.pm.PMInfo',
  'foam.nanos.script.Language',
  'foam.nanos.auth.Language',
  'foam.nanos.auth.Region',
  'foam.nanos.logger.LogLevel',
  'foam.nanos.logger.LogMessage',
  'foam.nanos.logger.LogLevelFilterLogger',
  'foam.nanos.logger.AbstractLogger',
  'foam.nanos.logger.DAOLogger',
  'foam.nanos.logger.FileLogger',
  'foam.nanos.logger.Logger',
  'foam.nanos.logger.NotificationLogMessageDAO',
  'foam.nanos.logger.RepeatLogMessageDAO',
  'foam.nanos.logger.ProxyLogger',
  'foam.nanos.logger.LogsView',
  'foam.nanos.menu.Menu',
  'foam.nanos.menu.DAOMenu',
  'foam.nanos.menu.DocumentMenu',
  'foam.nanos.menu.DocumentFileMenu',
  'foam.nanos.menu.LinkMenu',
  'foam.nanos.menu.ListMenu',
  'foam.nanos.menu.MenuBar',
  'foam.nanos.menu.PopupMenu',
  'foam.nanos.menu.SubMenu',
  'foam.nanos.menu.SubMenuView',
  'foam.nanos.menu.TabsMenu',
  'foam.nanos.menu.ViewMenu',
  'foam.nanos.notification.email.EmailMessage',
  'foam.nanos.notification.email.EmailService',
  'foam.nanos.notification.email.EmailTemplate',
  'foam.nanos.notification.email.SMTPEmailService',
  'foam.nanos.notification.email.ClientEmailService',
  'foam.nanos.notification.email.NullEmailService',
  'foam.nanos.notification.email.DAOEmailService',
  'foam.nanos.notification.email.SMTPEmailMessageDAO',
  'foam.nanos.notification.email.POP3Email',
  'foam.nanos.notification.email.ClientPOP3EmailService',
  'foam.nanos.notification.push.PushService',
  'foam.nanos.notification.push.FirebasePushService',
  'foam.nanos.notification.Notification',
  'foam.nanos.notification.NotificationTemplateDAO',
  'foam.nanos.notification.notifications.ScriptRunNotification',
  'foam.nanos.script.Script',
  'foam.nanos.script.TestRunnerScript',
  'foam.nanos.test.Test',
  'foam.nanos.cron.Cron',
  'foam.dao.history.PropertyUpdate',
  'foam.dao.history.HistoryRecord',
  'foam.dao.FixedSizeDAO',
  'foam.mop.MOP',
  'foam.u2.Element',
  'foam.u2.Visibility',
  'foam.nanos.export.ExportDriverRegistry',
  'foam.dao.pg.ConnectionPool',
  'foam.lib.Outputter',
  'foam.lib.parse.Parser',
  'foam.lib.parse.PStream',
  'foam.lib.json.OutputJSON',
  'foam.lib.json.OutputterMode',
  'foam.lib.json.UnknownFObject',
  'foam.lib.json.UnknownFObjectArray',
  'foam.lib.json.ClassReferenceParserTest',
  'foam.blob.Buffer',
  'foam.blob.Blob',
  'foam.blob.BlobService',
  'foam.blob.AbstractBlob',
  'foam.blob.AbstractBlobService',
  'foam.blob.SubBlob',
  'foam.blob.IdentifiedBlob',
  'foam.blob.BlobStore',

  'foam.nanos.geocode.GoogleMapsAddressComponent',
  'foam.nanos.geocode.GoogleMapsCoordinates',
  'foam.nanos.geocode.GoogleMapsGeocodeResponse',
  'foam.nanos.geocode.GoogleMapsGeocodeResult',
  'foam.nanos.geocode.GoogleMapsGeometry',
  'foam.nanos.geocode.GoogleMapsBoundary',

  'foam.nanos.demo.DemoObject',
  'foam.nanos.demo.relationship.Student',
  'foam.nanos.demo.relationship.Professor',
  'foam.nanos.demo.relationship.Course',
  'foam.nanos.demo.relationship.CourseType',
  'foam.nanos.demo.relationship.StudentCourseJunction',
  'foam.nanos.fs.File',

  'foam.crypto.hash.Hasher',
  'foam.crypto.hash.HashableTest',

  'foam.crypto.sign.Signer',
  'foam.crypto.sign.SignableTest',

  'foam.nanos.http.Command',
  'foam.nanos.http.Format',
  'foam.nanos.http.DefaultHttpParameters',
  'foam.nanos.http.HttpParameters',
  'foam.nanos.dig.DIG',
  'foam.nanos.dig.DUG',

  'foam.nanos.jetty.HttpServer',
  'foam.nanos.servlet.ServletMapping',
  'foam.nanos.servlet.ErrorPageMapping',
  'foam.nanos.servlet.FilterMapping',
  'foam.nanos.servlet.VirtualHostRoutingServlet',

  'foam.lib.query.TestModel',
  'foam.lib.query.FooEnum',
  'foam.demos.net.nap.web.model.RegulatoryNotice',
  'foam.demos.net.nap.web.model.RegulatoryNoticeAudit',

  'foam.parse.QueryParserUserTest',
  'foam.util.EmailTest',
  'foam.util.PasswordTest',
  'foam.util.SecurityUtilTest',
  'foam.test.TestObj',
  'foam.core.FObjectTest',

  'foam.nanos.dig.exception.DigErrorMessage',
  'foam.nanos.dig.exception.DAONotFoundException',
  'foam.nanos.dig.exception.ParsingErrorException',
  'foam.nanos.dig.exception.DAOPutException',
  'foam.nanos.dig.exception.EmptyDataException',
  'foam.nanos.dig.exception.UnsupportException',
  'foam.nanos.dig.exception.UnknownIdException',
  'foam.nanos.dig.exception.DigSuccessMessage',

  'foam.flow.Document',
  'foam.flow.DocumentationFolderDAO',

  //Support Files
  'foam.support.model.TicketMessage',
  'foam.support.model.SupportEmail',
  'foam.support.model.Ticket'
];

var abstractClasses = [
  'foam.nanos.menu.AbstractMenu',
//  'foam.json.Outputter'
];

var skeletons = [
  'foam.dao.DAO',
  'foam.mop.MOP',
  'foam.nanos.auth.AuthService',
  'foam.nanos.auth.AgentAuthService',
  'foam.nanos.auth.email.EmailDocInterface',
  'foam.nanos.auth.twofactor.OTPAuthService',
  'foam.nanos.auth.token.TokenService',
  'foam.nanos.notification.email.EmailService',
  'foam.nanos.notification.email.POP3Email',
  'foam.nanos.notification.push.PushService'
];

var proxies = [
  'foam.dao.DAO',
  'foam.dao.Sink',
  'foam.mop.MOP',
  'foam.lib.Outputter',
  'foam.lib.parse.Parser',
  'foam.lib.parse.PStream',
  'foam.blob.Blob',
  'foam.blob.BlobService',
  'foam.nanos.auth.AuthService',
  'foam.nanos.auth.twofactor.OTPAuthService',
  'foam.nanos.http.WebAgent',
  'foam.nanos.notification.email.EmailService',
  'foam.nanos.notification.push.PushService',
];

var blacklist = [
];

module.exports = {
    classes: classes,
    abstractClasses: abstractClasses,
    skeletons: skeletons,
    proxies: proxies,
    blacklist: blacklist
}
<commit_msg>Removed trailing commas<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

var classes = [
  'foam.core.Axiom',
  'foam.core.Serializable',
  'foam.core.Exception',
  'foam.core.Freezable',
  'foam.core.ContextAgent',
  'foam.core.Identifiable',
  'foam.core.AbstractFObject',
  'foam.mlang.predicate.Predicate',
  'foam.mlang.predicate.True',
  'foam.mlang.predicate.False',
  'foam.mlang.predicate.And',
  'foam.mlang.predicate.Gt',
  'foam.mlang.predicate.Or',
  'foam.mlang.predicate.AbstractPredicate',
  'foam.mlang.predicate.Nary',
  'foam.mlang.predicate.Unary',
  'foam.mlang.predicate.Binary',
  'foam.mlang.predicate.ArrayBinary',
  'foam.mlang.predicate.Contains',
  'foam.mlang.predicate.ContainsIC',
  'foam.mlang.predicate.StartsWith',
  'foam.mlang.predicate.StartsWithIC',
  'foam.mlang.predicate.Gt',
  'foam.mlang.predicate.Gte',
  'foam.mlang.predicate.Neq',
  'foam.mlang.predicate.Not',
  'foam.mlang.predicate.Lt',
  'foam.mlang.predicate.In',
  'foam.mlang.predicate.Lte',
  'foam.mlang.predicate.Has',
  'foam.mlang.predicate.Keyword',
  'foam.mlang.predicate.IsInstanceOf',
  'foam.mlang.sink.Count',
  'foam.mlang.sink.GroupBy',
  'foam.mlang.F',
  'foam.mlang.Expr',
  'foam.mlang.AbstractExpr',
  'foam.mlang.predicate.Eq',
  'foam.mlang.Constant',
  'foam.mlang.ArrayConstant',
  'foam.box.Box',
  'foam.box.Skeleton',
  'foam.box.AbstractSkeleton',
  'foam.box.ProxyBox',
  'foam.box.SubBox',
  'foam.box.Message',
  'foam.box.RegisterSelfMessage',
  'foam.box.SubBoxMessage',
  'foam.box.SubscribeMessage',
  'foam.box.NamedBox',
  'foam.box.HTTPBox',
  'foam.box.HTTPReplyBox',
  'foam.nanos.app.AppConfig',
  'foam.nanos.http.WebAgent',
  'com.google.foam.demos.heroes.Hero',
  'com.google.auth.TokenVerifier',
  'foam.box.RemoteException',
  'foam.box.RPCMessage',
  'foam.box.RPCReturnBox',
  'foam.box.RPCReturnMessage',
  'foam.box.RPCErrorMessage',
  'foam.box.BoxRegistry',
  'foam.box.NoSuchNameException',
  'foam.box.ReplyBox',
  'foam.box.LocalBoxRegistry',
  'foam.box.BoxRegistryBox',
  'foam.box.RawWebSocketBox',
  'foam.box.ReturnBox',
  'foam.box.BoxService',
  'foam.box.CheckAuthenticationBox',
  'foam.box.SessionReplyBox',
  'foam.box.SessionClientBox',
  'foam.dao.DAO',
  'foam.dao.java.JDAO',
  'foam.dao.FilteredDAO',
  'foam.dao.Journal',
  'foam.dao.AbstractJournal',
  'foam.dao.ProxyJournal',
  'foam.dao.CompositeJournal',
  'foam.dao.FileJournal',
  'foam.dao.RoutingJournal',
  'foam.dao.RoutingJournalTest',
  'foam.dao.RoutingJDAO',
  'foam.dao.WriteOnlyJDAO',
  'foam.dao.WriteOnlyFileJournal',
  'foam.dao.BaseClientDAO',
  'foam.dao.ClientDAO',
  'foam.dao.ClientSink',
  'foam.dao.ResetSink',
  'foam.dao.DAOSink',
  'foam.dao.MergedResetSink',
  'foam.dao.Sink',
  'foam.dao.ArraySink',
  'foam.dao.AbstractSink',
  'foam.mlang.sink.AbstractUnarySink',
  'foam.dao.PredicatedSink',
  'foam.dao.OrderedSink',
  'foam.dao.LimitedSink',
  'foam.dao.SkipSink',
  'foam.dao.DedupSink',
  'foam.dao.ReadOnlyDAO',
  'foam.dao.RelationshipDAO',
  'foam.dao.ManyToManyRelationship',
  'foam.dao.ManyToManyRelationshipImpl',
  'foam.dao.ManyToManyRelationshipDAO',
  'foam.dao.SQLStatement',
  'foam.dao.EasyDAO',
  'foam.dao.EnabledAwareDAO',
  'foam.dao.index.PersistedIndexTest',
  'foam.mlang.order.Comparator',
  'foam.mlang.order.Desc',
  'foam.mlang.sink.Count',
  'foam.mlang.sink.Max',
  'foam.mlang.sink.Min',
  'foam.mlang.sink.Sum',
  'foam.mlang.sink.Map',
  'foam.nanos.actioncommand.ActionCommand',
  'foam.nanos.NanoService',
  'foam.nanos.boot.NSpec',
  'foam.nanos.app.Mode',
  'foam.nanos.bench.Benchmark',
  'foam.nanos.auth.EnabledAware',
  'foam.nanos.auth.Group',
  'foam.nanos.auth.CreatedAware',
  'foam.nanos.auth.CreatedAwareDAO',
  'foam.nanos.auth.CreatedByAware',
  'foam.nanos.auth.CreatedByAwareDAO',
  'foam.nanos.auth.LastModifiedAware',
  'foam.nanos.auth.LastModifiedAwareDAO',
  'foam.nanos.auth.LastModifiedByAware',
  'foam.nanos.auth.LastModifiedByAwareDAO',
  'foam.nanos.auth.Permission',
  'foam.nanos.auth.DayOfWeek',
  'foam.nanos.auth.Hours',
  'foam.nanos.auth.Address',
  'foam.nanos.auth.Phone',
  'foam.nanos.auth.HumanNameTrait',
  'foam.nanos.auth.User',
  'foam.nanos.auth.Country',
  'foam.nanos.auth.AuthService',
  'foam.nanos.auth.UserUserJunction',
  'foam.nanos.auth.ClientAuthService',
  'foam.nanos.auth.AgentAuthService',
  'foam.nanos.auth.ClientAgentAuthService',
  'foam.nanos.auth.HtmlDoc',
  'foam.nanos.auth.PasswordExpiryAuthService',
  'foam.nanos.auth.token.Token',
  'foam.nanos.auth.token.TokenService',
  'foam.nanos.auth.token.ClientTokenService',
  'foam.nanos.auth.token.AbstractTokenService',
  'foam.nanos.auth.email.EmailTokenService',
  'foam.nanos.auth.email.EmailDocService',
  'foam.nanos.auth.email.EmailDocInterface',
  'foam.nanos.auth.email.ClientEmailDocService',
  'foam.nanos.auth.resetPassword.ResetPasswordTokenService',
  'foam.nanos.auth.PreventDuplicateEmailDAO',
  'foam.nanos.auth.ServiceProvider',
  'foam.nanos.auth.twofactor.OTPAuthService',
  'foam.nanos.auth.twofactor.AbstractOTPAuthService',
  'foam.nanos.auth.twofactor.AbstractTOTPAuthService',
  'foam.nanos.auth.twofactor.ClientOTPAuthService',
  'foam.nanos.auth.twofactor.GoogleTOTPAuthService',
  'foam.nanos.http.HttpParameters',
  'foam.nanos.http.DefaultHttpParameters',
  'foam.nanos.session.Session',
  'foam.nanos.pool.AbstractFixedThreadPool',
  'foam.nanos.pm.PMInfo',
  'foam.nanos.script.Language',
  'foam.nanos.auth.Language',
  'foam.nanos.auth.Region',
  'foam.nanos.logger.LogLevel',
  'foam.nanos.logger.LogMessage',
  'foam.nanos.logger.LogLevelFilterLogger',
  'foam.nanos.logger.AbstractLogger',
  'foam.nanos.logger.DAOLogger',
  'foam.nanos.logger.FileLogger',
  'foam.nanos.logger.Logger',
  'foam.nanos.logger.NotificationLogMessageDAO',
  'foam.nanos.logger.RepeatLogMessageDAO',
  'foam.nanos.logger.ProxyLogger',
  'foam.nanos.logger.LogsView',
  'foam.nanos.menu.Menu',
  'foam.nanos.menu.DAOMenu',
  'foam.nanos.menu.DocumentMenu',
  'foam.nanos.menu.DocumentFileMenu',
  'foam.nanos.menu.LinkMenu',
  'foam.nanos.menu.ListMenu',
  'foam.nanos.menu.MenuBar',
  'foam.nanos.menu.PopupMenu',
  'foam.nanos.menu.SubMenu',
  'foam.nanos.menu.SubMenuView',
  'foam.nanos.menu.TabsMenu',
  'foam.nanos.menu.ViewMenu',
  'foam.nanos.notification.email.EmailMessage',
  'foam.nanos.notification.email.EmailService',
  'foam.nanos.notification.email.EmailTemplate',
  'foam.nanos.notification.email.SMTPEmailService',
  'foam.nanos.notification.email.ClientEmailService',
  'foam.nanos.notification.email.NullEmailService',
  'foam.nanos.notification.email.DAOEmailService',
  'foam.nanos.notification.email.SMTPEmailMessageDAO',
  'foam.nanos.notification.email.POP3Email',
  'foam.nanos.notification.email.ClientPOP3EmailService',
  'foam.nanos.notification.push.PushService',
  'foam.nanos.notification.push.FirebasePushService',
  'foam.nanos.notification.Notification',
  'foam.nanos.notification.NotificationTemplateDAO',
  'foam.nanos.notification.notifications.ScriptRunNotification',
  'foam.nanos.script.Script',
  'foam.nanos.script.TestRunnerScript',
  'foam.nanos.test.Test',
  'foam.nanos.cron.Cron',
  'foam.dao.history.PropertyUpdate',
  'foam.dao.history.HistoryRecord',
  'foam.dao.FixedSizeDAO',
  'foam.mop.MOP',
  'foam.u2.Element',
  'foam.u2.Visibility',
  'foam.nanos.export.ExportDriverRegistry',
  'foam.dao.pg.ConnectionPool',
  'foam.lib.Outputter',
  'foam.lib.parse.Parser',
  'foam.lib.parse.PStream',
  'foam.lib.json.OutputJSON',
  'foam.lib.json.OutputterMode',
  'foam.lib.json.UnknownFObject',
  'foam.lib.json.UnknownFObjectArray',
  'foam.lib.json.ClassReferenceParserTest',
  'foam.blob.Buffer',
  'foam.blob.Blob',
  'foam.blob.BlobService',
  'foam.blob.AbstractBlob',
  'foam.blob.AbstractBlobService',
  'foam.blob.SubBlob',
  'foam.blob.IdentifiedBlob',
  'foam.blob.BlobStore',

  'foam.nanos.geocode.GoogleMapsAddressComponent',
  'foam.nanos.geocode.GoogleMapsCoordinates',
  'foam.nanos.geocode.GoogleMapsGeocodeResponse',
  'foam.nanos.geocode.GoogleMapsGeocodeResult',
  'foam.nanos.geocode.GoogleMapsGeometry',
  'foam.nanos.geocode.GoogleMapsBoundary',

  'foam.nanos.demo.DemoObject',
  'foam.nanos.demo.relationship.Student',
  'foam.nanos.demo.relationship.Professor',
  'foam.nanos.demo.relationship.Course',
  'foam.nanos.demo.relationship.CourseType',
  'foam.nanos.demo.relationship.StudentCourseJunction',
  'foam.nanos.fs.File',

  'foam.crypto.hash.Hasher',
  'foam.crypto.hash.HashableTest',

  'foam.crypto.sign.Signer',
  'foam.crypto.sign.SignableTest',

  'foam.nanos.http.Command',
  'foam.nanos.http.Format',
  'foam.nanos.http.DefaultHttpParameters',
  'foam.nanos.http.HttpParameters',
  'foam.nanos.dig.DIG',
  'foam.nanos.dig.DUG',

  'foam.nanos.jetty.HttpServer',
  'foam.nanos.servlet.ServletMapping',
  'foam.nanos.servlet.ErrorPageMapping',
  'foam.nanos.servlet.FilterMapping',
  'foam.nanos.servlet.VirtualHostRoutingServlet',

  'foam.lib.query.TestModel',
  'foam.lib.query.FooEnum',
  'foam.demos.net.nap.web.model.RegulatoryNotice',
  'foam.demos.net.nap.web.model.RegulatoryNoticeAudit',

  'foam.parse.QueryParserUserTest',
  'foam.util.EmailTest',
  'foam.util.PasswordTest',
  'foam.util.SecurityUtilTest',
  'foam.test.TestObj',
  'foam.core.FObjectTest',

  'foam.nanos.dig.exception.DigErrorMessage',
  'foam.nanos.dig.exception.DAONotFoundException',
  'foam.nanos.dig.exception.ParsingErrorException',
  'foam.nanos.dig.exception.DAOPutException',
  'foam.nanos.dig.exception.EmptyDataException',
  'foam.nanos.dig.exception.UnsupportException',
  'foam.nanos.dig.exception.UnknownIdException',
  'foam.nanos.dig.exception.DigSuccessMessage',

  'foam.flow.Document',
  'foam.flow.DocumentationFolderDAO',

  //Support Files
  'foam.support.model.TicketMessage',
  'foam.support.model.SupportEmail',
  'foam.support.model.Ticket'
];

var abstractClasses = [
  'foam.nanos.menu.AbstractMenu',
//  'foam.json.Outputter'
];

var skeletons = [
  'foam.dao.DAO',
  'foam.mop.MOP',
  'foam.nanos.auth.AuthService',
  'foam.nanos.auth.AgentAuthService',
  'foam.nanos.auth.email.EmailDocInterface',
  'foam.nanos.auth.twofactor.OTPAuthService',
  'foam.nanos.auth.token.TokenService',
  'foam.nanos.notification.email.EmailService',
  'foam.nanos.notification.email.POP3Email',
  'foam.nanos.notification.push.PushService'
];

var proxies = [
  'foam.dao.DAO',
  'foam.dao.Sink',
  'foam.mop.MOP',
  'foam.lib.Outputter',
  'foam.lib.parse.Parser',
  'foam.lib.parse.PStream',
  'foam.blob.Blob',
  'foam.blob.BlobService',
  'foam.nanos.auth.AuthService',
  'foam.nanos.auth.twofactor.OTPAuthService',
  'foam.nanos.http.WebAgent',
  'foam.nanos.notification.email.EmailService',
  'foam.nanos.notification.push.PushService'
];

var blacklist = [
];

module.exports = {
    classes: classes,
    abstractClasses: abstractClasses,
    skeletons: skeletons,
    proxies: proxies,
    blacklist: blacklist
}
<|endoftext|>


<commit_before>/*
RegExr: Learn, Build, & Test RegEx
Copyright (C) 2017  gskinner.com, inc.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

import EventDispatcher from "../events/EventDispatcher";

import $ from "../utils/DOMUtils";
import Utils from "../utils/Utils";
import app from "../app";

import LinkRow from "../controls/LinkRow";
import Status from "../controls/Status";
import Account from "./Account";
import Server from "../net/Server";

export default class Share extends EventDispatcher {
	constructor (el) {
		super();
		this.el = el;
		this._pattern = false;
		this._initUI();
		app.on("change", () => this._handleAppChange());
		app.on("load", () => this._handleAppLoad());
		app.account.on("change", () => this._handleAccountChange());
	}

// public methods:
	get value() {
		return {
			id: this._pattern ? this._pattern.id : null,
			name: this.name,
			author: this.author,
			description: this.description,
			keywords: this.keywords
		}
	}

	set pattern(o) {
		this._pattern = o;
		this.name = o.name;
		this.description = o.description;
		this.keywords = o.keywords;

		this._updateUI();
		this._pushHistory(o);
	}

	get name() { return this.nameFld.value; }
	set name(val) { this.nameFld.value = val||""; }

	get author() { return this.authorFld.value; }
	set author(val) { this.authorFld.value = val||""; }

	get description() { return this.descriptionFld.value; }
	set description(val) { this.descriptionFld.value = val||""; }

	get keywords() { return this.keywordsFld.value; }
	set keywords(val) { this.keywordsFld.value = val||""; }

// private methods:
	_initUI() {
		let el = this.el;
		this.mainEl = $.query("> #share_main", el);
		let comEl = this.communityEl = $.query("> #share_community", el);

		// set up header:
		let hEl = $.query(".header .file");
		this.hNewBtn = $.query(".new", hEl);
		this.hForkBtn = $.query(".fork", hEl);
		this.hSaveBtn = $.query(".save", hEl);
		$.query(".savekey", this.hSaveBtn).innerText = "("+Utils.getCtrlKey()+"-s)";
		this.hSaveBtn.addEventListener("click", () => this._doSave());
		this.hForkBtn.addEventListener("click", () => this._doSave(true));
		this.hNewBtn.addEventListener("click", () => this._doNew());

		// set up main:
		this._privateRow = $.query(".row.private", this.mainEl);
		this._privateRow.addEventListener("click", ()=> this._doPrivate());
		this._privateStatus = new Status($.query(".status", this._privateRow));
		this._favoritesRow = $.query(".row.favorites", this.mainEl);
		this._favoritesRow.addEventListener("click", ()=> this._doFavorite());
		this._favoritesStatus = new Status($.query(".status", this._favoritesRow));
		this._communityRow = $.query(".row.community", this.mainEl);
		this._communityRow.addEventListener("click", ()=> this._showCommunity());
		this._deleteRow = $.query(".row.delete", this.mainEl);
		this._deleteRow.addEventListener("click", ()=> this._doDelete());
		this._deleteStatus = new Status($.query(".status", this._deleteRow));
		$.query(".row.signin a", this.mainEl).addEventListener("click", ()=> this._doSignin());

		// set up link row:
		this._linkRow = new LinkRow($.query(".link.row", this.mainEl));

		// set up save buttons:
		let saveEl = this.saveEl = $.query("> .save", this.mainEl);
		this.saveBtn = $.query(".button.save", saveEl);
		this.forkBtn = $.query(".button.fork", saveEl);
		this.saveBtn.addEventListener("click", ()=> this._doSave());
		this.forkBtn.addEventListener("click", ()=> this._doSave(true));
		this.saveStatus = new Status($.query(".status", saveEl));

		// set up input fields:
		let inputsEl = $.query(".inputs", saveEl);
		this.nameFld = $.query(".name", inputsEl);
		this.authorFld = $.query(".author", inputsEl);
		this.descriptionFld = $.query(".description", inputsEl);
		this.keywordsFld = $.query(".keywords", inputsEl);

		// listen for changes:
		this.nameFld.addEventListener("input", () => this._handleChange());
		this.authorFld.addEventListener("input", () => this._handleChange());
		this.descriptionFld.addEventListener("input", () => this._handleChange());
		this.keywordsFld.addEventListener("input", () => this._handleChange());

		/// set up community:
		let comInputsEl = $.query(".inputs", comEl)
		$.query(".button.cancel", comEl).addEventListener("click", ()=> app.sidebar.goto("share"));
		$.query(".button.share", comEl).addEventListener("click", ()=> this._doComSave());
		this.comSaveStatus = new Status($.query(".status", comEl));
		this._comNameFld = $.query(".name", comInputsEl);
		this._comAuthorFld = $.query(".author", comInputsEl);
		this._comDescriptionFld = $.query(".description", comInputsEl);
		this._comKeywordsFld = $.query(".keywords", comInputsEl);

		// set up cmd-s listener:
		window.document.addEventListener("keydown", (evt) => this._handleKey(evt) );
	}

	_updateUI() {
		let o = this._pattern, text;
		let isChanged = this._isChanged(), isNew = this._isNew(), isOwned = this._isOwned();

		$.toggleClass([this.forkBtn, this.hForkBtn], "disabled", !this._canFork());
		$.toggleClass([this.saveBtn, this.hSaveBtn], "disabled", !this._canSave());

		if (!isOwned) { text = "This pattern was created by '"+(o.author||"[anonymous]")+"'."; }
		else if (!isChanged) { text = "No unsaved changes." }
		else if (isNew) { text = "Save will create a shareable public link."; }
		else { text = "Save will update the current link."; }

		if (!isOwned && !isChanged) { text += " Fork to create your own copy."; }
		else if (!isNew) { text += " Fork will create a new link" + (isChanged ? " with your changes." : "."); }

		this._setSaveText(text);

		this._linkRow.pattern = this._pattern.id && this._pattern;

		$.toggleClass(this._privateRow, "disabled", isNew || !isOwned);
		$.toggleClass(this._favoritesRow, "disabled", isNew || !isOwned);
		$.toggleClass(this._communityRow, "disabled", isNew || !isOwned);
		$.toggleClass(this._deleteRow, "disabled", isNew || !isOwned);

		$.toggleClass(this._privateRow, "active", o.access === "private");
		$.toggleClass(this._favoritesRow, "active", !!o.favorite);
	}

	_isNew() {
		return !this._pattern.id;
	}

	_isOwned() {
		let o = this._pattern;
		return this._isNew() || (o.userId === app.account.userId);
	}

	_isChanged() {
		return app.unsaved;
	}

	_canSave() {
		return this._isChanged() && this._isOwned();
	}

	_canFork() {
		return !this._isNew();
	}

	_pushHistory(pattern) {
		let history = window.history, url = Utils.getPatternURL(pattern);
		let title = "RegExr: "+ (pattern.name || "Learn, Build, & Test RegEx");

		if (history.state && (pattern.id === history.state.id)) {
			history.replaceState(pattern, title, url);
		} else {
			history.pushState(pattern, title, url);
		}
		window.document.title = title;
	}

	_handleKey(evt) {
		let mac = Utils.isMac();
		if (evt.key === "s" && ((mac && evt.metaKey) || (!mac && evt.ctrlKey))) {
			this._doSave(false);
			evt.preventDefault();
		}
	}

	_doSave(fork) {
		// if we can't save for some reason, then show the panel.
		if (!fork && !this._canSave()) {
			app.sidebar.goto("share");
			return;
		}

		if (fork && !this._canFork()) { return; }

		let o = app.state;
		$.addClass($.query(".buttons", this.saveEl), "wait");
		this.saveStatus.distract();
		Server.save(o, fork)
			.then((data) => this._handleSave(data))
			.catch((err) => this._handleSaveErr(err));
	}

	_handleSave(data) {
		let isNew = (this._pattern.id == null), isFork = !isNew && (data.id !== this._pattern.id);
		$.removeClass($.query(".buttons", this.saveEl), "wait");
		this.saveStatus.hide();

		app.state = data;

		if (isFork || isNew) {
			app.sidebar.goto("share");
			if (isFork || !this.name) {
				this.nameFld.focus();
				this.nameFld.select();
			}

			this._linkRow.showMessage("Saved. New share link created. Click to copy to clipboard.");
		}
	}

	_handleSaveErr(err) {
		$.removeClass($.query(".buttons", this.saveEl), "wait");
		this.saveStatus.error(this._getErrMsg(err));
	}

	_doNew() {
		if (app.unsaved && !confirm("You have unsaved changes. Create new pattern without saving?")) { return; }
		app.state = {
			flavor: app.flavor.value
		}
	}

	_doPrivate() {
		let o = this._pattern;
		this._privateStatus.distract();
		Server.private(o.id, o.access !== "private")
			.then((data) => this._handlePrivate(data))
			.catch((err) => this._handleErr(err, this._privateStatus));
	}

	_handlePrivate(data) {
		if (data.id === this._pattern.id) {
			this._pattern.access = data.access;
			this._privateStatus.hide();
			this._updateUI();
		}
	}

	_doFavorite() {
		let o = this._pattern;
		this._favoritesStatus.distract();
		Server.favorite(o.id, !o.favorite)
			.then((data) => this._handleFavorite(data))
			.catch((err) => this._handleErr(err, this._favoritesStatus));
	}

	_handleFavorite(data) {
		if (data.id === this._pattern.id) {
			this._pattern.favorite = data.favorite;
			this._favoritesStatus.hide();
			this._updateUI();
		}
	}

	_doDelete() {
		let o = this._pattern;
		if (!confirm("Are you sure you want to permanently delete this pattern?")) { return; }
		this._deleteStatus.distract();
		Server.delete(o.id)
			.then((data) => this._handleDelete(data))
			.catch((err) => this._handleErr(err, this._deleteStatus));
	}

	_handleDelete(data) {
		this._deleteStatus.hide();
		app.state = {
			flavor: app.flavor.value
		}
	}

	_handleErr(err, status) {
		status.error(this._getErrMsg(err)).hide(6);
	}

	_showCommunity() {
		app.sidebar.goto("share_community");
		this._comNameFld.value = this.name;
		this._comAuthorFld.value = this.author;
		this._comDescriptionFld.value = this.description;
		this._comKeywordsFld.value = this.keywords;
	}

	_doComSave() {
		if (!this._comNameFld.value) {
			this._comNameFld.focus();
			return;
		}
		let o = app.state;
		this.name = o.name = this._comNameFld.value;
		this.author = o.author = this._comAuthorFld.value;
		this.description = o.description = this._comDescriptionFld.value;
		this.keywords = o.keywords = this._comKeywordsFld.value;
		o.access = "public";
		$.addClass($.query(".buttons", this.communityEl), "wait");
		this.comSaveStatus.distract();
		Server.save(o, true)
			.then((data) => this._handleComSave(data))
			.catch((err) => this._handleComSaveErr(err));
	}

	_handleComSave(data) {
		$.removeClass($.query(".buttons", this.communityEl), "wait");
		this.comSaveStatus.hide();
		app.sidebar.goto("share");
	}

	_handleComSaveErr(err) {
		$.removeClass($.query(".buttons", this.communityEl), "wait");
		this.comSaveStatus.error(this._getErrMsg(err));
	}

	_handleChange() {
		this.dispatchEvent("change");
	}

	_handleAppChange() {
		this._updateUI();
	}

	_handleAccountChange() {
		let acc = app.account, rowEl = $.query(".signin.row", this.mainEl);
		if (!this.authorFld.value) { this.authorFld.value = acc.author || acc.username; }
		$.toggleClass(rowEl, "authenticated", acc.authenticated);
		$.query(".username", rowEl).innerText = acc.username;
	}

	_handleAppLoad() {
		$.toggleClass($.query(".save .actions", this.mainEl), "disabled");
	}

	_doSignin() {
		app.account.showTooltip();
	}

	_setSaveText(str) {
		$.query(".save .message .label", this.mainEl).innerText = str;
	}

	_getErrMsg(err) {
		return "ERROR: "+app.reference.getError("servercomm");
	}
}<commit_msg>Add confirmation tip on delete.<commit_after>/*
RegExr: Learn, Build, & Test RegEx
Copyright (C) 2017  gskinner.com, inc.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

import EventDispatcher from "../events/EventDispatcher";

import $ from "../utils/DOMUtils";
import Utils from "../utils/Utils";
import app from "../app";

import LinkRow from "../controls/LinkRow";
import Status from "../controls/Status";
import Account from "./Account";
import Server from "../net/Server";

export default class Share extends EventDispatcher {
	constructor (el) {
		super();
		this.el = el;
		this._pattern = false;
		this._initUI();
		app.on("change", () => this._handleAppChange());
		app.on("load", () => this._handleAppLoad());
		app.account.on("change", () => this._handleAccountChange());
	}

// public methods:
	get value() {
		return {
			id: this._pattern ? this._pattern.id : null,
			name: this.name,
			author: this.author,
			description: this.description,
			keywords: this.keywords
		}
	}

	set pattern(o) {
		this._pattern = o;
		this.name = o.name;
		this.description = o.description;
		this.keywords = o.keywords;

		this._updateUI();
		this._pushHistory(o);
	}

	get name() { return this.nameFld.value; }
	set name(val) { this.nameFld.value = val||""; }

	get author() { return this.authorFld.value; }
	set author(val) { this.authorFld.value = val||""; }

	get description() { return this.descriptionFld.value; }
	set description(val) { this.descriptionFld.value = val||""; }

	get keywords() { return this.keywordsFld.value; }
	set keywords(val) { this.keywordsFld.value = val||""; }

// private methods:
	_initUI() {
		let el = this.el;
		this.mainEl = $.query("> #share_main", el);
		let comEl = this.communityEl = $.query("> #share_community", el);

		// set up header:
		let hEl = $.query(".header .file");
		this.hNewBtn = $.query(".new", hEl);
		this.hForkBtn = $.query(".fork", hEl);
		this.hSaveBtn = $.query(".save", hEl);
		$.query(".savekey", this.hSaveBtn).innerText = "("+Utils.getCtrlKey()+"-s)";
		this.hSaveBtn.addEventListener("click", () => this._doSave());
		this.hForkBtn.addEventListener("click", () => this._doSave(true));
		this.hNewBtn.addEventListener("click", () => this._doNew());

		// set up main:
		this._privateRow = $.query(".row.private", this.mainEl);
		this._privateRow.addEventListener("click", ()=> this._doPrivate());
		this._privateStatus = new Status($.query(".status", this._privateRow));
		this._favoritesRow = $.query(".row.favorites", this.mainEl);
		this._favoritesRow.addEventListener("click", ()=> this._doFavorite());
		this._favoritesStatus = new Status($.query(".status", this._favoritesRow));
		this._communityRow = $.query(".row.community", this.mainEl);
		this._communityRow.addEventListener("click", ()=> this._showCommunity());
		this._deleteRow = $.query(".row.delete", this.mainEl);
		this._deleteRow.addEventListener("click", ()=> this._doDelete());
		this._deleteStatus = new Status($.query(".status", this._deleteRow));
		$.query(".row.signin a", this.mainEl).addEventListener("click", ()=> this._doSignin());

		// set up link row:
		this._linkRow = new LinkRow($.query(".link.row", this.mainEl));

		// set up save buttons:
		let saveEl = this.saveEl = $.query("> .save", this.mainEl);
		this.saveBtn = $.query(".button.save", saveEl);
		this.forkBtn = $.query(".button.fork", saveEl);
		this.saveBtn.addEventListener("click", ()=> this._doSave());
		this.forkBtn.addEventListener("click", ()=> this._doSave(true));
		this.saveStatus = new Status($.query(".status", saveEl));

		// set up input fields:
		let inputsEl = $.query(".inputs", saveEl);
		this.nameFld = $.query(".name", inputsEl);
		this.authorFld = $.query(".author", inputsEl);
		this.descriptionFld = $.query(".description", inputsEl);
		this.keywordsFld = $.query(".keywords", inputsEl);

		// listen for changes:
		this.nameFld.addEventListener("input", () => this._handleChange());
		this.authorFld.addEventListener("input", () => this._handleChange());
		this.descriptionFld.addEventListener("input", () => this._handleChange());
		this.keywordsFld.addEventListener("input", () => this._handleChange());

		/// set up community:
		let comInputsEl = $.query(".inputs", comEl)
		$.query(".button.cancel", comEl).addEventListener("click", ()=> app.sidebar.goto("share"));
		$.query(".button.share", comEl).addEventListener("click", ()=> this._doComSave());
		this.comSaveStatus = new Status($.query(".status", comEl));
		this._comNameFld = $.query(".name", comInputsEl);
		this._comAuthorFld = $.query(".author", comInputsEl);
		this._comDescriptionFld = $.query(".description", comInputsEl);
		this._comKeywordsFld = $.query(".keywords", comInputsEl);

		// set up cmd-s listener:
		window.document.addEventListener("keydown", (evt) => this._handleKey(evt) );
	}

	_updateUI() {
		let o = this._pattern, text;
		let isChanged = this._isChanged(), isNew = this._isNew(), isOwned = this._isOwned();

		$.toggleClass([this.forkBtn, this.hForkBtn], "disabled", !this._canFork());
		$.toggleClass([this.saveBtn, this.hSaveBtn], "disabled", !this._canSave());

		if (!isOwned) { text = "This pattern was created by '"+(o.author||"[anonymous]")+"'."; }
		else if (!isChanged) { text = "No unsaved changes." }
		else if (isNew) { text = "Save will create a shareable public link."; }
		else { text = "Save will update the current link."; }

		if (!isOwned && !isChanged) { text += " Fork to create your own copy."; }
		else if (!isNew) { text += " Fork will create a new link" + (isChanged ? " with your changes." : "."); }

		this._setSaveText(text);

		this._linkRow.pattern = this._pattern.id && this._pattern;

		$.toggleClass(this._privateRow, "disabled", isNew || !isOwned);
		$.toggleClass(this._favoritesRow, "disabled", isNew || !isOwned);
		$.toggleClass(this._communityRow, "disabled", isNew || !isOwned);
		$.toggleClass(this._deleteRow, "disabled", isNew || !isOwned);

		$.toggleClass(this._privateRow, "active", o.access === "private");
		$.toggleClass(this._favoritesRow, "active", !!o.favorite);
	}

	_isNew() {
		return !this._pattern.id;
	}

	_isOwned() {
		let o = this._pattern;
		return this._isNew() || (o.userId === app.account.userId);
	}

	_isChanged() {
		return app.unsaved;
	}

	_canSave() {
		return this._isChanged() && this._isOwned();
	}

	_canFork() {
		return !this._isNew();
	}

	_pushHistory(pattern) {
		let history = window.history, url = Utils.getPatternURL(pattern);
		let title = "RegExr: "+ (pattern.name || "Learn, Build, & Test RegEx");

		if (history.state && (pattern.id === history.state.id)) {
			history.replaceState(pattern, title, url);
		} else {
			history.pushState(pattern, title, url);
		}
		window.document.title = title;
	}

	_handleKey(evt) {
		let mac = Utils.isMac();
		if (evt.key === "s" && ((mac && evt.metaKey) || (!mac && evt.ctrlKey))) {
			this._doSave(false);
			evt.preventDefault();
		}
	}

	_doSave(fork) {
		// if we can't save for some reason, then show the panel.
		if (!fork && !this._canSave()) {
			app.sidebar.goto("share");
			return;
		}

		if (fork && !this._canFork()) { return; }

		let o = app.state;
		$.addClass($.query(".buttons", this.saveEl), "wait");
		this.saveStatus.distract();
		Server.save(o, fork)
			.then((data) => this._handleSave(data))
			.catch((err) => this._handleSaveErr(err));
	}

	_handleSave(data) {
		let isNew = (this._pattern.id == null), isFork = !isNew && (data.id !== this._pattern.id);
		$.removeClass($.query(".buttons", this.saveEl), "wait");
		this.saveStatus.hide();

		app.state = data;

		if (isFork || isNew) {
			app.sidebar.goto("share");
			if (isFork || !this.name) {
				this.nameFld.focus();
				this.nameFld.select();
			}

			this._linkRow.showMessage("Saved. New share link created. Click to copy to clipboard.");
		}
	}

	_handleSaveErr(err) {
		$.removeClass($.query(".buttons", this.saveEl), "wait");
		this.saveStatus.error(this._getErrMsg(err));
	}

	_doNew() {
		if (app.unsaved && !confirm("You have unsaved changes. Create new pattern without saving?")) { return; }
		app.state = {
			flavor: app.flavor.value
		}
	}

	_doPrivate() {
		let o = this._pattern;
		this._privateStatus.distract();
		Server.private(o.id, o.access !== "private")
			.then((data) => this._handlePrivate(data))
			.catch((err) => this._handleErr(err, this._privateStatus));
	}

	_handlePrivate(data) {
		if (data.id === this._pattern.id) {
			this._pattern.access = data.access;
			this._privateStatus.hide();
			this._updateUI();
		}
	}

	_doFavorite() {
		let o = this._pattern;
		this._favoritesStatus.distract();
		Server.favorite(o.id, !o.favorite)
			.then((data) => this._handleFavorite(data))
			.catch((err) => this._handleErr(err, this._favoritesStatus));
	}

	_handleFavorite(data) {
		if (data.id === this._pattern.id) {
			this._pattern.favorite = data.favorite;
			this._favoritesStatus.hide();
			this._updateUI();
		}
	}

	_doDelete() {
		let o = this._pattern;
		if (!confirm("Are you sure you want to permanently delete this pattern?")) { return; }
		this._deleteStatus.distract();
		Server.delete(o.id)
			.then((data) => this._handleDelete(data))
			.catch((err) => this._handleErr(err, this._deleteStatus));
	}

	_handleDelete(data) {
		this._deleteStatus.hide();
		app.state = {
			flavor: app.flavor.value
		}
		setTimeout(()=>app.tooltip.toggle.showOn("delete", "Pattern was permanently deleted.", this._deleteRow, true, 0), 1);
	}

	_handleErr(err, status) {
		status.error(this._getErrMsg(err)).hide(6);
	}

	_showCommunity() {
		app.sidebar.goto("share_community");
		this._comNameFld.value = this.name;
		this._comAuthorFld.value = this.author;
		this._comDescriptionFld.value = this.description;
		this._comKeywordsFld.value = this.keywords;
	}

	_doComSave() {
		if (!this._comNameFld.value) {
			this._comNameFld.focus();
			return;
		}
		let o = app.state;
		this.name = o.name = this._comNameFld.value;
		this.author = o.author = this._comAuthorFld.value;
		this.description = o.description = this._comDescriptionFld.value;
		this.keywords = o.keywords = this._comKeywordsFld.value;
		o.access = "public";
		$.addClass($.query(".buttons", this.communityEl), "wait");
		this.comSaveStatus.distract();
		Server.save(o, true)
			.then((data) => this._handleComSave(data))
			.catch((err) => this._handleComSaveErr(err));
	}

	_handleComSave(data) {
		$.removeClass($.query(".buttons", this.communityEl), "wait");
		this.comSaveStatus.hide();
		app.sidebar.goto("share");
	}

	_handleComSaveErr(err) {
		$.removeClass($.query(".buttons", this.communityEl), "wait");
		this.comSaveStatus.error(this._getErrMsg(err));
	}

	_handleChange() {
		this.dispatchEvent("change");
	}

	_handleAppChange() {
		this._updateUI();
	}

	_handleAccountChange() {
		let acc = app.account, rowEl = $.query(".signin.row", this.mainEl);
		if (!this.authorFld.value) { this.authorFld.value = acc.author || acc.username; }
		$.toggleClass(rowEl, "authenticated", acc.authenticated);
		$.query(".username", rowEl).innerText = acc.username;
	}

	_handleAppLoad() {
		$.toggleClass($.query(".save .actions", this.mainEl), "disabled");
	}

	_doSignin() {
		app.account.showTooltip();
	}

	_setSaveText(str) {
		$.query(".save .message .label", this.mainEl).innerText = str;
	}

	_getErrMsg(err) {
		return "ERROR: "+app.reference.getError("servercomm");
	}
}<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

var classes = [
  'foam.core.Serializable',
  'foam.mlang.predicate.Predicate',
  'foam.mlang.predicate.True',
  'foam.mlang.predicate.False',
  'foam.mlang.predicate.And',
  'foam.mlang.predicate.Gt',
  'foam.mlang.predicate.Or',
  'foam.mlang.predicate.AbstractPredicate',
  'foam.mlang.predicate.Nary',
  'foam.mlang.predicate.Unary',
  'foam.mlang.predicate.Binary',
  'foam.mlang.predicate.ArrayBinary',
  'foam.mlang.predicate.Contains',
  'foam.mlang.predicate.StartsWithIC',
  'foam.mlang.predicate.Gt',
  'foam.mlang.predicate.Gte',
  'foam.mlang.predicate.Lt',
  'foam.mlang.predicate.In',
  'foam.mlang.predicate.Lte',
  'foam.mlang.predicate.Has',
  'foam.mlang.sink.Count',
  'foam.mlang.sink.GroupBy',
  'foam.mlang.F',
  'foam.mlang.Expr',
  'foam.mlang.AbstractExpr',
  'foam.mlang.predicate.Eq',
  'foam.mlang.Constant',
  'foam.box.Box',
  'foam.box.Skeleton',
  'foam.box.ProxyBox',
  'foam.box.SubBox',
  'foam.box.Message',
  'foam.box.SubBoxMessage',
  'foam.box.SubscribeMessage',
  'com.google.foam.demos.appengine.TestModel',
  'foam.box.HTTPReplyBox',
  'com.google.foam.demos.appengine.TestService',
  'com.google.foam.demos.heroes.Hero',
  'com.google.auth.TokenVerifier',
  'foam.box.RemoteException',
  'foam.box.RPCMessage',
  'foam.box.RPCReturnMessage',
  'foam.box.RPCErrorMessage',
  'foam.box.BoxRegistry',
  'foam.box.BoxRegistryBox',
  'foam.box.CheckAuthenticationBox',
  'foam.dao.DAO',
  'foam.dao.Sink',
  'foam.dao.AbstractSink',
  'foam.mlang.sink.AbstractUnarySink',
  'foam.dao.PredicatedSink',
  'foam.dao.OrderedSink',
  'foam.dao.LimitedSink',
  'foam.dao.SkipSink',
  'foam.dao.ReadOnlyDAO',
  'foam.dao.RelationshipPropertyValue',
  'foam.mlang.order.Comparator',
  'foam.mlang.order.Desc',
  'foam.mlang.sink.Count',
  'foam.mlang.sink.Max',
  'foam.mlang.sink.Min',
  'foam.mlang.sink.Sum',
  'foam.mlang.sink.Map',
  'foam.nanos.NanoService',
  'foam.nanos.boot.NSpec',
  'foam.nanos.auth.EnabledAware',
  'foam.nanos.auth.Group',
  'foam.nanos.auth.LastModifiedAware',
  'foam.nanos.auth.LastModifiedByAware',
  'foam.nanos.auth.Permission',
  'foam.nanos.auth.User',
  'foam.nanos.auth.AuthService',
  'foam.nanos.auth.WebAuthService',
  'foam.nanos.pool.AbstractFixedThreadPool',
  'foam.nanos.pm.PMInfo',
  'foam.nanos.script.Language',
  'foam.nanos.script.Script',
  'foam.nanos.test.Test',
  'foam.nanos.cron.Cron',
  'foam.dao.history.PropertyUpdate',
  'foam.dao.history.HistoryRecord',
  'foam.mop.MOP',
  'foam.nanos.export.ExportDriverRegistry'
];

var abstractClasses = [
//  'foam.json.Outputter'
];

var skeletons = [
  'com.google.foam.demos.appengine.TestService',
  'foam.dao.DAO',
  'foam.mop.MOP',
  'foam.nanos.auth.WebAuthService'
];

var proxies = [
  'foam.dao.DAO',
  'foam.dao.Sink',
  'com.google.foam.demos.appengine.TestService',
  'foam.mop.MOP'
];

module.exports = {
    classes: classes,
    abstractClasses: abstractClasses,
    skeletons: skeletons,
    proxies: proxies
}
<commit_msg>Add Country to classes.<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

var classes = [
  'foam.core.Serializable',
  'foam.mlang.predicate.Predicate',
  'foam.mlang.predicate.True',
  'foam.mlang.predicate.False',
  'foam.mlang.predicate.And',
  'foam.mlang.predicate.Gt',
  'foam.mlang.predicate.Or',
  'foam.mlang.predicate.AbstractPredicate',
  'foam.mlang.predicate.Nary',
  'foam.mlang.predicate.Unary',
  'foam.mlang.predicate.Binary',
  'foam.mlang.predicate.ArrayBinary',
  'foam.mlang.predicate.Contains',
  'foam.mlang.predicate.StartsWithIC',
  'foam.mlang.predicate.Gt',
  'foam.mlang.predicate.Gte',
  'foam.mlang.predicate.Lt',
  'foam.mlang.predicate.In',
  'foam.mlang.predicate.Lte',
  'foam.mlang.predicate.Has',
  'foam.mlang.sink.Count',
  'foam.mlang.sink.GroupBy',
  'foam.mlang.F',
  'foam.mlang.Expr',
  'foam.mlang.AbstractExpr',
  'foam.mlang.predicate.Eq',
  'foam.mlang.Constant',
  'foam.box.Box',
  'foam.box.Skeleton',
  'foam.box.ProxyBox',
  'foam.box.SubBox',
  'foam.box.Message',
  'foam.box.SubBoxMessage',
  'foam.box.SubscribeMessage',
  'com.google.foam.demos.appengine.TestModel',
  'foam.box.HTTPReplyBox',
  'com.google.foam.demos.appengine.TestService',
  'com.google.foam.demos.heroes.Hero',
  'com.google.auth.TokenVerifier',
  'foam.box.RemoteException',
  'foam.box.RPCMessage',
  'foam.box.RPCReturnMessage',
  'foam.box.RPCErrorMessage',
  'foam.box.BoxRegistry',
  'foam.box.BoxRegistryBox',
  'foam.box.CheckAuthenticationBox',
  'foam.dao.DAO',
  'foam.dao.Sink',
  'foam.dao.AbstractSink',
  'foam.mlang.sink.AbstractUnarySink',
  'foam.dao.PredicatedSink',
  'foam.dao.OrderedSink',
  'foam.dao.LimitedSink',
  'foam.dao.SkipSink',
  'foam.dao.ReadOnlyDAO',
  'foam.dao.RelationshipPropertyValue',
  'foam.mlang.order.Comparator',
  'foam.mlang.order.Desc',
  'foam.mlang.sink.Count',
  'foam.mlang.sink.Max',
  'foam.mlang.sink.Min',
  'foam.mlang.sink.Sum',
  'foam.mlang.sink.Map',
  'foam.nanos.NanoService',
  'foam.nanos.boot.NSpec',
  'foam.nanos.auth.EnabledAware',
  'foam.nanos.auth.Group',
  'foam.nanos.auth.LastModifiedAware',
  'foam.nanos.auth.LastModifiedByAware',
  'foam.nanos.auth.Permission',
  'foam.nanos.auth.User',
  'foam.nanos.auth.Country',
  'foam.nanos.auth.AuthService',
  'foam.nanos.auth.WebAuthService',
  'foam.nanos.pool.AbstractFixedThreadPool',
  'foam.nanos.pm.PMInfo',
  'foam.nanos.script.Language',
  'foam.nanos.script.Script',
  'foam.nanos.test.Test',
  'foam.nanos.cron.Cron',
  'foam.dao.history.PropertyUpdate',
  'foam.dao.history.HistoryRecord',
  'foam.mop.MOP',
  'foam.nanos.export.ExportDriverRegistry'
];

var abstractClasses = [
//  'foam.json.Outputter'
];

var skeletons = [
  'com.google.foam.demos.appengine.TestService',
  'foam.dao.DAO',
  'foam.mop.MOP',
  'foam.nanos.auth.WebAuthService'
];

var proxies = [
  'foam.dao.DAO',
  'foam.dao.Sink',
  'com.google.foam.demos.appengine.TestService',
  'foam.mop.MOP'
];

module.exports = {
    classes: classes,
    abstractClasses: abstractClasses,
    skeletons: skeletons,
    proxies: proxies
}
<|endoftext|>


<commit_before>
/**
 * snd.js
 *
 * The MIT License (MIT)
 * copyright (c) 2014 - 2015 N_H <h.10x64@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **/

(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['snd'], factory);
    } else if (typeof exports === 'object') {
        // Node
    } else {
        // Browser globals (root is window)
        root.snd = factory(root.snd);
    }
}(this, function(snd) {
    /**
     * コンストラクタは使用せず、snd.AUDIO_DATA_MANAGERを使用してください。

     * @class AudioBufferの管理を行うクラスです。

     * データの読み込みだけでなく、複数のAudioBufferのローディングを待機するときなどに使用してください。
     */
    snd.AudioDataManager = function() {
        /**
         * リクエストを格納するマップ

         * {キー:XMLHttpRequest}
         */
        this._requests = {};
        /**
         * データを格納するマップ

         * {キー:{data:AudioBuffer, doesLoaded:boolean}}
         */
        this._dataMap = {};
        /**
         * イベントの送り先を格納するマップ

         * {キー:{onload:[function]}}
         */
        this._eventListeners = {};
        this._allLoadEventListeners = [];

        Object.defineProperties(this, {
            data: {
                get: function() {
                    var ret = {};
                    var keys = Object.keys(this._dataMap);
                    for (var i = 0; i < keys.length; i++) {
                        (function(obj, key, thisarg) {
                            var prop = {};
                            prop[key] = {
                                get: function() {
                                    return thisarg._dataMap[key].data;
                                }};
                            Object.defineProperties(obj, prop);
                        })(ret, keys[i], this);
                    }
                    return ret;
                }
            }
        });

    };

    /**
     * 全データの読み込みが完了したときに呼ばれるメソッドです。

     * イベントをリスナに送る際にこのオブジェクトの内部で使用されるメソッドなので、書き換えないようにしてください。

     * 全データの読み込みが完了したときに呼ばれるコールバック関数を設定したい場合、addAllDataLoadListenerメソッドを使用してください。
     */
    snd.AudioDataManager.prototype.onload = function() {
        for (var i = 0; i < this._allLoadEventListeners.length; i++) {
            this._allLoadEventListeners[i]();
        }
    };

    /**
     * 全データ読込み終了イベントのリスナへfuncで指定されたメソッドを追加します。
     * @param {type} func 全データの読込みが終了した際に呼び出されるメソッド。呼び出す時は引数なしでfunc()を実行します。
     */
    snd.AudioDataManager.prototype.addAllDataLoadListener = function(func) {
        this._allLoadEventListeners.push(func);
    };

    /**
     * 全データ読込み終了イベントのリスナからfuncで指定されたメソッドを削除します。
     * @param {type} func リストから外すメソッド
     * @returns {Boolean} 削除した場合はtrue, 削除しなかった場合はfalse
     */
    snd.AudioDataManager.prototype.removeAllDataLoadListener = function(func) {
        for (var i = 0; i < this._allLoadEventListeners.length; i++) {
            var f = this._allLoadEventListeners[i];
            if (f === func) {
                this._allLoadEventListeners.splice(i, 1);
                return true;
            }
        }
        return false;
    };

    /**
     * keyで指定されたAudioBufferの読込が終了した際に呼ばれるコールバック関数を設定します。

     * 全てのAudioBufferの読込が終了した時に呼ばれるコールバック関数を設定したい場合、snd.AudioDataManager.onloadをオーバーライドしてください。
     * @param {type} key AudioBufferをあらわすキー値
     * @param {function} func keyで指定されたAudioBufferの読込が終了した時点で呼び出されるコールバック関数
     * @see {snd.AudioDataManager.onload}
     */
    snd.AudioDataManager.prototype.addOnLoadListener = function(key, func) {
        if (this._eventListeners[key] == null) {
            this._eventListeners[key] = {
                onload: []
            };
        }
        this._eventListeners[key].onload.push(func);
    };

    /**
     * keyで指定されたAudioBufferの読込が終了した際に呼び出されるコールバック関数を削除します。

     * 指定されたkeyで追加されたコールバック関数がない場合、削除は行いません。
     * @param {type} key
     * @returns {undefined}
     */
    snd.AudioDataManager.prototype.removeOnLoadListener = function(key) {
        if (this._eventListeners[key] != null) {
            delete this._eventListeners[key];
            return true;
        }

        return false;
    };

    /**
     * keyで指定されたAudioBufferを取得します。
     * @param {type} key
     * @returns {AudioBuffer} 音データオブジェクト
     */
    snd.AudioDataManager.prototype.getAudioBuffer = function(key) {
        if (this._dataMap[key] != null) {
            return this._dataMap[key].data;
        } else {
            null;
        }
    };

    /**
     * keyがキー値となるAudioBufferを追加します。
     * @param {type} key 追加されるAudioBufferのキー値
     * @param {type} url 追加されるAudioBufferが読込むURL
     */
    snd.AudioDataManager.prototype.add = function(key, url) {
        var _this = this;
        this._dataMap[key] = {doesLoaded: false};

        var request = new XMLHttpRequest();
        request.open("GET", url, true);
        request.responseType = "arraybuffer";

        request.onload = function() {
            snd.AUDIO_CONTEXT.decodeAudioData(
                    request.response,
                    function(buf) {
                        _this._dataMap[key].data = buf;
                        _this._dataMap[key].doesLoaded = true;
                        _this.loaded(key, buf);
                    });
        };

        this._requests[key] = request;
    };

    /**
     * keyがキー値となるAudioBufferを追加します。

     * このメソッドはBase64形式のデータ文字列をAudioBufferにデコードして使用します。          * @param {String} key キー値
     * @param {String} base64String Base64形式のデータ文字列
     **/
    snd.AudioDataManager.prototype.addBase64 = function(key, base64String) {
        var _this = this;
        this._dataMap[key] = {doesLoaded: false};

        var base64DataString = "";
        var matches = base64String.toLowerCase().match(/^data:audio.*base64,(.*)$/);
        if (matches) {
            base64DataString = matches[1];
        } else {
            base64DataString = base64String;
        }

        var data = atob(base64DataString);
        var dataArray = new ArrayBuffer(data.length);
        var dataBytes = new Uint8Array(dataArray);
        for (var i = 0; i < dataArray.byteLength; i++) {
            dataBytes[i] = data.charCodeAt(i) & 0xFF;
        }

        this._requests[key] = {};
        this._requests[key].send = function() {
            snd.AUDIO_CONTEXT.decodeAudioData(
                    dataArray,
                    function(buf) {
                        _this.loaded(key, buf);
                    });
        }
    };

    /**
     * 設定された全データのロードが完了しているかどうかを返します。
     * @returns {Boolean} 全データのロードが完了しているか否か
     */
    snd.AudioDataManager.prototype.doesAllDataLoaded = function() {
        for (var key in this._dataMap) {
            if (!this._dataMap[key].doesLoaded) {
                return false;
            }
        }
        return true;
    };

    /**
     * dataSetsで渡された全てのurlを追加します。

     * dataSetsには{キー:URL}となっているハッシュマップを渡してください。

     * キーが追加されるAudioBufferのキー値として使用され、URLがAudioBufferが読込むURLとして設定されます。

     * 渡されたURLが正規表現「/^data:audio.*base64,.*$/」とマッチする場合はDataURI文字列とし、base64の文字列部分をデータとして使用します。
     *

     * addAllを使用した時点ではまだ読込は開始されません。

     * データの読込を開始するには、load関数を使用する必要があります。
     * @param {HashMap} キー値と読み込むURLを指定したハッシュマップ
     * @see {snd.AudioDataManager.load}
     */
    snd.AudioDataManager.prototype.addAll = function(dataSets) {
        var keys = Object.keys(dataSets);
        for (var i = 0; i < keys.length; i++) {
            var key = keys[i];
            var uri = dataSets[key];
            if (uri != null) {
                var uriMatches = uri.match(/^data:audio.*base64,(.*)$/);
                if (uriMatches) {
                    var base64Data = uriMatches[1];
                    this.addBase64(key, base64Data);
                } else {
                    this.add(key, uri);
                }
            }
        }
    };

    /**
     * キーで指定されたデータをこのオブジェクトから削除します。
     * @param {type} key
     */
    snd.AudioDataManager.prototype.removeData = function(key) {
        if (this._requests[key] != null) {
            delete this._requests[key];
        }
        if (this._dataMap[key] != null) {
            delete this._dataMap[key];
        }
        if (this._eventListeners[key] != null) {
            delete this.eventLiteners[key];
        }
    }
    /**
     * keySetで指定された全てのデータをこのオブジェクトから削除します
     * @param {Array} keySet key文字列の配列
     */
    snd.AudioDataManager.prototype.removeAll = function(keySet) {
        for (var i = 0; i < keySet.length; i++) {
            removeData(keySet[i]);
        }
    }

    /**
     * keyで指定されたAudioBufferの読込を開始します。

     * 引数なし(またはkey==null)で、追加済みの全てのAudioBufferの読込を開始します。

     * 全てのデータの読込が終了した時点でonloadメソッドが呼ばれます。

     * (一つでも読込が終了していないAudioBufferがあるとonloadメソッドは呼ばれない点に注意してください。)

     * ある特定のAudioBufferに対して、読込終了時のコールバック関数を指定したい場合、setOnloadListenerメソッドを使用してください。
     * @param {String} key nullの場合全データロード
     * @see {snd.AudioDataManager.onload}
     * @see {snd.AudioDataManager.setOnloadListener}
     */
    snd.AudioDataManager.prototype.load = function(key) {
        if (!key) {
            var reqKeys = Object.keys(this._requests);
            for (var i = 0; i < reqKeys.length; i++) {
                var reqKey = reqKeys[i];
                if (this._dataMap[reqKey].doesLoaded == false) {
                    if (this._requests[reqKey].readyState == null || this._requests[reqKey].readyState < 2) {
                        this._requests[reqKey].send();
                    }
                }
            }
        } else {
            if (this._requests[key].readyState == null || this._requests[key].readyState < 2) {
                this._requests[key].send();
            }
        }
    };

    /**
     * keyで取得されるAudioBufferの読込が終了した際にsnd.AUDIO_CONTEXTから呼ばれるコールバック関数です。

     * AudioDataManagerが内部で使用するための関数なので、オーバーライドはしないでください。
     * @param {type} key 読み込みの終了したキー
     * @param {buffer} buf 読込んだバッファ
     */
    snd.AudioDataManager.prototype.loaded = function(key, buffer) {
        this._dataMap[key].data = buffer;
        this._dataMap[key].doesLoaded = true;
        if (this._eventListeners[key]) {
            for (var i = 0; i < this._eventListeners[key].onload.length; i++) {
                this._eventListeners[key].onload[i](buffer);
            }
        }

        for (var k in this._dataMap) {
            if (!this._dataMap[k].doesLoaded) {
                return;
            }
        }
        this.onload();
    };

    snd._AUDIO_DATA_MANAGER = new snd.AudioDataManager();

    return snd;
}));
<commit_msg>AudioDataManagerのJSDocコメントを修正<commit_after>
/**
 * snd.js
 *
 * The MIT License (MIT)
 * copyright (c) 2014 - 2015 N_H <h.10x64@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **/

(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['snd'], factory);
    } else if (typeof exports === 'object') {
        // Node
    } else {
        // Browser globals (root is window)
        root.snd = factory(root.snd);
    }
}(this, function(snd) {
    /**
     * コンストラクタは使用せず、snd.AUDIO_DATA_MANAGERを使用してください。

     * @class AudioBufferの管理を行うクラスです。

     * データの読み込みだけでなく、複数のAudioBufferのローディングを待機するときなどに使用してください。
     */
    snd.AudioDataManager = function() {
        /**
         * リクエストを格納するマップ

         * {キー:XMLHttpRequest}
         */
        this._requests = {};
        /**
         * データを格納するマップ

         * {キー:{data:AudioBuffer, doesLoaded:boolean}}
         */
        this._dataMap = {};
        /**
         * イベントの送り先を格納するマップ

         * {キー:{onload:[function]}}
         */
        this._eventListeners = {};
        this._allLoadEventListeners = [];

        Object.defineProperties(this, {
            data: {
                get: function() {
                    var ret = {};
                    var keys = Object.keys(this._dataMap);
                    for (var i = 0; i < keys.length; i++) {
                        (function(obj, key, thisarg) {
                            var prop = {};
                            prop[key] = {
                                get: function() {
                                    return thisarg._dataMap[key].data;
                                }};
                            Object.defineProperties(obj, prop);
                        })(ret, keys[i], this);
                    }
                    return ret;
                }
            }
        });

    };

    /**
     * 全データの読み込みが完了したときに呼ばれるメソッドです。

     * イベントをリスナに送る際にこのオブジェクトの内部で使用されるメソッドなので、書き換えないようにしてください。

     * 全データの読み込みが完了したときに呼ばれるコールバック関数を設定したい場合、addAllDataLoadListenerメソッドを使用してください。
     */
    snd.AudioDataManager.prototype.onload = function() {
        for (var i = 0; i < this._allLoadEventListeners.length; i++) {
            this._allLoadEventListeners[i]();
        }
    };

    /**
     * 全データ読込み終了イベントのリスナへfuncで指定されたメソッドを追加します。
     * @param {type} func 全データの読込みが終了した際に呼び出されるメソッド。呼び出す時は引数なしでfunc()を実行します。
     */
    snd.AudioDataManager.prototype.addAllDataLoadListener = function(func) {
        this._allLoadEventListeners.push(func);
    };

    /**
     * 全データ読込み終了イベントのリスナからfuncで指定されたメソッドを削除します。
     * @param {type} func リストから外すメソッド
     * @returns {Boolean} 削除した場合はtrue, 削除しなかった場合はfalse
     */
    snd.AudioDataManager.prototype.removeAllDataLoadListener = function(func) {
        for (var i = 0; i < this._allLoadEventListeners.length; i++) {
            var f = this._allLoadEventListeners[i];
            if (f === func) {
                this._allLoadEventListeners.splice(i, 1);
                return true;
            }
        }
        return false;
    };

    /**
     * keyで指定されたAudioBufferの読込が終了した際に呼ばれるコールバック関数を設定します。

     * 全てのAudioBufferの読込が終了した時に呼ばれるコールバック関数を設定したい場合、snd.AudioDataManager.onloadをオーバーライドしてください。
     * @param {type} key AudioBufferをあらわすキー値
     * @param {function} func keyで指定されたAudioBufferの読込が終了した時点で呼び出されるコールバック関数
     * @see {snd.AudioDataManager.onload}
     */
    snd.AudioDataManager.prototype.addOnLoadListener = function(key, func) {
        if (this._eventListeners[key] == null) {
            this._eventListeners[key] = {
                onload: []
            };
        }
        this._eventListeners[key].onload.push(func);
    };

    /**
     * keyで指定されたAudioBufferの読込が終了した際に呼び出されるコールバック関数を削除します。

     * 指定されたkeyで追加されたコールバック関数がない場合、削除は行いません。
     * @param {type} key
     * @returns {undefined}
     */
    snd.AudioDataManager.prototype.removeOnLoadListener = function(key) {
        if (this._eventListeners[key] != null) {
            delete this._eventListeners[key];
            return true;
        }

        return false;
    };

    /**
     * keyで指定されたAudioBufferを取得します。
     * @param {type} key
     * @returns {AudioBuffer} 音データオブジェクト
     */
    snd.AudioDataManager.prototype.getAudioBuffer = function(key) {
        if (this._dataMap[key] != null) {
            return this._dataMap[key].data;
        } else {
            null;
        }
    };

    /**
     * keyがキー値となるAudioBufferを追加します。
     * @param {type} key 追加されるAudioBufferのキー値
     * @param {type} url 追加されるAudioBufferが読込むURL
     */
    snd.AudioDataManager.prototype.add = function(key, url) {
        var _this = this;
        this._dataMap[key] = {doesLoaded: false};

        var request = new XMLHttpRequest();
        request.open("GET", url, true);
        request.responseType = "arraybuffer";

        request.onload = function() {
            snd.AUDIO_CONTEXT.decodeAudioData(
                    request.response,
                    function(buf) {
                        _this._dataMap[key].data = buf;
                        _this._dataMap[key].doesLoaded = true;
                        _this.loaded(key, buf);
                    });
        };

        this._requests[key] = request;
    };

    /**
     * keyがキー値となるAudioBufferを追加します。

     * このメソッドはBase64形式のデータ文字列をAudioBufferにデコードして使用します。
     * @param {String} key キー値
     * @param {String} base64String Base64形式のデータ文字列
     **/
    snd.AudioDataManager.prototype.addBase64 = function(key, base64String) {
        var _this = this;
        this._dataMap[key] = {doesLoaded: false};

        var base64DataString = "";
        var matches = base64String.toLowerCase().match(/^data:audio.*base64,(.*)$/);
        if (matches) {
            base64DataString = matches[1];
        } else {
            base64DataString = base64String;
        }

        var data = atob(base64DataString);
        var dataArray = new ArrayBuffer(data.length);
        var dataBytes = new Uint8Array(dataArray);
        for (var i = 0; i < dataArray.byteLength; i++) {
            dataBytes[i] = data.charCodeAt(i) & 0xFF;
        }

        this._requests[key] = {};
        this._requests[key].send = function() {
            snd.AUDIO_CONTEXT.decodeAudioData(
                    dataArray,
                    function(buf) {
                        _this.loaded(key, buf);
                    });
        }
    };

    /**
     * 設定された全データのロードが完了しているかどうかを返します。
     * @returns {Boolean} 全データのロードが完了しているか否か
     */
    snd.AudioDataManager.prototype.doesAllDataLoaded = function() {
        for (var key in this._dataMap) {
            if (!this._dataMap[key].doesLoaded) {
                return false;
            }
        }
        return true;
    };

    /**
     * dataSetsで渡された全てのurlを追加します。

     * dataSetsには{キー:URL}となっているハッシュマップを渡してください。

     * キーが追加されるAudioBufferのキー値として使用され、URLがAudioBufferが読込むURLとして設定されます。

     * 渡されたURLが正規表現「/^data:audio.*base64,.*$/」とマッチする場合はDataURI文字列とし、base64の文字列部分をデータとして使用します。
     *

     * addAllを使用した時点ではまだ読込は開始されません。

     * データの読込を開始するには、load関数を使用する必要があります。
     * @param {HashMap} キー値と読み込むURLを指定したハッシュマップ
     * @see {snd.AudioDataManager.load}
     */
    snd.AudioDataManager.prototype.addAll = function(dataSets) {
        var keys = Object.keys(dataSets);
        for (var i = 0; i < keys.length; i++) {
            var key = keys[i];
            var uri = dataSets[key];
            if (uri != null) {
                var uriMatches = uri.match(/^data:audio.*base64,(.*)$/);
                if (uriMatches) {
                    var base64Data = uriMatches[1];
                    this.addBase64(key, base64Data);
                } else {
                    this.add(key, uri);
                }
            }
        }
    };

    /**
     * キーで指定されたデータをこのオブジェクトから削除します。
     * @param {type} key
     */
    snd.AudioDataManager.prototype.removeData = function(key) {
        if (this._requests[key] != null) {
            delete this._requests[key];
        }
        if (this._dataMap[key] != null) {
            delete this._dataMap[key];
        }
        if (this._eventListeners[key] != null) {
            delete this.eventLiteners[key];
        }
    }
    /**
     * keySetで指定された全てのデータをこのオブジェクトから削除します
     * @param {Array} keySet key文字列の配列
     */
    snd.AudioDataManager.prototype.removeAll = function(keySet) {
        for (var i = 0; i < keySet.length; i++) {
            removeData(keySet[i]);
        }
    }

    /**
     * keyで指定されたAudioBufferの読込を開始します。

     * 引数なし(またはkey==null)で、追加済みの全てのAudioBufferの読込を開始します。

     * 全てのデータの読込が終了した時点でonloadメソッドが呼ばれます。

     * (一つでも読込が終了していないAudioBufferがあるとonloadメソッドは呼ばれない点に注意してください。)

     * ある特定のAudioBufferに対して、読込終了時のコールバック関数を指定したい場合、setOnloadListenerメソッドを使用してください。
     * @param {String} key nullの場合全データロード
     * @see {snd.AudioDataManager.onload}
     * @see {snd.AudioDataManager.setOnloadListener}
     */
    snd.AudioDataManager.prototype.load = function(key) {
        if (!key) {
            var reqKeys = Object.keys(this._requests);
            for (var i = 0; i < reqKeys.length; i++) {
                var reqKey = reqKeys[i];
                if (this._dataMap[reqKey].doesLoaded == false) {
                    if (this._requests[reqKey].readyState == null || this._requests[reqKey].readyState < 2) {
                        this._requests[reqKey].send();
                    }
                }
            }
        } else {
            if (this._requests[key].readyState == null || this._requests[key].readyState < 2) {
                this._requests[key].send();
            }
        }
    };

    /**
     * keyで取得されるAudioBufferの読込が終了した際にsnd.AUDIO_CONTEXTから呼ばれるコールバック関数です。

     * AudioDataManagerが内部で使用するための関数なので、オーバーライドはしないでください。
     * @param {type} key 読み込みの終了したキー
     * @param {buffer} buf 読込んだバッファ
     */
    snd.AudioDataManager.prototype.loaded = function(key, buffer) {
        this._dataMap[key].data = buffer;
        this._dataMap[key].doesLoaded = true;
        if (this._eventListeners[key]) {
            for (var i = 0; i < this._eventListeners[key].onload.length; i++) {
                this._eventListeners[key].onload[i](buffer);
            }
        }

        for (var k in this._dataMap) {
            if (!this._dataMap[k].doesLoaded) {
                return;
            }
        }
        this.onload();
    };

    snd._AUDIO_DATA_MANAGER = new snd.AudioDataManager();

    return snd;
}));
<|endoftext|>


<commit_before>var urlParams;
var levelParam;
var gameOnlyMode;
var startAkihabara;

function compressObject(obj) {
  var jsonString = jQuery.toJSON(obj);
  var compressed = LZMA.compress(jsonString);
  compressed     = jQuery.toJSON(compressed);
  return jQuery.base64.encode(compressed);
}

function decompressToObject(paramsCompressed) {
  var paramsDecoded      = jQuery.base64.decode(paramsCompressed);
  paramsDecoded          = jQuery.parseJSON(paramsDecoded);
  var paramsDeCompressed = LZMA.decompress(paramsDecoded);
  return jQuery.parseJSON(paramsDeCompressed);
}

function getURLParam(name) {
  return urlParams[name] || '';
}

function initGameMode() {
  $('#top_tools').hide();
  $('#credits').hide();
  var url = window.location.protocol + "//" + window.location.host + window.location.pathname + '?encoded='+compressObject({ level: levelParam, plugins: getURLParam("plugins")});
  // var url = window.location.protocol + "//" + window.location.host + window.location.pathname + '?encoded=';
  $('#intro p').first().html('Click here to make more levels like this one, right in your browser!')
  $('#imageView').hide();
  $('#admin_sidebar').hide();
}

function loadPalette() {
  imgs = [];
  for(var i = 0; i < 10; i++) {
    var img = new Image();
    img.src = 'resources/palettes/default/' + i.toString() + '.png';
    img.id = 'brush' + i;
    img.setAttribute("class", "brush");
    $(img).appendTo('#palette');
  }
	head.ready(function (){
		for(pluginID in loadedPlugins){
			var plugin = loadedPlugins[pluginID];
			if(plugin.paletteImage){
				var img = new Image();
				img.src = plugin.paletteImage;
				img.id = "brush"+pluginID;
				img.setAttribute("class", "brush");
				$(img).appendTo('#palette');
			}
		}
	});

}

function collapseLongText() {
  $('.fulltext').hide();
  $('.shorttext').click(function() {
    $(this).hide().siblings('.fulltext').show();
  });
}

function initEditorControls() {
  $().enableUndo({ redoCtrlChar : 'y', redoShiftReq : false });

  $('#imageView').mouseup(function() {
    if ($('#toggle_autoupdate input:checked').length) {
      redrawMap();
    }
  });

  $('
UndoRedo
').appendTo('#undo_counter').find("a:contains('Undo')").click(function() {
    $().undo();
  }).parent().find("a:contains('Redo')").click(function() {
    $().redo();
  });

  $('#generate_url').click(function() {
    generateShortURL();

    return false;
  });

  if (name = getURLParam('name')) {
    $('#level_name input').val(name);
  }

  $('.credits a').attr('target', '_blank');
}<commit_msg>Re-enabled history<commit_after>var urlParams;
var levelParam;
var gameOnlyMode;
var startAkihabara;

function compressObject(obj) {
  var jsonString = jQuery.toJSON(obj);
  var compressed = LZMA.compress(jsonString);
  compressed     = jQuery.toJSON(compressed);
  return jQuery.base64.encode(compressed);
}

function decompressToObject(paramsCompressed) {
  var paramsDecoded      = jQuery.base64.decode(paramsCompressed);
  paramsDecoded          = jQuery.parseJSON(paramsDecoded);
  var paramsDeCompressed = LZMA.decompress(paramsDecoded);
  return jQuery.parseJSON(paramsDeCompressed);
}

function getURLParam(name) {
  return urlParams[name] || '';
}

function initGameMode() {
  $('#top_tools').hide();
  $('#credits').hide();
  var url = window.location.protocol + "//" + window.location.host + window.location.pathname + '?encoded='+compressObject({ level: levelParam, plugins: getURLParam("plugins")});
  // var url = window.location.protocol + "//" + window.location.host + window.location.pathname + '?encoded=';
  $('#intro p').first().html('Click here to make more levels like this one, right in your browser!')
  $('#imageView').hide();
  $('#admin_sidebar').hide();
}

function loadPalette() {
  imgs = [];
  for(var i = 0; i < 10; i++) {
    var img = new Image();
    img.src = 'resources/palettes/default/' + i.toString() + '.png';
    img.id = 'brush' + i;
    img.setAttribute("class", "brush");
    $(img).appendTo('#palette');
  }
	head.ready(function (){
		for(pluginID in loadedPlugins){
			var plugin = loadedPlugins[pluginID];
			if(plugin.paletteImage){
				var img = new Image();
				img.src = plugin.paletteImage;
				img.id = "brush"+pluginID;
				img.setAttribute("class", "brush");
				$(img).appendTo('#palette');
			}
		}
	});

}

function collapseLongText() {
  $('.fulltext').hide();
  $('.shorttext').click(function() {
    $(this).hide().siblings('.fulltext').show();
  });
}

function initEditorControls() {
  $().enableUndo({ redoCtrlChar : 'y', redoShiftReq : false });

  $('#imageView').mouseup(function() {
    redrawMap();
  });

  $('
UndoRedo
').appendTo('#undo_counter').find("a:contains('Undo')").click(function() {
    $().undo();
  }).parent().find("a:contains('Redo')").click(function() {
    $().redo();
  });

  $('#generate_url').click(function() {
    generateShortURL();

    return false;
  });

  if (name = getURLParam('name')) {
    $('#level_name input').val(name);
  }

  $('.credits a').attr('target', '_blank');
}<|endoftext|>