<commit_before>var Hoptoad = {
  VERSION           : '0.1.0',
  NOTICE_XML        : '<?xml version="1.0" encoding="UTF-8"?><notice version="2.0"><api-key></api-key><notifier><name>airbrake_js</name><version>0.1.0</version><url>http://airbrake.io</url></notifier><error><class>EXCEPTION_CLASS</class><message>EXCEPTION_MESSAGE</message><backtrace>BACKTRACE_LINES</backtrace></error><request><url>REQUEST_URL</url><component>REQUEST_COMPONENT</component><action>REQUEST_ACTION</action></request><server-environment><project-root>PROJECT_ROOT</project-root><environment-name>production</environment-name></server-environment></notice>',
  ROOT              : window.location.protocol + '//' + window.location.host,
  BACKTRACE_MATCHER : /^(.*)\@(.*)\:(\d+)$/,
  backtrace_filters : [/notifier\.js/],

  notify: function(error) {
    var xml     = escape(Hoptoad.generateXML(error));
    var host    = Hoptoad.host || 'airbrake.io';
    var url     = '//' + host + '/notifier_api/v2/notices?data=' + xml;
    var request = document.createElement('iframe');

    request.style.width   = '1px';
    request.style.height  = '1px';
    request.style.display = 'none';
    request.src = url;

    document.getElementsByTagName('head')[0].appendChild(request);
  },

  setEnvironment: function(value) {
    var matcher = /<environment-name>.*<\/environment-name>/;

    Hoptoad.NOTICE_XML  = Hoptoad.NOTICE_XML.replace(matcher,
                                                     '<environment-name>' +
                                                       value +
                                                     '</environment-name>')
  },

  setHost: function(value) {
    Hoptoad.host = value;
  },

  setKey: function(value) {
    var matcher = /<api-key>.*<\/api-key>/;

    Hoptoad.NOTICE_XML = Hoptoad.NOTICE_XML.replace(matcher,
                                                    '<api-key>' +
                                                      value +
                                                    '</api-key>');
  },

  setErrorDefaults: function(value) {
    Hoptoad.errorDefaults = value;
  },

  generateXML: function(errorWithoutDefaults) {
    var error = Hoptoad.mergeDefault(Hoptoad.errorDefaults, errorWithoutDefaults);

    var xml       = Hoptoad.NOTICE_XML;
    var baseUrl   = error.url     || '';
    var hash      = location.hash || '';
    var url       = Hoptoad.escapeText((baseUrl + hash) || '');
    var component = Hoptoad.escapeText(error.component  || '');
    var action    = Hoptoad.escapeText(error.action     || '');
    var errorType = Hoptoad.escapeText(error.type       || 'Error');
    var message   = Hoptoad.escapeText(error.message    || 'Unknown error.');
    var backtrace = Hoptoad.generateBacktrace(error);

    if (Hoptoad.trim(url) == '' && Hoptoad.trim(component) == '') {
      xml = xml.replace(/<request>.*<\/request>/, '');
    } else {
      var data    = '';

      var cgi_data = error['cgi-data'] || {};
      cgi_data["HTTP_USER_AGENT"] = navigator.userAgent;
      data += '<cgi-data>';
      data += Hoptoad.generateVariables(cgi_data);
      data += '</cgi-data>';

      var methods = ['params', 'session'];

      for (var i = 0; i < 2; i++) {
        var type = methods[i];

        if (error[type]) {
          data += '<' + type + '>';
          data += Hoptoad.generateVariables(error[type]);
          data += '</' + type + '>';
        }
      }

      xml = xml.replace('</request>',        data + '</request>')
               .replace('REQUEST_URL',       url)
               .replace('REQUEST_ACTION',    action)
               .replace('REQUEST_COMPONENT', component);
    }

    return xml.replace('PROJECT_ROOT',      Hoptoad.ROOT)
              .replace('EXCEPTION_CLASS',   errorType)
              .replace('EXCEPTION_MESSAGE', message)
              .replace('BACKTRACE_LINES',   backtrace.join(''));
  },

  generateBacktrace: function(error) {
    error = error || {};

    if (typeof error.stack != 'string') {
      try {
        (0)();
      } catch(e) {
        error.stack = e.stack;
      }
    }

    var backtrace  = [];
    var stacktrace = Hoptoad.getStackTrace(error);

    for (var i = 0, l = stacktrace.length; i < l; i++) {
      var line    = stacktrace[i];
      var matches = line.match(Hoptoad.BACKTRACE_MATCHER);

      if (matches && Hoptoad.validBacktraceLine(line)) {
        var file = matches[2].replace(Hoptoad.ROOT, '[PROJECT_ROOT]');

        if (i == 0) {
          if (matches[2].match(document.location.href)) {
            backtrace.push('<line method="" file="internal: " number=""/>');
          }
        }

        backtrace.push('<line method="' + Hoptoad.escapeText(matches[1]) +
                       '" file="' + Hoptoad.escapeText(file) +
                       '" number="' + matches[3] + '" />');
      }
    }

    return backtrace;
  },

  getStackTrace: function(error) {
    var stacktrace = printStackTrace({ e : error, guess : false });

    for (var i = 0, l = stacktrace.length; i < l; i++) {
      if (stacktrace[i].match(/\:\d+$/)) {
        continue;
      }

      if (stacktrace[i].indexOf('@') == -1) {
        stacktrace[i] += '@unsupported.js';
      }

      stacktrace[i] += ':0';
    }

    return stacktrace;
  },

  validBacktraceLine: function(line) {
    for (var i = 0; i < Hoptoad.backtrace_filters.length; i++) {
      if (line.match(Hoptoad.backtrace_filters[i])) {
        return false;
      }
    }

    return true;
  },

  generateVariables: function(parameters) {
    var key;
    var result = '';

    for (key in parameters) {
      result += '<var key="' + Hoptoad.escapeText(key) + '">' +
                  Hoptoad.escapeText(parameters[key]) +
                '</var>';
    }

    return result;
  },

  escapeText: function(text) {
    return text.replace(/&/g, '&')
               .replace(/</g, '<')
               .replace(/>/g, '>')
               .replace(/'/g, ''')
               .replace(/"/g, '"');
  },

  trim: function(text) {
    return text.toString().replace(/^\s+/, '').replace(/\s+$/, '');
  },

  mergeDefault: function(defaults, hash) {
    var cloned = {};
    var key;

    for (key in hash) {
      cloned[key] = hash[key];
    }

    for (key in defaults) {
      if (!cloned.hasOwnProperty(key)) {
        cloned[key] = defaults[key];
      }
    }

    return cloned;
  }
};

// Domain Public by Eric Wendelin http://eriwen.com/ (2008)
//                  Luke Smith http://lucassmith.name/ (2008)
//                  Loic Dachary <loic@dachary.org> (2008)
//                  Johan Euphrosine <proppy@aminche.com> (2008)
//                  Ã˜yvind Sean Kinsey http://kinsey.no/blog (2010)
//                  Victor Homyakov <victor-homyakov@users.sourceforge.net> (2010)
//
// Information and discussions
// http://jspoker.pokersource.info/skin/test-printstacktrace.html
// http://eriwen.com/javascript/js-stack-trace/
// http://eriwen.com/javascript/stacktrace-update/
// http://pastie.org/253058
//
// guessFunctionNameFromLines comes from firebug
//
// Software License Agreement (BSD License)
//
// Copyright (c) 2007, Parakey Inc.
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above
//   copyright notice, this list of conditions and the
//   following disclaimer.
//
// * Redistributions in binary form must reproduce the above
//   copyright notice, this list of conditions and the
//   following disclaimer in the documentation and/or other
//   materials provided with the distribution.
//
// * Neither the name of Parakey Inc. nor the names of its
//   contributors may be used to endorse or promote products
//   derived from this software without specific prior
//   written permission of Parakey Inc.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function printStackTrace(a){var a=a||{guess:!0},b=a.e||null,a=!!a.guess,c=new printStackTrace.implementation,b=c.run(b);return a?c.guessFunctions(b):b}printStackTrace.implementation=function(){};
printStackTrace.implementation.prototype={run:function(a){var a=a||this.createException(),b=this.mode(a);return b==="other"?this.other(arguments.callee):this[b](a)},createException:function(){try{return this.undef(),null}catch(a){return a}},mode:function(a){if(a.arguments&&a.stack)return this._mode="chrome";else if(typeof window!=="undefined"&&window.opera)return this._mode=a.stacktrace?"opera10":"opera";else if(a.stack)return this._mode="firefox";return this._mode="other"},instrumentFunction:function(a,
b,c){a=a||window;a["_old"+b]=a[b];a[b]=function(){c.call(this,printStackTrace());return a["_old"+b].apply(this,arguments)};a[b]._instrumented=!0},deinstrumentFunction:function(a,b){a[b].constructor===Function&&a[b]._instrumented&&a["_old"+b].constructor===Function&&(a[b]=a["_old"+b])},chrome:function(a){return a.stack.replace(/^[^\(]+?[\n$]/gm,"").replace(/^\s+at\s+/gm,"").replace(/^Object.<anonymous>\s*\(/gm,"{anonymous}()@").split("\n")},firefox:function(a){return a.stack.replace(/(?:\n@:0)?\s+$/m,
"").replace(/^\(/gm,"{anonymous}(").split("\n")},opera10:function(a){var a=a.stacktrace.split("\n"),b=/.*line (\d+), column (\d+) in ((<anonymous function\:?\s*(\S+))|([^\(]+)\([^\)]*\))(?: in )?(.*)\s*$/i,c,d,e;c=2;d=0;for(e=a.length;c<e-2;c++)if(b.test(a[c])){var g=RegExp.$6+":"+RegExp.$1+":"+RegExp.$2,f=RegExp.$3,f=f.replace(/<anonymous function\:?\s?(\S+)?>/g,"{anonymous}");a[d++]=f+"@"+g}a.splice(d,a.length-d);return a},opera:function(a){var a=a.message.split("\n"),b=/Line\s+(\d+).*script\s+(http\S+)(?:.*in\s+function\s+(\S+))?/i,
c,d,e;c=4;d=0;for(e=a.length;c<e;c+=2)b.test(a[c])&&(a[d++]=(RegExp.$3?RegExp.$3+"()@"+RegExp.$2+RegExp.$1:"{anonymous}()@"+RegExp.$2+":"+RegExp.$1)+" -- "+a[c+1].replace(/^\s+/,""));a.splice(d,a.length-d);return a},other:function(a){for(var b=/function\s*([\w\-$]+)?\s*\(/i,c=[],d,e;a&&c.length<10;)d=b.test(a.toString())?RegExp.$1||"{anonymous}":"{anonymous}",e=Array.prototype.slice.call(a.arguments||[]),c[c.length]=d+"("+this.stringifyArguments(e)+")",a=a.caller;return c},stringifyArguments:function(a){for(var b=
0;b<a.length;++b){var c=a[b];c===void 0?a[b]="undefined":c===null?a[b]="null":c.constructor&&(c.constructor===Array?a[b]=c.length<3?"["+this.stringifyArguments(c)+"]":"["+this.stringifyArguments(Array.prototype.slice.call(c,0,1))+"..."+this.stringifyArguments(Array.prototype.slice.call(c,-1))+"]":c.constructor===Object?a[b]="#object":c.constructor===Function?a[b]="#function":c.constructor===String&&(a[b]='"'+c+'"'))}return a.join(",")},sourceCache:{},ajax:function(a){var b=this.createXMLHTTPObject();
if(b)return b.open("GET",a,!1),b.setRequestHeader("User-Agent","XMLHTTP/1.0"),b.send(""),b.responseText},createXMLHTTPObject:function(){for(var a,b=[function(){return new XMLHttpRequest},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Msxml3.XMLHTTP")},function(){return new ActiveXObject("Microsoft.XMLHTTP")}],c=0;c<b.length;c++)try{return a=b[c](),this.createXMLHTTPObject=b[c],a}catch(d){}},isSameDomain:function(a){return a.indexOf(location.hostname)!==
-1},getSource:function(a){a in this.sourceCache||(this.sourceCache[a]=this.ajax(a).split("\n"));return this.sourceCache[a]},guessFunctions:function(a){for(var b=0;b<a.length;++b){var c=a[b],d=/\{anonymous\}\(.*\)@(\w+:\/\/([\-\w\.]+)+(:\d+)?[^:]+):(\d+):?(\d+)?/.exec(c);if(d){var e=d[1],d=d[4];e&&this.isSameDomain(e)&&d&&(e=this.guessFunctionName(e,d),a[b]=c.replace("{anonymous}",e))}}return a},guessFunctionName:function(a,b){var c;try{c=this.guessFunctionNameFromLines(b,this.getSource(a))}catch(d){c=
"getSource failed with url: "+a+", exception: "+d.toString()}return c},guessFunctionNameFromLines:function(a,b){for(var c=/function ([^(]*)\(([^)]*)\)/,d=/['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(function|eval|new Function)/,e="",g=0;g<10;++g)if(e=b[a-g]+e,e!==void 0){var f=d.exec(e);if(f&&f[1])return f[1];else if((f=c.exec(e))&&f[1])return f[1]}return"(?)"}};

window.onerror = function(message, file, line) {
  setTimeout(function() {
    Hoptoad.notify({
      message : message,
      stack   : '()@' + file + ':' + line
    });
  }, 100);
  return true;
};
<commit_msg>Fixed spacing.<commit_after>var Hoptoad = {
	VERSION: '0.1.0',
	NOTICE_XML: '<?xml version="1.0" encoding="UTF-8"?><notice version="2.0"><api-key></api-key><notifier><name>airbrake_js</name><version>0.1.0</version><url>http://airbrake.io</url></notifier><error><class>EXCEPTION_CLASS</class><message>EXCEPTION_MESSAGE</message><backtrace>BACKTRACE_LINES</backtrace></error><request><url>REQUEST_URL</url><component>REQUEST_COMPONENT</component><action>REQUEST_ACTION</action></request><server-environment><project-root>PROJECT_ROOT</project-root><environment-name>production</environment-name></server-environment></notice>',
	ROOT: window.location.protocol + '//' + window.location.host,
	BACKTRACE_MATCHER: /^(.*)\@(.*)\:(\d+)$/,
	backtrace_filters: [/notifier\.js/],

	notify: function(error) {
		var xml = escape(Hoptoad.generateXML(error));
		var host = Hoptoad.host || 'airbrake.io';
		var url = '//' + host + '/notifier_api/v2/notices?data=' + xml;
		var request = document.createElement('iframe');

		request.style.width = '1px';
		request.style.height = '1px';
		request.style.display = 'none';
		request.src = url;

		document.getElementsByTagName('head')[0].appendChild(request);
	},

	setEnvironment: function(value) {
		var find = /<environment-name>.*<\/environment-name>/,
			replace = '<environment-name>' + value + '</environment-name>';

		Hoptoad.NOTICE_XML  = Hoptoad.NOTICE_XML.replace(find, replace)
	},

	setHost: function(value) {
		Hoptoad.host = value;
	},

	setKey: function(value) {
		var find = /<api-key>.*<\/api-key>/,
			replace = '<api-key>' + value + '</api-key>';

		Hoptoad.NOTICE_XML = Hoptoad.NOTICE_XML.replace(find, replace);
	},

	setErrorDefaults: function(value) {
		Hoptoad.errorDefaults = value;
	},

	generateXML: function(errorWithoutDefaults) {
		var error = Hoptoad.mergeDefault(Hoptoad.errorDefaults, errorWithoutDefaults);

		var xml = Hoptoad.NOTICE_XML;
		var baseUrl = error.url || '';
		var hash = location.hash || '';
		var url = Hoptoad.escapeText((baseUrl + hash) || '');
		var component = Hoptoad.escapeText(error.component || '');
		var action = Hoptoad.escapeText(error.action || '');
		var errorType = Hoptoad.escapeText(error.type || 'Error');
		var message = Hoptoad.escapeText(error.message || 'Unknown error.');
		var backtrace = Hoptoad.generateBacktrace(error);

		if (Hoptoad.trim(url) == '' && Hoptoad.trim(component) == '') {
			xml = xml.replace(/<request>.*<\/request>/, '');
		} else {
			var data = '';

			var cgi_data = error['cgi-data'] || {};
			cgi_data["HTTP_USER_AGENT"] = navigator.userAgent;
			data += '<cgi-data>';
			data += Hoptoad.generateVariables(cgi_data);
			data += '</cgi-data>';

			var methods = ['params', 'session'];

			for (var i = 0; i < 2; i++) {
				var type = methods[i];

				if (error[type]) {
					data += '<' + type + '>';
					data += Hoptoad.generateVariables(error[type]);
					data += '</' + type + '>';
				}
			}

			xml = xml.replace('</request>', data + '</request>')
				.replace('REQUEST_URL', url)
				.replace('REQUEST_ACTION', action)
				.replace('REQUEST_COMPONENT', component);
		}

		return xml.replace('PROJECT_ROOT', Hoptoad.ROOT)
			.replace('EXCEPTION_CLASS', errorType)
			.replace('EXCEPTION_MESSAGE', message)
			.replace('BACKTRACE_LINES', backtrace.join(''));
	},

	generateBacktrace: function(error) {
		error = error || {};

		if (typeof error.stack != 'string') {
			try {
				(0)();
			} catch(e) {
				error.stack = e.stack;
			}
		}

		var backtrace  = [];
		var stacktrace = Hoptoad.getStackTrace(error);

		for (var i = 0, l = stacktrace.length; i < l; i++) {
			var line    = stacktrace[i];
			var matches = line.match(Hoptoad.BACKTRACE_MATCHER);

			if (matches && Hoptoad.validBacktraceLine(line)) {
				var file = matches[2].replace(Hoptoad.ROOT, '[PROJECT_ROOT]');

				if (i == 0 && matches[2].match(document.location.href)) {
					backtrace.push('<line method="" file="internal: " number=""/>');
				}

				backtrace.push('<line method="' + Hoptoad.escapeText(matches[1]) +
					'" file="' + Hoptoad.escapeText(file) +
					'" number="' + matches[3] + '" />');
			}
		}

		return backtrace;
	},

	getStackTrace: function(error) {
		var stacktrace = printStackTrace({ e : error, guess : false });

		for (var i = 0, l = stacktrace.length; i < l; i++) {
			if (stacktrace[i].match(/\:\d+$/)) {
				continue;
			}

			if (stacktrace[i].indexOf('@') == -1) {
				stacktrace[i] += '@unsupported.js';
			}

			stacktrace[i] += ':0';
		}

		return stacktrace;
	},

	validBacktraceLine: function(line) {
		for (var i = 0; i < Hoptoad.backtrace_filters.length; i++) {
			if (line.match(Hoptoad.backtrace_filters[i])) {
				return false;
			}
		}

		return true;
	},

	generateVariables: function(parameters) {
		var key;
		var result = '';

		for (key in parameters) {
			result += '<var key="' + Hoptoad.escapeText(key) + '">'
				+ Hoptoad.escapeText(parameters[key])
				+ '</var>';
		}

		return result;
	},

	escapeText: function(text) {
		return text.replace(/&/g, '&')
			.replace(/</g, '<')
			.replace(/>/g, '>')
			.replace(/'/g, ''')
			.replace(/"/g, '"');
	},

	trim: function(text) {
		return text.toString().replace(/^\s+/, '').replace(/\s+$/, '');
	},

	mergeDefault: function(defaults, hash) {
		var cloned = {};
		var key;

		for (key in hash) {
			cloned[key] = hash[key];
		}

		for (key in defaults) {
			if (!cloned.hasOwnProperty(key)) {
				cloned[key] = defaults[key];
			}
		}

		return cloned;
	}
};

// Domain Public by Eric Wendelin http://eriwen.com/ (2008)
//                  Luke Smith http://lucassmith.name/ (2008)
//                  Loic Dachary <loic@dachary.org> (2008)
//                  Johan Euphrosine <proppy@aminche.com> (2008)
//                  Ã˜yvind Sean Kinsey http://kinsey.no/blog (2010)
//                  Victor Homyakov <victor-homyakov@users.sourceforge.net> (2010)
//
// Information and discussions
// http://jspoker.pokersource.info/skin/test-printstacktrace.html
// http://eriwen.com/javascript/js-stack-trace/
// http://eriwen.com/javascript/stacktrace-update/
// http://pastie.org/253058
//
// guessFunctionNameFromLines comes from firebug
//
// Software License Agreement (BSD License)
//
// Copyright (c) 2007, Parakey Inc.
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above
//   copyright notice, this list of conditions and the
//   following disclaimer.
//
// * Redistributions in binary form must reproduce the above
//   copyright notice, this list of conditions and the
//   following disclaimer in the documentation and/or other
//   materials provided with the distribution.
//
// * Neither the name of Parakey Inc. nor the names of its
//   contributors may be used to endorse or promote products
//   derived from this software without specific prior
//   written permission of Parakey Inc.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function printStackTrace(a){var a=a||{guess:!0},b=a.e||null,a=!!a.guess,c=new printStackTrace.implementation,b=c.run(b);return a?c.guessFunctions(b):b}printStackTrace.implementation=function(){};
printStackTrace.implementation.prototype={run:function(a){var a=a||this.createException(),b=this.mode(a);return b==="other"?this.other(arguments.callee):this[b](a)},createException:function(){try{return this.undef(),null}catch(a){return a}},mode:function(a){if(a.arguments&&a.stack)return this._mode="chrome";else if(typeof window!=="undefined"&&window.opera)return this._mode=a.stacktrace?"opera10":"opera";else if(a.stack)return this._mode="firefox";return this._mode="other"},instrumentFunction:function(a,
b,c){a=a||window;a["_old"+b]=a[b];a[b]=function(){c.call(this,printStackTrace());return a["_old"+b].apply(this,arguments)};a[b]._instrumented=!0},deinstrumentFunction:function(a,b){a[b].constructor===Function&&a[b]._instrumented&&a["_old"+b].constructor===Function&&(a[b]=a["_old"+b])},chrome:function(a){return a.stack.replace(/^[^\(]+?[\n$]/gm,"").replace(/^\s+at\s+/gm,"").replace(/^Object.<anonymous>\s*\(/gm,"{anonymous}()@").split("\n")},firefox:function(a){return a.stack.replace(/(?:\n@:0)?\s+$/m,
"").replace(/^\(/gm,"{anonymous}(").split("\n")},opera10:function(a){var a=a.stacktrace.split("\n"),b=/.*line (\d+), column (\d+) in ((<anonymous function\:?\s*(\S+))|([^\(]+)\([^\)]*\))(?: in )?(.*)\s*$/i,c,d,e;c=2;d=0;for(e=a.length;c<e-2;c++)if(b.test(a[c])){var g=RegExp.$6+":"+RegExp.$1+":"+RegExp.$2,f=RegExp.$3,f=f.replace(/<anonymous function\:?\s?(\S+)?>/g,"{anonymous}");a[d++]=f+"@"+g}a.splice(d,a.length-d);return a},opera:function(a){var a=a.message.split("\n"),b=/Line\s+(\d+).*script\s+(http\S+)(?:.*in\s+function\s+(\S+))?/i,
c,d,e;c=4;d=0;for(e=a.length;c<e;c+=2)b.test(a[c])&&(a[d++]=(RegExp.$3?RegExp.$3+"()@"+RegExp.$2+RegExp.$1:"{anonymous}()@"+RegExp.$2+":"+RegExp.$1)+" -- "+a[c+1].replace(/^\s+/,""));a.splice(d,a.length-d);return a},other:function(a){for(var b=/function\s*([\w\-$]+)?\s*\(/i,c=[],d,e;a&&c.length<10;)d=b.test(a.toString())?RegExp.$1||"{anonymous}":"{anonymous}",e=Array.prototype.slice.call(a.arguments||[]),c[c.length]=d+"("+this.stringifyArguments(e)+")",a=a.caller;return c},stringifyArguments:function(a){for(var b=
0;b<a.length;++b){var c=a[b];c===void 0?a[b]="undefined":c===null?a[b]="null":c.constructor&&(c.constructor===Array?a[b]=c.length<3?"["+this.stringifyArguments(c)+"]":"["+this.stringifyArguments(Array.prototype.slice.call(c,0,1))+"..."+this.stringifyArguments(Array.prototype.slice.call(c,-1))+"]":c.constructor===Object?a[b]="#object":c.constructor===Function?a[b]="#function":c.constructor===String&&(a[b]='"'+c+'"'))}return a.join(",")},sourceCache:{},ajax:function(a){var b=this.createXMLHTTPObject();
if(b)return b.open("GET",a,!1),b.setRequestHeader("User-Agent","XMLHTTP/1.0"),b.send(""),b.responseText},createXMLHTTPObject:function(){for(var a,b=[function(){return new XMLHttpRequest},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Msxml3.XMLHTTP")},function(){return new ActiveXObject("Microsoft.XMLHTTP")}],c=0;c<b.length;c++)try{return a=b[c](),this.createXMLHTTPObject=b[c],a}catch(d){}},isSameDomain:function(a){return a.indexOf(location.hostname)!==
-1},getSource:function(a){a in this.sourceCache||(this.sourceCache[a]=this.ajax(a).split("\n"));return this.sourceCache[a]},guessFunctions:function(a){for(var b=0;b<a.length;++b){var c=a[b],d=/\{anonymous\}\(.*\)@(\w+:\/\/([\-\w\.]+)+(:\d+)?[^:]+):(\d+):?(\d+)?/.exec(c);if(d){var e=d[1],d=d[4];e&&this.isSameDomain(e)&&d&&(e=this.guessFunctionName(e,d),a[b]=c.replace("{anonymous}",e))}}return a},guessFunctionName:function(a,b){var c;try{c=this.guessFunctionNameFromLines(b,this.getSource(a))}catch(d){c=
"getSource failed with url: "+a+", exception: "+d.toString()}return c},guessFunctionNameFromLines:function(a,b){for(var c=/function ([^(]*)\(([^)]*)\)/,d=/['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(function|eval|new Function)/,e="",g=0;g<10;++g)if(e=b[a-g]+e,e!==void 0){var f=d.exec(e);if(f&&f[1])return f[1];else if((f=c.exec(e))&&f[1])return f[1]}return"(?)"}};

window.onerror = function(message, file, line) {
	setTimeout(function() {
		Hoptoad.notify({
			message: message,
			stack: '()@' + file + ':' + line
		});
	}, 100);
	return true;
};
<|endoftext|>


<commit_before>/*
 Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

import { getCurrentLanguage } from './languageHandler';
import MatrixClientPeg from './MatrixClientPeg';
import PlatformPeg from './PlatformPeg';
import SdkConfig from './SdkConfig';

function getRedactedUrl() {
    const base = window.location.pathname.split('/').slice(-2).join('/');
    const redactedHash = window.location.hash.replace(/#\/(room|user)\/(.+)/, "#/$1/<redacted>");
    return base + redactedHash;
}

const customVariables = {
    'App Platform': 1,
    'App Version': 2,
    'User Type': 3,
    'Chosen Language': 4,
};

class Analytics {
    constructor() {
        this._paq = null;
        this.disabled = true;
        this.firstPage = true;
    }

    /**
     * Enable Analytics if initialized but disabled
     * otherwise try and initalize, no-op if piwik config missing
     */
    enable() {
        if (this._paq || this._init()) {
            this.disabled = false;
        }
    }

    /**
     * Disable Analytics calls, will not fully unload Piwik until a refresh,
     * but this is second best, Piwik should not pull anything implicitly.
     */
    disable() {
        this.disabled = true;
    }

    _init() {
        const config = SdkConfig.get();
        if (!config || !config.piwik || !config.piwik.url || !config.piwik.siteId) return;

        const url = config.piwik.url;
        const siteId = config.piwik.siteId;
        const self = this;

        window._paq = this._paq = window._paq || [];

        this._paq.push(['setTrackerUrl', url+'piwik.php']);
        this._paq.push(['setSiteId', siteId]);

        this._paq.push(['trackAllContentImpressions']);
        this._paq.push(['discardHashTag', false]);
        this._paq.push(['enableHeartBeatTimer']);
        this._paq.push(['enableLinkTracking', true]);

        const platform = PlatformPeg.get();
        this._setVisitVariable('App Platform', platform.getHumanReadableName());
        platform.getAppVersion().then((version) => {
            this._setVisitVariable('App Version', version);
        }).catch(() => {
            this._setVisitVariable('App Version', 'unknown');
        });

        this._setVisitVariable('Chosen Language', getCurrentLanguage());

        (function() {
            const g = document.createElement('script');
            const s = document.getElementsByTagName('script')[0];
            g.type='text/javascript'; g.async=true; g.defer=true; g.src=url+'piwik.js';

            g.onload = function() {
                console.log('Initialised anonymous analytics');
                self._paq = window._paq;
            };

            s.parentNode.insertBefore(g, s);
        })();

        return true;
    }

    trackPageChange() {
        if (this.disabled) return;
        if (this.firstPage) {
            // De-duplicate first page
            // router seems to hit the fn twice
            this.firstPage = false;
            return;
        }
        this._paq.push(['setCustomUrl', getRedactedUrl()]);
        this._paq.push(['trackPageView']);
    }

    trackEvent(category, action, name) {
        if (this.disabled) return;
        this._paq.push(['trackEvent', category, action, name]);
    }

    logout() {
        if (this.disabled) return;
        this._paq.push(['deleteCookies']);
    }

    login() { // not used currently
        const cli = MatrixClientPeg.get();
        if (this.disabled || !cli) return;

        this._paq.push(['setUserId', `@${cli.getUserIdLocalpart()}:${cli.getDomain()}`]);
    }

    _setVisitVariable(key, value) {
        this._paq.push(['setCustomVariable', customVariables[key], key, value, 'visit']);
    }

    setGuest(guest) {
        if (this.disabled) return;
        this._setVisitVariable('User Type', guest ? 'Guest' : 'Logged In');
    }
}

if (!global.mxAnalytics) {
    global.mxAnalytics = new Analytics();
}
module.exports = global.mxAnalytics;
<commit_msg>hardcode logged url to riot.im/app so piwik has a base to work with, it gets confused when a CustomURL isn't actually a URL (like it wasn't after the latest redaction fixes.<commit_after>/*
 Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

import { getCurrentLanguage } from './languageHandler';
import MatrixClientPeg from './MatrixClientPeg';
import PlatformPeg from './PlatformPeg';
import SdkConfig from './SdkConfig';

function getRedactedUrl() {
    const redactedHash = window.location.hash.replace(/#\/(room|user)\/(.+)/, "#/$1/<redacted>");
    // hardcoded url to make piwik happy
    return 'https://riot.im/app/' + redactedHash;
}

const customVariables = {
    'App Platform': 1,
    'App Version': 2,
    'User Type': 3,
    'Chosen Language': 4,
};

class Analytics {
    constructor() {
        this._paq = null;
        this.disabled = true;
        this.firstPage = true;
    }

    /**
     * Enable Analytics if initialized but disabled
     * otherwise try and initalize, no-op if piwik config missing
     */
    enable() {
        if (this._paq || this._init()) {
            this.disabled = false;
        }
    }

    /**
     * Disable Analytics calls, will not fully unload Piwik until a refresh,
     * but this is second best, Piwik should not pull anything implicitly.
     */
    disable() {
        this.disabled = true;
    }

    _init() {
        const config = SdkConfig.get();
        if (!config || !config.piwik || !config.piwik.url || !config.piwik.siteId) return;

        const url = config.piwik.url;
        const siteId = config.piwik.siteId;
        const self = this;

        window._paq = this._paq = window._paq || [];

        this._paq.push(['setTrackerUrl', url+'piwik.php']);
        this._paq.push(['setSiteId', siteId]);

        this._paq.push(['trackAllContentImpressions']);
        this._paq.push(['discardHashTag', false]);
        this._paq.push(['enableHeartBeatTimer']);
        this._paq.push(['enableLinkTracking', true]);

        const platform = PlatformPeg.get();
        this._setVisitVariable('App Platform', platform.getHumanReadableName());
        platform.getAppVersion().then((version) => {
            this._setVisitVariable('App Version', version);
        }).catch(() => {
            this._setVisitVariable('App Version', 'unknown');
        });

        this._setVisitVariable('Chosen Language', getCurrentLanguage());

        (function() {
            const g = document.createElement('script');
            const s = document.getElementsByTagName('script')[0];
            g.type='text/javascript'; g.async=true; g.defer=true; g.src=url+'piwik.js';

            g.onload = function() {
                console.log('Initialised anonymous analytics');
                self._paq = window._paq;
            };

            s.parentNode.insertBefore(g, s);
        })();

        return true;
    }

    trackPageChange() {
        if (this.disabled) return;
        if (this.firstPage) {
            // De-duplicate first page
            // router seems to hit the fn twice
            this.firstPage = false;
            return;
        }
        this._paq.push(['setCustomUrl', getRedactedUrl()]);
        this._paq.push(['trackPageView']);
    }

    trackEvent(category, action, name) {
        if (this.disabled) return;
        this._paq.push(['trackEvent', category, action, name]);
    }

    logout() {
        if (this.disabled) return;
        this._paq.push(['deleteCookies']);
    }

    login() { // not used currently
        const cli = MatrixClientPeg.get();
        if (this.disabled || !cli) return;

        this._paq.push(['setUserId', `@${cli.getUserIdLocalpart()}:${cli.getDomain()}`]);
    }

    _setVisitVariable(key, value) {
        this._paq.push(['setCustomVariable', customVariables[key], key, value, 'visit']);
    }

    setGuest(guest) {
        if (this.disabled) return;
        this._setVisitVariable('User Type', guest ? 'Guest' : 'Logged In');
    }
}

if (!global.mxAnalytics) {
    global.mxAnalytics = new Analytics();
}
module.exports = global.mxAnalytics;
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const dirToJson = require('dir-to-json');
const fs = require('fs');
const yaml = require('js-yaml');

const config = require('../config/');
const helpers = require('./helpers');

const createAnchorPeerFile = (req, res) => {
  const channelName = req.query.channelName;
  const profileName = req.query.profileName;
  const orgName = req.query.orgName;

  const terminalCommand = `cd ${config.getDirUri()} && export FABRIC_CFG_PATH=$PWD && export CHANNEL_NAME=${channelName} && configtxgen -profile ${profileName} -outputAnchorPeersUpdate ./channel/${orgName}Anchors.tx -channelID $CHANNEL_NAME -asOrg ${orgName}`;

  helpers.runTerminalCommand(terminalCommand)
    .then(output => {
      return res.status(201).json({ "message": "created anchor peer file", "path": config.getDirUri() + `channel/${orgName}Anchors.tx` });
    })
    .catch(err => {
      console.error(`\n!!! Error generating Anchor Peer file: ${err}\n`);
      return errorResponse(res, 'Error generating Anchor Peer file', err);
    });
};

const createChannel = (req, res) => {
  const channelName = req.query.channelName;
  const profileName = req.query.profileName;

  const terminalCommand = `cd ${config.getDirUri()} && export FABRIC_CFG_PATH=$PWD && export CHANNEL_NAME=${channelName} && configtxgen -profile ${profileName} -outputCreateChannelTx ./channel/${channelName}.tx -channelID $CHANNEL_NAME`;

  helpers.runTerminalCommand(terminalCommand)
    .then(output => {
      return res.status(201).json({ "message": "created channel file", "path": config.getDirUri() + `channel/${channelName}.tx` });
    })
    .catch(err => {
      console.error(`\n!!! Error Creating Channel: ${err}\n`);
      return errorResponse(res, 'Error Creating Channel', err);
    });
};

const createGenesisBlock = (req, res) => {
  const profileName = req.query.profileName;

  const terminalCommand = `cd ${config.getDirUri()} && export FABRIC_CFG_PATH=$PWD && mkdir -p channel && configtxgen -profile ${profileName} -outputBlock ./channel/genesis.block`;

  helpers.runTerminalCommand(terminalCommand)
    .then(output => {
      return res.status(201).json({ "message": "created genesis file", "path": config.getDirUri() + 'channel/genesis.block' });
    })
    .catch(err => {
      console.error(`\n!!! Error generating Genesis File: ${err}\n`);
      return errorResponse(res, 'Error generating Genesis File', err);
    });
};

const createNetwork = (req, res) => {
  const fileName = req.query.fileName || 'docker-compose.yaml';
  const terminalCommand = `cd ${config.getDirUri()} && docker-compose -f ${fileName} up -d`;

  helpers.createBaseYamlFile()
    .then(success => {
      return helpers.runTerminalCommand(terminalCommand);
    })
    .then(output => {
      return res.status(201).json({ "message": "Network created" });
    })
    .catch(err => {
      console.error(`\n!!! Error creating network: ${err}\n`);
      return errorResponse(res, 'Error creating network', err);
    });
};

const createYamlFile = (req, res) => {
  const fileName = req.query.fileName || 'myYamlFile.yaml';
  const doc = yaml.safeDump(req.body);
  fs.writeFileSync(config.getDirUri() + fileName, doc);
  return res.status(201).json({ "message": "YAML file created", path: config.getDirUri() + fileName });
};

const getYamlFile = (req, res) => {
  const fileName = req.query.fileName || 'myYamlFile.yaml';
  const doc = yaml.safeLoad(fs.readFileSync(config.getDirUri() + fileName, 'utf8'));
  return res.status(200).json({ "message": "Retrieved file", file: doc });
};

const runCryptogen = (req, res) => {
  const fileName = req.query.fileName || 'crypto-config.yaml';
  const terminalCommand = `cd ${config.getDirUri()} && rm -rf crypto-config && cryptogen generate --config=${fileName}`;

  helpers.runTerminalCommand(terminalCommand)
    .then(output => {
      return res.status(201).json({ "message": "certificates generated", "path": config.getDirUri() });
    })
    .catch(err => {
      console.error(`\n!!! Error running Cryptogen: ${err}\n`);
      return errorResponse(res, 'Error running Cryptogen', err);
    });
};

const createDockerCompose = (req, res) => {
  const caDirectory = {};
  const peerDirectory = {};
  const ordererDirectory = {};
  dirToJson(config.getDirUri() + "crypto-config") // reading crypto-config library
    .then(dirTree => {
      const peerOrganizations = helpers.getPeerOrganizations(dirTree);
      const ordererOrganizations = helpers.getOrdererOrganizations(dirTree);

      let peerNames;
      if (peerOrganizations) peerNames = helpers.getNames(dirTree);

      let ordererNames;
      if (ordererOrganizations) ordererNames = helpers.getOrdererNames(dirTree);

      // Peer directory and CA directory
      if (peerOrganizations) {
        _.map(peerOrganizations, peer => {
          const files = helpers.getChildren(peer);
          _.map(files, item => {

            if (item.name == "ca") { // reading CA certificates
              caDirectory[peer.name] = [];
              _.map(item.children, specificCA => {
                caDirectory[peer.name].push(specificCA.name);
              });
            } else if (item.name == "peers") { // reading Peer certificates
              peerDirectory[peer.name] = [];
              _.map(item.children, specificPeer => {
                peerDirectory[peer.name].push(specificPeer.name);
              });
            }

          });
        });
      }

      // Orderer directory
      if (ordererOrganizations) {
        _.map(ordererOrganizations, orderer => {
          const files = helpers.getChildren(orderer);
          _.map(files, item => {
            if (item.name == "orderers") { // reading orderer certificates
              ordererDirectory[orderer.name] = [];
              _.map(item.children, specificOrderer => {
                ordererDirectory[orderer.name].push(specificOrderer.name);
              });
            }
          });
        });
      }

      const fileName = req.query.fileName || 'docker-compose.yaml';
      try {
        const doc = yaml.safeDump(helpers.getDockerComposeJSON(caDirectory, peerDirectory, ordererDirectory));
        fs.writeFileSync(config.getDirUri() + fileName, doc);
      } catch (err) {
        console.error(`\n!!! Error generating docker-compose.yaml: ${err}\n`);
        return errorResponse(res, 'Error generating docker-compose.yaml', err);
      }
      return res.status(201).json({ "message": "Docker-compose file is generated successfully!", path: config.getDirUri() + fileName });

    })
    .catch(err => {
      console.error(`\n!!! Error generating docker-compose.yaml: ${err}\n`);
      return errorResponse(res, 'Error generating docker-compose.yaml. Cannot parse directory structure', err);
    });
};

const errorResponse = (res, message, error, status = 500) =>
  res.status(status).json({ "status": status, "message": message, "error": error });

module.exports = {
  createAnchorPeerFile,
  createChannel,
  createDockerCompose,
  createGenesisBlock,
  createNetwork,
  createYamlFile,
  getYamlFile,
  runCryptogen
};
<commit_msg>Added error handling for reading and writing files. Fixes #3<commit_after>'use strict';

const _ = require('lodash');
const dirToJson = require('dir-to-json');
const fs = require('fs');
const yaml = require('js-yaml');

const config = require('../config/');
const helpers = require('./helpers');

const createAnchorPeerFile = (req, res) => {
  const channelName = req.query.channelName;
  const profileName = req.query.profileName;
  const orgName = req.query.orgName;

  const terminalCommand = `cd ${config.getDirUri()} && export FABRIC_CFG_PATH=$PWD && export CHANNEL_NAME=${channelName} && configtxgen -profile ${profileName} -outputAnchorPeersUpdate ./channel/${orgName}Anchors.tx -channelID $CHANNEL_NAME -asOrg ${orgName}`;

  helpers.runTerminalCommand(terminalCommand)
    .then(output => {
      return res.status(201).json({ "message": "created anchor peer file", "path": config.getDirUri() + `channel/${orgName}Anchors.tx` });
    })
    .catch(err => {
      console.error(`\n!!! Error generating Anchor Peer file: ${err}\n`);
      return errorResponse(res, 'Error generating Anchor Peer file', err);
    });
};

const createChannel = (req, res) => {
  const channelName = req.query.channelName;
  const profileName = req.query.profileName;

  const terminalCommand = `cd ${config.getDirUri()} && export FABRIC_CFG_PATH=$PWD && export CHANNEL_NAME=${channelName} && configtxgen -profile ${profileName} -outputCreateChannelTx ./channel/${channelName}.tx -channelID $CHANNEL_NAME`;

  helpers.runTerminalCommand(terminalCommand)
    .then(output => {
      return res.status(201).json({ "message": "created channel file", "path": config.getDirUri() + `channel/${channelName}.tx` });
    })
    .catch(err => {
      console.error(`\n!!! Error Creating Channel: ${err}\n`);
      return errorResponse(res, 'Error Creating Channel', err);
    });
};

const createGenesisBlock = (req, res) => {
  const profileName = req.query.profileName;

  const terminalCommand = `cd ${config.getDirUri()} && export FABRIC_CFG_PATH=$PWD && mkdir -p channel && configtxgen -profile ${profileName} -outputBlock ./channel/genesis.block`;

  helpers.runTerminalCommand(terminalCommand)
    .then(output => {
      return res.status(201).json({ "message": "created genesis file", "path": config.getDirUri() + 'channel/genesis.block' });
    })
    .catch(err => {
      console.error(`\n!!! Error generating Genesis File: ${err}\n`);
      return errorResponse(res, 'Error generating Genesis File', err);
    });
};

const createNetwork = (req, res) => {
  const fileName = req.query.fileName || 'docker-compose.yaml';
  const terminalCommand = `cd ${config.getDirUri()} && docker-compose -f ${fileName} up -d`;

  helpers.createBaseYamlFile()
    .then(success => {
      return helpers.runTerminalCommand(terminalCommand);
    })
    .then(output => {
      return res.status(201).json({ "message": "Network created" });
    })
    .catch(err => {
      console.error(`\n!!! Error creating network: ${err}\n`);
      return errorResponse(res, 'Error creating network', err);
    });
};

const createYamlFile = (req, res) => {
  const fileName = req.query.fileName || 'myYamlFile.yaml';
  const doc = yaml.safeDump(req.body);
  fs.writeFile(config.getDirUri() + fileName, doc, (err) => {
    if (err) {
      return errorResponse(res, `could not create file: ${fileName}`, err, 500);
    }
    return res.status(201).json({ "message": "YAML file created", path: config.getDirUri() + fileName });
  });
};

const getYamlFile = (req, res) => {
  const fileName = req.query.fileName || 'myYamlFile.yaml';
  fs.readFile(config.getDirUri() + fileName, 'utf8', (err, data) => {
    if (err) {
      return errorResponse(res, `could not read file: ${fileName}`, err, 500);
    }
    const doc = yaml.safeLoad(data);
    return res.status(200).json({ "message": "Retrieved file", file: doc });
  });
};

const runCryptogen = (req, res) => {
  const fileName = req.query.fileName || 'crypto-config.yaml';
  const terminalCommand = `cd ${config.getDirUri()} && rm -rf crypto-config && cryptogen generate --config=${fileName}`;

  helpers.runTerminalCommand(terminalCommand)
    .then(output => {
      return res.status(201).json({ "message": "certificates generated", "path": config.getDirUri() });
    })
    .catch(err => {
      console.error(`\n!!! Error running Cryptogen: ${err}\n`);
      return errorResponse(res, 'Error running Cryptogen', err);
    });
};

const createDockerCompose = (req, res) => {
  const caDirectory = {};
  const peerDirectory = {};
  const ordererDirectory = {};
  dirToJson(config.getDirUri() + "crypto-config") // reading crypto-config library
    .then(dirTree => {
      const peerOrganizations = helpers.getPeerOrganizations(dirTree);
      const ordererOrganizations = helpers.getOrdererOrganizations(dirTree);

      let peerNames;
      if (peerOrganizations) peerNames = helpers.getNames(dirTree);

      let ordererNames;
      if (ordererOrganizations) ordererNames = helpers.getOrdererNames(dirTree);

      // Peer directory and CA directory
      if (peerOrganizations) {
        _.map(peerOrganizations, peer => {
          const files = helpers.getChildren(peer);
          _.map(files, item => {

            if (item.name == "ca") { // reading CA certificates
              caDirectory[peer.name] = [];
              _.map(item.children, specificCA => {
                caDirectory[peer.name].push(specificCA.name);
              });
            } else if (item.name == "peers") { // reading Peer certificates
              peerDirectory[peer.name] = [];
              _.map(item.children, specificPeer => {
                peerDirectory[peer.name].push(specificPeer.name);
              });
            }

          });
        });
      }

      // Orderer directory
      if (ordererOrganizations) {
        _.map(ordererOrganizations, orderer => {
          const files = helpers.getChildren(orderer);
          _.map(files, item => {
            if (item.name == "orderers") { // reading orderer certificates
              ordererDirectory[orderer.name] = [];
              _.map(item.children, specificOrderer => {
                ordererDirectory[orderer.name].push(specificOrderer.name);
              });
            }
          });
        });
      }

      const fileName = req.query.fileName || 'docker-compose.yaml';
      try {
        const doc = yaml.safeDump(helpers.getDockerComposeJSON(caDirectory, peerDirectory, ordererDirectory));
        fs.writeFileSync(config.getDirUri() + fileName, doc);
      } catch (err) {
        console.error(`\n!!! Error generating docker-compose.yaml: ${err}\n`);
        return errorResponse(res, 'Error generating docker-compose.yaml', err);
      }
      return res.status(201).json({ "message": "Docker-compose file is generated successfully!", path: config.getDirUri() + fileName });

    })
    .catch(err => {
      console.error(`\n!!! Error generating docker-compose.yaml: ${err}\n`);
      return errorResponse(res, 'Error generating docker-compose.yaml. Cannot parse directory structure', err);
    });
};

const errorResponse = (res, message, error, status = 500) =>
  res.status(status).json({ "status": status, "message": message, "error": error });

module.exports = {
  createAnchorPeerFile,
  createChannel,
  createDockerCompose,
  createGenesisBlock,
  createNetwork,
  createYamlFile,
  getYamlFile,
  runCryptogen
};
<|endoftext|>


<commit_before>var Backbone = require('backbone');
var _ = require('underscore');
var WindshaftFiltersCollection = require('./filters/collection');
var WindshaftLayerGroupConfig = require('./layergroup-config');
var WindshaftNamedMapConfig = require('./namedmap-config');
var WindshaftConfig = require('./config');
var EMPTY_GIF = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

var WindshaftMap = Backbone.Model.extend({

  initialize: function (attrs, options) {
    this.client = options.client;
    this.statTag = options.statTag;
    this.configGenerator = options.configGenerator;

    // TODO: What params are really used?
    this.pngParams = ['map_key', 'api_key', 'cache_policy', 'updated_at'];
    this.gridParams = ['map_key', 'api_key', 'cache_policy', 'updated_at'];

    this.set({
      urlTemplate: this.client.urlTemplate,
      userName: this.client.userName
    });
  },

  isNamedMap: function () {
    return this.configGenerator === WindshaftNamedMapConfig;
  },

  isAnonymousMap: function () {
    return this.configGenerator === WindshaftLayerGroupConfig;
  },

  createInstance: function (options) {
    options = options || {};
    // WindshaftMap knows what types of layers should be sent to Windshaft:
    var layers = _.select(options.layers, function (layer) {
      return layer.get('type') === 'CartoDB' || layer.get('type') === 'torque';
    });
    var dataviews = options.dataviews;
    var sourceLayerId = options.sourceLayerId;
    var forceFetch = options.forceFetch;

    var mapConfig = this.configGenerator.generate({
      layers: layers,
      dataviews: dataviews
    });

    var filtersFromVisibleLayers = [];
    if (dataviews) {
      filtersFromVisibleLayers = dataviews.chain()
        .filter(function (dataview) {
          return dataview.layer.isVisible();
        })
        .map(function (dataview) {
          return dataview.filter;
        })
        .compact() // not all dataviews have filters
        .value();
    }

    var filters = new WindshaftFiltersCollection(filtersFromVisibleLayers, layers);

    this.client.instantiateMap({
      mapDefinition: mapConfig,
      statTag: this.statTag,
      filters: filters.toJSON(),
      success: function (mapInstance) {
        this.set(mapInstance);
        this.trigger('instanceCreated', this, sourceLayerId, forceFetch);

        // TODO: Revisit this (will layerIndex work for NamedMaps??)
        // Should we move it somewhere else?
        _.each(options.layers, function (layer, layerIndex) {
          if (layer.get('type') === 'torque') {
            layer.set('meta', this.getLayerMeta(layerIndex));
            layer.set('urls', this.getTiles('torque'));
          } else if (layer.get('type') === 'CartoDB' || layer.get('type') === 'mapnik') {
            layer.set('meta', this.getLayerMeta(layerIndex));
          }
        }, this);
      }.bind(this),
      error: function (error) {
        console.log('Error creating the map instance on Windshaft: ' + error);
      }
    });

    return this;
  },

  TILE_EXTENSIONS_BY_LAYER_TYPE: {
    'mapnik': '.png',
    'torque': '.json.torque'
  },

  getBaseURL: function (subhost) {
    return [
      this._getHost(subhost),
      WindshaftConfig.MAPS_API_BASE_URL,
      this.get('layergroupid')
    ].join('/');
  },

  _getHost: function (subhost) {
    var userName = this.get('userName');
    var protocol = this._useHTTPS() ? 'https' : 'http';
    subhost = subhost ? subhost + '.' : '';
    var host = this.get('urlTemplate').replace('{user}', userName);
    var cdnHost = this.get('cdn_url') && this.get('cdn_url')[protocol];
    if (cdnHost) {
      host = [protocol, '://', subhost, cdnHost, '/', userName].join('');
    }

    return host;
  },

  _useHTTPS: function () {
    return this.get('urlTemplate').indexOf('https') === 0;
  },

  getDataviewURL: function (options) {
    var dataviewId = options.dataviewId;
    var protocol = options.protocol;
    var url;
    var layers = this.get('metadata') && this.get('metadata').layers;

    _.each(layers, function (layer) {
      // TODO layer.widgets is the raw data returned from metadata… should be renamed once the result from Windshaft is changed
      var dataviews = layer.widgets;
      for (var id in dataviews) {
        if (dataviewId === id) {
          url = dataviews[id].url[protocol];
          return;
        }
      }
    });

    return url;
  },

  getTiles: function (layerType, params) {
    var grids = [];
    var tiles = [];

    var pngParams = this._encodeParams(params, this.pngParams);
    var gridParams = this._encodeParams(params, this.gridParams);
    var subdomains = ['0', '1', '2', '3'];

    if (this._useHTTPS()) {
      subdomains = [''];
    }

    layerType = layerType || 'mapnik';

    var layerIndexes = this._getLayerIndexesByType(layerType);
    if (layerIndexes.length) {
      var gridTemplate = '/{z}/{x}/{y}';

      for (var i = 0; i < subdomains.length; ++i) {
        var subdomain = subdomains[i];
        var tileURLTemplate = [
          this.getBaseURL(subdomain),
          '/',
          layerIndexes.join(','),
          '/{z}/{x}/{y}',
          this.TILE_EXTENSIONS_BY_LAYER_TYPE[layerType],
          (pngParams ? '?' + pngParams : '')
        ].join('');

        tiles.push(tileURLTemplate);

        // for mapnik layers add grid json too
        if (layerType === 'mapnik') {
          for (var layer = 0; layer < this.get('metadata').layers.length; ++layer) {
            var index = this._getLayerIndexByType(layer, 'mapnik');
            if (index >= 0) {
              var gridURLTemplate = [
                this.getBaseURL(subdomain),
                '/',
                index,
                gridTemplate,
                '.grid.json',
                (gridParams ? '?' + gridParams : '')
              ].join('');
              grids[layer] = grids[layer] || [];
              grids[layer].push(gridURLTemplate);
            }
          }
        }
      }
    } else {
      // TODO: Clients of this method should decide what to render if no layers are present
      tiles = [EMPTY_GIF];
    }

    this.urls = {
      tiles: tiles,
      grids: grids
    };
    return this.urls;
  },

  getLayerMeta: function (layerIndex) {
    var layerMeta = {};
    var layers = this.get('metadata') && this.get('metadata').layers;
    if (layers && layers[layerIndex]) {
      layerMeta = layers[layerIndex].meta || {};
    }
    return layerMeta;
  },

  _encodeParams: function (params, included) {
    if (!params) return '';
    var url_params = [];
    included = included || _.keys(params);
    for (var i in included) {
      var k = included[i];
      var p = params[k];
      if (p) {
        if (_.isArray(p)) {
          for (var j = 0, len = p.length; j < len; j++) {
            url_params.push(k + '[]=' + encodeURIComponent(p[j]));
          }
        } else {
          var q = encodeURIComponent(p);
          q = q.replace(/%7Bx%7D/g, '{x}').replace(/%7By%7D/g, '{y}').replace(/%7Bz%7D/g, '{z}');
          url_params.push(k + '=' + q);
        }
      }
    }
    return url_params.join('&');
  },

  /**
   * Returns the index of a layer of a given type, as the tiler kwows it.
   *
   * @param {string|array} types - Type or types of layers
   */
  _getLayerIndexesByType: function (types) {
    var layers = this.get('metadata') && this.get('metadata').layers;

    if (!layers) {
      return;
    }
    var layerIndexes = [];
    for (var i = 0; i < layers.length; i++) {
      var layer = layers[i];
      var isValidType = false;
      if (types && types.length > 0) {
        isValidType = types.indexOf(layer.type) !== -1;
      }
      if (isValidType) {
        layerIndexes.push(i);
      }
    }
    return layerIndexes;
  },

  /**
   * Returns the index of a layer of a given type, as the tiler kwows it.
   *
   * @param {integer} index - number of layer of the specified type
   * @param {string} layerType - type of the layers
   */
  _getLayerIndexByType: function (index, layerType) {
    var layers = this.get('metadata') && this.get('metadata').layers;

    if (!layers) {
      return index;
    }

    var tilerLayerIndex = {};
    var j = 0;
    for (var i = 0; i < layers.length; i++) {
      if (layers[i].type === layerType) {
        tilerLayerIndex[j] = i;
        j++;
      }
    }
    if (tilerLayerIndex[index] === undefined) {
      return -1;
    }
    return tilerLayerIndex[index];
  }
});

module.exports = WindshaftMap;
<commit_msg>removes check for mapnik layers<commit_after>var Backbone = require('backbone');
var _ = require('underscore');
var WindshaftFiltersCollection = require('./filters/collection');
var WindshaftLayerGroupConfig = require('./layergroup-config');
var WindshaftNamedMapConfig = require('./namedmap-config');
var WindshaftConfig = require('./config');
var EMPTY_GIF = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

var WindshaftMap = Backbone.Model.extend({

  initialize: function (attrs, options) {
    this.client = options.client;
    this.statTag = options.statTag;
    this.configGenerator = options.configGenerator;

    // TODO: What params are really used?
    this.pngParams = ['map_key', 'api_key', 'cache_policy', 'updated_at'];
    this.gridParams = ['map_key', 'api_key', 'cache_policy', 'updated_at'];

    this.set({
      urlTemplate: this.client.urlTemplate,
      userName: this.client.userName
    });
  },

  isNamedMap: function () {
    return this.configGenerator === WindshaftNamedMapConfig;
  },

  isAnonymousMap: function () {
    return this.configGenerator === WindshaftLayerGroupConfig;
  },

  createInstance: function (options) {
    options = options || {};
    // WindshaftMap knows what types of layers should be sent to Windshaft:
    var layers = _.select(options.layers, function (layer) {
      return layer.get('type') === 'CartoDB' || layer.get('type') === 'torque';
    });
    var dataviews = options.dataviews;
    var sourceLayerId = options.sourceLayerId;
    var forceFetch = options.forceFetch;

    var mapConfig = this.configGenerator.generate({
      layers: layers,
      dataviews: dataviews
    });

    var filtersFromVisibleLayers = [];
    if (dataviews) {
      filtersFromVisibleLayers = dataviews.chain()
        .filter(function (dataview) {
          return dataview.layer.isVisible();
        })
        .map(function (dataview) {
          return dataview.filter;
        })
        .compact() // not all dataviews have filters
        .value();
    }

    var filters = new WindshaftFiltersCollection(filtersFromVisibleLayers, layers);

    this.client.instantiateMap({
      mapDefinition: mapConfig,
      statTag: this.statTag,
      filters: filters.toJSON(),
      success: function (mapInstance) {
        this.set(mapInstance);
        this.trigger('instanceCreated', this, sourceLayerId, forceFetch);

        // TODO: Revisit this (will layerIndex work for NamedMaps??)
        // Should we move it somewhere else?
        _.each(options.layers, function (layer, layerIndex) {
          if (layer.get('type') === 'torque') {
            layer.set('meta', this.getLayerMeta(layerIndex));
            layer.set('urls', this.getTiles('torque'));
          } else if (layer.get('type') === 'CartoDB') {
            layer.set('meta', this.getLayerMeta(layerIndex));
          }
        }, this);
      }.bind(this),
      error: function (error) {
        console.log('Error creating the map instance on Windshaft: ' + error);
      }
    });

    return this;
  },

  TILE_EXTENSIONS_BY_LAYER_TYPE: {
    'mapnik': '.png',
    'torque': '.json.torque'
  },

  getBaseURL: function (subhost) {
    return [
      this._getHost(subhost),
      WindshaftConfig.MAPS_API_BASE_URL,
      this.get('layergroupid')
    ].join('/');
  },

  _getHost: function (subhost) {
    var userName = this.get('userName');
    var protocol = this._useHTTPS() ? 'https' : 'http';
    subhost = subhost ? subhost + '.' : '';
    var host = this.get('urlTemplate').replace('{user}', userName);
    var cdnHost = this.get('cdn_url') && this.get('cdn_url')[protocol];
    if (cdnHost) {
      host = [protocol, '://', subhost, cdnHost, '/', userName].join('');
    }

    return host;
  },

  _useHTTPS: function () {
    return this.get('urlTemplate').indexOf('https') === 0;
  },

  getDataviewURL: function (options) {
    var dataviewId = options.dataviewId;
    var protocol = options.protocol;
    var url;
    var layers = this.get('metadata') && this.get('metadata').layers;

    _.each(layers, function (layer) {
      // TODO layer.widgets is the raw data returned from metadata… should be renamed once the result from Windshaft is changed
      var dataviews = layer.widgets;
      for (var id in dataviews) {
        if (dataviewId === id) {
          url = dataviews[id].url[protocol];
          return;
        }
      }
    });

    return url;
  },

  getTiles: function (layerType, params) {
    var grids = [];
    var tiles = [];

    var pngParams = this._encodeParams(params, this.pngParams);
    var gridParams = this._encodeParams(params, this.gridParams);
    var subdomains = ['0', '1', '2', '3'];

    if (this._useHTTPS()) {
      subdomains = [''];
    }

    layerType = layerType || 'mapnik';

    var layerIndexes = this._getLayerIndexesByType(layerType);
    if (layerIndexes.length) {
      var gridTemplate = '/{z}/{x}/{y}';

      for (var i = 0; i < subdomains.length; ++i) {
        var subdomain = subdomains[i];
        var tileURLTemplate = [
          this.getBaseURL(subdomain),
          '/',
          layerIndexes.join(','),
          '/{z}/{x}/{y}',
          this.TILE_EXTENSIONS_BY_LAYER_TYPE[layerType],
          (pngParams ? '?' + pngParams : '')
        ].join('');

        tiles.push(tileURLTemplate);

        // for mapnik layers add grid json too
        if (layerType === 'mapnik') {
          for (var layer = 0; layer < this.get('metadata').layers.length; ++layer) {
            var index = this._getLayerIndexByType(layer, 'mapnik');
            if (index >= 0) {
              var gridURLTemplate = [
                this.getBaseURL(subdomain),
                '/',
                index,
                gridTemplate,
                '.grid.json',
                (gridParams ? '?' + gridParams : '')
              ].join('');
              grids[layer] = grids[layer] || [];
              grids[layer].push(gridURLTemplate);
            }
          }
        }
      }
    } else {
      // TODO: Clients of this method should decide what to render if no layers are present
      tiles = [EMPTY_GIF];
    }

    this.urls = {
      tiles: tiles,
      grids: grids
    };
    return this.urls;
  },

  getLayerMeta: function (layerIndex) {
    var layerMeta = {};
    var layers = this.get('metadata') && this.get('metadata').layers;
    if (layers && layers[layerIndex]) {
      layerMeta = layers[layerIndex].meta || {};
    }
    return layerMeta;
  },

  _encodeParams: function (params, included) {
    if (!params) return '';
    var url_params = [];
    included = included || _.keys(params);
    for (var i in included) {
      var k = included[i];
      var p = params[k];
      if (p) {
        if (_.isArray(p)) {
          for (var j = 0, len = p.length; j < len; j++) {
            url_params.push(k + '[]=' + encodeURIComponent(p[j]));
          }
        } else {
          var q = encodeURIComponent(p);
          q = q.replace(/%7Bx%7D/g, '{x}').replace(/%7By%7D/g, '{y}').replace(/%7Bz%7D/g, '{z}');
          url_params.push(k + '=' + q);
        }
      }
    }
    return url_params.join('&');
  },

  /**
   * Returns the index of a layer of a given type, as the tiler kwows it.
   *
   * @param {string|array} types - Type or types of layers
   */
  _getLayerIndexesByType: function (types) {
    var layers = this.get('metadata') && this.get('metadata').layers;

    if (!layers) {
      return;
    }
    var layerIndexes = [];
    for (var i = 0; i < layers.length; i++) {
      var layer = layers[i];
      var isValidType = false;
      if (types && types.length > 0) {
        isValidType = types.indexOf(layer.type) !== -1;
      }
      if (isValidType) {
        layerIndexes.push(i);
      }
    }
    return layerIndexes;
  },

  /**
   * Returns the index of a layer of a given type, as the tiler kwows it.
   *
   * @param {integer} index - number of layer of the specified type
   * @param {string} layerType - type of the layers
   */
  _getLayerIndexByType: function (index, layerType) {
    var layers = this.get('metadata') && this.get('metadata').layers;

    if (!layers) {
      return index;
    }

    var tilerLayerIndex = {};
    var j = 0;
    for (var i = 0; i < layers.length; i++) {
      if (layers[i].type === layerType) {
        tilerLayerIndex[j] = i;
        j++;
      }
    }
    if (tilerLayerIndex[index] === undefined) {
      return -1;
    }
    return tilerLayerIndex[index];
  }
});

module.exports = WindshaftMap;
<|endoftext|>


<commit_before>function loadJS(url, isExternal)
{
	if( isExternal )
		url = document.location.protocol == 'file:' ? 'http:' + url : url;
	else
		url += '?v=' + app.version + (!app.isProduction ? '&_=' + new Date().getTime() : '');

	document.write("<script language='javascript' type='text/javascript' src='" + url + "'><\/script>");
}

function loadCSS(url, isExternal)
{
	if( isExternal )
		url = document.location.protocol == 'file:' ? 'http:' + url : url;
	else
		url += '?v=' + app.version + (!app.isProduction ? '&_=' + new Date().getTime() : '');

	var el = document.createElement("link");
	el.setAttribute("rel", "stylesheet");
	el.setAttribute("type", "text/css");
	el.setAttribute("href", url);
	document.getElementsByTagName("head")[0].appendChild(el);
}

function getUrlVar(name)
{
	var vars = [], hash;
	if( window.location.href.indexOf('?') == -1 ) return null;

	var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
	for(var i = 0; i < hashes.length; i++){
		hash = hashes[i].split('=');
		hash[0] = hash[0].split('#')[0];
		vars.push(hash[0]);
		vars[hash[0]] = (hash[1] == undefined) ? true : hash[1];
	}
	return vars[name];
}

function defineDojoConfig()
{
	var path1 = location.pathname.replace(/\/[^/]+$/, '/');

	window.dojoConfig = {
		parseOnLoad: true,
		isDebug: false,
		useDeferredInstrumentation: true,
		//cacheBust: ! app.isProduction,
		packages: [
			{
				name: 'storymaps',
				location: path1 + 'app/storymaps'
			},
			{
				name: 'lib-app',
				location: path1 + 'lib-app'
			},
			{
				name: 'lib-build',
				location: path1 + 'lib-build'
			},
			{
				name: 'commonResources',
				location: path1 + (app.isProduction ? 'resources/common' : 'app/storymaps/common/_resources/')
			}
		],
		aliases: [
			['text', 'lib-build/text'],
			['underscore', 'lib-build/lodash']
		]
	};

	if (location.search.match(/locale=([\w\-]+)/)) {
		window.dojoConfig.locale = RegExp.$1;
	}
}

app.isProduction = false;

defineDojoConfig();

app.isInBuilder = getUrlVar('edit') || getUrlVar('fromScratch') || getUrlVar('fromscratch');
app.indexCfg = configOptions;

loadCSS(app.pathJSAPI + "esri/css/esri.css", true);
loadCSS(app.pathJSAPI + "dijit/themes/claro/claro.css", true);

if( app.isProduction ) {
	if ( app.isInBuilder )
		loadCSS("app/builder-min.css");
	else
		loadCSS("app/viewer-min.css");
}

loadJS(app.pathJSAPI + 'init.js', true);
loadJS('app/config.js');

CKEDITOR_BASEPATH = app.isProduction ? 'resources/lib/ckeditor/' : 'lib-app/ckeditor/';

if( app.isProduction ) {
	_ = {};

	if ( app.isInBuilder )
		loadJS('app/builder-min.js');
	else
		loadJS('app/viewer-min.js');
}

loadJS('app/main-app.js');

// Enable Google Analytics on storymaps.esri.com
if (window.location.href.toLowerCase().indexOf("storymaps.esri.com") >= 0) {
	var _gaq = _gaq || [];
	_gaq.push(['_setAccount', 'UA-38806035-1']);
	_gaq.push(['_trackPageview']);

	(function() {
		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
	})();
}<commit_msg>Updated Google Analytics code<commit_after>function loadJS(url, isExternal)
{
	if( isExternal )
		url = document.location.protocol == 'file:' ? 'http:' + url : url;
	else
		url += '?v=' + app.version + (!app.isProduction ? '&_=' + new Date().getTime() : '');

	document.write("<script language='javascript' type='text/javascript' src='" + url + "'><\/script>");
}

function loadCSS(url, isExternal)
{
	if( isExternal )
		url = document.location.protocol == 'file:' ? 'http:' + url : url;
	else
		url += '?v=' + app.version + (!app.isProduction ? '&_=' + new Date().getTime() : '');

	var el = document.createElement("link");
	el.setAttribute("rel", "stylesheet");
	el.setAttribute("type", "text/css");
	el.setAttribute("href", url);
	document.getElementsByTagName("head")[0].appendChild(el);
}

function getUrlVar(name)
{
	var vars = [], hash;
	if( window.location.href.indexOf('?') == -1 ) return null;

	var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
	for(var i = 0; i < hashes.length; i++){
		hash = hashes[i].split('=');
		hash[0] = hash[0].split('#')[0];
		vars.push(hash[0]);
		vars[hash[0]] = (hash[1] == undefined) ? true : hash[1];
	}
	return vars[name];
}

function defineDojoConfig()
{
	var path1 = location.pathname.replace(/\/[^/]+$/, '/');

	window.dojoConfig = {
		parseOnLoad: true,
		isDebug: false,
		useDeferredInstrumentation: true,
		//cacheBust: ! app.isProduction,
		packages: [
			{
				name: 'storymaps',
				location: path1 + 'app/storymaps'
			},
			{
				name: 'lib-app',
				location: path1 + 'lib-app'
			},
			{
				name: 'lib-build',
				location: path1 + 'lib-build'
			},
			{
				name: 'commonResources',
				location: path1 + (app.isProduction ? 'resources/common' : 'app/storymaps/common/_resources/')
			}
		],
		aliases: [
			['text', 'lib-build/text'],
			['underscore', 'lib-build/lodash']
		]
	};

	if (location.search.match(/locale=([\w\-]+)/)) {
		window.dojoConfig.locale = RegExp.$1;
	}
}

app.isProduction = false;

defineDojoConfig();

app.isInBuilder = getUrlVar('edit') || getUrlVar('fromScratch') || getUrlVar('fromscratch');
app.indexCfg = configOptions;

loadCSS(app.pathJSAPI + "esri/css/esri.css", true);
loadCSS(app.pathJSAPI + "dijit/themes/claro/claro.css", true);

if( app.isProduction ) {
	if ( app.isInBuilder )
		loadCSS("app/builder-min.css");
	else
		loadCSS("app/viewer-min.css");
}

loadJS(app.pathJSAPI + 'init.js', true);
loadJS('app/config.js');

CKEDITOR_BASEPATH = app.isProduction ? 'resources/lib/ckeditor/' : 'lib-app/ckeditor/';

if( app.isProduction ) {
	_ = {};

	if ( app.isInBuilder )
		loadJS('app/builder-min.js');
	else
		loadJS('app/viewer-min.js');
}

loadJS('app/main-app.js');

// Enable Google Analytics on storymaps.esri.com
//if (window.location.href.toLowerCase().indexOf("storymaps.esri.com") >= 0) {
	var _gaq = _gaq || [];
	_gaq.push(['_setAccount', 'UA-38806035-3']);
	_gaq.push(['_trackPageview']);

	(function() {
		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
	})();
//}<|endoftext|>


<commit_before>'use strict';

// Configuring the Articles module
angular.module('chats').run(['Menus',
	function(Menus) {
		// Set top bar menu items
		Menus.addMenuItem('topbar', 'Chats', 'chats', '', '/chats/');
	}
]);
<commit_msg>removed chat from menu<commit_after>'use strict';

// Configuring the Articles module
angular.module('chats').run(['Menus',
	function(Menus) {
		// Set top bar menu items
		//Menus.addMenuItem('topbar', 'Chats', 'chats', '', '/chats/');
	}
]);
<|endoftext|>


<commit_before>var leaves;

// Testing flag, for mocking the dates of the events
// without having to change the dates in the events.json
var testing = true;
var first = true;

Number.prototype.pad = function(size) {
  var s = String(this);
  while (s.length < (size || 2)) {s = "0" + s;}
  return s;
}

var app = new Vue({
  el: '#app',
  data: {
    showoptions: false,
    foodNotify: true,
    talksNotify: true,
    eventsNotify: true,
    bieneNotify: false,
    timeline: null,
    animation: true
  },
  methods: {
    options: function() {
      this.showoptions = this.showoptions ? false : true;
    },
    updateTimetable: function () {
    this.$http.get('/assets/data/events.json?nocache=' + Math.floor(Math.random()*100))
      .then(function(response) {
        timeline = this.$get('timeline')
        events = response.body.events;

        if(first) {
          for(var i = 0; i < events.length; i++) {
            events[i].notifySent = false;
          }
        } else {
          for(var i = 0; i < events.length; i++) {
            events[i].notifySent = timeline[i].notifySent;
          }
        }

        // For testing we use the current time and create
        // events in the near future
        if(testing && first) {
          first = false;
          for(var i = 0; i < events.length; i++) {
            events[i].begin = new Date(Date.now() + i*30000);
            events[i].end = new Date(Date.now() + (i+1)*30000);
          }
        } else if(!testing) {
          for(var i = 0; i < events.length; i++) {
            events[i].begin = new Date(events[i].begin);
            events[i].end = new Date(events[i].end);
          }
        } else { // for testing, we keep the old times
          for(var i = 0; i < events.length; i++) {
            events[i].begin = timeline[i].begin;
            events[i].end = timeline[i].end;
          }
        }

        for(var i = 0; i < events.length; i++) {
          if(app.whereAreWe(events[i].begin, events[i].end) > 0 && !events[i].notifySent){
            events[i].notifySent = true;
            app.notify(events[i].title, events[i].place, events[i].type);
          }
        }

        this.$set('timeline', events);
      }, function(response) {
        console.log("Sth wrong");
      });
    },
    // Toggles animation between stopped and started state
    toggleAnimation: function (data) {
      console.log("toggle");
      if(data == false) {
        leaves.stop();
      } else {
        leaves.restart();
      }
    },
    // Starts background animation
    startAnimation: function () {
      leaves = new Leaves(true);
      leaves.start();
    },
    // Returns false if not in range and percentage of completion if true
    whereAreWe: function (start, end) {
      d = new Date(Date.now());

      if(start <= d && d <= end) { // Inside the range
        return (d - start)/(end - start);
      } else if(d < start) {
        return -2; // Before the range
      } else if(d > end) {
        return -1; // After the range
      }
    },
    notify: function (title, place, type) {
      permission = Notification.permission;
      if(permission !== "denied") {
        if(permission === "default") {
          Notification.requestPermission();
        }

        notifiable = false;
        if((type === "food" && this.foodNotify)
          || (type === "events" && this.eventsNotify)
          || (type === "talks" && this.talksNotify)
          || (type === "essential")) {
          notifiable = true;
        }

        if (permission === "granted" && notifiable) {
          var options = {
            body: place != null ? 'happening right now at ' + place : '',
            icon: '/favicon.ico',
          }

          new Notification(title, options);
        }
      }
    }
  },
  watch: {
    animation: function (data) {
      this.toggleAnimation(data);
    }
  },
  computed: {
    completedEvents: function() {
      return this.timeline.filter(function(data) {
        return app.whereAreWe(data.begin, data.end) === -1;
      }).slice(-5);
    },
    currentEvents: function() {
      return this.timeline.filter(function(data) {
        percentage = app.whereAreWe(data.begin, data.end);
        if(percentage > 0) {
          if(!data.notifySent) {
            app.notify(data.title, data.place, "essential");
            data.notifySent = true;
          }
          return true;
        }
      });
    },
    futureEvents: function() {
      return this.timeline.filter(function(data) {
        return app.whereAreWe(data.begin, data.end) === -2;
      });
    }
  },
  filters: {
    hackupcdate: function (date) {
      return date.getHours() + ":" + date.getMinutes().pad(2) + ":" + date.getSeconds().pad(2);
    }
  }
});

app.updateTimetable();
app.startAnimation();
app.notify("Welcome to HackUPC Live", null, "essential");

if(testing){
   window.setInterval(function(){
      app.updateTimetable();
    }, 1000);
} else {
  window.setInterval(function(){
    app.updateTimetable();
  }, 15000);
}
<commit_msg>Reduced past events shown from 5 to 2<commit_after>var leaves;

// Testing flag, for mocking the dates of the events
// without having to change the dates in the events.json
var testing = true;
var first = true;

Number.prototype.pad = function(size) {
  var s = String(this);
  while (s.length < (size || 2)) {s = "0" + s;}
  return s;
}

var app = new Vue({
  el: '#app',
  data: {
    showoptions: false,
    foodNotify: true,
    talksNotify: true,
    eventsNotify: true,
    bieneNotify: false,
    timeline: null,
    animation: true
  },
  methods: {
    options: function() {
      this.showoptions = this.showoptions ? false : true;
    },
    updateTimetable: function () {
    this.$http.get('/assets/data/events.json?nocache=' + Math.floor(Math.random()*100))
      .then(function(response) {
        timeline = this.$get('timeline')
        events = response.body.events;

        if(first) {
          for(var i = 0; i < events.length; i++) {
            events[i].notifySent = false;
          }
        } else {
          for(var i = 0; i < events.length; i++) {
            events[i].notifySent = timeline[i].notifySent;
          }
        }

        // For testing we use the current time and create
        // events in the near future
        if(testing && first) {
          first = false;
          for(var i = 0; i < events.length; i++) {
            events[i].begin = new Date(Date.now() + i*30000);
            events[i].end = new Date(Date.now() + (i+1)*30000);
          }
        } else if(!testing) {
          for(var i = 0; i < events.length; i++) {
            events[i].begin = new Date(events[i].begin);
            events[i].end = new Date(events[i].end);
          }
        } else { // for testing, we keep the old times
          for(var i = 0; i < events.length; i++) {
            events[i].begin = timeline[i].begin;
            events[i].end = timeline[i].end;
          }
        }

        for(var i = 0; i < events.length; i++) {
          if(app.whereAreWe(events[i].begin, events[i].end) > 0 && !events[i].notifySent){
            events[i].notifySent = true;
            app.notify(events[i].title, events[i].place, events[i].type);
          }
        }

        this.$set('timeline', events);
      }, function(response) {
        console.log("Sth wrong");
      });
    },
    // Toggles animation between stopped and started state
    toggleAnimation: function (data) {
      console.log("toggle");
      if(data == false) {
        leaves.stop();
      } else {
        leaves.restart();
      }
    },
    // Starts background animation
    startAnimation: function () {
      leaves = new Leaves(true);
      leaves.start();
    },
    // Returns false if not in range and percentage of completion if true
    whereAreWe: function (start, end) {
      d = new Date(Date.now());

      if(start <= d && d <= end) { // Inside the range
        return (d - start)/(end - start);
      } else if(d < start) {
        return -2; // Before the range
      } else if(d > end) {
        return -1; // After the range
      }
    },
    notify: function (title, place, type) {
      permission = Notification.permission;
      if(permission !== "denied") {
        if(permission === "default") {
          Notification.requestPermission();
        }

        notifiable = false;
        if((type === "food" && this.foodNotify)
          || (type === "events" && this.eventsNotify)
          || (type === "talks" && this.talksNotify)
          || (type === "essential")) {
          notifiable = true;
        }

        if (permission === "granted" && notifiable) {
          var options = {
            body: place != null ? 'happening right now at ' + place : '',
            icon: '/favicon.ico',
          }

          new Notification(title, options);
        }
      }
    }
  },
  watch: {
    animation: function (data) {
      this.toggleAnimation(data);
    }
  },
  computed: {
    completedEvents: function() {
      return this.timeline.filter(function(data) {
        return app.whereAreWe(data.begin, data.end) === -1;
      }).slice(-2);
    },
    currentEvents: function() {
      return this.timeline.filter(function(data) {
        percentage = app.whereAreWe(data.begin, data.end);
        if(percentage > 0) {
          if(!data.notifySent) {
            app.notify(data.title, data.place, "essential");
            data.notifySent = true;
          }
          return true;
        }
      });
    },
    futureEvents: function() {
      return this.timeline.filter(function(data) {
        return app.whereAreWe(data.begin, data.end) === -2;
      });
    }
  },
  filters: {
    hackupcdate: function (date) {
      return date.getHours() + ":" + date.getMinutes().pad(2) + ":" + date.getSeconds().pad(2);
    }
  }
});

app.updateTimetable();
app.startAnimation();
app.notify("Welcome to HackUPC Live", null, "essential");

if(testing){
   window.setInterval(function(){
      app.updateTimetable();
    }, 1000);
} else {
  window.setInterval(function(){
    app.updateTimetable();
  }, 15000);
}
<|endoftext|>


<commit_before>;(function($) {

    // Datatables defaults
    //
    // Bootstrap layout

    /* API method to get paging information */
    $.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings )
    {
        return {
            "iStart":         oSettings._iDisplayStart,
            "iEnd":           oSettings.fnDisplayEnd(),
            "iLength":        oSettings._iDisplayLength,
            "iTotal":         oSettings.fnRecordsTotal(),
            "iFilteredTotal": oSettings.fnRecordsDisplay(),
            "iPage":          Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ),
            "iTotalPages":    Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength )
        };
    }

    /* Bootstrap style pagination control */
    $.extend($.fn.dataTableExt.oPagination, {
        "bootstrap": {
            "fnInit": function( oSettings, nPaging, fnDraw ) {
                var oLang = oSettings.oLanguage.oPaginate;
                var fnClickHandler = function ( e ) {
                    e.preventDefault();
                    if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) {
                        fnDraw( oSettings );
                    }
                };

                $(nPaging).addClass('pagination').append(
                    '
'+
                    '
← '+oLang.sPrevious+'
'+
                    '
'+oLang.sNext+' →
'+
                    '
'
                );
                var els = $('a', nPaging);
                $(els[0]).bind( 'click.DT', { action: "previous" }, fnClickHandler );
                $(els[1]).bind( 'click.DT', { action: "next" }, fnClickHandler );
            },

            "fnUpdate": function ( oSettings, fnDraw ) {
                var iListLength = 5;
                var oPaging = oSettings.oInstance.fnPagingInfo();
                var an = oSettings.aanFeatures.p;
                var i, j, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2);

                if ( oPaging.iTotalPages < iListLength) {
                    iStart = 1;
                    iEnd = oPaging.iTotalPages;
                }
                else if ( oPaging.iPage <= iHalf ) {
                    iStart = 1;
                    iEnd = iListLength;
                } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) {
                    iStart = oPaging.iTotalPages - iListLength + 1;
                    iEnd = oPaging.iTotalPages;
                } else {
                    iStart = oPaging.iPage - iHalf + 1;
                    iEnd = iStart + iListLength - 1;
                }

                for ( i=0 ; i<an.length ; i++ ) {
                    // Remove the middle elements
                    $('li:gt(0)', an[i]).filter(':not(:last)').remove();

                    // Add the new list items and their event handlers
                    for ( j=iStart ; j<=iEnd ; j++ ) {
                        sClass = (j==oPaging.iPage+1) ? 'class="active"' : '';
                        $('
'+j+'
')
                        .insertBefore( $('li:last', an[i])[0] )
                        .bind('click', function (e) {
                            e.preventDefault();
                            oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength;
                            fnDraw( oSettings );
                        } );
                    }

                    // Add / remove disabled classes from the static elements
                    if ( oPaging.iPage === 0 ) {
                        $('li:first', an[i]).addClass('disabled');
                    } else {
                        $('li:first', an[i]).removeClass('disabled');
                    }

                    if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) {
                        $('li:last', an[i]).addClass('disabled');
                    } else {
                        $('li:last', an[i]).removeClass('disabled');
                    }
                }
            }
        }
    });

    $.extend($.fn.dataTable.defaults, {
        "sDom": "R<'row'<'span6'f><'span6'l>r>t<'row'<'span6'i><'span6'p>>",
        "sPaginationType": "bootstrap",
        "oLanguage": {
            "sEmptyTable": "Tabellen innehåller ingen data",
            "sInfo": "Visar _START_ till _END_ av totalt _TOTAL_ rader",
            "sInfoEmpty": "Visar 0 till 0 av totalt 0 rader",
            "sInfoFiltered": "(filtrerade från totalt _MAX_ rader)",
            "sInfoPostFix": "",
            "sInfoThousands": ",",
            "sLengthMenu": "Visa _MENU_ rader",
            "sLoadingRecords": "Laddar...",
            "sProcessing": "Bearbetar...",
            "sSearch": "Sök i alla kolumner:",
            "sUrl": "",
            "sZeroRecords": "Hittade inga matchande resultat",
            "oPaginate": {
                "sFirst": "Första",
                "sLast": "Sista",
                "sNext": "Nästa",
                "sPrevious": "Föregående"
            },
            "oAria": {
                "sSortAscending": ": aktivera för att sortera kolumnen i stigande ordning",
                "sSortDescending": ": aktivera för att sortera kolumnen i fallande ordning"
            }
        }
    });

    $.extend($.fn.dataTableExt.oStdClasses, {
        "sSortAsc": "header headerSortDown",
        "sSortDesc": "header headerSortUp",
        "sSortable": "header"
    });

})(window.jQuery);
<commit_msg>Fix for layout bug<commit_after>;(function($) {

    // Datatables defaults
    //
    // Bootstrap layout

    /* API method to get paging information */
    $.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings )
    {
        return {
            "iStart":         oSettings._iDisplayStart,
            "iEnd":           oSettings.fnDisplayEnd(),
            "iLength":        oSettings._iDisplayLength,
            "iTotal":         oSettings.fnRecordsTotal(),
            "iFilteredTotal": oSettings.fnRecordsDisplay(),
            "iPage":          Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ),
            "iTotalPages":    Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength )
        };
    }

    /* Bootstrap style pagination control */
    $.extend($.fn.dataTableExt.oPagination, {
        "bootstrap": {
            "fnInit": function( oSettings, nPaging, fnDraw ) {
                var oLang = oSettings.oLanguage.oPaginate;
                var fnClickHandler = function ( e ) {
                    e.preventDefault();
                    if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) {
                        fnDraw( oSettings );
                    }
                };

                $(nPaging).addClass('pagination').append(
                    '
'+
                    '
← '+oLang.sPrevious+'
'+
                    '
'+oLang.sNext+' →
'+
                    '
'
                );
                var els = $('a', nPaging);
                $(els[0]).bind( 'click.DT', { action: "previous" }, fnClickHandler );
                $(els[1]).bind( 'click.DT', { action: "next" }, fnClickHandler );
            },

            "fnUpdate": function ( oSettings, fnDraw ) {
                var iListLength = 5;
                var oPaging = oSettings.oInstance.fnPagingInfo();
                var an = oSettings.aanFeatures.p;
                var i, j, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2);

                if ( oPaging.iTotalPages < iListLength) {
                    iStart = 1;
                    iEnd = oPaging.iTotalPages;
                }
                else if ( oPaging.iPage <= iHalf ) {
                    iStart = 1;
                    iEnd = iListLength;
                } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) {
                    iStart = oPaging.iTotalPages - iListLength + 1;
                    iEnd = oPaging.iTotalPages;
                } else {
                    iStart = oPaging.iPage - iHalf + 1;
                    iEnd = iStart + iListLength - 1;
                }

                for ( i=0 ; i<an.length ; i++ ) {
                    // Remove the middle elements
                    $('li:gt(0)', an[i]).filter(':not(:last)').remove();

                    // Add the new list items and their event handlers
                    for ( j=iStart ; j<=iEnd ; j++ ) {
                        sClass = (j==oPaging.iPage+1) ? 'class="active"' : '';
                        $('
'+j+'
')
                        .insertBefore( $('li:last', an[i])[0] )
                        .bind('click', function (e) {
                            e.preventDefault();
                            oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength;
                            fnDraw( oSettings );
                        } );
                    }

                    // Add / remove disabled classes from the static elements
                    if ( oPaging.iPage === 0 ) {
                        $('li:first', an[i]).addClass('disabled');
                    } else {
                        $('li:first', an[i]).removeClass('disabled');
                    }

                    if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) {
                        $('li:last', an[i]).addClass('disabled');
                    } else {
                        $('li:last', an[i]).removeClass('disabled');
                    }
                }
            }
        }
    });

    $.extend($.fn.dataTable.defaults, {
        "sDom": "R<'row-fluid'<'span6'f><'span6'l>r>t<'row-fluid'<'span6'i><'span6'p>>",
        "sPaginationType": "bootstrap",
        "oLanguage": {
            "sEmptyTable": "Tabellen innehåller ingen data",
            "sInfo": "Visar _START_ till _END_ av totalt _TOTAL_ rader",
            "sInfoEmpty": "Visar 0 till 0 av totalt 0 rader",
            "sInfoFiltered": "(filtrerade från totalt _MAX_ rader)",
            "sInfoPostFix": "",
            "sInfoThousands": ",",
            "sLengthMenu": "Visa _MENU_ rader",
            "sLoadingRecords": "Laddar...",
            "sProcessing": "Bearbetar...",
            "sSearch": "Sök i alla kolumner:",
            "sUrl": "",
            "sZeroRecords": "Hittade inga matchande resultat",
            "oPaginate": {
                "sFirst": "Första",
                "sLast": "Sista",
                "sNext": "Nästa",
                "sPrevious": "Föregående"
            },
            "oAria": {
                "sSortAscending": ": aktivera för att sortera kolumnen i stigande ordning",
                "sSortDescending": ": aktivera för att sortera kolumnen i fallande ordning"
            }
        }
    });

    $.extend($.fn.dataTableExt.oStdClasses, {
        "sSortAsc": "header headerSortDown",
        "sSortDesc": "header headerSortUp",
        "sSortable": "header"
    });

})(window.jQuery);
<|endoftext|>