void ReportException(TryCatch &try_catch, bool show_line, std::string& err_msg) {
  HandleScope scope;

  if (show_line) DisplayExceptionLine(try_catch, err_msg);

  String::Utf8Value trace(try_catch.StackTrace());

  // range errors have a trace member set to undefined
  if (trace.length() > 0 && !try_catch.StackTrace()->IsUndefined()) {
    fprintf(stderr, "%s\n", *trace);
    err_msg +=  *trace;
    err_msg +=  "\n";
  } else {
    // this really only happens for RangeErrors, since they're the only
    // kind that won't have all this info in the trace, or when non-Error
    // objects are thrown manually.
    Local<Value> er = try_catch.Exception();
    bool isErrorObject = er->IsObject() &&
      !(er->ToObject()->Get(String::New("message"))->IsUndefined()) &&
      !(er->ToObject()->Get(String::New("name"))->IsUndefined());

    if (isErrorObject) {
      String::Utf8Value name(er->ToObject()->Get(String::New("name")));
      fprintf(stderr, "%s: ", *name);
      err_msg += *name;
      err_msg += ": ";
    }

    String::Utf8Value msg(!isErrorObject ? er
                         : er->ToObject()->Get(String::New("message")));
    fprintf(stderr, "%s\n", *msg);
    err_msg += *msg;
    err_msg += "\n";
  }

  fflush(stderr);
}
Handle<Value> TiTitaniumObject::_globalInclude(void*, TiObject*, const Arguments& args)
{
	if (args.Length() < 2)
	{
		return ThrowException(String::New(Ti::Msg::Missing_argument));
	}

	string id = *String::Utf8Value(args[0]->ToString());

	string parentFolder = *String::Utf8Value(args[1]->ToString());

	// CommonJS path rules
	if (id.find("/") == 0) {
		id.replace(id.find("/"), std::string("/").length(), rootFolder);
	}
	else if (id.find("./") == 0) {
		id.replace(id.find("./"), std::string("./").length(), parentFolder);
	}
	else if (id.find("../") == 0) {
		// count ../../../ in id and strip off back of parentFolder
		int count = 0;
		size_t idx = 0;
		size_t pos = 0;
		while (true) {
			idx = id.find("../", pos);
			if (idx == std::string::npos) {
				break;
			} else {
				pos = idx + 3;
				count++;
			}
		}

		// strip leading ../../ off module id
		id = id.substr(pos);

		// strip paths off the parent folder
		idx = 0;
		pos = parentFolder.size();
		for (int i = 0; i < count; i++) {
			idx = parentFolder.find_last_of("/", pos);
			pos = idx - 1;
		}

		if (idx == std::string::npos) {
			return ThrowException(String::New("Unable to find module"));
		}

		parentFolder = parentFolder.substr(0, idx + 1);

		id = parentFolder + id;
	}
	else {
		string tempId = rootFolder + id;

		ifstream ifs((tempId).c_str());
		if (!ifs) {
			id = parentFolder + id;
		}
		else {
			id = rootFolder + id;
		}
	}

	string filename = id;

	string javascript;
	{
		ifstream ifs((filename).c_str());
		if (!ifs)
		{
			Local<Value> taggedMessage = String::New((string(Ti::Msg::No_such_native_module) + " " + id).c_str());
			return ThrowException(taggedMessage);
		}
		getline(ifs, javascript, string::traits_type::to_char_type(string::traits_type::eof()));
		ifs.close();
	}

	// wrap the module
	{
		size_t idx = filename.find_last_of("/");
		parentFolder = filename.substr(0, idx + 1);
		static const string preWrap = "Ti.include = function (id) { Ti.globalInclude(id, '" + parentFolder + "')};\n";
		javascript = preWrap + javascript;
	}

	TryCatch tryCatch;
	Handle<Script> compiledScript = Script::Compile(String::New(javascript.c_str()), String::New(filename.c_str()));
	if (compiledScript.IsEmpty())
	{
		DisplayExceptionLine(tryCatch);
		return tryCatch.ReThrow();
	}

	Persistent<Value> result = Persistent<Value>::New(compiledScript->Run());
	if (result.IsEmpty())
	{
		return tryCatch.ReThrow();
	}


    return Undefined();
}
Handle<Value> TiRootObject::_globalRequire(void*, TiObject*, const Arguments& args)
{
	if (args.Length() < 2)
	{
		return ThrowException(String::New(Ti::Msg::Missing_argument));
	}

	string id = *String::Utf8Value(args[0]->ToString());

	string parentFolder = *String::Utf8Value(args[1]->ToString());

	// CommonJS path rules
	if (id.find("/") == 0) {
		id.replace(id.find("/"), std::string("/").length(), rootFolder);
	}
	else if (id.find("./") == 0) {
		id.replace(id.find("./"), std::string("./").length(), parentFolder);
	}
	else if (id.find("../") == 0) {
		// count ../../../ in id and strip off back of parentFolder
		int count = 0;
		size_t idx = 0;
		size_t pos = 0;
		while (true) {
			idx = id.find("../", pos);
			if (idx == std::string::npos) {
				break;
			} else {
				pos = idx + 3;
				count++;
			}
		}

		// strip leading ../../ off module id
		id = id.substr(pos);

		// strip paths off the parent folder
		idx = 0;
		pos = parentFolder.size();
		for (int i = 0; i < count; i++) {
			idx = parentFolder.find_last_of("/", pos);
			pos = idx - 1;
		}

		if (idx == std::string::npos) {
			return ThrowException(String::New("Unable to find module"));
		}

		parentFolder = parentFolder.substr(0, idx + 1);

		id = parentFolder + id;
	}
	else {
		string tempId = rootFolder + id;

		ifstream ifs((tempId + ".js").c_str());
		if (!ifs) {
			id = parentFolder + id;
		}
		else {
			id = rootFolder + id;
		}
	}

	string filename = id + ".js";

	// check if cached
	static map<string, Persistent<Value> > cache;
	map<string, Persistent<Value> >::const_iterator cachedValue = cache.find(id);
	if (cachedValue != cache.end())
	{
		return cachedValue->second;
	}

	string javascript;
	{
		ifstream ifs((filename).c_str());
		if (!ifs)
		{
			Local<Value> taggedMessage = String::New((string(Ti::Msg::No_such_native_module) + " " + id).c_str());
			return ThrowException(taggedMessage);
		}
		getline(ifs, javascript, string::traits_type::to_char_type(string::traits_type::eof()));
		ifs.close();
	}

	// wrap the module
	{
		size_t idx = filename.find_last_of("/");
		parentFolder = filename.substr(0, idx + 1);
		static const string requireWithParent = "var require = function (id) { return globalRequire(id, '" + parentFolder + "')};\n";
		static const string preWrap = "(function () {" + requireWithParent + "\nvar module = { exports: {} }; var exports = module.exports;\n";
		static const string postWrap = "\nreturn module.exports; })();";
		javascript =  preWrap + javascript + postWrap;
	}

	TryCatch tryCatch;
	Handle<Script> compiledScript = Script::Compile(String::New(javascript.c_str()), String::New(filename.c_str()));
	if (compiledScript.IsEmpty())
	{
		DisplayExceptionLine(tryCatch);
		return tryCatch.ReThrow();
	}

	Persistent<Value> result = Persistent<Value>::New(compiledScript->Run());
	if (result.IsEmpty())
	{
		return tryCatch.ReThrow();
	}

	// cache result
	cache.insert(pair<string, Persistent<Value> >(id, result));

	return result;
}