diff --git a/RueI/RueI.csproj b/RueI/RueI.csproj
index 1c3841d..ed27197 100644
--- a/RueI/RueI.csproj
+++ b/RueI/RueI.csproj
@@ -1,99 +1,89 @@
-
-
- net48
- latest
- enable
- enable
- AnyCPU;x64
- RueI
- CC0 1.0
- 2.0.4
- Rue <3, Override (some help)
- True
- True
- universal hint framework for scp:sl
- https://github.com/Ruemena/RueI
- https://github.com/Ruemena/RueI
- scpsl;hints;scp;exiled;nwapi
- 2.0.4
- 2.0.4
- README.md
- LICENSE
- False
- various fixes, improvements to docs, new reflection helpers, and general cleanup
-
-
-
- True
- portable
-
-
-
- True
- portable
-
-
-
- portable
-
-
-
- portable
-
-
-
-
-
+
+ net48
+ latest
+ enable
+ enable
+ AnyCPU;x64
+ RueI
+ CC0 1.0
+ 2.0.4
+ Rue <3, Override (some help)
+ True
+ True
+ universal hint framework for scp:sl
+ https://github.com/Ruemena/RueI
+ https://github.com/Ruemena/RueI
+ scpsl;hints;scp;exiled;nwapi
+ 2.0.4
+ 2.0.4
+ README.md
+ LICENSE
+ False
+ various fixes, improvements to docs, new reflection helpers, and general cleanup
+
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
- ../References/Assembly-CSharp.dll
-
-
- ../References/Assembly-CSharp-firstpass.dll
-
-
- ../References/Mirror.dll
-
-
- ../References/NorthwoodLib.dll
-
-
- ../References/PluginAPI.dll
-
-
- ../References/UnityEngine.dll
-
-
- ../References/UnityEngine.CoreModule.dll
-
-
- ../References/System.Collections.Immutable.dll
-
-
-
-
-
- True
- \
-
-
- True
- \
-
-
-
+
+ True
+ portable
+
+
+ True
+ portable
+
+
+ portable
+
+
+ portable
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+ ../References/Assembly-CSharp.dll
+
+
+ ../References/Assembly-CSharp-firstpass.dll
+
+
+ ../References/Mirror.dll
+
+
+ ../References/NorthwoodLib.dll
+
+
+ ../References/PluginAPI.dll
+
+
+ ../References/UnityEngine.dll
+
+
+ ../References/UnityEngine.CoreModule.dll
+
+
+ ../References/System.Collections.Immutable.dll
+
+
+
+
+ True
+ \
+
+
+ True
+ \
+
+
\ No newline at end of file
diff --git a/RueI/RueI/Displays/AutoElements/AutoElements.cs b/RueI/RueI/Displays/AutoElements/AutoElement.cs
similarity index 74%
rename from RueI/RueI/Displays/AutoElements/AutoElements.cs
rename to RueI/RueI/Displays/AutoElements/AutoElement.cs
index d43a251..e80890b 100644
--- a/RueI/RueI/Displays/AutoElements/AutoElements.cs
+++ b/RueI/RueI/Displays/AutoElements/AutoElement.cs
@@ -18,7 +18,12 @@
///
public class AutoElement
{
- private record PeriodicUpdate(TimeSpan time, int priority, JobToken token);
+ ///
+ /// Represents a periodic update for an .
+ ///
+ /// How often the should schedule an auto-update.
+ /// The priority of the scheduled job.
+ public record PeriodicUpdate(TimeSpan time, int priority = 10);
private const int AUTOUPDATEPRIORITY = 5;
@@ -29,7 +34,7 @@ private record PeriodicUpdate(TimeSpan time, int priority, JobToken token);
private readonly IElemReference reference = DisplayCore.GetReference();
- private PeriodicUpdate? periodicUpdate;
+ private (PeriodicUpdate update, JobToken token)? autoUpdate = null;
static AutoElement()
{
@@ -68,23 +73,32 @@ public AutoElement(Roles roles, Element element)
public Roles Roles { get; set; }
///
- /// Disables this .
+ /// Gets or sets a indicating how often this should
+ /// schedule an update for players with the element, or null if it should not auto-update.
///
- public virtual void Disable()
+ public PeriodicUpdate? UpdateEvery
{
- AutoElements.Remove(this);
+ get => autoUpdate?.update;
+
+ set
+ {
+ if (value != null)
+ {
+ autoUpdate = (value, new());
+ }
+ else
+ {
+ autoUpdate = null;
+ }
+ }
}
///
- /// Schedules an update for all players with one of the every .
+ /// Disables this .
///
- /// How often to schedule an update.
- /// The priority of the update.
- /// A reference to this .
- public AutoElement UpdateEvery(TimeSpan span, int priority = 35)
+ public virtual void Disable()
{
- periodicUpdate = new(span, priority, new());
- return this;
+ AutoElements.Remove(this);
}
///
@@ -102,9 +116,9 @@ protected virtual void GiveTo(DisplayCore core)
core.AddAsReference(reference, creator!(core));
}
- if (periodicUpdate != null)
+ if (autoUpdate != null)
{
- ScheduleUpdate(core, periodicUpdate);
+ ScheduleUpdate(core, autoUpdate.Value);
}
}
@@ -116,9 +130,9 @@ protected virtual void RemoveFrom(DisplayCore core)
{
core.RemoveReference(reference);
- if (periodicUpdate != null)
+ if (autoUpdate != null)
{
- core.Scheduler.KillJob(periodicUpdate.token);
+ core.Scheduler.KillJob(autoUpdate.Value.token);
}
}
@@ -144,8 +158,8 @@ private static void OnRoleChanged(ReferenceHub hub, PlayerRoleBase prevRole, Pla
}
}
- private static void ScheduleUpdate(DisplayCore core, PeriodicUpdate update)
+ private static void ScheduleUpdate(DisplayCore core, (PeriodicUpdate update, JobToken token) autoUpdate)
{
- core.Scheduler.Schedule(update.time, () => ScheduleUpdate(core, update), update.token);
+ core.Scheduler.Schedule(autoUpdate.update.time, () => ScheduleUpdate(core, autoUpdate), autoUpdate.token);
}
}
\ No newline at end of file
diff --git a/RueI/RueI/Displays/DisplayCore.cs b/RueI/RueI/Displays/DisplayCore.cs
index 21a6408..236387b 100644
--- a/RueI/RueI/Displays/DisplayCore.cs
+++ b/RueI/RueI/Displays/DisplayCore.cs
@@ -1,7 +1,7 @@
namespace RueI.Displays;
-using RueI.Elements;
using RueI.Displays.Scheduling;
+using RueI.Elements;
using RueI.Extensions;
///
@@ -41,14 +41,14 @@ protected DisplayCore(ReferenceHub hub)
public Scheduler Scheduler { get; }
///
- /// Gets a dictionary containing the DisplayCores for each ReferenceHub.
+ /// Gets the that this display is for.
///
- internal static Dictionary DisplayCores { get; } = new();
+ public ReferenceHub Hub { get; }
///
- /// Gets the that this display is for.
+ /// Gets a dictionary containing the DisplayCores for each ReferenceHub.
///
- internal ReferenceHub Hub { get; }
+ internal static Dictionary DisplayCores { get; } = new();
///
/// Gets or sets a value indicating whether or not updates will currently be ignored.
diff --git a/RueI/RueI/Displays/ElemCombiner.cs b/RueI/RueI/Displays/ElemCombiner.cs
index 68df15b..7e48369 100644
--- a/RueI/RueI/Displays/ElemCombiner.cs
+++ b/RueI/RueI/Displays/ElemCombiner.cs
@@ -4,8 +4,8 @@
using NorthwoodLib.Pools;
-using RueI.Extensions;
using RueI.Elements;
+using RueI.Extensions;
using RueI.Parsing.Records;
///
@@ -32,6 +32,7 @@ public static string Combine(IEnumerable enumElems)
}
StringBuilder sb = StringBuilderPool.Shared.Rent();
+
float totalOffset = 0;
float lastPosition = 0;
@@ -54,7 +55,7 @@ public static string Combine(IEnumerable enumElems)
if (i != 0)
{
float calcedOffset = CalculateOffset(lastPosition, lastOffset, funcPos);
- sb.Append($"\n");
+ sb.Append($"\n");
totalOffset += calcedOffset;
}
else
@@ -70,8 +71,12 @@ public static string Combine(IEnumerable enumElems)
}
ListPool.Shared.Return(elements);
- sb.Insert(0, $"\n");
- sb.Append(Constants.ZeroWidthSpace);
+ sb.Insert(0, $"\n.");
+
+ // a zero width space is appended here to ensure that trailing newlines still occur
+ // since this is after all tags have been closed, its guaranteed to not
+ // do anything at all except stop trailing newlines
+ sb.Append(".");
return StringBuilderPool.Shared.ToStringReturn(sb);
}
diff --git a/RueI/RueI/Displays/Scheduling/JobToken.cs b/RueI/RueI/Displays/Scheduling/JobToken.cs
index 03d6a47..5253d42 100644
--- a/RueI/RueI/Displays/Scheduling/JobToken.cs
+++ b/RueI/RueI/Displays/Scheduling/JobToken.cs
@@ -1,12 +1,14 @@
namespace RueI.Displays.Scheduling;
///
-/// Represents a reference to any number of .
+/// Represents a reference to any number of .
///
///
-/// A provides a unique identifier for a within any number of s. In other words, a can reference multiple (or no) , but only a single with the given can exist in a .
+/// A provides a unique identifier for a within any number of
+/// s. In other words, a can reference multiple (or no) jobs,
+/// but only a single job with the given can exist in a .
///
-///
+///
public class JobToken
{
///
diff --git a/RueI/RueI/Displays/Scheduling/Records/BatchJob.cs b/RueI/RueI/Displays/Scheduling/Records/BatchJob.cs
index c5e05bd..21eb911 100644
--- a/RueI/RueI/Displays/Scheduling/Records/BatchJob.cs
+++ b/RueI/RueI/Displays/Scheduling/Records/BatchJob.cs
@@ -3,7 +3,8 @@
///
/// Defines a number of s that will performed at a certain time.
///
-internal class BatchJob
+///
+internal record BatchJob
{
///
/// Initializes a new instance of the class.
diff --git a/RueI/RueI/Displays/Scheduling/Records/ScheduledJob.cs b/RueI/RueI/Displays/Scheduling/ScheduledJob.cs
similarity index 94%
rename from RueI/RueI/Displays/Scheduling/Records/ScheduledJob.cs
rename to RueI/RueI/Displays/Scheduling/ScheduledJob.cs
index c8b3948..731858b 100644
--- a/RueI/RueI/Displays/Scheduling/Records/ScheduledJob.cs
+++ b/RueI/RueI/Displays/Scheduling/ScheduledJob.cs
@@ -1,4 +1,4 @@
-namespace RueI.Displays.Scheduling.Records;
+namespace RueI.Displays.Scheduling;
using RueI.Extensions;
@@ -37,7 +37,7 @@ internal ScheduledJob(DateTimeOffset finishAt, Action action, int priority, JobT
///
/// Gets the priority of the element.
///
- internal int Priority { get; private set; } = 1;
+ internal int Priority { get; private set; }
///
/// Gets the of this, if it has one.
diff --git a/RueI/RueI/Displays/Scheduling/Scheduler.cs b/RueI/RueI/Displays/Scheduling/Scheduler.cs
index abb24de..dc1a900 100644
--- a/RueI/RueI/Displays/Scheduling/Scheduler.cs
+++ b/RueI/RueI/Displays/Scheduling/Scheduler.cs
@@ -15,13 +15,15 @@
///
public class Scheduler
{
+ private static readonly Action EmptyAction = () => { };
private static readonly TimeSpan MinimumBatch = TimeSpan.FromMilliseconds(625);
+ private readonly DisplayCore core;
+
private readonly Cooldown hintRateLimit = new();
private readonly List jobs = new();
private readonly UpdateTask performTask = new();
- private readonly DisplayCore core;
private BatchJob? nextBatch;
@@ -29,7 +31,7 @@ public class Scheduler
/// Initializes a new instance of the class.
///
/// The to use.
- public Scheduler(DisplayCore core)
+ internal Scheduler(DisplayCore core)
{
this.core = core;
}
@@ -118,10 +120,21 @@ public void Schedule(ScheduledJob job, params ScheduledJob[] jobs)
/// The priority of the , giving it additional weight when calculating.
public void ScheduleUpdate(TimeSpan time, int priority)
{
- jobs.Add(new(Now + time, () => { }, priority));
+ jobs.Add(new(Now + time, EmptyAction, priority));
UpdateBatches();
}
+ ///
+ /// Schedules an update with the .
+ ///
+ /// How long into the future to update at.
+ /// The priority of the , giving it additional weight when calculating.
+ /// A token to assign to the .
+ public void ScheduleUpdateToken(TimeSpan time, int priority, JobToken token)
+ {
+ Schedule(new ScheduledJob(Now + time, EmptyAction, priority, token));
+ }
+
///
/// Schedules a new .
///
diff --git a/RueI/RueI/Displays/Screen.cs b/RueI/RueI/Displays/Screen.cs
index 028330c..1c27303 100644
--- a/RueI/RueI/Displays/Screen.cs
+++ b/RueI/RueI/Displays/Screen.cs
@@ -1,7 +1,7 @@
namespace RueI.Displays;
-using RueI.Elements;
using RueI.Displays.Interfaces;
+using RueI.Elements;
///
/// Represents a inside a .
diff --git a/RueI/RueI/Displays/ScreenDisplay.cs b/RueI/RueI/Displays/ScreenDisplay.cs
index cc0c48e..94a4632 100644
--- a/RueI/RueI/Displays/ScreenDisplay.cs
+++ b/RueI/RueI/Displays/ScreenDisplay.cs
@@ -1,7 +1,7 @@
namespace RueI.Displays;
-using RueI.Extensions;
using RueI.Elements;
+using RueI.Extensions;
///
/// Represents a display attached to a with support for s.
diff --git a/RueI/RueI/Extensions/ElementHelpers.cs b/RueI/RueI/Extensions/ElementHelpers.cs
index 5ebcd92..a51a19f 100644
--- a/RueI/RueI/Extensions/ElementHelpers.cs
+++ b/RueI/RueI/Extensions/ElementHelpers.cs
@@ -1,7 +1,6 @@
namespace RueI.Extensions;
using RueI.Elements;
-using RueI.Displays.Interfaces;
///
/// Provides extensions and helpers for working with elements.
@@ -13,7 +12,20 @@ public static class ElementHelpers
///
/// The elements to filter.
/// The filtered .
- public static IEnumerable FilterDisabled(this IEnumerable elements) => elements.Where(x => x.Enabled);
+ public static IEnumerable FilterDisabled(this IEnumerable elements)
+ {
+ using IEnumerator enumerator = elements.GetEnumerator();
+
+ while (enumerator.MoveNext())
+ {
+ Element element = enumerator.Current;
+
+ if (element.Enabled)
+ {
+ yield return element;
+ }
+ }
+ }
///
/// Gets the functional (un-scaled) position of an element.
diff --git a/RueI/RueI/Extensions/IComparableExtensions.cs b/RueI/RueI/Extensions/IComparableExtensions.cs
index b6b3aa9..0a88ed6 100644
--- a/RueI/RueI/Extensions/IComparableExtensions.cs
+++ b/RueI/RueI/Extensions/IComparableExtensions.cs
@@ -30,12 +30,12 @@ public static T Max(this T first, T second)
///
/// The type to use.
/// The first value.
- /// Whether or not to return the first value.
+ /// Whether or not to perform the check.
/// The second value.
/// The maximum of the two, or the first value if the bool is true.
- public static T MaxIf(this T first, bool skip, T second)
+ public static T MaxIf(this T first, bool check, T second)
where T : IComparable
{
- return skip ? first : first.Max(second);
+ return check ? first.Max(second) : first;
}
}
\ No newline at end of file
diff --git a/RueI/RueI/Parsing/Parser.cs b/RueI/RueI/Parsing/Parser.cs
index d563319..caec303 100644
--- a/RueI/RueI/Parsing/Parser.cs
+++ b/RueI/RueI/Parsing/Parser.cs
@@ -154,15 +154,6 @@ public static float CalculateCharacterLength(TextInfo context, char ch)
/// Whether or not the line break was caused by an overflow.
public static void CreateLineBreak(ParserContext context, bool isOverflow = false)
{
- if (context.LineHasAnyChars)
- {
- context.NewOffset += CalculateSizeOffset(context.BiggestCharSize);
- }
- else
- {
- context.NewOffset += CalculateSizeOffset(Constants.DEFAULTSIZE);
- }
-
if (context.WidthSinceSpace > context.FunctionalWidth)
{
context.CurrentLineWidth = 0;
@@ -444,10 +435,6 @@ void FailTagMatch() // not a tag, unload buffer
} // foreach
context.ApplyClosingTags();
- if (context.WidthSinceSpace > 0 || context.CurrentLineWidth > 0) // acount for the last line's size offset
- {
- context.NewOffset += CalculateSizeOffset(context.BiggestCharSize);
- }
StringBuilderPool.Shared.Return(tagBuffer);
StringBuilderPool.Shared.Return(paramBuffer);
@@ -459,7 +446,7 @@ void FailTagMatch() // not a tag, unload buffer
///
/// The size of the biggest char within the line.
/// An offset that should be added to the parser.
- private static float CalculateSizeOffset(float biggestChar) => (((biggestChar / Constants.DEFAULTSIZE * 0.2f) + 0.8f) * Constants.DEFAULTHEIGHT) - Constants.DEFAULTHEIGHT;
+ private static float CalculateSizeOffset(float biggestChar) => (1 - (biggestChar / Constants.DEFAULTSIZE)) * 8.485f; // (((biggestChar / Constants.DEFAULTSIZE * 0.2f) + 0.8f) * Constants.DEFAULTHEIGHT) - Constants.DEFAULTHEIGHT;
private static bool IsValidTagChar(char ch) => (ch > '\u0060' && ch < '\u007B') || ch == '-' || ch == '/';
diff --git a/RueI/RueI/Parsing/ParserContext.cs b/RueI/RueI/Parsing/ParserContext.cs
index c12394b..3cb18d4 100644
--- a/RueI/RueI/Parsing/ParserContext.cs
+++ b/RueI/RueI/Parsing/ParserContext.cs
@@ -56,6 +56,11 @@ public class ParserContext : TextInfo, IDisposable
///
public float SpaceBuffer { get; set; } = 0;
+ ///
+ /// Gets or sets the newline buffer of the parser.
+ ///
+ public float NewlineBuffer { get; set; } = 0;
+
///
/// Gets or sets the current indent of the parser.
///
@@ -72,7 +77,7 @@ public class ParserContext : TextInfo, IDisposable
public float LineIndent { get; set; } = 0;
///
- /// Gets or sets a value indicating whether the parser should parse tags other than noparse.
+ /// Gets or sets a value indicating whether the parser should parse tags other than .
///
public bool ShouldParse { get; set; } = true;
diff --git a/RueI/RueI/Parsing/Records/ParsedData.cs b/RueI/RueI/Parsing/Records/ParsedData.cs
index 900df6a..3d66351 100644
--- a/RueI/RueI/Parsing/Records/ParsedData.cs
+++ b/RueI/RueI/Parsing/Records/ParsedData.cs
@@ -19,7 +19,7 @@ internal ParsedData(string content, float offset)
///
/// Gets the content of the element.
///
- public string Content { get; }
+ public string Content { get; }
///
/// Gets the offset that should be applied to the element.
diff --git a/RueI/RueI/Parsing/Tags/ConcreteTags/CloseLineHeightTag.cs b/RueI/RueI/Parsing/Tags/ConcreteTags/CloseLineHeightTag.cs
index f62dd48..2135d5a 100644
--- a/RueI/RueI/Parsing/Tags/ConcreteTags/CloseLineHeightTag.cs
+++ b/RueI/RueI/Parsing/Tags/ConcreteTags/CloseLineHeightTag.cs
@@ -1,17 +1,22 @@
namespace RueI.Parsing.Tags.ConcreteTags;
///
-/// Provides a way to handle closing line-height tags.
+/// Provides a way to handle closing size tags.
///
[RichTextTag]
-public class CloseLineHeightTag : ClosingTag
+public class CloseLineHeightTag : NoParamsTag
{
+ private const string TAGFORMAT = "";
+
///
- public override string Name { get; } = "/line-height";
+ public override string[] Names { get; } = { "/line-height" };
///
- protected override void ApplyTo(ParserContext context)
+ public override bool HandleTag(ParserContext context)
{
- context.CurrentLineHeight = 0;
+ context.CurrentLineHeight = Constants.DEFAULTHEIGHT;
+ context.ResultBuilder.Append(TAGFORMAT);
+
+ return true;
}
}
diff --git a/RueI/RueI/Parsing/Tags/ConcreteTags/CloseNoparseTag.cs b/RueI/RueI/Parsing/Tags/ConcreteTags/CloseNoparseTag.cs
index cae6ed8..cccab90 100644
--- a/RueI/RueI/Parsing/Tags/ConcreteTags/CloseNoparseTag.cs
+++ b/RueI/RueI/Parsing/Tags/ConcreteTags/CloseNoparseTag.cs
@@ -3,6 +3,10 @@
///
/// Provides a way to handle closing noparse tags.
///
+///
+/// The RueI allows this tag to be matched even when is false.
+/// This replicates the behavior of normal TextMesh Pro.
+///
[RichTextTag]
public class CloseNoparseTag : ClosingTag
{
diff --git a/RueI/RueI/Parsing/Tags/ConcreteTags/LineHeightTag.cs b/RueI/RueI/Parsing/Tags/ConcreteTags/LineHeightTag.cs
index 33aa3a7..6218de8 100644
--- a/RueI/RueI/Parsing/Tags/ConcreteTags/LineHeightTag.cs
+++ b/RueI/RueI/Parsing/Tags/ConcreteTags/LineHeightTag.cs
@@ -19,10 +19,11 @@ public override bool HandleTag(ParserContext context, MeasurementInfo info)
{
var (value, style) = info;
+ // the line height of ems and percentages changes based on the current size
float convertedValue = style switch
{
- MeasurementUnit.Percentage => value / 100 * Constants.DEFAULTHEIGHT,
- MeasurementUnit.Ems => value * Constants.EMSTOPIXELS,
+ MeasurementUnit.Percentage => value / 100 * Constants.DEFAULTHEIGHT * (context.Size / Constants.DEFAULTSIZE),
+ MeasurementUnit.Ems => value * Constants.EMSTOPIXELS * (context.Size / Constants.DEFAULTSIZE),
_ => value
};
diff --git a/RueI/RueI/Patches/HintPatch.cs b/RueI/RueI/Patches/HintPatch.cs
index c03daa9..2a20dd2 100644
--- a/RueI/RueI/Patches/HintPatch.cs
+++ b/RueI/RueI/Patches/HintPatch.cs
@@ -29,6 +29,8 @@ public static class HintPatch
private const float MAXANONYMOUSHINTTIME = 3;
private const int UPDATEPRIORITY = 10;
+ private static readonly JobToken UpdateToken = new();
+
private delegate bool TryGetHub(GameObject player, out ReferenceHub hub);
///
@@ -64,7 +66,8 @@ public static IEnumerable Transpiler(IEnumerable Transpiler(IEnumerable new MECAsyncOperation(span, action);
///
- internal override void ShowHint(ReferenceHub hub, string message) => hub.connectionToClient.Send(new HintMessage(new TextHint(message, new HintParameter[] { new StringHintParameter(message) }, new HintEffect[] { HintEffectPresets.FadeIn(0, 0, 1) }, 99999)));
+ internal override void ShowHint(ReferenceHub hub, string message) => hub.connectionToClient.Send(new HintMessage(new TextHint(message, new HintParameter[] { new StringHintParameter(message) }, null, 99999)));
///
/// Represents an async operation using a .
@@ -197,7 +197,7 @@ public class MECAsyncOperation : IAsyncOperation
/// The action to run when finished.
public MECAsyncOperation(TimeSpan span, Action action)
{
- handle = Timing.CallDelayed(((float)span.TotalSeconds).Max(0), action);
+ handle = Timing.CallDelayed(((float)span.TotalSeconds).Max(0f), action);
}
///
diff --git a/RueITests/TestExtensions.cs b/RueITests/TestExtensions.cs
index d447fe2..0ff90a4 100644
--- a/RueITests/TestExtensions.cs
+++ b/RueITests/TestExtensions.cs
@@ -1,9 +1,18 @@
using RueI.Extensions;
+using RueI.Extensions.HintBuilding;
+using System.Drawing;
namespace RueITest;
[TestClass]
public class TestExtensions
{
+ [TestMethod]
+ public void TestMax()
+ {
+ int maxOne = Math.Max(5, 3);
+ int maxTwo = 5.Max(3);
+ Assert.AreEqual(maxOne, maxTwo);
+ }
}
///"\"hello world - - - again\""
\ No newline at end of file