_.mixin({
    isPlainObject: function (obj) {

        var plainObject = {};

        // Not plain objects:
        // - Any object or value whose internal [[Class]] property is not "[object Object]"
        // - DOM nodes
        if (!_.isObject(obj) || obj.nodeType) {
            return false;
        }

        if (obj.constructor &&
				!plainObject.hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) {
            return false;
        }
        //.hasOwnProperty
        return true;

    }
});


_.mixin({
    deepExtend: function () {

        var options, name, src, copy, copyIsArray, clone,
            target = arguments[ 0 ] || {},
            i = 1,
            length = arguments.length,
            deep = false;

        // Handle a deep copy situation
        if ( typeof target === "boolean" ) {
            deep = target;

            // Skip the boolean and the target
            target = arguments[ i ] || {};
            i++;
        }

        // Handle case when target is a string or something (possible in deep copy)
        if ( typeof target !== "object" && !_.isFunction( target ) ) {
            target = {};
        }

        // Extend jQuery itself if only one argument is passed
        if ( i === length ) {
            target = this;
            i--;
        }

        for ( ; i < length; i++ ) {

            // Only deal with non-null/undefined values
            if ( ( options = arguments[ i ] ) != null ) {

                // Extend the base object
                for ( name in options ) {
                    src = target[ name ];
                    copy = options[ name ];

                    // Prevent never-ending loop
                    if ( target === copy ) {
                        continue;
                    }

                    // Recurse if we're merging plain objects or arrays
                    if ( deep && copy && ( _.isPlainObject( copy ) ||
                        ( copyIsArray = _.isArray( copy ) ) ) ) {

                        if ( copyIsArray ) {
                            copyIsArray = false;
                            clone = src && _.isArray( src ) ? src : [];

                        } else {
                            clone = src && _.isPlainObject( src ) ? src : {};
                        }

                        // Never move original objects, clone them
                        target[name] = _.deepExtend(clone, copy);

                        // Don't bring in undefined values
                    } else if ( copy !== undefined ) {
                        target[ name ] = copy;
                    }
                }
            }
        }

        // Return the modified object
        return target;
    }
});


_.mixin({

    extrude: function (src, path) {

        var success = false,
            target = src,
            targetPropName = null,
            items = path.split("."),
            lastIndex = items.length - 1;

        _.each(items, function (item, index) {
            if (target != null && target[item] != undefined) {
                if (index === lastIndex) {
                    success = true;
                    targetPropName = item;
                }
                else {
                    target = target[item];
                }
            }
            else {
                target = null;
            }
        });

        return {
            get: function (value) {

                var result = undefined;

                if (success) {
                    result = target[targetPropName]; 
                }

                if (result == undefined) {
                    result = value;
                }

                return result;

            },
            set: function (value) {

                if (success) {
                    target[targetPropName] = value;
                }

            }
        };

    },

    extract: function (target, path, defaultValue) {
        return _.extrude(target, path).get(defaultValue);
    }

});