public override object CallLateBound(object thisObject, params object[] argumentValues)
            {
                var target  = argumentValues.Length >= 1 ? argumentValues[0] : this.Engine.Object.Construct();
                var source  = argumentValues.Length >= 2 ? argumentValues[1] : null;
                var deep    = argumentValues.Length >= 3 && TypeConverter.ToBoolean(argumentValues[2]);
                var resolve = argumentValues.Length >= 4 ? argumentValues[3] : true;

                if (target == null || target == Null.Value || target == Undefined.Value)
                {
                    target = this.Engine.Object.Construct();
                }

                if (TypeConverter.ToBoolean(target) && TypeUtilities.IsString(source) == false && source != null && source != Null.Value && source != Undefined.Value)
                {
                    var sourceObj = TypeConverter.ToObject(this.Engine, source);
                    var targetObj = TypeConverter.ToObject(this.Engine, target);

                    foreach (var kvp in sourceObj.Properties)
                    {
                        if (!ObjectInstance.HasOwnProperty(this.Engine, source, kvp.Name) || !TypeConverter.ToBoolean(target))
                        {
                            continue;
                        }

                        var val = kvp.Value;

                        var goDeep = deep && JurassicHelper.IsObjectType(val);

                        //Conflict!
                        if (targetObj.HasProperty(kvp.Name) && targetObj[kvp.Name] != Undefined.Value && (target is ArrayInstance) == false)
                        {
                            //Do not merge.
                            if (TypeConverter.ToBoolean(resolve) == false && !goDeep)
                            {
                                continue;
                            }

                            //if the source value is null, and the target is null, don't set the value
                            //if this isn't here string properties will get set to string 'null'
                            var targetValue = targetObj[kvp.Name];
                            if ((targetValue == null || targetValue == Null.Value) && (val == null || val == Null.Value))
                            {
                                continue;
                            }

                            // Use the result of the callback as the result.
                            if (resolve is FunctionInstance)
                            {
                                val = (resolve as FunctionInstance).Call(source, kvp.Name, targetObj[kvp.Name], sourceObj[kvp.Name]);

                                //Hack to fix issue with a resolve function returning a double, when the source type is an int.
                                if (sourceObj[kvp.Name].GetType() != val.GetType())
                                {
                                    val = TypeConverter.ConvertTo(this.Engine, val, sourceObj[kvp.Name].GetType());
                                }
                            }
                            else if (TypeConverter.ToBoolean(resolve))
                            {
                                val = kvp.Value;
                            }
                        }

                        // Deep merging.
                        if (goDeep)
                        {
                            if (val is DateInstance)
                            {
                                val = this.Engine.Date.Construct((val as DateInstance).GetTime());
                            }
                            else if (val is RegExpInstance)
                            {
                                val = this.Engine.RegExp.Construct((val as RegExpInstance).Source, (val as RegExpInstance).Flags);
                            }
                            else
                            {
                                if (!TypeConverter.ToBoolean(targetObj[kvp.Name]))
                                {
                                    if (val is ArrayInstance)
                                    {
                                        targetObj[kvp.Name] = this.Engine.Array.Construct();
                                    }
                                    else
                                    {
                                        targetObj[kvp.Name] = this.Engine.Object.Construct();
                                    }
                                }

                                CallLateBound(thisObject, targetObj[kvp.Name], sourceObj[kvp.Name], deep, resolve);
                                continue;
                            }
                        }

                        if (target is ArrayInstance && kvp.Name == "length")
                        {
                            continue;
                        }

                        targetObj.SetPropertyValue(kvp.Name, val, false);
                    }

                    target = targetObj;
                }

                return(target);
            }