internal void Initialize(SystemPackageInfo info, IEnumerable <SystemAssembly> assemblies, bool isInternal) { this.isInternal = isInternal; this.name = info.Name ?? string.Empty; this.version = info.Version ?? string.Empty; this.description = info.Description ?? string.Empty; this.targetFramework = info.TargetFramework; this.gacRoot = info.GacRoot; this.gacPackage = info.IsGacPackage; IsFrameworkPackage = info.IsFrameworkPackage; IsCorePackage = info.IsCorePackage; this.Requires = info.Requires; SystemAssembly last = null; foreach (SystemAssembly asm in assemblies) { if (asm == null) { continue; } asm.Package = this; if (this.assemblies == null) { this.assemblies = asm; } else { last.NextSamePackage = asm; } last = asm; } }
/// <summary> /// Executes an assembly using this runtime and the specified framework. /// </summary> /// <param name="pinfo"> /// Information of the process to execute /// </param> /// <param name="fx"> /// Framework on which the assembly has to be executed. /// </param> /// <returns> /// The started process. /// </returns> public virtual Process ExecuteAssembly(ProcessStartInfo pinfo, TargetFramework fx) { if (fx == null) { TargetFrameworkMoniker fxId = Runtime.SystemAssemblyService.GetTargetFrameworkForAssembly(this, pinfo.FileName); fx = Runtime.SystemAssemblyService.GetTargetFramework(fxId); if (!IsInstalled(fx)) { // Look for a compatible framework which is installed foreach (TargetFramework f in Runtime.SystemAssemblyService.GetTargetFrameworks()) { if (IsInstalled(f) && f.IsCompatibleWithFramework(fx.Id)) { fx = f; break; } } } if (!IsInstalled(fx)) { throw new InvalidOperationException(string.Format("No compatible framework found for assembly '{0}' (required framework: {1})", pinfo.FileName, fxId)); } } ConvertAssemblyProcessStartInfo(pinfo); return(Process.Start(pinfo)); }
string GetOldMcsName(TargetFrameworkMoniker fx) { //old compilers for specific frameworks switch (fx.Identifier) { case TargetFrameworkMoniker.ID_NET_FRAMEWORK: { switch (fx.Version) { case "1.1": return("mcs"); case "2.0": case "3.0": case "3.5": return("gmcs"); case "4.0": return("dmcs"); } } break; case TargetFrameworkMoniker.ID_MONODROID: case TargetFrameworkMoniker.ID_MONOTOUCH: case TargetFrameworkMoniker.ID_SILVERLIGHT: return("smcs"); } return("mcs"); }
protected static IEnumerable <TargetFramework> FindTargetFrameworks(FilePath frameworksDirectory) { foreach (FilePath idDir in Directory.GetDirectories(frameworksDirectory)) { var id = idDir.FileName; foreach (FilePath versionDir in Directory.GetDirectories(idDir)) { var version = versionDir.FileName; var moniker = new TargetFrameworkMoniker(id, version); var fx = ReadTargetFramework(moniker, versionDir); if (fx != null) { yield return(fx); } var profileListDir = versionDir.Combine("Profile"); if (!Directory.Exists(profileListDir)) { continue; } foreach (FilePath profileDir in Directory.GetDirectories(profileListDir)) { var profile = profileDir.FileName; moniker = new TargetFrameworkMoniker(id, version, profile); fx = ReadTargetFramework(moniker, profileDir); if (fx != null) { yield return(fx); } } } } }
//FIXME: the fallback is broken since multiple frameworks can have the same corlib public TargetFrameworkMoniker GetTargetFrameworkForAssembly(TargetRuntime tr, string file) { if (!File.Exists(file)) { return(TargetFrameworkMoniker.UNKNOWN); } var universe = CreateClosedUniverse(); try { IKVM.Reflection.Assembly assembly = universe.LoadFile(file); var att = assembly.CustomAttributes.FirstOrDefault(a => a.AttributeType.FullName == "System.Runtime.Versioning.TargetFrameworkAttribute" ); if (att != null) { if (att.ConstructorArguments.Count == 1) { var v = att.ConstructorArguments[0].Value as string; TargetFrameworkMoniker m; if (v != null && TargetFrameworkMoniker.TryParse(v, out m)) { return(m); } } LoggingService.LogError("Invalid TargetFrameworkAttribute in assembly {0}", file); } foreach (var r in assembly.GetReferencedAssemblies()) { if (r.Name == "mscorlib") { TargetFramework compatibleFramework = null; // If there are several frameworks that can run the file, pick one that is installed foreach (TargetFramework tf in GetKnownFrameworks()) { if (tf.GetCorlibVersion() == r.Version.ToString()) { compatibleFramework = tf; if (tr.IsInstalled(tf)) { return(tf.Id); } } } if (compatibleFramework != null) { return(compatibleFramework.Id); } break; } } } catch (Exception ex) { LoggingService.LogError("Error determining target framework for assembly {0}: {1}", file, ex); return(TargetFrameworkMoniker.UNKNOWN); } finally { universe.Dispose(); } LoggingService.LogError("Failed to determine target framework for assembly {0}", file); return(TargetFrameworkMoniker.UNKNOWN); }
/// <summary> /// Executes an assembly using this runtime and the specified framework. /// </summary> /// <param name="pinfo"> /// Information of the process to execute /// </param> /// <param name="fx"> /// Framework on which the assembly has to be executed. /// </param> /// <returns> /// The started process. /// </returns> public virtual Process ExecuteAssembly(ProcessStartInfo pinfo, TargetFramework fx) { if (fx == null) { TargetFrameworkMoniker fxId = Runtime.SystemAssemblyService.GetTargetFrameworkForAssembly(this, pinfo.FileName); fx = Runtime.SystemAssemblyService.GetTargetFramework(fxId); if (!IsInstalled(fx)) { // Look for a compatible framework which is installed foreach (TargetFramework f in Runtime.SystemAssemblyService.GetTargetFrameworks()) { if (IsInstalled(f) && f.IsCompatibleWithFramework(fx.Id)) { fx = f; break; } } } if (!IsInstalled(fx)) { throw new InvalidOperationException(string.Format("No compatible framework found for assembly '{0}' (required framework: {1})", pinfo.FileName, fxId)); } } // Make a copy of the ProcessStartInfo because we are going to modify it ProcessStartInfo cp = new ProcessStartInfo(); cp.Arguments = pinfo.Arguments; cp.CreateNoWindow = pinfo.CreateNoWindow; cp.Domain = pinfo.Domain; cp.ErrorDialog = pinfo.ErrorDialog; cp.ErrorDialogParentHandle = pinfo.ErrorDialogParentHandle; cp.FileName = pinfo.FileName; cp.LoadUserProfile = pinfo.LoadUserProfile; cp.Password = pinfo.Password; cp.UseShellExecute = pinfo.UseShellExecute; cp.RedirectStandardError = pinfo.RedirectStandardError; cp.RedirectStandardInput = pinfo.RedirectStandardInput; cp.RedirectStandardOutput = pinfo.RedirectStandardOutput; cp.StandardErrorEncoding = pinfo.StandardErrorEncoding; cp.StandardOutputEncoding = pinfo.StandardOutputEncoding; cp.UserName = pinfo.UserName; cp.Verb = pinfo.Verb; cp.WindowStyle = pinfo.WindowStyle; cp.WorkingDirectory = pinfo.WorkingDirectory; foreach (string key in pinfo.EnvironmentVariables.Keys) { cp.EnvironmentVariables [key] = pinfo.EnvironmentVariables [key]; } // Set the runtime env vars GetToolsExecutionEnvironment(fx).MergeTo(cp); ConvertAssemblyProcessStartInfo(pinfo); return(Process.Start(pinfo)); }
internal TargetFramework(TargetFrameworkMoniker id) { this.id = id; this.name = id.Profile == null ? string.Format("{0} {1}", id.Identifier, id.Version) : string.Format("{0} {1} {2} Profile", id.Identifier, id.Version, id.Profile); Assemblies = new AssemblyInfo [0]; }
public static TargetFramework FromFrameworkDirectory(TargetFrameworkMoniker moniker, FilePath dir) { var fxListFile = dir.Combine("RedistList", "FrameworkList.xml"); var fxListInfo = new FileInfo(fxListFile); if (!fxListInfo.Exists) { return(null); } var fxCacheDir = UserProfile.Current.CacheDir.Combine("FrameworkInfo"); var cacheKey = moniker.Identifier + "_" + moniker.Version; if (!string.IsNullOrEmpty(moniker.Profile)) { cacheKey += "_" + moniker.Profile; } FrameworkInfo fxInfo; var cachedListFile = fxCacheDir.Combine(cacheKey + ".xml"); var cachedListInfo = new FileInfo(cachedListFile); if (cachedListInfo.Exists && cachedListInfo.LastWriteTime == fxListInfo.LastWriteTime) { fxInfo = FrameworkInfo.Load(moniker, cachedListFile); } else { fxInfo = FrameworkInfo.Load(moniker, fxListFile); var supportedFrameworksDir = dir.Combine("SupportedFrameworks"); if (Directory.Exists(supportedFrameworksDir)) { foreach (var sfx in Directory.EnumerateFiles(supportedFrameworksDir)) { fxInfo.SupportedFrameworks.Add(SupportedFramework.Load(sfx)); } } if (fxInfo.Assemblies.Count == 0) { fxInfo.Assemblies = ScanAssemblyDirectory(moniker, fxInfo.TargetFrameworkDirectory); } Directory.CreateDirectory(fxCacheDir); fxInfo.Save(cachedListFile); File.SetLastWriteTime(cachedListFile, fxListInfo.LastWriteTime); } return(new TargetFramework(moniker) { name = fxInfo.Name, includesFramework = fxInfo.IncludeFramework, Assemblies = fxInfo.Assemblies.ToArray(), supportedFrameworks = fxInfo.SupportedFrameworks, FrameworkAssembliesDirectory = fxInfo.TargetFrameworkDirectory }); }
static TargetFramework ReadTargetFramework(TargetFrameworkMoniker moniker, FilePath directory) { try { return(TargetFramework.FromFrameworkDirectory(moniker, directory)); } catch (Exception ex) { LoggingService.LogError("Error reading framework definition '" + directory + "'", ex); } return(null); }
public bool IsCompatibleWithFramework(TargetFrameworkMoniker fxId) { // FIXME: this is a hack which should really be done using the xml definitions for each .NETPortable profile if (fxId.Identifier == ".NETPortable" && fxId.Version == "4.0") { return(HackyCheckForPLPCompatibility(fxId)); } return(fxId.Identifier == this.id.Identifier && new Version(fxId.Version).CompareTo(new Version(this.id.Version)) <= 0); }
internal TargetFramework(TargetFrameworkMoniker id) { Index = FrameworkCount++; this.id = id; this.name = id.Profile == null ? string.Format("{0} {1}", id.Identifier, id.Version) : string.Format("{0} {1} {2} Profile", id.Identifier, id.Version, id.Profile); clrVersion = ClrVersion.Default; Assemblies = new AssemblyInfo[0]; }
public void StoreCustomData(PcFile pcfile, LibraryPackageInfo pinfo) { TargetFramework commonFramework = null; bool inconsistentFrameworks = false; foreach (PackageAssemblyInfo pi in pinfo.Assemblies) { TargetFrameworkMoniker targetFramework = Runtime.SystemAssemblyService.GetTargetFrameworkForAssembly(Runtime.SystemAssemblyService.CurrentRuntime, pi.File); if (commonFramework == null) { commonFramework = Runtime.SystemAssemblyService.GetTargetFramework(targetFramework); if (commonFramework == null) { inconsistentFrameworks = true; } } else if (targetFramework != null) { TargetFramework newfx = Runtime.SystemAssemblyService.GetTargetFramework(targetFramework); if (newfx == null) { inconsistentFrameworks = true; } else { if (newfx.CanReferenceAssembliesTargetingFramework(commonFramework)) { commonFramework = newfx; } else if (!commonFramework.CanReferenceAssembliesTargetingFramework(newfx)) { inconsistentFrameworks = true; } } } if (inconsistentFrameworks) { break; } } if (inconsistentFrameworks) { LoggingService.LogError("Inconsistent target frameworks found in " + pcfile); } if (commonFramework != null) { pinfo.SetData("targetFramework", commonFramework.Id.ToString()); } else { pinfo.SetData("targetFramework", "FxUnknown"); } }
public TargetFramework GetTargetFramework(TargetFrameworkMoniker id) { TargetFramework fx; if (frameworks.TryGetValue(id, out fx)) { return(fx); } LoggingService.LogWarning("Unregistered TargetFramework '{0}' is being requested from SystemAssemblyService", id); UpdateFrameworks(new [] { new TargetFramework(id) }); return(frameworks [id]); }
static TargetFramework GetTargetFramework(TargetFrameworkMoniker id, Dictionary <TargetFrameworkMoniker, TargetFramework> frameworks) { TargetFramework fx; if (frameworks.TryGetValue(id, out fx)) { return(fx); } LoggingService.LogWarning("Unregistered TargetFramework '{0}' is being requested from SystemAssemblyService", id); fx = new TargetFramework(id); frameworks[id] = fx; return(fx); }
bool HackyCheckForPLPCompatibility(TargetFrameworkMoniker fxId) { int profile, this_profile; if (fxId.Profile == null || fxId.Profile.Length < 8 || !int.TryParse(fxId.Profile.Substring(7), out profile)) { return(false); } switch (this.id.Identifier) { case TargetFrameworkMoniker.ID_NET_FRAMEWORK: if (new Version(fxId.Version).CompareTo(new Version(this.id.Version)) > 0) { return(false); } return(profile >= 1 && profile <= 3); // Profile4 does not support .NETFramework case TargetFrameworkMoniker.ID_MONOTOUCH: case TargetFrameworkMoniker.ID_MONODROID: return(profile >= 1 && profile <= 3); case TargetFrameworkMoniker.ID_PORTABLE: if (this.id.Profile == null || this.id.Profile.Length < 8 || !int.TryParse(this.id.Profile.Substring(7), out this_profile)) { return(false); } switch (this_profile) { case 1: return(true); case 2: return(profile == 2); case 3: return(profile == 3); case 4: return(profile == 4); default: return(false); } default: return(false); } }
public TargetFramework GetTargetFramework(TargetFrameworkMoniker id) { foreach (TargetFramework fx in frameworks) { if (fx.Id == id) { return(fx); } } LoggingService.LogWarning("Unregistered TargetFramework '{0}' is being requested from SystemAssemblyService", id); TargetFramework f = new TargetFramework(id); frameworks.Add(f); return(f); }
static string GetClrVersion(TargetFrameworkMoniker id) { if (id.Identifier != TargetFrameworkMoniker.ID_NET_FRAMEWORK) { return(null); } switch (id.Version) { case "2.0": return("v2.0.50727"); // The 4.5 binaries have the same version as the 4.0 binaries case "4.0": case "4.5": return("v4.0.30319"); default: return(null); } }
internal SystemPackageInfo(LibraryPackageInfo info) { Name = info.Name; IsGacPackage = info.IsGacPackage; Version = info.Version; Description = info.Description; TargetFramework = TargetFrameworkMoniker.Parse(info.GetData("targetFramework")); CustomData = info.CustomData; Requires = info.Requires; Assemblies = new List <AssemblyInfo> (); if (info.IsValidPackage) { foreach (PackageAssemblyInfo asm in info.Assemblies) { Assemblies.Add(new AssemblyInfo(asm)); } } }
static List <AssemblyInfo> ScanAssemblyDirectory(TargetFrameworkMoniker tfm, FilePath dir) { var assemblies = new List <AssemblyInfo> (); foreach (var f in Directory.EnumerateFiles(dir, "*.dll")) { try { var an = SystemAssemblyService.GetAssemblyNameObj(dir.Combine(f)); var ainfo = new AssemblyInfo(); ainfo.Update(an); assemblies.Add(ainfo); } catch (BadImageFormatException ex) { LoggingService.LogError("Invalid assembly in framework '{0}': {1}{2}{3}", tfm, f, Environment.NewLine, ex.ToString()); } catch (Exception ex) { LoggingService.LogError("Error reading assembly '{0}' in framework '{1}':{2}{3}", f, tfm, Environment.NewLine, ex.ToString()); } } return(assemblies); }
protected static IEnumerable <TargetFramework> FindTargetFrameworks(FilePath frameworksDirectory, bool rescanKnownFrameworks) { foreach (FilePath idDir in Directory.EnumerateDirectories(frameworksDirectory)) { var id = idDir.FileName; foreach (FilePath versionDir in Directory.EnumerateDirectories(idDir)) { var version = versionDir.FileName; var moniker = new TargetFrameworkMoniker(id, version); if (rescanKnownFrameworks || !Runtime.SystemAssemblyService.IsKnownFramework(moniker)) { var fx = ReadTargetFramework(moniker, versionDir); if (fx != null) { yield return(fx); } } var profileListDir = versionDir.Combine("Profile"); if (!Directory.Exists(profileListDir)) { continue; } foreach (FilePath profileDir in Directory.EnumerateDirectories(profileListDir)) { var profile = profileDir.FileName; moniker = new TargetFrameworkMoniker(id, version, profile); if (rescanKnownFrameworks || !Runtime.SystemAssemblyService.IsKnownFramework(moniker)) { var fx = ReadTargetFramework(moniker, profileDir); if (fx != null) { yield return(fx); } } } } } }
public TargetFramework GetTargetFramework(TargetFrameworkMoniker id) { TargetFramework fx; if (frameworks.TryGetValue(id, out fx)) { return(fx); } LoggingService.LogDebug("Unregistered TargetFramework '{0}' is being requested from SystemAssemblyService, ensuring rutimes initialized and trying again", id); foreach (var r in runtimes) { r.EnsureInitialized(); } if (frameworks.TryGetValue(id, out fx)) { return(fx); } LoggingService.LogWarning("Unregistered TargetFramework '{0}' is being requested from SystemAssemblyService, returning empty TargetFramework", id); UpdateFrameworks(new [] { new TargetFramework(id) }); return(frameworks [id]); }
public bool IsCompatibleWithFramework(TargetFrameworkMoniker fxId) { foreach (var sfx in SupportedFrameworks) { if (sfx.Identifier != fxId.Identifier) { continue; } if (!ProfileMatchesPattern(fxId.Profile, sfx.Profile)) { continue; } var version = new Version(fxId.Version); if (version >= sfx.MinimumVersion && version <= sfx.MaximumVersion) { return(true); } } // FIXME: this is a hack until we have .NETPortable profiles for MonoTouch & MonoDroid if (fxId.Identifier == ".NETPortable" && fxId.Version == "4.0") { switch (id.Identifier) { case TargetFrameworkMoniker.ID_MONOTOUCH: case TargetFrameworkMoniker.ID_MONODROID: return(true); } } return(fxId.Identifier == this.id.Identifier && new Version(fxId.Version).CompareTo(new Version(this.id.Version)) <= 0); }
public static TargetFramework FromFrameworkDirectory(TargetFrameworkMoniker moniker, FilePath dir) { var fxList = dir.Combine("RedistList", "FrameworkList.xml"); if (!File.Exists(fxList)) { return(null); } var fx = new TargetFramework(moniker); using (var reader = System.Xml.XmlReader.Create(fxList)) { if (!reader.ReadToDescendant("FileList")) { throw new Exception("Missing FileList element"); } //not sure what this is for //if (reader.MoveToAttribute ("Redist") && reader.ReadAttributeValue ()) // redist = reader.ReadContentAsString (); if (reader.MoveToAttribute("Name") && reader.ReadAttributeValue()) { fx.name = reader.ReadContentAsString(); } if (reader.MoveToAttribute("RuntimeVersion") && reader.ReadAttributeValue()) { string runtimeVersion = reader.ReadContentAsString(); switch (runtimeVersion) { case "2.0": fx.clrVersion = ClrVersion.Net_2_0; break; case "4.0": fx.clrVersion = ClrVersion.Net_4_0; break; case "4.5": case "4.5.1": fx.clrVersion = ClrVersion.Net_4_5; break; default: LoggingService.LogInfo("Framework {0} has unknown RuntimeVersion {1}", moniker, runtimeVersion); return(null); } } if (reader.MoveToAttribute("ToolsVersion") && reader.ReadAttributeValue()) { string toolsVersion = reader.ReadContentAsString(); switch (toolsVersion) { case "2.0": fx.toolsVersion = TargetFrameworkToolsVersion.V2_0; break; case "3.5": fx.toolsVersion = TargetFrameworkToolsVersion.V3_5; break; case "4.0": fx.toolsVersion = TargetFrameworkToolsVersion.V4_0; break; case "4.5": fx.toolsVersion = TargetFrameworkToolsVersion.V4_5; break; default: LoggingService.LogInfo("Framework {0} has unknown ToolsVersion {1}", moniker, toolsVersion); return(null); } } if (reader.MoveToAttribute("IncludeFramework") && reader.ReadAttributeValue()) { string include = reader.ReadContentAsString(); if (!string.IsNullOrEmpty(include)) { fx.includesFramework = include; } } //this is a Mono-specific extension if (reader.MoveToAttribute("TargetFrameworkDirectory") && reader.ReadAttributeValue()) { string targetDir = reader.ReadContentAsString(); if (!string.IsNullOrEmpty(targetDir)) { targetDir = targetDir.Replace('\\', System.IO.Path.DirectorySeparatorChar); dir = fxList.ParentDirectory.Combine(targetDir).FullPath; } } var assemblies = new List <AssemblyInfo> (); if (reader.ReadToFollowing("File")) { do { var ainfo = new AssemblyInfo(); assemblies.Add(ainfo); if (reader.MoveToAttribute("AssemblyName") && reader.ReadAttributeValue()) { ainfo.Name = reader.ReadContentAsString(); } if (string.IsNullOrEmpty(ainfo.Name)) { throw new Exception("Missing AssemblyName attribute"); } if (reader.MoveToAttribute("Version") && reader.ReadAttributeValue()) { ainfo.Version = reader.ReadContentAsString(); } if (reader.MoveToAttribute("PublicKeyToken") && reader.ReadAttributeValue()) { ainfo.PublicKeyToken = reader.ReadContentAsString(); } if (reader.MoveToAttribute("Culture") && reader.ReadAttributeValue()) { ainfo.Culture = reader.ReadContentAsString(); } if (reader.MoveToAttribute("ProcessorArchitecture") && reader.ReadAttributeValue()) { ainfo.ProcessorArchitecture = (ProcessorArchitecture) Enum.Parse(typeof(ProcessorArchitecture), reader.ReadContentAsString(), true); } if (reader.MoveToAttribute("InGac") && reader.ReadAttributeValue()) { ainfo.InGac = reader.ReadContentAsBoolean(); } } while (reader.ReadToFollowing("File")); } else { // HACK: we were using EnumerateFiles but it's broken in some Mono releases // https://bugzilla.xamarin.com/show_bug.cgi?id=2975 var files = Directory.GetFiles(dir, "*.dll"); foreach (var f in files) { try { var an = SystemAssemblyService.GetAssemblyNameObj(dir.Combine(f)); var ainfo = new AssemblyInfo(); ainfo.Update(an); assemblies.Add(ainfo); } catch (Exception ex) { LoggingService.LogError("Error reading name for assembly '{0}' in framework '{1}':\n{2}", f, fx.Id, ex.ToString()); } } } fx.Assemblies = assemblies.ToArray(); } var supportedFrameworksDir = dir.Combine("SupportedFrameworks"); if (Directory.Exists(supportedFrameworksDir)) { foreach (var sfx in Directory.GetFiles(supportedFrameworksDir)) { fx.SupportedFrameworks.Add(SupportedFramework.Load(fx, sfx)); } } return(fx); }
public bool IncludesFramework(TargetFrameworkMoniker id) { return(id == this.id || includedFrameworks.Contains(id)); }
public bool CanReferenceAssembliesTargetingFramework(TargetFrameworkMoniker fxId) { var fx = Runtime.SystemAssemblyService.GetTargetFramework(fxId); return(fx != null && CanReferenceAssembliesTargetingFramework(fx)); }
internal bool IsKnownFramework(TargetFrameworkMoniker moniker) { return(frameworks.ContainsKey(moniker)); }
internal protected override object OnDeserialize(SerializationContext serCtx, object mapData, DataNode data) { return(TargetFrameworkMoniker.Parse(((DataValue)data).Value)); }
public TargetFramework GetTargetFramework(TargetFrameworkMoniker id) { EnsureRuntimesInitialized(); return(GetTargetFramework(id, frameworks)); }
//HACK: this is so that MonoTargetRuntime can access the core frameworks while it's doing its broken assembly->framework mapping internal TargetFramework GetCoreFramework(TargetFrameworkMoniker id) { return(GetTargetFramework(id, frameworks)); }
public bool IsCompatibleWithFramework(TargetFrameworkMoniker fxId) { return(fxId.Identifier == this.id.Identifier && new Version(fxId.Version).CompareTo(new Version(this.id.Version)) <= 0); }