/// <summary>
		/// recursively looks for all folders containing '-dir.info' file, which describe kind of special folder. 
		/// "dlls" folders - added to dll search path.
		/// </summary>
		/// <param name="di">directory where scan will be done</param>
		public static void ScanSpecialFolders(DirectoryInfo di) {
			var fi = di.GetFiles(BootstrapperDirInfo.fileName).FirstOrDefault();
			if (fi != null) {
				try {
					using (var fs = fi.OpenRead()) {
						using (var xr = new XmlTextReader(fs)) {
							var dirInfo = xr.Deserialize<BootstrapperDirInfo>();
							if (dirInfo.type == "dlls") {
								if (!Utils.SetDllDirectory(di.FullName)) {
									log.WriteError(String.Format("failed to set dll search path '{0}'", di.FullName));
								}
							}
						}
					}
				} catch (Exception err) {
					log.WriteError(String.Format("failed to deserialize dir.info file with error:{0}", err.Message));
					dbg.Break();
				}
			}
			foreach (var sdi in di.GetDirectories()) {
				ScanSpecialFolders(sdi);
			}
		}
		public static IEnumerable<SpecialFolderDescription> EnumSpecialFolders(DirectoryInfo di) {
			var fi = di.GetFiles(BootstrapperDirInfo.fileName).FirstOrDefault();
			if (fi != null) {
				SpecialFolderDescription sfd = null;
				try {
					using (var fs = fi.OpenRead()) {
						using (var xr = new XmlTextReader(fs)) {
							var dirInfo = xr.Deserialize<BootstrapperDirInfo>();
							sfd = new SpecialFolderDescription { info = dirInfo, directory = di };
						}
					}
				} catch (Exception err) {
					log.WriteError(String.Format("failed to deserialize dir.info file with error:{0}", err.Message));
					dbg.Break();
				}
				if (sfd != null) {
					yield return sfd;
				}
			}
			foreach (var sdi in di.GetDirectories()) {
				foreach (var sfd in EnumSpecialFolders(sdi)) {
					yield return sfd;
				}
			}
		}