text: define(["./kernel", "../on", "../topic", "../aspect", "./event", "../mouse", "./sniff", "./lang", "../keys"], function(dojo, on, hub, aspect, eventModule, mouse, has, lang){
  // module:
  //		dojo/_base/connect
  
  has.add("events-keypress-typed", function(){ // keypresses should only occur a printable character is hit
  	var testKeyEvent = {charCode: 0};
  	try{
  		testKeyEvent = document.createEvent("KeyboardEvent");
  		(testKeyEvent.initKeyboardEvent || testKeyEvent.initKeyEvent).call(testKeyEvent, "keypress", true, true, null, false, false, false, false, 9, 3);
  	}catch(e){}
  	return testKeyEvent.charCode == 0 && !has("opera");
  });
  
  function connect_(obj, event, context, method, dontFix){
  	method = lang.hitch(context, method);
  	if(!obj || !(obj.addEventListener || obj.attachEvent)){
  		// it is a not a DOM node and we are using the dojo.connect style of treating a
  		// method like an event, must go right to aspect
  		return aspect.after(obj || dojo.global, event, method, true);
  	}
  	if(typeof event == "string" && event.substring(0, 2) == "on"){
  		event = event.substring(2);
  	}
  	if(!obj){
  		obj = dojo.global;
  	}
  	if(!dontFix){
  		switch(event){
  			// dojo.connect has special handling for these event types
  			case "keypress":
  				event = keypress;
  				break;
  			case "mouseenter":
  				event = mouse.enter;
  				break;
  			case "mouseleave":
  				event = mouse.leave;
  				break;
  		}
  	}
  	return on(obj, event, method, dontFix);
  }
  
  var _punctMap = {
  	106:42,
  	111:47,
  	186:59,
  	187:43,
  	188:44,
  	189:45,
  	190:46,
  	191:47,
  	192:96,
  	219:91,
  	220:92,
  	221:93,
  	222:39,
  	229:113
  };
  var evtCopyKey = has("mac") ? "metaKey" : "ctrlKey";
  
  
  var _synthesizeEvent = function(evt, props){
  	var faux = lang.mixin({}, evt, props);
  	setKeyChar(faux);
  	// FIXME: would prefer to use lang.hitch: lang.hitch(evt, evt.preventDefault);
  	// but it throws an error when preventDefault is invoked on Safari
  	// does Event.preventDefault not support "apply" on Safari?
  	faux.preventDefault = function(){ evt.preventDefault(); };
  	faux.stopPropagation = function(){ evt.stopPropagation(); };
  	return faux;
  };
  function setKeyChar(evt){
  	evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
  	evt.charOrCode = evt.keyChar || evt.keyCode;
  }
  var keypress;
  if(has("events-keypress-typed")){
  	// this emulates Firefox's keypress behavior where every keydown can correspond to a keypress
  	var _trySetKeyCode = function(e, code){
  		try{
  			// squelch errors when keyCode is read-only
  			// (e.g. if keyCode is ctrl or shift)
  			return (e.keyCode = code);
  		}catch(e){
  			return 0;
  		}
  	};
  	keypress = function(object, listener){
  		var keydownSignal = on(object, "keydown", function(evt){
  			// munge key/charCode
  			var k=evt.keyCode;
  			// These are Windows Virtual Key Codes
  			// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
  			var unprintable = (k!=13) && k!=32 && (k!=27||!has("ie")) && (k<48||k>90) && (k<96||k>111) && (k<186||k>192) && (k<219||k>222) && k!=229;
  			// synthesize keypress for most unprintables and CTRL-keys
  			if(unprintable||evt.ctrlKey){
  				var c = unprintable ? 0 : k;
  				if(evt.ctrlKey){
  					if(k==3 || k==13){
  						return listener.call(evt.currentTarget, evt); // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
  					}else if(c>95 && c<106){
  						c -= 48; // map CTRL-[numpad 0-9] to ASCII
  					}else if((!evt.shiftKey)&&(c>=65&&c<=90)){
  						c += 32; // map CTRL-[A-Z] to lowercase
  					}else{
  						c = _punctMap[c] || c; // map other problematic CTRL combinations to ASCII
  					}
  				}
  				// simulate a keypress event
  				var faux = _synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
  				listener.call(evt.currentTarget, faux);
  				if(has("ie")){
  					_trySetKeyCode(evt, faux.keyCode);
  				}
  			}
  		});
  		var keypressSignal = on(object, "keypress", function(evt){
  			var c = evt.charCode;
  			c = c>=32 ? c : 0;
  			evt = _synthesizeEvent(evt, {charCode: c, faux: true});
  			return listener.call(this, evt);
  		});
  		return {
  			remove: function(){
  				keydownSignal.remove();
  				keypressSignal.remove();
  			}
  		};
  	};
  }else{
  	if(has("opera")){
  		keypress = function(object, listener){
  			return on(object, "keypress", function(evt){
  				var c = evt.which;
  				if(c==3){
  					c=99; // Mozilla maps CTRL-BREAK to CTRL-c
  				}
  				// can't trap some keys at all, like INSERT and DELETE
  				// there is no differentiating info between DELETE and ".", or INSERT and "-"
  				c = c<32 && !evt.shiftKey ? 0 : c;
  				if(evt.ctrlKey && !evt.shiftKey && c>=65 && c<=90){
  					// lowercase CTRL-[A-Z] keys
  					c += 32;
  				}
  				return listener.call(this, _synthesizeEvent(evt, { charCode: c }));
  			});
  		};
  	}else{
  		keypress = function(object, listener){
  			return on(object, "keypress", function(evt){
  				setKeyChar(evt);
  				return listener.call(this, evt);
  			});
  		};
  	}
  }
  
  var connect = {
  	// summary:
  	//		This module defines the dojo.connect API.
  	//		This modules also provides keyboard event handling helpers.
  	//		This module exports an extension event for emulating Firefox's keypress handling.
  	//		However, this extension event exists primarily for backwards compatibility and
  	//		is not recommended. WebKit and IE uses an alternate keypress handling (only
  	//		firing for printable characters, to distinguish from keydown events), and most
  	//		consider the WebKit/IE behavior more desirable.
  
  	_keypress:keypress,
  
  	connect:function(obj, event, context, method, dontFix){
  		// summary:
  		//		`dojo.connect` is a deprecated event handling and delegation method in
  		//		Dojo. It allows one function to "listen in" on the execution of
  		//		any other, triggering the second whenever the first is called. Many
  		//		listeners may be attached to a function, and source functions may
  		//		be either regular function calls or DOM events.
  		//
  		// description:
  		//		Connects listeners to actions, so that after event fires, a
  		//		listener is called with the same arguments passed to the original
  		//		function.
  		//
  		//		Since `dojo.connect` allows the source of events to be either a
  		//		"regular" JavaScript function or a DOM event, it provides a uniform
  		//		interface for listening to all the types of events that an
  		//		application is likely to deal with though a single, unified
  		//		interface. DOM programmers may want to think of it as
  		//		"addEventListener for everything and anything".
  		//
  		//		When setting up a connection, the `event` parameter must be a
  		//		string that is the name of the method/event to be listened for. If
  		//		`obj` is null, `kernel.global` is assumed, meaning that connections
  		//		to global methods are supported but also that you may inadvertently
  		//		connect to a global by passing an incorrect object name or invalid
  		//		reference.
  		//
  		//		`dojo.connect` generally is forgiving. If you pass the name of a
  		//		function or method that does not yet exist on `obj`, connect will
  		//		not fail, but will instead set up a stub method. Similarly, null
  		//		arguments may simply be omitted such that fewer than 4 arguments
  		//		may be required to set up a connection See the examples for details.
  		//
  		//		The return value is a handle that is needed to
  		//		remove this connection with `dojo.disconnect`.
  		//
  		// obj: Object?
  		//		The source object for the event function.
  		//		Defaults to `kernel.global` if null.
  		//		If obj is a DOM node, the connection is delegated
  		//		to the DOM event manager (unless dontFix is true).
  		//
  		// event: String
  		//		String name of the event function in obj.
  		//		I.e. identifies a property `obj[event]`.
  		//
  		// context: Object|null
  		//		The object that method will receive as "this".
  		//
  		//		If context is null and method is a function, then method
  		//		inherits the context of event.
  		//
  		//		If method is a string then context must be the source
  		//		object object for method (context[method]). If context is null,
  		//		kernel.global is used.
  		//
  		// method: String|Function
  		//		A function reference, or name of a function in context.
  		//		The function identified by method fires after event does.
  		//		method receives the same arguments as the event.
  		//		See context argument comments for information on method's scope.
  		//
  		// dontFix: Boolean?
  		//		If obj is a DOM node, set dontFix to true to prevent delegation
  		//		of this connection to the DOM event manager.
  		//
  		// example:
  		//		When obj.onchange(), do ui.update():
  		//	|	dojo.connect(obj, "onchange", ui, "update");
  		//	|	dojo.connect(obj, "onchange", ui, ui.update); // same
  		//
  		// example:
  		//		Using return value for disconnect:
  		//	|	var link = dojo.connect(obj, "onchange", ui, "update");
  		//	|	...
  		//	|	dojo.disconnect(link);
  		//
  		// example:
  		//		When onglobalevent executes, watcher.handler is invoked:
  		//	|	dojo.connect(null, "onglobalevent", watcher, "handler");
  		//
  		// example:
  		//		When ob.onCustomEvent executes, customEventHandler is invoked:
  		//	|	dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
  		//	|	dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
  		//
  		// example:
  		//		When ob.onCustomEvent executes, customEventHandler is invoked
  		//		with the same scope (this):
  		//	|	dojo.connect(ob, "onCustomEvent", null, customEventHandler);
  		//	|	dojo.connect(ob, "onCustomEvent", customEventHandler); // same
  		//
  		// example:
  		//		When globalEvent executes, globalHandler is invoked
  		//		with the same scope (this):
  		//	|	dojo.connect(null, "globalEvent", null, globalHandler);
  		//	|	dojo.connect("globalEvent", globalHandler); // same
  
  		// normalize arguments
  		var a=arguments, args=[], i=0;
  		// if a[0] is a String, obj was omitted
  		args.push(typeof a[0] == "string" ? null : a[i++], a[i++]);
  		// if the arg-after-next is a String or Function, context was NOT omitted
  		var a1 = a[i+1];
  		args.push(typeof a1 == "string" || typeof a1 == "function" ? a[i++] : null, a[i++]);
  		// absorb any additional arguments
  		for(var l=a.length; i<l; i++){	args.push(a[i]); }
  		return connect_.apply(this, args);
  	},
  
  	disconnect:function(handle){
  		// summary:
  		//		Remove a link created by dojo.connect.
  		// description:
  		//		Removes the connection between event and the method referenced by handle.
  		// handle: Handle
  		//		the return value of the dojo.connect call that created the connection.
  
  		if(handle){
  			handle.remove();
  		}
  	},
  
  	subscribe:function(topic, context, method){
  		// summary:
  		//		Attach a listener to a named topic. The listener function is invoked whenever the
  		//		named topic is published (see: dojo.publish).
  		//		Returns a handle which is needed to unsubscribe this listener.
  		// topic: String
  		//		The topic to which to subscribe.
  		// context: Object?
  		//		Scope in which method will be invoked, or null for default scope.
  		// method: String|Function
  		//		The name of a function in context, or a function reference. This is the function that
  		//		is invoked when topic is published.
  		// example:
  		//	|	dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); });
  		//	|	dojo.publish("alerts", [ "read this", "hello world" ]);
  		return hub.subscribe(topic, lang.hitch(context, method));
  	},
  
  	publish:function(topic, args){
  		// summary:
  		//		Invoke all listener method subscribed to topic.
  		// topic: String
  		//		The name of the topic to publish.
  		// args: Array?
  		//		An array of arguments. The arguments will be applied
  		//		to each topic subscriber (as first class parameters, via apply).
  		// example:
  		//	|	dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
  		//	|	dojo.publish("alerts", [ "read this", "hello world" ]);
  		return hub.publish.apply(hub, [topic].concat(args));
  	},
  
  	connectPublisher:function(topic, obj, event){
  		// summary:
  		//		Ensure that every time obj.event() is called, a message is published
  		//		on the topic. Returns a handle which can be passed to
  		//		dojo.disconnect() to disable subsequent automatic publication on
  		//		the topic.
  		// topic: String
  		//		The name of the topic to publish.
  		// obj: Object?
  		//		The source object for the event function. Defaults to kernel.global
  		//		if null.
  		// event: String
  		//		The name of the event function in obj.
  		//		I.e. identifies a property obj[event].
  		// example:
  		//	|	dojo.connectPublisher("/ajax/start", dojo, "xhrGet");
  		var pf = function(){ connect.publish(topic, arguments); };
  		return event ? connect.connect(obj, event, pf) : connect.connect(obj, pf); //Handle
  	},
  
  	isCopyKey: function(e){
  		// summary:
  		//		Checks an event for the copy key (meta on Mac, and ctrl anywhere else)
  		// e: Event
  		//		Event object to examine
  		return e[evtCopyKey];	// Boolean
  	}
  };
  
  connect.unsubscribe = connect.disconnect;
  /*=====
   connect.unsubscribe = function(handle){
  	 // summary:
  	 //		Remove a topic listener.
  	 // handle: Handle
  	 //		The handle returned from a call to subscribe.
  	 // example:
  	 //	|	var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
  	 //	|	...
  	 //	|	dojo.unsubscribe(alerter);
   };
   =====*/
  
  has("extend-dojo") && lang.mixin(dojo, connect);
  return connect;
  
  });
  
  
  