loader.js 31.5 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
define(["./kernel", "../has", "require", "module", "../json", "./lang", "./array"], function(dojo, has, require, thisModule, json, lang, array) {
	// module:
	//		dojo/_base/loader

	//		This module defines the v1.x synchronous loader API.

	// signal the loader in sync mode...
	//>>pure-amd

	if (!has("dojo-loader")){
		console.error("cannot load the Dojo v1.x loader with a foreign loader");
		return 0;
	}

	has.add("dojo-fast-sync-require", 1);


	var makeErrorToken = function(id){
			return {src:thisModule.id, id:id};
		},

		slashName = function(name){
			return name.replace(/\./g, "/");
		},

		buildDetectRe = /\/\/>>built/,

		dojoRequireCallbacks = [],
		dojoRequireModuleStack = [],

		dojoRequirePlugin = function(mid, require, loaded){
			dojoRequireCallbacks.push(loaded);
			array.forEach(mid.split(","), function(mid){
				var module = getModule(mid, require.module);
				dojoRequireModuleStack.push(module);
				injectModule(module);
			});
			checkDojoRequirePlugin();
		},

		checkDojoRequirePlugin = (has("dojo-fast-sync-require") ?
			// This version of checkDojoRequirePlugin makes the observation that all dojoRequireCallbacks can be released
			// when all *non-dojo/require!, dojo/loadInit!* modules are either executed, not requested, or arrived. This is
			// the case since there are no more modules the loader is waiting for, therefore, dojo/require! must have
			// everything it needs on board.
			//
			// The potential weakness of this algorithm is that dojo/require will not execute callbacks until *all* dependency
			// trees are ready. It is possible that some trees may be ready earlier than others, and this extra wait is non-optimal.
			// Still, for big projects, this seems better than the original algorithm below that proved slow in some cases.
			// Note, however, the original algorithm had the potential to execute partial trees,  but that potential was never enabled.
			// There are also other optimization available with the original algorithm that have not been explored.
			function(){
				var module, mid;
				for(mid in modules){
					module = modules[mid];
					if(module.noReqPluginCheck===undefined){
						// tag the module as either a loadInit or require plugin or not for future reference
						module.noReqPluginCheck = /loadInit\!/.test(mid) || /require\!/.test(mid) ? 1 : 0;
					}
					if(!module.executed && !module.noReqPluginCheck && module.injected==requested){
						return;
					}
				}

				guardCheckComplete(function(){
					var oldCallbacks = dojoRequireCallbacks;
					dojoRequireCallbacks = [];
					array.forEach(oldCallbacks, function(cb){cb(1);});
				});
		} : (function(){
			// Note: this is the original checkDojoRequirePlugin that is much slower than the algorithm above. However, we know it
			// works, so we leave it here in case the algorithm above fails in some corner case.
			//
			// checkDojoRequirePlugin inspects all of the modules demanded by a dojo/require!<module-list> dependency
			// to see if they have arrived. The loader does not release *any* of these modules to be instantiated
			// until *all* of these modules are on board, thereby preventing the evaluation of a module with dojo.require's
			// that reference modules that are not available.
			//
			// The algorithm works by traversing the dependency graphs (remember, there can be cycles so they are not trees)
			// of each module in the dojoRequireModuleStack array (which contains the list of modules demanded by dojo/require!).
			// The moment a single module is discovered that is missing, the algorithm gives up and indicates that not all
			// modules are on board. dojo/loadInit! and dojo/require! are ignored because there dependencies are inserted
			// directly in dojoRequireModuleStack. For example, if "your/module" module depends on "dojo/require!my/module", then
			// *both* "dojo/require!my/module" and "my/module" will be in dojoRequireModuleStack. Obviously, if "my/module"
			// is on board, then "dojo/require!my/module" is also satisfied, so the algorithm doesn't check for "dojo/require!my/module".
			//
			// Note: inserting a dojo/require!<some-module-list> dependency in the dojoRequireModuleStack achieves nothing
			// with the current algorithm; however, having such modules present makes it possible to optimize the algorithm
			//
			// Note: prior versions of this algorithm had an optimization that signaled loaded on dojo/require! dependencies
			// individually (rather than waiting for them all to be resolved). The implementation proved problematic with cycles
			// and plugins. However, it is possible to reattach that strategy in the future.

			// a set from module-id to {undefined | 1 | 0}, where...
			//	 undefined => the module has not been inspected
			//	 0 => the module or at least one of its dependencies has not arrived
			//	 1 => the module is a loadInit! or require! plugin resource, or is currently being traversed (therefore, assume
			//		  OK until proven otherwise), or has been completely traversed and all dependencies have arrived

			var touched,
			traverse = function(m){
				touched[m.mid] = 1;
				for(var t, module, deps = m.deps || [], i= 0; i<deps.length; i++){
					module = deps[i];
					if(!(t = touched[module.mid])){
						if(t===0 || !traverse(module)){
							touched[m.mid] = 0;
							return false;
						}
					}
				}
				return true;
			};

			return function(){
				// initialize the touched hash with easy-to-compute values that help short circuit recursive algorithm;
				// recall loadInit/require plugin modules are dependencies of modules in dojoRequireModuleStack...
				// which would cause a circular dependency chain that would never be resolved if checked here
				// notice all dependencies of any particular loadInit/require plugin module will already
				// be checked since those are pushed into dojoRequireModuleStack explicitly by the
				// plugin...so if a particular loadInitPlugin module's dependencies are not really
				// on board, that *will* be detected elsewhere in the traversal.
				var module, mid;
				touched = {};
				for(mid in modules){
					module = modules[mid];
					if(module.executed || module.noReqPluginCheck){
						touched[mid] = 1;
					}else{
						if(module.noReqPluginCheck!==0){
							// tag the module as either a loadInit or require plugin or not for future reference
							module.noReqPluginCheck = /loadInit\!/.test(mid) || /require\!/.test(mid) ? 1 : 0;
						}
						if(module.noReqPluginCheck){
							touched[mid] = 1;
						}else if(module.injected!==arrived){
							// not executed, has not arrived, and is not a loadInit or require plugin resource
							touched[mid] = 0;
						}// else, leave undefined and we'll traverse the dependencies
					}
				}
				for(var t, i = 0, end = dojoRequireModuleStack.length; i<end; i++){
					module = dojoRequireModuleStack[i];
					if(!(t = touched[module.mid])){
						if(t===0 || !traverse(module)){
							return;
						}
					}
				}
				guardCheckComplete(function(){
					var oldCallbacks = dojoRequireCallbacks;
					dojoRequireCallbacks = [];
					array.forEach(oldCallbacks, function(cb){cb(1);});
				});
			};
		})()),

		dojoLoadInitPlugin = function(mid, require, loaded){
			// mid names a module that defines a "dojo load init" bundle, an object with two properties:
			//
			//	 * names: a vector of module ids that give top-level names to define in the lexical scope of def
			//	 * def: a function that contains some some legacy loader API applications
			//
			// The point of def is to possibly cause some modules to be loaded (but not executed) by dojo/require! where the module
			// ids are possibly-determined at runtime. For example, here is dojox.gfx from v1.6 expressed as an AMD module using the dojo/loadInit
			// and dojo/require plugins.
			//
			// // dojox/gfx:
			//
			//	 define("*loadInit_12, {
			//	   names:["dojo", "dijit", "dojox"],
			//	   def: function(){
			//		 dojo.loadInit(function(){
			//		   var gfx = lang.getObject("dojox.gfx", true);
			//
			//		   //
			//		   // code required to set gfx properties ommitted...
			//		   //
			//
			//		   // now use the calculations to include the runtime-dependent module
			//		   dojo.require("dojox.gfx." + gfx.renderer);
			//		 });
			//	   }
			//	 });
			//
			//	 define(["dojo", "dojo/loadInit!" + id].concat("dojo/require!dojox/gfx/matric,dojox/gfx/_base"), function(dojo){
			//	   // when this AMD factory function is executed, the following modules are guaranteed downloaded but not executed:
			//	   //	"dojox.gfx." + gfx.renderer
			//	   //	dojox.gfx.matrix
			//	   //	dojox.gfx._base
			//	   dojo.provide("dojo.gfx");
			//	   dojo.require("dojox.gfx.matrix");
			//	   dojo.require("dojox.gfx._base");
			//	   dojo.require("dojox.gfx." + gfx.renderer);
			//	   return lang.getObject("dojo.gfx");
			//	 });
			//	})();
			//
			// The idea is to run the legacy loader API with global variables shadowed, which allows these variables to
			// be relocated. For example, dojox and dojo could be relocated to different names by giving a map and the code above will
			// execute properly (because the plugin below resolves the load init bundle.names module with respect to the module that demanded
			// the plugin resource).
			//
			// Note that the relocation is specified in the runtime configuration; relocated names need not be set at build-time.
			//
			// Warning: this is not the best way to express dojox.gfx as and AMD module. In fact, the module has been properly converted in
			// v1.7. However, this technique allows the builder to convert legacy modules into AMD modules and guarantee the codepath is the
			// same in the converted AMD module.
			require([mid], function(bundle){
				// notice how names is resolved with respect to the module that demanded the plugin resource
				require(bundle.names, function(){
					// bring the bundle names into scope
					for(var scopeText = "", args= [], i = 0; i<arguments.length; i++){
						scopeText+= "var " + bundle.names[i] + "= arguments[" + i + "]; ";
						args.push(arguments[i]);
					}
					eval(scopeText);

					var callingModule = require.module,
						// the list of modules that need to be downloaded but not executed before the callingModule can be executed
						requireList = [],

						// the list of i18n bundles that are xdomain; undefined if none
						i18nDeps,

						syncLoaderApi = {
							provide:function(moduleName){
								// mark modules that arrive consequent to multiple provides in this module as arrived since they can't be injected
								moduleName = slashName(moduleName);
								var providedModule = getModule(moduleName, callingModule);
								if(providedModule!==callingModule){
									setArrived(providedModule);
								}
							},
							require:function(moduleName, omitModuleCheck){
								moduleName = slashName(moduleName);
								omitModuleCheck && (getModule(moduleName, callingModule).result = nonmodule);
								requireList.push(moduleName);
							},
							requireLocalization:function(moduleName, bundleName, locale){
								// since we're going to need dojo/i8n, add it to i18nDeps if not already there
								if(!i18nDeps){
									// don't have to map since that will occur when the dependency is resolved
									i18nDeps = ["dojo/i18n"];
								}

								// figure out if the bundle is xdomain; if so, add it to the i18nDepsSet
								locale = (locale || dojo.locale).toLowerCase();
								moduleName = slashName(moduleName) + "/nls/" + (/root/i.test(locale) ? "" : locale + "/") + slashName(bundleName);
								if(getModule(moduleName, callingModule).isXd){
									// don't have to map since that will occur when the dependency is resolved
									i18nDeps.push("dojo/i18n!" + moduleName);
								}// else the bundle will be loaded synchronously when the module is evaluated
							},
							loadInit:function(f){
								f();
							}
						},

						hold = {},
						p;

					// hijack the correct dojo and apply bundle.def
					try{
						for(p in syncLoaderApi){
							hold[p] = dojo[p];
							dojo[p] = syncLoaderApi[p];
						}
						bundle.def.apply(null, args);
					}catch(e){
						signal("error", [makeErrorToken("failedDojoLoadInit"), e]);
					}finally{
						for(p in syncLoaderApi){
							dojo[p] = hold[p];
						}
					}

					if(i18nDeps){
						requireList = requireList.concat(i18nDeps);
					}

					if(requireList.length){
						dojoRequirePlugin(requireList.join(","), require, loaded);
					}else{
						loaded();
					}
				});
			});
		},

		extractApplication = function(
			text,			  // the text to search
			startSearch,	  // the position in text to start looking for the closing paren
			startApplication  // the position in text where the function application expression starts
		){
			// find end of the call by finding the matching end paren
			// Warning: as usual, this will fail in the presense of unmatched right parans contained in strings, regexs, or unremoved comments
			var parenRe = /\(|\)/g,
				matchCount = 1,
				match;
			parenRe.lastIndex = startSearch;
			while((match = parenRe.exec(text))){
				if(match[0] == ")"){
					matchCount -= 1;
				}else{
					matchCount += 1;
				}
				if(matchCount == 0){
					break;
				}
			}

			if(matchCount != 0){
				throw "unmatched paren around character " + parenRe.lastIndex + " in: " + text;
			}

			//Put the master matching string in the results.
			return [dojo.trim(text.substring(startApplication, parenRe.lastIndex))+";\n", parenRe.lastIndex];
		},

		// the following regex is taken from 1.6. It is a very poor technique to remove comments and
		// will fail in some cases; for example, consider the code...
		//
		//	  var message = "Category-1 */* Category-2";
		//
		// The regex that follows will see a /* comment and trash the code accordingly. In fact, there are all
		// kinds of cases like this with strings and regexs that will cause this design to fail miserably.
		//
		// Alternative regex designs exist that will result in less-likely failures, but will still fail in many cases.
		// The only solution guaranteed 100% correct is to parse the code and that seems overkill for this
		// backcompat/unbuilt-xdomain layer. In the end, since it's been this way for a while, we won't change it.
		// See the opening paragraphs of Chapter 7 or ECME-262 which describes the lexical abiguity further.
		removeCommentRe = /(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg,

		syncLoaderApiRe = /(^|\s)dojo\.(loadInit|require|provide|requireLocalization|requireIf|requireAfterIf|platformRequire)\s*\(/mg,

		amdLoaderApiRe = /(^|\s)(require|define)\s*\(/m,

		extractLegacyApiApplications = function(text, noCommentText){
			// scan the noCommentText for any legacy loader API applications. Copy such applications into result (this is
			// used by the builder). Move dojo.loadInit applications to loadInitApplications string. Copy all other applications
			// to otherApplications string. If no applications were found, return 0, signalling an AMD module. Otherwise, return
			// loadInitApplications + otherApplications. Fixup text by replacing
			//
			//	 dojo.loadInit(// etc...
			//
			// with
			//
			//	 \n 0 && dojo.loadInit(// etc...
			//
			// Which results in the dojo.loadInit from *not* being applied. This design goes a long way towards protecting the
			// code from an over-agressive removeCommentRe. However...
			//
			// WARNING: the removeCommentRe will cause an error if a detected comment removes all or part of a legacy-loader application
			// that is not in a comment.

			var match, startSearch, startApplication, application,
				loadInitApplications = [],
				otherApplications = [],
				allApplications = [];

			// noCommentText may be provided by a build app with comments extracted by a better method than regex (hopefully)
			noCommentText = noCommentText || text.replace(removeCommentRe, function(match){
				// remove iff the detected comment has text that looks like a sync loader API application; this helps by
				// removing as little as possible, minimizing the changes the janky regex will kill the module
				syncLoaderApiRe.lastIndex = amdLoaderApiRe.lastIndex = 0;
				return (syncLoaderApiRe.test(match) || amdLoaderApiRe.test(match)) ? "" : match;
			});

			// find and extract all dojo.loadInit applications
			while((match = syncLoaderApiRe.exec(noCommentText))){
				startSearch = syncLoaderApiRe.lastIndex;
				startApplication = startSearch	- match[0].length;
				application = extractApplication(noCommentText, startSearch, startApplication);
				if(match[2]=="loadInit"){
					loadInitApplications.push(application[0]);
				}else{
					otherApplications.push(application[0]);
				}
				syncLoaderApiRe.lastIndex = application[1];
			}
			allApplications = loadInitApplications.concat(otherApplications);
			if(allApplications.length || !amdLoaderApiRe.test(noCommentText)){
				// either there were some legacy loader API applications or there were no AMD API applications
				return [text.replace(/(^|\s)dojo\.loadInit\s*\(/g, "\n0 && dojo.loadInit("), allApplications.join(""), allApplications];
			}else{
				// legacy loader API *was not* detected and AMD API *was* detected; therefore, assume it's an AMD module
				return 0;
			}
		},

		transformToAmd = function(module, text){
			// This is roughly the equivalent of dojo._xdCreateResource in 1.6-; however, it expresses a v1.6- dojo
			// module in terms of AMD define instead of creating the dojo proprietary xdomain module expression.
			// The module could have originated from several sources:
			//
			//	 * amd require() a module, e.g., require(["my/module"])
			//	 * amd require() a nonmodule, e.g., require(["my/resource.js"')
			//	 * amd define() deps vector (always a module)
			//	 * dojo.require() a module, e.g. dojo.require("my.module")
			//	 * dojo.require() a nonmodule, e.g., dojo.require("my.module", true)
			//	 * dojo.requireIf/requireAfterIf/platformRequire a module
			//
			// The module is scanned for legacy loader API applications; if none are found, then assume the module is an
			// AMD module and return 0. Otherwise, a synthetic dojo/loadInit plugin resource is created and the module text
			// is rewritten as an AMD module with the single dependency of this synthetic resource. When the dojo/loadInit
			// plugin loaded the synthetic resource, it will cause all dojo.loadInit's to be executed, find all dojo.require's
			// (either directly consequent to dojo.require or indirectly consequent to dojo.require[After]If or
			// dojo.platformRequire, and finally cause loading of all dojo.required modules with the dojo/require plugin. Thus,
			// when the dojo/loadInit plugin reports it has been loaded, all modules required by the given module are guaranteed
			// loaded (but not executed). This then allows the module to execute it's code path without interupts, thereby
			// following the synchronous code path.
			//
			// Notice that this function behaves the same whether or not it happens to be in a mapped dojo/loader module.

			var extractResult, id, names = [], namesAsStrings = [];
			if(buildDetectRe.test(text) || !(extractResult = extractLegacyApiApplications(text))){
				// buildDetectRe.test(text) => a built module, always AMD
				// extractResult==0 => no sync API
				return 0;
			}

			// manufacture a synthetic module id that can never be a real mdule id (just like require does)
			id = module.mid + "-*loadInit";

			// construct the dojo/loadInit names vector which causes any relocated names to be defined as lexical variables under their not-relocated name
			// the dojo/loadInit plugin assumes the first name in names is "dojo"

			for(var p in getModule("dojo", module).result.scopeMap){
				names.push(p);
				namesAsStrings.push('"' + p + '"');
			}

			// rewrite the module as a synthetic dojo/loadInit plugin resource + the module expressed as an AMD module that depends on this synthetic resource
			// don't have to map dojo/init since that will occur when the dependency is resolved
			return "// xdomain rewrite of " + module.mid + "\n" +
				"define('" + id + "',{\n" +
				"\tnames:" + json.stringify(names) + ",\n" +
				"\tdef:function(" + names.join(",") + "){" + extractResult[1] + "}" +
				"});\n\n" +
				"define(" + json.stringify(names.concat(["dojo/loadInit!"+id])) + ", function(" + names.join(",") + "){\n" + extractResult[0] + "});";
		},

		loaderVars = require.initSyncLoader(dojoRequirePlugin, checkDojoRequirePlugin, transformToAmd),

		sync =
			loaderVars.sync,

		requested =
			loaderVars.requested,

		arrived =
			loaderVars.arrived,

		nonmodule =
			loaderVars.nonmodule,

		executing =
			loaderVars.executing,

		executed =
			loaderVars.executed,

		syncExecStack =
			loaderVars.syncExecStack,

		modules =
			loaderVars.modules,

		execQ =
			loaderVars.execQ,

		getModule =
			loaderVars.getModule,

		injectModule =
			loaderVars.injectModule,

		setArrived =
			loaderVars.setArrived,

		signal =
			loaderVars.signal,

		finishExec =
			loaderVars.finishExec,

		execModule =
			loaderVars.execModule,

		getLegacyMode =
			loaderVars.getLegacyMode,

		guardCheckComplete =
			loaderVars.guardCheckComplete;

	// there is exactly one dojoRequirePlugin among possibly-many dojo/_base/loader's (owing to mapping)
	dojoRequirePlugin = loaderVars.dojoRequirePlugin;

	dojo.provide = function(mid){
		var executingModule = syncExecStack[0],
			module = lang.mixin(getModule(slashName(mid), require.module), {
				executed:executing,
				result:lang.getObject(mid, true)
			});
		setArrived(module);
		if(executingModule){
			(executingModule.provides || (executingModule.provides = [])).push(function(){
				module.result = lang.getObject(mid);
				delete module.provides;
				module.executed!==executed && finishExec(module);
			});
		}// else dojo.provide called not consequent to loading; therefore, give up trying to publish module value to loader namespace
		return module.result;
	};

	has.add("config-publishRequireResult", 1, 0, 0);

	dojo.require = function(moduleName, omitModuleCheck) {
		// summary:
		//		loads a Javascript module from the appropriate URI
		//
		// moduleName: String
		//		module name to load, using periods for separators,
		//		 e.g. "dojo.date.locale".  Module paths are de-referenced by dojo's
		//		internal mapping of locations to names and are disambiguated by
		//		longest prefix. See `dojo.registerModulePath()` for details on
		//		registering new modules.
		//
		// omitModuleCheck: Boolean?
		//		if `true`, omitModuleCheck skips the step of ensuring that the
		//		loaded file actually defines the symbol it is referenced by.
		//		For example if it called as `dojo.require("a.b.c")` and the
		//		file located at `a/b/c.js` does not define an object `a.b.c`,
		//		and exception will be throws whereas no exception is raised
		//		when called as `dojo.require("a.b.c", true)`
		//
		// description:
		//		Modules are loaded via dojo.require by using one of two loaders: the normal loader
		//		and the xdomain loader. The xdomain loader is used when dojo was built with a
		//		custom build that specified loader=xdomain and the module lives on a modulePath
		//		that is a whole URL, with protocol and a domain. The versions of Dojo that are on
		//		the Google and AOL CDNs use the xdomain loader.
		//
		//		If the module is loaded via the xdomain loader, it is an asynchronous load, since
		//		the module is added via a dynamically created script tag. This
		//		means that dojo.require() can return before the module has loaded. However, this
		//		should only happen in the case where you do dojo.require calls in the top-level
		//		HTML page, or if you purposely avoid the loader checking for dojo.require
		//		dependencies in your module by using a syntax like dojo["require"] to load the module.
		//
		//		Sometimes it is useful to not have the loader detect the dojo.require calls in the
		//		module so that you can dynamically load the modules as a result of an action on the
		//		page, instead of right at module load time.
		//
		//		Also, for script blocks in an HTML page, the loader does not pre-process them, so
		//		it does not know to download the modules before the dojo.require calls occur.
		//
		//		So, in those two cases, when you want on-the-fly module loading or for script blocks
		//		in the HTML page, special care must be taken if the dojo.required code is loaded
		//		asynchronously. To make sure you can execute code that depends on the dojo.required
		//		modules, be sure to add the code that depends on the modules in a dojo.addOnLoad()
		//		callback. dojo.addOnLoad waits for all outstanding modules to finish loading before
		//		executing.
		//
		//		This type of syntax works with both xdomain and normal loaders, so it is good
		//		practice to always use this idiom for on-the-fly code loading and in HTML script
		//		blocks. If at some point you change loaders and where the code is loaded from,
		//		it will all still work.
		//
		//		More on how dojo.require
		//		`dojo.require("A.B")` first checks to see if symbol A.B is
		//		defined. If it is, it is simply returned (nothing to do).
		//
		//		If it is not defined, it will look for `A/B.js` in the script root
		//		directory.
		//
		//		`dojo.require` throws an exception if it cannot find a file
		//		to load, or if the symbol `A.B` is not defined after loading.
		//
		//		It returns the object `A.B`, but note the caveats above about on-the-fly loading and
		//		HTML script blocks when the xdomain loader is loading a module.
		//
		//		`dojo.require()` does nothing about importing symbols into
		//		the current namespace.	It is presumed that the caller will
		//		take care of that.
		//
		// example:
		//		To use dojo.require in conjunction with dojo.ready:
		//
		//		|	dojo.require("foo");
		//		|	dojo.require("bar");
		//		|	dojo.addOnLoad(function(){
		//		|		//you can now safely do something with foo and bar
		//		|	});
		//
		// example:
		//		For example, to import all symbols into a local block, you might write:
		//
		//		|	with (dojo.require("A.B")) {
		//		|		...
		//		|	}
		//
		//		And to import just the leaf symbol to a local variable:
		//
		//		|	var B = dojo.require("A.B");
		//		|	...
		//
		// returns:
		//		the required namespace object
		function doRequire(mid, omitModuleCheck){
			var module = getModule(slashName(mid), require.module);
			if(syncExecStack.length && syncExecStack[0].finish){
				// switched to async loading in the middle of evaluating a legacy module; stop
				// applying dojo.require so the remaining dojo.requires are applied in order
				syncExecStack[0].finish.push(mid);
				return undefined;
			}

			// recall module.executed has values {0, executing, executed}; therefore, truthy indicates executing or executed
			if(module.executed){
				return module.result;
			}
			omitModuleCheck && (module.result = nonmodule);

			// rcg...why here and in two lines??
			var currentMode = getLegacyMode();

			// recall, in sync mode to inject is to *eval* the module text
			// if the module is a legacy module, this is the same as executing
			// but if the module is an AMD module, this means defining, not executing
			injectModule(module);
			// the inject may have changed the mode
			currentMode = getLegacyMode();

			// in sync mode to dojo.require is to execute
			if(module.executed!==executed && module.injected===arrived){
				// the module was already here before injectModule was called probably finishing up a xdomain
				// load, but maybe a module given to the loader directly rather than having the loader retrieve it

				loaderVars.guardCheckComplete(function(){
					execModule(module);
				});
			}
			if(module.executed){
				return module.result;
			}

			if(currentMode==sync){
				// the only way to get here is in sync mode and dojo.required a module that
				//	 * was loaded async in the injectModule application a few lines up
				//	 * was an AMD module that had deps that are being loaded async and therefore couldn't execute
				if(module.cjs){
					// the module was an AMD module; unshift, not push, which causes the current traversal to be reattempted from the top
					execQ.unshift(module);
				}else{
					// the module was a legacy module
					syncExecStack.length && (syncExecStack[0].finish= [mid]);
				}
			}else{
				// the loader wasn't in sync mode on entry; probably async mode; therefore, no expectation of getting
				// the module value synchronously; make sure it gets executed though
				execQ.push(module);
			}

			return undefined;
		}

		var result = doRequire(moduleName, omitModuleCheck);
		if(has("config-publishRequireResult") && !lang.exists(moduleName) && result!==undefined){
			lang.setObject(moduleName, result);
		}
		return result;
	};

	dojo.loadInit = function(f) {
		f();
	};

	dojo.registerModulePath = function(/*String*/moduleName, /*String*/prefix){
		// summary:
		//		Maps a module name to a path
		// description:
		//		An unregistered module is given the default path of ../[module],
		//		relative to Dojo root. For example, module acme is mapped to
		//		../acme.  If you want to use a different module name, use
		//		dojo.registerModulePath.
		// example:
		//		If your dojo.js is located at this location in the web root:
		//	|	/myapp/js/dojo/dojo/dojo.js
		//		and your modules are located at:
		//	|	/myapp/js/foo/bar.js
		//	|	/myapp/js/foo/baz.js
		//	|	/myapp/js/foo/thud/xyzzy.js
		//		Your application can tell Dojo to locate the "foo" namespace by calling:
		//	|	dojo.registerModulePath("foo", "../../foo");
		//		At which point you can then use dojo.require() to load the
		//		modules (assuming they provide() the same things which are
		//		required). The full code might be:
		//	|	<script type="text/javascript"
		//	|		src="/myapp/js/dojo/dojo/dojo.js"></script>
		//	|	<script type="text/javascript">
		//	|		dojo.registerModulePath("foo", "../../foo");
		//	|		dojo.require("foo.bar");
		//	|		dojo.require("foo.baz");
		//	|		dojo.require("foo.thud.xyzzy");
		//	|	</script>

		var paths = {};
		paths[moduleName.replace(/\./g, "/")] = prefix;
		require({paths:paths});
	};

	dojo.platformRequire = function(/*Object*/modMap){
		// summary:
		//		require one or more modules based on which host environment
		//		Dojo is currently operating in
		// description:
		//		This method takes a "map" of arrays which one can use to
		//		optionally load dojo modules. The map is indexed by the
		//		possible dojo.name_ values, with two additional values:
		//		"default" and "common". The items in the "default" array will
		//		be loaded if none of the other items have been choosen based on
		//		dojo.name_, set by your host environment. The items in the
		//		"common" array will *always* be loaded, regardless of which
		//		list is chosen.
		// example:
		//		|	dojo.platformRequire({
		//		|		browser: [
		//		|			"foo.sample", // simple module
		//		|			"foo.test",
		//		|			["foo.bar.baz", true] // skip object check in _loadModule (dojo.require)
		//		|		],
		//		|		default: [ "foo.sample._base" ],
		//		|		common: [ "important.module.common" ]
		//		|	});

		var result = (modMap.common || []).concat(modMap[dojo._name] || modMap["default"] || []),
			temp;
		while(result.length){
			if(lang.isArray(temp = result.shift())){
				dojo.require.apply(dojo, temp);
			}else{
				dojo.require(temp);
			}
		}
	};

	dojo.requireIf = dojo.requireAfterIf = function(/*Boolean*/ condition, /*String*/ moduleName, /*Boolean?*/omitModuleCheck){
		// summary:
		//		If the condition is true then call `dojo.require()` for the specified
		//		resource
		//
		// example:
		//	|	dojo.requireIf(dojo.isBrowser, "my.special.Module");

		if(condition){
			dojo.require(moduleName, omitModuleCheck);
		}
	};

	dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale){
		require(["../i18n"], function(i18n){
			i18n.getLocalization(moduleName, bundleName, locale);
		});
	};

	return {
		// summary:
		//		This module defines the v1.x synchronous loader API.

		extractLegacyApiApplications:extractLegacyApiApplications,
		require:dojoRequirePlugin,
		loadInit:dojoLoadInitPlugin
	};
});