/// <summary>
        /// Finds all assets in the project with the specified component type in their hierarchies.
        /// </summary>
        /// <param name="components">
        /// For each asset in the project where <typeparamref name="T"/> were found, all <typeparamref name="T"> found
        /// in the asset's hierarchy as well as its path.
        /// </param>
        /// <typeparam name="T">A <see cref="UnityEngine.Component"/> type.</typeparam>
        public static void FindAllAssetsWithComponent <T>(ref Dictionary <List <T>, string> components) where T : Component
        {
            Dictionary <List <T>, string>    internalComponents = new Dictionary <List <T>, string>();
            Dictionary <GameObject, string>  gameObjects        = new Dictionary <GameObject, string>();
            AssetMatchPredicate <GameObject> hasComponents      = delegate(GameObject asset, string assetPath)
            {
                if (asset == null)
                {
                    return(false);
                }
                List <T> comps = new List <T>();
                asset.GetComponentsInChildren(true, comps);
                if (comps.Count > 0)
                {
                    internalComponents.Add(comps, assetPath);
                    return(true);
                }
                return(false);
            };

            FindAllAssets(gameObjects, hasComponents);
            components = components ?? new Dictionary <List <T>, string>();
            components.Clear();
            foreach (KeyValuePair <List <T>, string> kv in internalComponents)
            {
                components.Add(kv.Key, kv.Value);
            }
        }
        /// <summary>
        /// Performs the specified modification on all assets in the project of the specified type.
        /// </summary>
        /// <param name="onModifyAsset">The callback to invoke for each asset found.</param>
        /// <param name="undoMessage">Optional undo message to use.</param>
        /// <param name="isMatch">Optional predicate to determine whether the found asset should be included.</param>
        /// <typeparam name="T">A <see cref="UnityEngine.Object"/> type.</typeparam>
        public static void ModifyAllAssetsInProject <T>(
            ModifyAssetCallback <T> onModifyAsset, string undoMessage = null, AssetMatchPredicate <T> isMatch = null
            ) where T : Object
        {
            Dictionary <T, string> assets = null;

            FindAllAssets(assets, isMatch);
            ModifyAllAssetsInProject(assets, onModifyAsset, undoMessage);
        }
        /// <summary>
        /// Finds all assets in the project of the specified type.
        /// </summary>
        /// <param name="assets">The asset and its path for each match found in the project.</param>
        /// <param name="isMatch">Optional predicate to determine whether the found asset should be included.</param>
        /// <typeparam name="T">A <see cref="UnityEngine.Object"/> type.</typeparam>
        public static void FindAllAssets <T>(Dictionary <T, string> assets, AssetMatchPredicate <T> isMatch = null)
            where T : Object
        {
            assets.Clear();
            AssetDatabase.SaveAssets();
            bool hasMatchPredicate = isMatch != null;

            foreach (string guid in AssetDatabase.FindAssets(string.Format("t:{0}", typeof(T).Name)))
            {
                string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                T      asset     = AssetDatabase.LoadAssetAtPath(assetPath, typeof(T)) as T;
                if (asset != null && (!hasMatchPredicate || isMatch(asset, assetPath)))
                {
                    assets.Add(asset, assetPath);
                }
            }
        }