diff --git a/.github/workflows/Benchmark.yml b/.github/workflows/Benchmark.yml index f7b8ecbfd..a79ee0486 100644 --- a/.github/workflows/Benchmark.yml +++ b/.github/workflows/Benchmark.yml @@ -5,13 +5,13 @@ jobs: Rendering: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'recursive' - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + - name: Setup .NET + uses: actions/setup-dotnet@v5 with: - dotnet-version: 3.1.401 + dotnet-version: '10.0.x' - run: dotnet run -p CSharpMath.Rendering.Benchmarks - name: Store benchmark result uses: Happypig375/github-action-benchmark@v1 diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index b788a313f..8b745dde1 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -5,18 +5,16 @@ jobs: Everything: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'recursive' - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + - name: Setup .NET + uses: actions/setup-dotnet@v5 with: - dotnet-version: '3.1.401' - - name: Setup NuGet - uses: NuGet/setup-nuget@v1.0.5 + dotnet-version: '10.0.x' - name: Setup MSBuild Path - uses: microsoft/setup-msbuild@v1.0.2 + uses: microsoft/setup-msbuild@v2 - name: Restore NuGet Packages - run: nuget restore CSharpMath.sln + run: dotnet restore BuildEverythingYml.slnf - name: Build Everything - run: msbuild CSharpMath.sln /p:Configuration=Release + run: msbuild BuildEverythingYml.slnf /p:Configuration=Release diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 4ffeb554c..94f275950 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -7,13 +7,13 @@ jobs: CSharpMath: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'recursive' - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + - name: Setup .NET + uses: actions/setup-dotnet@v5 with: - dotnet-version: '3.1.401' + dotnet-version: '10.0.x' - name: Build GitHub Releases draft artifacts env: RELEASE_NOTES: | diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml index 93d2064ae..93b450bcc 100644 --- a/.github/workflows/Test.yml +++ b/.github/workflows/Test.yml @@ -7,25 +7,16 @@ jobs: steps: - name: Update draft on GitHub Releases id: release_drafter - uses: release-drafter/release-drafter@v5 + uses: release-drafter/release-drafter@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'recursive' - - name: Setup .NET Core # Required to execute ReportGenerator - uses: actions/setup-dotnet@v1 + - name: Setup .NET + uses: actions/setup-dotnet@v5 with: - dotnet-version: '3.1.401' - - name: Update dependencies in CSharpMath.Xaml.Tests.NuGet - run: | - dotnet tool install -g dotnet-outdated - update() { - dotnet outdated -u CSharpMath.Xaml.Tests.NuGet - dotnet outdated -pre Always -inc CSharpMath -u CSharpMath.Xaml.Tests.NuGet - } - # retry 5 times since dotnet outdated fails often: https://github.com/jerriep/dotnet-outdated/issues/299 - update || update || update || update || update + dotnet-version: '10.0.x' - name: Build and Test env: RELEASE_NOTES: | @@ -35,15 +26,15 @@ jobs: run: | # .NET Core MSBuild cannot parse , and ; correctly so we replace them with substitutions: https://github.com/dotnet/msbuild/issues/471#issuecomment-366268743 # https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion - # ${parameter/pattern/string} If pattern begins with ‘/’, all matches of pattern are replaced with string. Normally only the first match is replaced. + # ${parameter/pattern/string} If pattern begins with '/', all matches of pattern are replaced with string. Normally only the first match is replaced. RELEASE_NOTES=${RELEASE_NOTES//,/%2C} RELEASE_NOTES=${RELEASE_NOTES//;/%3B} # --collect:"XPlat Code Coverage" means collect test coverage with https://github.com/coverlet-coverage/coverlet # Coverlet settings come after --: https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/VSTestIntegration.md#advanced-options-supported-via-runsettings - dotnet test CSharpMath.CrossPlatform.slnf -c Release -l GitHubActions --blame --collect:"XPlat Code Coverage" -r .testcoverage -p:PackageReleaseNotes="$RELEASE_NOTES" -p:PackageVersion=${{ steps.release_drafter.outputs.tag_name || format('{0}-pr', github.event.number) }}-ci-${{ github.sha }} -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.IncludeTestAssembly=true + dotnet test CSharpMath.CrossPlatform.slnf -c Release -l GitHubActions --blame --collect:"XPlat Code Coverage" --results-directory .testcoverage -p:PackageReleaseNotes="$RELEASE_NOTES" -p:PackageVersion=${{ steps.release_drafter.outputs.tag_name || format('{0}-pr', github.event.number) }}-ci-${{ github.sha }} -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.IncludeTestAssembly=true - name: Run ReportGenerator on Test Coverage results - uses: danielpalme/ReportGenerator-GitHub-Action@4.6.7 + uses: danielpalme/ReportGenerator-GitHub-Action@5 with: reports: '.testcoverage/**/*.*' # REQUIRED # The coverage reports that should be parsed (separated by semicolon). Globbing is supported. targetdir: '.testcoverage/report' # REQUIRED # The directory where the generated report should be saved. @@ -51,30 +42,30 @@ jobs: title: 'CSharpMath test coverage results' # Optional title. tag: ${{ steps.release_drafter.outputs.tag_name || format('{0}-pr', github.event.number) }}-ci-${{ github.sha }} # Optional tag or build version. - name: Upload CSharpMath test coverage results as CI artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: CSharpMath test coverage results path: .testcoverage/ - name: Upload CSharpMath test coverage results to codecov.io - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4 with: file: .testcoverage/**/*.xml # optional name: CSharpMath test coverage # optional - fail_ci_if_error: true # optional (default = false) + fail_ci_if_error: false # optional (default = false) - name: Upload CSharpMath.Rendering.Tests results as CI artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() # Run even when a previous step failed: https://stackoverflow.com/a/58859404/5429648 with: name: CSharpMath.Rendering.Tests results path: CSharpMath.Rendering.Tests/*/*.png - name: Upload CSharpMath.Xaml.Tests.NuGet results as CI artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: CSharpMath.Xaml.Tests.NuGet results path: CSharpMath.Xaml.Tests.NuGet/*.png - name: Upload NuGet packages as CI artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: always() with: name: NuGet packages @@ -86,93 +77,4 @@ jobs: # So we must specify api-key directly in "dotnet nuget push" instead of following the GitHub Packages documentation # We use quotes to avoid shell globbing: https://github.com/NuGet/Home/issues/4393#issuecomment-667618120 # --no-symbols true to not let GitHub Releases interpret .snupkg as .nupkg - dotnet nuget push '.nupkgs/*.nupkg' --source 'https://nuget.pkg.github.com/verybadcat/index.json' --api-key ${{ github.token }} --skip-duplicate --no-symbols true - Ios: - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: 'recursive' - - run: nuget restore CSharpMath.sln - - run: msbuild CSharpMath.Ios.Tests - - name: Run tests - env: - IOS_SIM_NAME: iPhone 11 # https://github.com/actions/virtual-environments/blob/master/images/macos/macos-10.15-Readme.md#installed-simulators - BUNDLE_IDENTIFIER: CSharpMath.Ios.Unit-Tests # Located inside CSharpMath.Ios.Tests Info.plist file - APP_PATH: CSharpMath.Ios.Tests/bin/iPhoneSimulator/Debug/CSharpMath.Ios.Tests.app - run: | - # This script is a heavily modified version of https://gist.github.com/jerrymarino/1f9eb6a06c423f9744ea297d80193a9b - - IOS_SIM_UDID=`xcrun simctl list | grep -w "$IOS_SIM_NAME" | awk 'match($0, /\(([-0-9A-F]+)\)/) { print substr( $0, RSTART + 1, RLENGTH - 2 )}' | head -1` - SIMULATOR_PATH='/Applications/Xcode.app/Contents/Developer/Applications/Simulator.app/Contents/MacOS/Simulator' - - # run_ios_sim builds and runs an iOS app on the simulator - # - # It is designed to replicate the behavior of "Run" in Xcode and assumes basic - # xcodebuild usage. - # - # USAGE: - # export IOS_SIM_UDID=342F9A20-DF48-41A9-BE60-C6B35F47E97F; \ - # export BUNDLE_IDENTIFIER=a.Some; \ - # export APP_PATH=$PWD/Build/Debug-iphonesimulator/$APP_NAME.app \ - # /path/to/run_ios_sim.sh - # - # Note that the UDID must match a device where runtime is installed See - # available devices with "simctl list" - # - # Tested on Xcode 8.3.1 a few times - # Author: Jerry Marino - @jerrymarino - - APP_NAME=`echo ""${APP_PATH##*/}"" | cut -d'.' -f1` - - echo "Running sim for $APP_NAME - $BUNDLE_IDENTIFIER" - - # If the booted simulator does not match, then we need to restart it. Expect an - # output list of the form - # "Phone: iPhone 7 Plus (342F9A20-DF48-41A9-BE60-C6B35F47E97F) (Booted)" - BOOTED_UDID=`xcrun simctl list | grep Booted | perl -pe 's/(.*\()(.*)\)+ (.*)/\2/' | sed -n 1p` - if [[ $BOOTED_UDID != $IOS_SIM_UDID ]]; then - killall Simulator || true # Ignore error code 1: No matching process has been found - else - # FIXME: We don't need to do this for all cases and - # it is slow - killall Simulator || true # Ignore error code 1: No matching process has been found - fi - - # Open the simulator - open -a "$SIMULATOR_PATH" --args -CurrentDeviceUDID $IOS_SIM_UDID - - # Wait until there is a device booted - - function booted_sim_ct() { - echo `xcrun simctl list | grep Booted | wc -l | sed -e 's/ //g'` - } - - while [ `booted_sim_ct` -lt 1 ] - do - sleep 1 - done - - echo "Installing app at path $APP_PATH" - xcrun simctl install booted $APP_PATH - - # Launch the app program into the booted sim - TESTS_OUTPUT=`xcrun simctl launch --console booted "$BUNDLE_IDENTIFIER" 2>&1` - # 2>&1 means "redirect stderr to stdout": https://stackoverflow.com/a/818284/5429648 - - echo "$TESTS_OUTPUT" - - # Move artifacts (generated pictures) to a known path for uploading - TESTS_ARTIFACTS="`xcrun simctl get_app_container booted $BUNDLE_IDENTIFIER data`/Documents/*" - mkdir -p /tmp/tests_artifacts - mv $TESTS_ARTIFACTS /tmp/tests_artifacts # We don't put $TESTS_ARTIFACTS in double quotes because we need path expansion - - # We fail this workflow if the debug output contains [FAIL] (i.e. a test has failed). - if [[ "$TESTS_OUTPUT" == *"[FAIL]"* ]] - then exit 1 - fi - - uses: actions/upload-artifact@v2 - if: always() # Run even when a previous step failed: https://stackoverflow.com/a/58859404/5429648 - with: - name: CSharpMath.Ios.Tests Results - path: /tmp/tests_artifacts + dotnet nuget push '.nupkgs/*.nupkg' --source 'https://nuget.pkg.github.com/verybadcat/index.json' --api-key ${{ github.token }} --skip-duplicate --no-symbols true \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 09164e2b0..8bcba5cb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "Typography"] path = Typography url = https://github.com/LayoutFarm/Typography.git -[submodule "Wiki"] - path = CSharpMath.Wiki - url = https://github.com/verybadcat/CSharpMath.wiki.git diff --git a/BuildEverythingYml.slnf b/BuildEverythingYml.slnf new file mode 100644 index 000000000..d0cad7238 --- /dev/null +++ b/BuildEverythingYml.slnf @@ -0,0 +1,29 @@ +{ + "solution": { + "path": "CSharpMath.sln", + "projects": [ + "CSharpMath\\CSharpMath.csproj", + "CSharpMath.CoreTests\\CSharpMath.CoreTests.csproj", + "CSharpMath.Editor\\CSharpMath.Editor.csproj", + "CSharpMath.Editor.Tests\\CSharpMath.Editor.Tests.csproj", + "CSharpMath.Editor.Tests.Visualizer\\CSharpMath.Editor.Tests.Visualizer.csproj", + "CSharpMath.Evaluation\\CSharpMath.Evaluation.csproj", + "CSharpMath.Evaluation.Tests\\CSharpMath.Evaluation.Tests.csproj", + "CSharpMath.Rendering.Benchmarks\\CSharpMath.Rendering.Benchmarks.csproj", + "CSharpMath.Rendering.Tests\\CSharpMath.Rendering.Tests.csproj", + "CSharpMath.Rendering.Tests.FSharp\\CSharpMath.Rendering.Tests.FSharp.fsproj", + "CSharpMath.Rendering.Text.Tests\\CSharpMath.Rendering.Text.Tests.csproj", + "CSharpMath.Rendering\\CSharpMath.Rendering.csproj", + "CSharpMath.TestUtils\\CSharpMath.TestUtils.csproj", + "CSharpMath.Xaml.Tests\\CSharpMath.Xaml.Tests.csproj", + "CSharpMath.Xaml.Tests.NuGet\\CSharpMath.Xaml.Tests.NuGet.csproj", + "CSharpMath.Playground\\CSharpMath.Playground.csproj", + "CSharpMath.Avalonia\\CSharpMath.Avalonia.csproj", + "CSharpMath.Avalonia.Example\\CSharpMath.Avalonia.Example.csproj", + "CSharpMath.SkiaSharp\\CSharpMath.SkiaSharp.csproj", + "CSharpMath.Forms\\CSharpMath.Forms.csproj", + "CSharpMath.Forms.Example\\CSharpMath.Forms.Example\\CSharpMath.Forms.Example.csproj", + "CSharpMath.Forms.Tests\\CSharpMath.Forms.Tests.csproj" + ] + } +} diff --git a/CSharpMath.Apple/AppleMathView.cs b/CSharpMath.Apple/AppleMathView.cs deleted file mode 100644 index 19ae208aa..000000000 --- a/CSharpMath.Apple/AppleMathView.cs +++ /dev/null @@ -1,128 +0,0 @@ -using CSharpMath.Atom; -using CSharpMath.Display; -using CSharpMath.Display.FrontEnd; -using CoreGraphics; -using UIKit; -using TGlyph = System.UInt16; -using TFont = CSharpMath.Apple.AppleMathFont; -using CoreText; -using System; -using Foundation; -#if __IOS__ -using NView = UIKit.UIView; -using NColor = UIKit.UIColor; -using NContentInsets = UIKit.UIEdgeInsets; -#else -using NView = AppKit.NSView; -#endif - -namespace CSharpMath.Apple { - public class AppleMathView : NView { - public string? ErrorMessage { get; set; } - private IDisplay? _displayList = null; - public float FontSize { get; set; } = 20f; - public ColumnAlignment TextAlignment { get; set; } = ColumnAlignment.Left; - public NContentInsets ContentInsets { get; set; } - private LineStyle _style = LineStyle.Display; - public LineStyle LineStyle { - get => _style; - set { - _style = value; - if (_mathList != null) { - _displayList = Typesetter.CreateLine(_mathList, - TFont.LatinMath(FontSize), _typesettingContext, _style); - } - InvalidateIntrinsicContentSize(); - SetNeedsLayout(); - } - } - private MathList _mathList = new MathList(); - public MathList MathList { - get => _mathList; - set { - _mathList = value; - LaTeX = LaTeXParser.MathListToLaTeX(value).ToString(); - InvalidateIntrinsicContentSize(); - SetNeedsLayout(); - } - } - private string _latex = ""; - public string LaTeX { - get => _latex; - set { - _latex = value; - (_mathList, ErrorMessage) = LaTeXParser.MathListFromLaTeX(value); - if (_mathList != null) { - _displayList = Typesetter.CreateLine(_mathList, - TFont.LatinMath(FontSize), _typesettingContext, _style); - } - InvalidateIntrinsicContentSize(); - SetNeedsLayout(); - } - } - public bool DisplayErrorInline { get; set; } = true; - public NColor TextColor { get; set; } - private readonly TypesettingContext _typesettingContext; - public AppleMathView - (TypesettingContext typesettingContext, float fontSize) { - Layer.GeometryFlipped = true; - BackgroundColor = NColor.FromRGB(0.9f, 0.9f, 0.9f); - TextColor = NColor.Black; - FontSize = fontSize; - _typesettingContext = typesettingContext; - } - public override CGSize SizeThatFits(CGSize size) { - CGSize r; - if (_displayList != null) { - r = _displayList.DisplayBounds().Size; - r.Width += ContentInsets.Left + ContentInsets.Right; - r.Height += ContentInsets.Top + ContentInsets.Bottom; - } else { - r = new CGSize(320, 40); - } - return r; - } - public override void LayoutSubviews() { - if (_mathList != null && _displayList != null) { - float displayWidth = _displayList.Width; - var textX = TextAlignment switch - { - ColumnAlignment.Left => ContentInsets.Left, - ColumnAlignment.Center => - (Bounds.Size.Width - ContentInsets.Right - displayWidth) / 2, - ColumnAlignment.Right => - Bounds.Size.Width - ContentInsets.Right - displayWidth, - _ => 0, - }; - var availableHeight = - Bounds.Size.Height - ContentInsets.Top - ContentInsets.Bottom; - var contentHeight = - Math.Max(_displayList.Ascent + _displayList.Descent, FontSize / 2); - var textY = - (availableHeight - contentHeight) / 2 - + ContentInsets.Bottom + _displayList.Descent; - _displayList.Position = new System.Drawing.PointF((float)textX, (float)textY); - } - } - public override void Draw(CGRect rect) { - base.Draw(rect); - var cgContext = UIGraphics.GetCurrentContext(); - if (_mathList != null && _displayList != null) { - cgContext.SaveState(); - cgContext.SetStrokeColor(TextColor.CGColor); - cgContext.SetFillColor(TextColor.CGColor); - _displayList.Draw(new AppleGraphicsContext(cgContext)); - cgContext.RestoreState(); - } else if (ErrorMessage != null) { - cgContext.SaveState(); - float errorFontSize = 20; - cgContext.TextPosition = new CGPoint(0, Bounds.Size.Height - errorFontSize); - new CTLine(new NSAttributedString(ErrorMessage, new UIStringAttributes { - ForegroundColor = NColor.Red, - Font = UIFont.SystemFontOfSize(errorFontSize), - })).Draw(cgContext); - cgContext.RestoreState(); - } - } - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/BackEnd/AppleFontMeasurer.cs b/CSharpMath.Apple/BackEnd/AppleFontMeasurer.cs deleted file mode 100644 index 023aabec5..000000000 --- a/CSharpMath.Apple/BackEnd/AppleFontMeasurer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace CSharpMath.Apple { - public class AppleFontMeasurer : Display.FrontEnd.IFontMeasurer { - private AppleFontMeasurer() { } - public static AppleFontMeasurer Instance { get; } = new AppleFontMeasurer(); - public int GetUnitsPerEm(AppleMathFont font) => (int)font.CtFont.UnitsPerEmMetric; - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/BackEnd/AppleGlyphBoundsProvider.cs b/CSharpMath.Apple/BackEnd/AppleGlyphBoundsProvider.cs deleted file mode 100644 index 71f44661d..000000000 --- a/CSharpMath.Apple/BackEnd/AppleGlyphBoundsProvider.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using CoreGraphics; -using CoreText; -using CSharpMath.Display; -using CSharpMath.Display.FrontEnd; -using TGlyph = System.UInt16; -using TFont = CSharpMath.Apple.AppleMathFont; - -namespace CSharpMath.Apple { - public class AppleGlyphBoundsProvider: IGlyphBoundsProvider { - private AppleGlyphBoundsProvider() { } - public static AppleGlyphBoundsProvider Instance { get; } = new AppleGlyphBoundsProvider(); - public (IEnumerable Advances, float Total) GetAdvancesForGlyphs - (TFont font, IEnumerable glyphs, int nGlyphs) { - using var glyphArray = new Structures.RentedArray(glyphs, nGlyphs); - var advanceSizes = new CGSize[nGlyphs]; - var combinedAdvance = font.CtFont.GetAdvancesForGlyphs - (CTFontOrientation.Default, glyphArray.Result.Array, advanceSizes, nGlyphs); - return (advanceSizes.Select(advance => (float)advance.Width), (float)combinedAdvance); - } - public IEnumerable GetBoundingRectsForGlyphs(TFont font, IEnumerable glyphs, int nVariants) { - using var glyphArray = new Structures.RentedArray(glyphs, nVariants); - var rects = new CGRect[nVariants]; - font.CtFont.GetBoundingRects(CTFontOrientation.Horizontal, glyphArray.Result.Array, rects, nVariants); - return rects.Select(rect => (RectangleF)rect); - } - public float GetTypographicWidth(TFont font, AttributedGlyphRun run) { - using var aString = run.ToNsAttributedString(); - using var ctLine = new CTLine(aString); - return (float)ctLine.GetTypographicBounds(); - } - } -} diff --git a/CSharpMath.Apple/BackEnd/AppleGlyphNameProvider.cs b/CSharpMath.Apple/BackEnd/AppleGlyphNameProvider.cs deleted file mode 100644 index 556c5611c..000000000 --- a/CSharpMath.Apple/BackEnd/AppleGlyphNameProvider.cs +++ /dev/null @@ -1,11 +0,0 @@ -using CoreGraphics; -using TGlyph = System.UInt16; -namespace CSharpMath.Apple { - public class AppleGlyphNameProvider : Display.FrontEnd.IGlyphNameProvider { - private readonly CGFont _cgFont; - public AppleGlyphNameProvider(CGFont someCgFontSizeIrrelevant) => - _cgFont = someCgFontSizeIrrelevant; - public TGlyph GetGlyph(string glyphName) => _cgFont.GetGlyphWithGlyphName(glyphName); - public string GetGlyphName(TGlyph glyph) => _cgFont.GlyphNameForGlyph(glyph); - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/BackEnd/AppleGraphicsContext.cs b/CSharpMath.Apple/BackEnd/AppleGraphicsContext.cs deleted file mode 100644 index 68bdbf5eb..000000000 --- a/CSharpMath.Apple/BackEnd/AppleGraphicsContext.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using CoreGraphics; -using CoreText; -using CSharpMath.Display; -using TFont = CSharpMath.Apple.AppleMathFont; -using TGlyph = System.UInt16; - -namespace CSharpMath.Apple { - public class AppleGraphicsContext : Display.FrontEnd.IGraphicsContext { - public AppleGraphicsContext(CGContext cgContext) => CgContext = cgContext; - public CGContext CgContext { get; set; } - public void DrawGlyphsAtPoints - (IReadOnlyList glyphs, TFont font, IEnumerable points, Color? color) { - if (color.HasValue) CgContext.SetFillColor(color.GetValueOrDefault().ToCGColor()); - font.CtFont.DrawGlyphs(CgContext, glyphs.ToArray(), points.Select(p => (CGPoint)p).ToArray()); - } - - public void DrawLine(float x1, float y1, float x2, float y2, float lineThickness, Color? color) { - CgContext.SetLineWidth(lineThickness); - CgContext.SetLineCap(CGLineCap.Round); - if (color.HasValue) CgContext.SetStrokeColor(color.GetValueOrDefault().ToCGColor()); - CgContext.AddLines(new[] { new CGPoint(x1, y1), new CGPoint(x2, y2) }); - CgContext.StrokePath(); - } - - public void DrawGlyphRunWithOffset(AttributedGlyphRun run, PointF offset, Color? color) { - CgContext.TextPosition = new CGPoint - (CgContext.TextPosition.X + offset.X, CgContext.TextPosition.Y + offset.Y); - if (color.HasValue) CgContext.SetFillColor(color.GetValueOrDefault().ToCGColor()); - using var textLine = new CTLine(run.ToNsAttributedString()); - textLine.Draw(CgContext); - } - - public void FillRect(RectangleF rect, Color color) { - CgContext.SetFillColor(color.ToCGColor()); - CgContext.FillRect(new CGRect(rect.X, rect.Y, rect.Width, rect.Height)); - } - - public void RestoreState() { - CgContext.RestoreState(); - } - - public void SaveState() { - CgContext.SaveState(); - } - - public void SetTextPosition(PointF position) { - CgContext.TextPosition = position; - } - - public void Translate(PointF dxy) { - CgContext.TranslateCTM(dxy.X, dxy.Y); - } - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/BackEnd/AppleMathFont.cs b/CSharpMath.Apple/BackEnd/AppleMathFont.cs deleted file mode 100644 index 61cf2f954..000000000 --- a/CSharpMath.Apple/BackEnd/AppleMathFont.cs +++ /dev/null @@ -1,38 +0,0 @@ -using CoreGraphics; -using CoreText; - -namespace CSharpMath.Apple { - /// Corresponds to MTFont in iosMath. - public struct AppleMathFont : Display.FrontEnd.IFont { - public float PointSize { get; } - public CGFont CgFont { get; private set; } - public CTFont CtFont { get; private set; } - public string Name { get; private set; } - internal AppleMathFont(string name, CGFont cgFont, float size) { - PointSize = size; - Name = name; - CgFont = cgFont; - CtFont = new CTFont(CgFont, size, CGAffineTransform.MakeIdentity()); - } - public AppleMathFont(AppleMathFont cloneMe, float pointSize) { - PointSize = pointSize; - Name = cloneMe.Name; - CgFont = cloneMe.CgFont; - CtFont = new CTFont(CgFont, pointSize, CGAffineTransform.MakeIdentity()); - } - private const string LatinMathFontName = "latinmodern-math"; - static AppleMathFont() { - using var fontDataProvider = new CGDataProvider( - Foundation.NSData.FromStream( - new Resources.ManifestResourceProvider( - System.Reflection.Assembly.GetExecutingAssembly() - ).ManifestStream(LatinMathFontName + ".otf") - ) - ); - LatinMathCG = CGFont.CreateFromProvider(fontDataProvider); - } - public static CGFont LatinMathCG { get; } - public static AppleMathFont LatinMath(float pointSize) => - new AppleMathFont(LatinMathFontName, LatinMathCG, pointSize); - } -} diff --git a/CSharpMath.Apple/BackEnd/AppleTypesetters.cs b/CSharpMath.Apple/BackEnd/AppleTypesetters.cs deleted file mode 100644 index 319fc4f11..000000000 --- a/CSharpMath.Apple/BackEnd/AppleTypesetters.cs +++ /dev/null @@ -1,18 +0,0 @@ -using CSharpMath.Display.FrontEnd; -using TGlyph = System.UInt16; - -namespace CSharpMath.Apple { - public static class AppleTypesetters { - public static TypesettingContext LatinMath { get; } = - new TypesettingContext( - (font, size) => new AppleMathFont(font, size), - AppleGlyphBoundsProvider.Instance, - CtFontGlyphFinder.Instance, - new JsonMathTable( - AppleFontMeasurer.Instance, - Resources.ManifestResources.LatinMath, - new AppleGlyphNameProvider(AppleMathFont.LatinMath(20).CgFont), - AppleGlyphBoundsProvider.Instance) - ); - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/BackEnd/CtFontGlyphFinder.cs b/CSharpMath.Apple/BackEnd/CtFontGlyphFinder.cs deleted file mode 100644 index 026ef06bd..000000000 --- a/CSharpMath.Apple/BackEnd/CtFontGlyphFinder.cs +++ /dev/null @@ -1,40 +0,0 @@ -using CSharpMath.Display.FrontEnd; -using TFont = CSharpMath.Apple.AppleMathFont; -using TGlyph = System.UInt16; -using System.Globalization; -using System.Collections.Generic; - -namespace CSharpMath.Apple { - public class CtFontGlyphFinder : IGlyphFinder { - private CtFontGlyphFinder() { } - public static CtFontGlyphFinder Instance { get; } = new CtFontGlyphFinder(); - public IEnumerable FindGlyphs(TFont font, string str) { - // not completely sure this is correct. Need an actual - // example of a composed character sequence coming from LaTeX. - var unicodeIndexes = StringInfo.ParseCombiningCharacters(str); - foreach (var index in unicodeIndexes) { - yield return FindGlyphForCharacterAtIndex(font, index, str); - } - } - public bool GlyphIsEmpty(TGlyph glyph) => glyph == 0; - public TGlyph EmptyGlyph => 0; - public TGlyph FindGlyphForCharacterAtIndex(TFont font, int index, string str) { - var unicodeIndices = StringInfo.ParseCombiningCharacters(str); - int start = 0; - int end = str.Length; - foreach (var unicodeIndex in unicodeIndices) { - if (unicodeIndex <= index) { - start = unicodeIndex; - } else { - end = unicodeIndex; - break; - } - } - int length = end - start; - TGlyph[] glyphs = new TGlyph[length]; - font.CtFont.GetGlyphsForCharacters( - str.Substring(start, length).ToCharArray(), glyphs, length); - return glyphs[0]; - } - } -} diff --git a/CSharpMath.Apple/BackEnd/IFontMeasurer.cs b/CSharpMath.Apple/BackEnd/IFontMeasurer.cs deleted file mode 100644 index a32602cd9..000000000 --- a/CSharpMath.Apple/BackEnd/IFontMeasurer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace CSharpMath.Display.FrontEnd { - public interface IFontMeasurer where TFont: IFont { - /// A proportionality constant that is applied when - /// reading from the Json table. - int GetUnitsPerEm(TFont font); - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/BackEnd/IGlyphNameProvider.cs b/CSharpMath.Apple/BackEnd/IGlyphNameProvider.cs deleted file mode 100644 index 0918bf91d..000000000 --- a/CSharpMath.Apple/BackEnd/IGlyphNameProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace CSharpMath.Display.FrontEnd { - /// - /// The names provided by this class are used to lookup spacings in JsonMathTable.cs. - /// - public interface IGlyphNameProvider { - string GetGlyphName(TGlyph glyph); - TGlyph GetGlyph(string glyphName); - } -} diff --git a/CSharpMath.Apple/CSharpMath.Apple.projitems b/CSharpMath.Apple/CSharpMath.Apple.projitems deleted file mode 100644 index 2d0cd4e8e..000000000 --- a/CSharpMath.Apple/CSharpMath.Apple.projitems +++ /dev/null @@ -1,36 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - {1E62C0F0-B5C9-430E-ADDC-6F6EC6E0BDE1} - - - CSharpMath.Apple - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/CSharpMath.Apple/Extensions/AttributedGlyphRun.cs b/CSharpMath.Apple/Extensions/AttributedGlyphRun.cs deleted file mode 100644 index 6aede1974..000000000 --- a/CSharpMath.Apple/Extensions/AttributedGlyphRun.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Globalization; -using CoreText; -using CSharpMath.Display; -using Foundation; -using TFont = CSharpMath.Apple.AppleMathFont; -using TGlyph = System.UInt16; - -namespace CSharpMath.Apple { - public static partial class Extensions { - public static NSMutableAttributedString ToNsAttributedString - (this AttributedGlyphRun glyphRun) { - var text = glyphRun.Text.ToString(); - var unicodeIndexes = StringInfo.ParseCombiningCharacters(text); - var attributedString = new NSMutableAttributedString(text, new CTStringAttributes { - ForegroundColorFromContext = true, - Font = glyphRun.Font.CtFont - }); - var kernedGlyphs = glyphRun.GlyphInfos; - for (int i = 0; i < kernedGlyphs.Count; i++) { - var range = new NSRange(unicodeIndexes[i], - (i < unicodeIndexes.Length - 1 ? unicodeIndexes[i + 1] : text.Length) - - unicodeIndexes[i]); - if (kernedGlyphs[i].KernAfterGlyph is var kern && !(kern is 0)) - attributedString.AddAttribute - (CTStringAttributeKey.KerningAdjustment, new NSNumber(kern), range); - if (kernedGlyphs[i].Foreground is System.Drawing.Color foreground) - attributedString.AddAttribute(CTStringAttributeKey.ForegroundColor, - ObjCRuntime.Runtime.GetNSObject(foreground.ToCGColor().Handle), range); - } - return attributedString; - } - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/Extensions/Color.cs b/CSharpMath.Apple/Extensions/Color.cs deleted file mode 100644 index 828c7de96..000000000 --- a/CSharpMath.Apple/Extensions/Color.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace CSharpMath.Apple { - using System.Drawing; - partial class Extensions { - public static CoreGraphics.CGColor ToCGColor(this Color color) => - new CoreGraphics.CGColor(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f); - public static UIKit.UIColor ToUIColor(this Color color) => - new UIKit.UIColor(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f); - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/Resources/AssemblyExtensions.cs b/CSharpMath.Apple/Resources/AssemblyExtensions.cs deleted file mode 100644 index ba2c465e2..000000000 --- a/CSharpMath.Apple/Resources/AssemblyExtensions.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; - -namespace CSharpMath.Resources { - public static class Extensions { - public static string? ManifestResourcePrefix(this Assembly assembly) { - string? r = null; - const string resourceString = ".Resources."; - int resourcesStringLength = resourceString.Length; - foreach (string name in assembly.GetManifestResourceNames()) { - int resIndex = name.LastIndexOf(resourceString, StringComparison.OrdinalIgnoreCase); - if (resIndex > 0) { - int resEndIndex = resIndex + resourcesStringLength; - r = name.Substring(0, resEndIndex); - break; - } - } - return r; - } - public static List ManifestEntriesWithPrefix - (this Assembly assembly, string prefix -#if DEBUG - , bool recursingIsOK = true -#endif - ) { - var r = new List(); - var namePrefix = assembly.ManifestResourcePrefix(); - if (namePrefix != null) { - int resEndIndex = namePrefix.Length; - string[] names = assembly.GetManifestResourceNames(); - string fullPrefix = namePrefix + prefix; - foreach (string name in names) { - if (name.StartsWith(fullPrefix, StringComparison.OrdinalIgnoreCase)) { - string removeMyName = name.Substring(resEndIndex); - r.Add(removeMyName); - } - } -#if DEBUG - if (r.Count == 0) { - string errorMessage; - if (fullPrefix.ToLowerInvariant().IndexOf("resources.resources.resources", StringComparison.OrdinalIgnoreCase) != -1) { - errorMessage = prefix + " not found! Input path should not start with 'Resources' as that is added in this method."; - } else { - errorMessage = prefix + " not found! Probably either an incorrect path or incorrect resource type (should be EmbeddedResource)."; - } - - if (recursingIsOK) { - int length = prefix.Length; - while (length > 1) { - length--; - string shorterPrefix = prefix.Substring(0, length); - var shorterList = assembly.ManifestEntriesWithPrefix(shorterPrefix, false); - if (shorterList.Count > 1) { - string firstPartial = shorterList[0]; - } - } - if (length == 1) { - throw new FileNotFoundException("No matches found, even of the first character", prefix); - } - } - throw new FileNotFoundException(errorMessage); - } -#endif - } - return r; - } - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/Resources/ManifestResourceProvider.cs b/CSharpMath.Apple/Resources/ManifestResourceProvider.cs deleted file mode 100644 index 1dafa2b31..000000000 --- a/CSharpMath.Apple/Resources/ManifestResourceProvider.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.IO; -using System.Reflection; - -namespace CSharpMath.Resources { - public class ManifestResourceProvider { - private readonly Assembly _resourceAssembly; - /// Pass in the assembly where the resources are stored. - public ManifestResourceProvider(Assembly resourceAssembly) => - _resourceAssembly = resourceAssembly; - public Stream? ManifestStream(string resourceName) => - _resourceAssembly.GetManifestResourceStream - (_resourceAssembly.ManifestResourcePrefix() + resourceName); - } -} diff --git a/CSharpMath.Apple/Resources/ManifestResources.cs b/CSharpMath.Apple/Resources/ManifestResources.cs deleted file mode 100644 index 14ac0b96a..000000000 --- a/CSharpMath.Apple/Resources/ManifestResources.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Newtonsoft.Json.Linq; -using System.IO; - -namespace CSharpMath.Resources { - public static class ManifestResources { - private static JToken? _latinMath; - internal static Stream LatinMathContent => - new ManifestResourceProvider(System.Reflection.Assembly.GetExecutingAssembly()) - .ManifestStream("latinmodern-math.json") - ?? throw new Structures.InvalidCodePathException("Failed to load Latin Modern Math"); - public static JToken LatinMath { - get { - if (_latinMath is null) { - using var textReader = new StreamReader(LatinMathContent); - using var reader = new Newtonsoft.Json.JsonTextReader(textReader); - _latinMath = - new Newtonsoft.Json.JsonSerializer().Deserialize(reader).Root; - } - return _latinMath; - } - } - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/Resources/latinmodern-math.json b/CSharpMath.Apple/Resources/latinmodern-math.json deleted file mode 100644 index f1db31b53..000000000 --- a/CSharpMath.Apple/Resources/latinmodern-math.json +++ /dev/null @@ -1,5662 +0,0 @@ -{ - "italic" : { - "uni23DE.h3" : 28, - "u1D72C.sts" : 151, - "udieresis" : 7, - "u1D71B" : 17, - "uhungarumlaut" : 7, - "uni2231" : 361, - "u1D44C.st" : 209, - "u1D62B" : 84, - "acircumflextilde.st" : 3, - "uni2A11.v1" : 591, - "u1D44B" : 51, - "u1D738" : 55, - "uhorntilde.st" : 37, - "shade" : 28, - "u1D44D.st" : 47, - "u1D720" : 43, - "u1D648" : 76, - "u1D744.st" : 3, - "uni23E1.h1" : 28, - "acircumflexdotbelow.st" : 3, - "u1D630" : 50, - "Uhorn" : 4, - "u1D5B7" : 13, - "u1D69F" : 3, - "alpha.st" : 8, - "u1D6FE" : 53, - "bracketleft" : 6, - "u1D56E.st" : 3, - "u1D7C5" : 52, - "Uhornhookabove" : 4, - "u1D450" : 25, - "uhornacute.sts" : 10, - "u1D586" : 13, - "u1D441.sts" : 41, - "u1D580.st" : 17, - "Racute.st" : 16, - "u1D50E" : 50, - "u1D794" : 105, - "ncaron" : 7, - "u1D449.sts" : 200, - "Uhorntilde" : 4, - "aring" : 11, - "registered.sts" : 28, - "uni23DF.h6" : 28, - "u1D44A.sts" : 98, - "u1D62C" : 82, - "u1D746.st" : 4, - "uni23B4.h5" : 28, - "aogonek" : 11, - "u1D44C" : 209, - "u1D513" : 9, - "u1D475.sts" : 60, - "u1D46A.sts" : 18, - "u1D65A" : 59, - "u1D739" : 19, - "u1D747.st" : 50, - "u1D721" : 60, - "u1D481.sts" : 14, - "u1D649" : 76, - "u1D73B.st" : 18, - "u1D631" : 46, - "dcaron" : 46, - "u1D47A" : 49, - "u1D5B8" : 24, - "u1D47E.sts" : 136, - "u1D6FF" : 36, - "uhornhookabove.sts" : 10, - "u1D469" : 16, - "u1D7C6" : 59, - "u1D451" : 24, - "u1D677" : 5, - "uni23DF.h1" : 28, - "u1D73C.st" : 10, - "u1D50F" : 7, - "u1D795" : 106, - "Chi" : 4, - "uni2232" : 350, - "u1D41F" : 114, - "iota" : 24, - "emdash.alt" : 27, - "u1D71D" : 16, - "u1D749.st" : 100, - "uni23DC.h4" : 28, - "u1D62D" : 93, - "u1D509.st" : 12, - "u1D604" : 3, - "u1D44D" : 68, - "uni22C4" : 8, - "copyleft.sts" : 28, - "u1D65B" : 217, - "u1D424" : 8, - "mu.st" : 8, - "u1D722" : 73, - "u1D632" : 42, - "u1D47B" : 163, - "Yacute" : 16, - "f_f" : 73, - "u1D7C7" : 27, - "u1D6CA.sts" : 6, - "Ygrave.st" : 3, - "u1D660" : 72, - "uni222C" : 332, - "uhorngrave.sts" : 10, - "u1D466.st" : 9, - "u1D796" : 76, - "u1D6F5.sts" : 123, - "u1D6EA.sts" : 11, - "itilde.st" : 51, - "u1D480" : 228, - "u1D70F.sts" : 39, - "u1D71E" : 148, - "uni23B5.h3" : 28, - "copyright" : 28, - "u1D62E" : 17, - "uni23DD.h7" : 28, - "acircumflex.st" : 3, - "u1D6FE.sts" : 4, - "Uhornacute" : 4, - "u1D467.st" : 3, - "u1D72F.sts" : 163, - "f_k" : 3, - "u1D7AB" : 42, - "yen.st" : 3, - "u1D65C" : 99, - "integralbt" : 591, - "u1D723" : 5, - "u1D56C" : 8, - "uni212D" : 29, - "icircumflex.st" : 19, - "amacron.st" : 3, - "u1D633" : 110, - "u1D5CB" : 13, - "u1D47C" : 105, - "lcaron.st" : 47, - "u1D74F.sts" : 38, - "uni27E6.v5" : 5, - "u1D68A" : 22, - "bracketleft.v4" : 4, - "u1D7C8" : 29, - "uni23E0.h5" : 28, - "u1D453" : 90, - "recipe" : 24, - "u1D59A" : 44, - "u1D6D8" : 29, - "u1D7B0" : 41, - "uni23DD.h2" : 28, - "u1D661" : 106, - "u1D7D5.st" : 5, - "u1D571" : 41, - "u1D797" : 53, - "u1D5D0" : 13, - "u1D754.st" : 4, - "asciitilde.st" : 27, - "uni2233" : 350, - "u1D481" : 60, - "iota.st" : 7, - "adieresis" : 11, - "u1D62F" : 16, - "bracketleft.v6" : 9, - "dotlessi.ssbo" : 56, - "q.st" : 9, - "ohorntilde.st" : 7, - "u1D45E.st" : 15, - "u1D44F" : 14, - "u1D74D" : 3, - "u1D7AC" : 67, - "gbreve.st" : 4, - "u1D65D" : 42, - "utilde" : 7, - "uni00B5" : 6, - "u1D426" : 5, - "u1D724" : 83, - "u1D470.st" : 61, - "u1D57F.st" : 6, - "u1D5CC" : 5, - "u1D634" : 79, - "chi.st" : 8, - "u1D47D" : 235, - "u1D45F.st" : 10, - "dkshade" : 28, - "u1D470.sts" : 22, - "uni2231.v1" : 591, - "u1D7C9" : 57, - "u1D6EA" : 85, - "u1D454" : 25, - "u1D46D.sts" : 146, - "u1D7B1" : 66, - "endash" : 27, - "u1D662" : 42, - "u1D471.st" : 77, - "uni222D" : 332, - "u1D798" : 76, - "chi" : 24, - "u1D5D1" : 27, - "Itilde.st" : 6, - "uni23DE.h5" : 28, - "u1D690" : 12, - "u1D517.st" : 8, - "underscore" : 28, - "f_f.sts" : 59, - "u1D472.st" : 46, - "asciicircum.sts" : 33, - "u1D7AD" : 53, - "u1D517" : 35, - "u1D65E" : 109, - "u1D518.st" : 23, - "u1D427" : 4, - "u1D725" : 60, - "u1D56E" : 34, - "uni23E1.h3" : 28, - "atilde" : 11, - "SF010000" : 48, - "u1D635" : 77, - "u1D47E" : 142, - "itilde.sts" : 34, - "ordmasculine" : 5, - "lcaron.sts" : 24, - "uhorngrave" : 43, - "u1D6EB" : 68, - "u1D7B2" : 5, - "Yacute.st" : 3, - "u1D474.st" : 84, - "u1D663" : 42, - "u1D6C2" : 30, - "abrevedotbelow" : 11, - "u1D799" : 104, - "f_f.st" : 65, - "u1D5D2" : 13, - "uni222F.v1" : 591, - "u1D483" : 13, - "SF080000" : 48, - "u1D6D8.sts" : 5, - "u1D6CD.sts" : 6, - "u1D691" : 15, - "u1D475.st" : 91, - "u1D6F0" : 5, - "abrevegrave.st" : 3, - "u1D6E4.sts" : 106, - "u1D50E.st" : 24, - "lambda.st" : 38, - "u1D715.sts" : 21, - "uni23B4.h7" : 28, - "u1D74F.st" : 54, - "u1D74F" : 57, - "uni22C6" : 25, - "u1D721.sts" : 14, - "u1D6ED.sts" : 35, - "u1D518" : 49, - "u1D7AE" : 31, - "u1D65F" : 102, - "u1D71E.sts" : 146, - "u1D46A.st" : 51, - "u1D6C2.st" : 26, - "u1D636" : 40, - "u1D47F" : 34, - "gcommaaccent.st" : 4, - "u1D68D" : 15, - "married.sts" : 99, - "u1D749.sts" : 67, - "nacute" : 7, - "u1D477.st" : 160, - "u1D59D" : 19, - "u1D754" : 13, - "u1D7B3" : 4, - "u1D664" : 53, - "uni23DF.h3" : 28, - "uni23B4.h2" : 28, - "yen" : 16, - "u1D484" : 26, - "iacute" : 13, - "uni23DC.h6" : 28, - "uni2A11" : 361, - "u1D70A" : 12, - "u1D6F1" : 77, - "u1D46C.st" : 27, - "u1D61A" : 79, - "threequartersemdash" : 27, - "u1D609" : 57, - "u1D52A" : 19, - "u1D599.st" : 11, - "u1D7AF" : 24, - "u1D519" : 23, - "u1D479.st" : 37, - "u1D46D.st" : 154, - "u1D727" : 102, - "uni03F5" : 35, - "abrevetilde" : 11, - "u1D5CF" : 13, - "u1D411" : 23, - "u1D637" : 107, - "uni2A0C.v1" : 591, - "u1D447.sts" : 123, - "u1D43C.sts" : 11, - "leaf" : 39, - "u1D453.sts" : 36, - "u1D6ED" : 102, - "uni23DC.h1" : 28, - "u1D457" : 13, - "u1D755" : 8, - "u1D665" : 50, - "u1D485" : 22, - "u1D480.st" : 239, - "udotbelow" : 7, - "uni23B5.h5" : 28, - "u1D46F.st" : 55, - "acircumflexhookabove.st" : 3, - "u1D6F2" : 140, - "u1D70B" : 25, - "u1D487.sts" : 51, - "u1D47C.sts" : 60, - "u1D61B" : 137, - "u1D52B" : 23, - "u1D481.st" : 47, - "u1D51A.st" : 11, - "abrevedotbelow.st" : 3, - "u1D43B" : 78, - "umacron" : 7, - "u1D728" : 105, - "asciitilde.sts" : 27, - "u1D710" : 12, - "u1D638" : 107, - "uni23E0" : 28, - "uni27E6.v7" : 6, - "u1D620" : 172, - "u1D6EE" : 106, - "uni23E0.h7" : 28, - "u1D458" : 15, - "endash.st" : 19, - "u1D7B5" : 4, - "uni222F" : 332, - "u1D440" : 102, - "u1D666" : 58, - "uni23DD.h4" : 28, - "Rcommaaccent" : 24, - "u1D576" : 52, - "u1D483.st" : 4, - "u1D694" : 11, - "u1D70C" : 13, - "u1D6F3" : 5, - "dotlessi.sso" : 39, - "u1D61C" : 81, - "uni27E6.v2" : 6, - "u1D484.st" : 20, - "copyleft.st" : 28, - "u1D43C" : 85, - "SF020000" : 48, - "uni23E0.h2" : 28, - "u1D729" : 54, - "u1D64A" : 54, - "uni2581" : 28, - "u1D639" : 104, - "contourintegral.v1" : 591, - "u1D70D.sts" : 4, - "u1D485.st" : 18, - "u1D621" : 119, - "u1D46A" : 66, - "u1D724.sts" : 22, - "u1D6EF" : 63, - "u1D531" : 44, - "dcaron.sts" : 16, - "u1D7B6" : 59, - "u1D730.sts" : 158, - "published.st" : 28, - "u1D441" : 106, - "u1D667" : 108, - "abrevehookabove" : 11, - "abrevetilde.st" : 3, - "u1D5FF" : 12, - "Ygrave" : 16, - "abrevegrave" : 11, - "u1D577" : 6, - "asciitilde" : 27, - "u1D59A.st" : 13, - "u1D738.sts" : 28, - "uni23DE.h7" : 28, - "u1D47A.st" : 34, - "u1D487" : 86, - "uni2A0C" : 332, - "uogonek" : 27, - "u1D70D" : 74, - "ydieresis" : 8, - "u1D6F4" : 54, - "u1D531.st" : 18, - "u1D61D" : 161, - "emdash" : 27, - "u1D487.st" : 78, - "u1D411.st" : 19, - "u1D47B.st" : 169, - "u1D43D" : 106, - "u1D73B" : 42, - "u1D504" : 20, - "u1D64B" : 75, - "uhorn.st" : 37, - "uni23E1" : 28, - "uni23E1.h5" : 28, - "u1D488.st" : 4, - "ahookabove.st" : 3, - "u1D622" : 21, - "u1D46B" : 5, - "u1D41F.sts" : 115, - "u1D47C.st" : 90, - "uni23DE.h2" : 28, - "u1D532" : 25, - "yhookabove" : 8, - "u1D436.sts" : 7, - "lambda" : 54, - "u1D442" : 5, - "u1D668" : 75, - "u1D650" : 76, - "u1D578" : 21, - "u1D47D.st" : 249, - "atilde.st" : 3, - "u1D488" : 17, - "u1D470" : 83, - "lacute.st" : 17, - "u1D696" : 19, - "u1D6F5" : 148, - "R.st" : 16, - "registered.st" : 28, - "u1D70E" : 24, - "u1D61E" : 161, - "u1D45F.sts" : 9, - "u1D47E.st" : 145, - "u1D6CA.st" : 25, - "u1D43E" : 68, - "u1D73C" : 22, - "yacute" : 8, - "u1D64C" : 54, - "u1D490.st" : 3, - "u1D713" : 12, - "uni2232.v1" : 591, - "dcaron.st" : 39, - "u1D47F.st" : 11, - "u1D623" : 46, - "integral" : 332, - "u1D46C" : 43, - "u1D6CB.st" : 25, - "u1D7B8" : 29, - "uni23DF.h5" : 28, - "u1D443" : 140, - "u1D669" : 70, - "u1D491.st" : 4, - "u1D7A0" : 75, - "u1D651" : 143, - "u1D579" : 14, - "u1D49A" : 20, - "uni222C.v1" : 591, - "u1D6D8.st" : 25, - "u1D701.st" : 34, - "uni23B4.h4" : 28, - "u1D6CC.st" : 65, - "u1D5C0" : 13, - "Ydieresis" : 16, - "u1D471" : 91, - "u1D697" : 15, - "u1D70F" : 102, - "divorced.st" : 230, - "u1D6F6" : 146, - "adotbelow" : 11, - "u1D492.st" : 16, - "u1D61F" : 119, - "Itilde" : 15, - "u1D52F" : 34, - "u1D702.st" : 6, - "u1D6CD.st" : 25, - "u1D73D" : 13, - "uni2111" : 7, - "u1D6C2.sts" : 6, - "u1D64D" : 77, - "u1D416" : 3, - "u1D714" : 10, - "u1D624" : 83, - "u1D6CB.sts" : 6, - "u1D46D" : 148, - "abrevehookabove.st" : 3, - "uni23DC.h3" : 28, - "u1D7B9" : 57, - "u1D742" : 54, - "registered" : 28, - "u1D58B" : 28, - "ohorndotbelow.st" : 7, - "u1D5EA" : 3, - "u1D7A1" : 53, - "u1D652" : 145, - "u1D6F6.sts" : 116, - "u1D49B" : 11, - "asciicircum.st" : 33, - "kappa" : 23, - "u1D727.sts" : 47, - "idieresis.st" : 13, - "u1D472" : 60, - "uhorntilde" : 43, - "uni2145" : 15, - "u1D6F7" : 4, - "Rcaron" : 24, - "u1D733.sts" : 73, - "uni23B5.h7" : 28, - "f.sts" : 58, - "uni03D1" : 21, - "SF100000" : 48, - "u1D747.sts" : 14, - "uni23DC" : 28, - "u1D420.st" : 5, - "u1D64E" : 68, - "emdash.st" : 11, - "asciitilde.low" : 27, - "u1D52F.st" : 7, - "u1D715" : 63, - "u1D625" : 93, - "longs.st" : 72, - "aogonek.st" : 7, - "u1D411.sts" : 7, - "u1D535" : 10, - "u1D67C" : 10, - "uni23B5.h2" : 28, - "uni20EB" : 31, - "u1D445" : 24, - "u1D743" : 11, - "u1D7A2" : 106, - "uni23DD.h6" : 28, - "u1D653" : 88, - "u1D41A.sts" : 6, - "Imacron.st" : 21, - "u1D439.sts" : 107, - "u1D6F8" : 51, - "seven" : 13, - "u1D6E4.st" : 128, - "u1D681" : 25, - "u1D708.st" : 42, - "u1D591" : 7, - "uni27E6.v4" : 5, - "leaf.st" : 34, - "integral.v1" : 591, - "uni23E0.h4" : 28, - "uhorndotbelow.sts" : 10, - "u1D508" : 7, - "ohorngrave" : 16, - "u1D64F" : 126, - "u1D418" : 8, - "u1D709.st" : 4, - "uni23DD.h1" : 28, - "u1D471.sts" : 50, - "abreveacute" : 11, - "u1D626" : 55, - "u1D46F" : 73, - "uhornacute.st" : 37, - "u1D479.sts" : 15, - "u1D6DC" : 27, - "u1D446" : 60, - "u1D6E6.st" : 30, - "u1D744" : 12, - "u1D7A3" : 126, - "u1D5EC" : 3, - "u1D654" : 147, - "u1D79B" : 76, - "uhorngrave.st" : 37, - "uni03F5.st" : 18, - "uni2146" : 75, - "acircumflexacute.st" : 3, - "u1D474" : 102, - "u1D6F9" : 109, - "u1D6E7.st" : 47, - "u1D592" : 7, - "u1D60A" : 107, - "uhornacute" : 43, - "uni23DD" : 28, - "u1D51A" : 37, - "u1D509" : 38, - "u1D41A.st" : 18, - "u1D42A" : 22, - "u1D6E8.st" : 52, - "u1D6DC.st" : 17, - "R" : 24, - "Y.st" : 3, - "uni23E1.h7" : 28, - "u1D5BF" : 69, - "u1D627" : 217, - "uni23DE.h4" : 28, - "V" : 8, - "u1D6DD" : 22, - "W" : 9, - "u1D447" : 148, - "X" : 4, - "u1D6DD.st" : 13, - "u1D58E" : 24, - "Y" : 16, - "u1D745" : 14, - "u1D655" : 106, - "u1D7A4" : 88, - "u1D79C" : 76, - "u1D5C4" : 10, - "u1D475" : 105, - "u1D6F1.sts" : 6, - "uni23E1.h2" : 28, - "a" : 11, - "u1D60B" : 52, - "u1D6F9.sts" : 54, - "u1D6EE.sts" : 41, - "u1D722.sts" : 19, - "u1D51B" : 18, - "uni2113" : 9, - "uhorndotbelow.st" : 37, - "f" : 79, - "u1D72B.sts" : 17, - "g" : 13, - "Ytilde" : 16, - "abreve.st" : 3, - "h" : 7, - "u1D742.sts" : 17, - "u1D628" : 99, - "k" : 11, - "u1D610" : 81, - "u1D6F1.st" : 51, - "l" : 5, - "u1D715.st" : 52, - "m" : 8, - "u1D448" : 105, - "u1D746" : 13, - "n" : 7, - "u1D7A5" : 46, - "uni23DF.h7" : 28, - "uogonek.st" : 7, - "u1D656" : 49, - "u1D79D" : 114, - "uacute" : 7, - "q" : 27, - "ohorn.st" : 7, - "lcaron" : 52, - "u1D49A.st" : 7, - "u1D6F2.st" : 135, - "uni2147" : 17, - "u1D41F.st" : 120, - "u1D476" : 6, - "uni23B4.h6" : 28, - "u" : 7, - "u1D684" : 23, - "bracketleft.v5" : 7, - "ohorngrave.st" : 7, - "u1D6E3" : 25, - "Ytilde.st" : 3, - "adieresis.st" : 3, - "u1D60C" : 118, - "v" : 8, - "u1D5F3" : 73, - "uni23DE" : 28, - "w" : 9, - "x" : 16, - "y" : 8, - "u1D440.sts" : 35, - "u1D70B.st" : 4, - "u1D72A" : 6, - "uni23DF.h2" : 28, - "u1D719" : 5, - "u1D63A" : 107, - "u1D448.sts" : 41, - "star.alt" : 23, - "u1D43D.sts" : 46, - "u1D701" : 64, - "u1D629" : 16, - "married" : 105, - "uni23B4.h1" : 28, - "u1D6F4.st" : 31, - "bracketleft.v7" : 8, - "u1D611" : 92, - "uni23DC.h5" : 28, - "published.sts" : 28, - "u1D449" : 214, - "u1D747" : 66, - "u1D7A6" : 71, - "adotbelow.st" : 3, - "u1D431" : 6, - "u1D657" : 50, - "u1D474.sts" : 47, - "u1D79E" : 54, - "u1D6F5.st" : 143, - "u1D480.sts" : 236, - "iacute.st" : 4, - "dotlessi.fra" : 17, - "aacute" : 11, - "u1D477" : 154, - "dotlessj.ssbo" : 56, - "u1D70D.st" : 52, - "acircumflextilde" : 11, - "u1D47D.sts" : 253, - "u1D685" : 9, - "ydotbelow" : 8, - "u1D6E4" : 134, - "acircumflex" : 11, - "u1D60D" : 132, - "u1D5F4" : 12, - "u1D6F6.st" : 140, - "uni2233.v1" : 591, - "u1D6EA.st" : 58, - "u1D70E.st" : 4, - "u1D72B" : 72, - "seven.st" : 4, - "ohornacute.st" : 7, - "u1D63B" : 87, - "block" : 28, - "emdash.alt.st" : 11, - "u1D702" : 27, - "u1D720.st" : 27, - "u1D612" : 119, - "u1D6EB.st" : 47, - "ygrave" : 8, - "u1D70F.st" : 83, - "uni222D.v1" : 591, - "uni23B5.h4" : 28, - "u1D748" : 13, - "u1D7A7" : 91, - "kappa.st" : 7, - "copyright.st" : 28, - "u1D658" : 80, - "u1D436.st" : 52, - "Racute" : 24, - "u1D42A.st" : 8, - "u1D6F8.st" : 24, - "u1D640" : 105, - "u1D721.st" : 47, - "asciitilde.low.st" : 27, - "imacron" : 70, - "u1D730" : 159, - "u1D79F" : 75, - "uni2148" : 80, - "leaf.sts" : 16, - "u1D7D5" : 11, - "integraltp" : 591, - "u1D686" : 16, - "icircumflex" : 41, - "u1D60E" : 90, - "uni23DF" : 28, - "u1D6F9.st" : 93, - "u1D722.st" : 55, - "uni27E6.v6" : 6, - "u1D6ED.st" : 79, - "u1D51E" : 25, - "contourintegral" : 332, - "u1D6E8.sts" : 7, - "u1D42E" : 4, - "u1D72C" : 154, - "uni23E0.h6" : 28, - "u1D438.st" : 30, - "uni23DD.h3" : 28, - "u1D703" : 14, - "u1D725.sts" : 12, - "u1D6EE.st" : 83, - "aring.st" : 3, - "u1D45C" : 12, - "u1D523" : 23, - "u1D749" : 111, - "u1D66A" : 57, - "u1D7A8" : 70, - "u1D439.st" : 128, - "abreve" : 11, - "Rcaron.st" : 16, - "u1D659" : 106, - "ncommaaccent" : 7, - "u1D724.st" : 61, - "u1D641" : 120, - "u1D6EF.st" : 40, - "u1D6A0" : 11, - "uni27E6.v1" : 6, - "uhornhookabove.st" : 37, - "u1D479" : 37, - "Uhorngrave" : 4, - "uni23E0.h1" : 28, - "Ydotbelow" : 16, - "u1D6E6" : 54, - "u1D597" : 22, - "u1D60F" : 81, - "u1D725.st" : 46, - "abreveacute.st" : 3, - "Imacron.sts" : 6, - "u1D72D" : 5, - "u1D440.st" : 79, - "u1D63D" : 49, - "a.st" : 3, - "ntilde" : 7, - "iogonek" : 3, - "u1D614" : 75, - "u1D45D" : 15, - "u1D7BA" : 28, - "ucircumflex" : 7, - "u1D443.sts" : 110, - "u1D441.st" : 83, - "u1D66B" : 93, - "Imacron" : 29, - "u1D6CA" : 30, - "u1D7A9" : 38, - "u1D732" : 34, - "uni03D1.st" : 3, - "u1D727.st" : 84, - "uni23DE.h6" : 28, - "SF050000" : 48, - "itilde" : 56, - "u1D642" : 81, - "u1D44C.sts" : 193, - "alpha" : 24, - "longs" : 79, - "u1D48B" : 7, - "uni2149" : 80, - "u1D688" : 8, - "u1D6E7" : 68, - "u1D728.st" : 91, - "uni23E1.h4" : 28, - "u1D477.sts" : 151, - "agrave.st" : 3, - "uhorntilde.sts" : 10, - "dotlessj.sso" : 39, - "u1D580" : 49, - "Uhorndotbelow" : 4, - "threequartersemdash.st" : 16, - "uni23DE.h1" : 29, - "Ydieresis.st" : 3, - "acircumflexdotbelow" : 11, - "u1D490" : 12, - "u1D443.st" : 135, - "u1D72E" : 44, - "u1D63E" : 98, - "u1D729.st" : 38, - "uni211C" : 26, - "kcommaaccent" : 11, - "u1D615" : 79, - "u1D45E" : 34, - "u1D7BB" : 5, - "published" : 28, - "u1D66C" : 94, - "u1D6CB" : 30, - "longs.sts" : 58, - "u1D435" : 25, - "ohorntilde" : 16, - "u1D6FA.st" : 20, - "u1D71E.st" : 154, - "u1D733" : 106, - "uhorndotbelow" : 43, - "u1D643" : 76, - "Rcommaaccent.st" : 16, - "u1D6A2" : 3, - "Ydotbelow.st" : 3, - "uhorn.sts" : 10, - "u1D69A" : 40, - "u1D445.st" : 16, - "u1D463" : 11, - "u1D730.st" : 164, - "u1D6E8" : 78, - "lcommaaccent" : 5, - "u1D599" : 42, - "u1D581" : 13, - "u1D446.st" : 36, - "u1D491" : 13, - "u1D72F" : 163, - "uni23DF.h4" : 28, - "u1D63F" : 52, - "u1D6CC.sts" : 37, - "uni23B4.h3" : 28, - "u1D616" : 54, - "acircumflexacute" : 11, - "u1D45F" : 13, - "u1D447.st" : 143, - "lacute" : 26, - "u1D7BC" : 58, - "u1D43B.st" : 52, - "u1D526" : 17, - "u1D66D" : 77, - "u1D732.st" : 11, - "u1D6CC" : 73, - "ahookabove" : 11, - "u1D436" : 73, - "asciicircum" : 33, - "u1D57D" : 28, - "Yhookabove.st" : 3, - "u1D6FD.st" : 12, - "ohornhookabove.st" : 7, - "u1D644" : 76, - "u1D728.sts" : 60, - "u1D734" : 35, - "uni23DC.h7" : 28, - "u1D448.st" : 83, - "u1D43C.st" : 58, - "ltshade" : 28, - "u1D6FA" : 42, - "u1D464" : 3, - "u1D6FE.st" : 39, - "u1D733.st" : 98, - "u1D6E9" : 5, - "u1D7C1" : 36, - "underscore.st" : 28, - "uring" : 7, - "u1D582" : 33, - "u1D449.st" : 214, - "u1D492" : 29, - "u1D43D.st" : 85, - "u1D734.st" : 20, - "married.st" : 107, - "u1D6FF.st" : 10, - "uni23DC.h2" : 28, - "u1D41A" : 22, - "copyright.sts" : 28, - "u1D617" : 79, - "f.st" : 72, - "u1D43E.st" : 47, - "u1D7BD" : 57, - "uni23B4" : 28, - "u1D66E" : 93, - "uni23B5.h6" : 28, - "u1D6CD" : 30, - "u1D437" : 4, - "u1D645" : 76, - "u1D450.st" : 12, - "ohornacute" : 16, - "ohorn" : 16, - "u1D43B.sts" : 7, - "u1D7C2" : 36, - "u1D571.st" : 10, - "ugrave" : 7, - "underscore.sts" : 28, - "acircumflexgrave" : 11, - "aacute.st" : 3, - "u1D451.st" : 8, - "idieresis" : 27, - "u1D583" : 14, - "uni2230.v1" : 591, - "g.st" : 4, - "u1D493" : 4, - "divorced" : 216, - "u1D72B.st" : 53, - "u1D791" : 49, - "uni23B5.h1" : 28, - "u1D472.sts" : 12, - "uni2230" : 332, - "u1D708" : 58, - "gcommaaccent" : 13, - "asciitilde.low.sts" : 27, - "u1D46F.sts" : 19, - "uni23DD.h5" : 28, - "recipe.st" : 16, - "u1D618" : 54, - "u1D47B.sts" : 163, - "u1D738.st" : 49, - "u1D7BE" : 36, - "u1D72C.st" : 160, - "u1D66F" : 79, - "SF060000" : 48, - "gbreve" : 13, - "u1D438" : 54, - "u1D510" : 28, - "u1D57F" : 37, - "u1D420" : 11, - "u1D646" : 104, - "u1D453.st" : 75, - "u1D6A5" : 5, - "uni27E6.v3" : 5, - "divorced.sts" : 238, - "u1D5B5" : 13, - "uni23E0.h3" : 28, - "u1D466" : 28, - "Yhookabove" : 16, - "u1D7C3" : 48, - "u1D674" : 5, - "uhornhookabove" : 43, - "u1D454.st" : 7, - "copyleft" : 28, - "agrave" : 11, - "ytilde" : 8, - "ohornhookabove" : 16, - "acircumflexhookabove" : 11, - "u1D72E.st" : 28, - "u1D792" : 120, - "uhorn" : 43, - "u1D71A" : 13, - "mu" : 23, - "u1D709" : 36, - "u1D62A" : 92, - "u1D619" : 82, - "uni27E6" : 6, - "ohorndotbelow" : 16, - "u1D72F.st" : 169, - "dotlessi.frab" : 24, - "u1D529" : 26, - "u1D44A" : 132, - "u1D7BF" : 30, - "u1D576.st" : 21, - "uni23B5" : 28, - "u1D511" : 26, - "u1D439" : 134, - "u1D737" : 6, - "u1D421" : 4, - "u1D44A.st" : 125, - "imacron.st" : 66, - "uhookabove" : 7, - "u1D557" : 27, - "u1D5B6" : 13, - "u1D69E" : 15, - "amacron" : 11, - "u1D6F2.sts" : 110, - "u1D467" : 30, - "u1D6FD" : 36, - "acircumflexgrave.st" : 3, - "imacron.sts" : 51, - "uni23E1.h6" : 28, - "u1D44B.st" : 24, - "u1D742.st" : 44 - }, - "v_variants" : { - "uni21A1" : [ - "uni21A1", - "uni21A1.v1" - ], - "uni230A" : [ - "uni230A", - "uni230A.v1", - "uni230A.v2", - "uni230A.v3", - "uni230A.v4", - "uni230A.v5", - "uni230A.v6", - "uni230A.v7" - ], - "uni22A4" : [ - "uni22A4", - "uni27D9" - ], - "uni2A02" : [ - "uni2A02", - "uni2A02.v1" - ], - "uni21A7" : [ - "uni21A7", - "uni21A7.v1" - ], - "parenleft" : [ - "parenleft", - "parenleft.v1", - "parenleft.v2", - "parenleft.v3", - "parenleft.v4", - "parenleft.v5", - "parenleft.v6", - "parenleft.v7" - ], - "uni2A05" : [ - "uni2A05", - "uni2A05.v1" - ], - "arrowdown" : [ - "arrowdown", - "arrowdown.v1" - ], - "uni21BE" : [ - "uni21BE", - "uni21BE.v1" - ], - "uni27E8" : [ - "uni27E8", - "uni27E8.v1", - "uni27E8.v2", - "uni27E8.v3", - "uni27E8.v4", - "uni27E8.v5", - "uni27E8.v6", - "uni27E8.v7" - ], - "uni21D6" : [ - "uni21D6", - "uni21D6.v1" - ], - "uni2210" : [ - "uni2210", - "uni2210.v1" - ], - "uni2198" : [ - "uni2198", - "uni2198.v1" - ], - "angleleft" : [ - "angleleft", - "uni27E8.v1", - "uni27E8.v2", - "uni27E8.v3", - "uni27E8.v4", - "uni27E8.v5", - "uni27E8.v6", - "uni27E8.v7" - ], - "uni21D9" : [ - "uni21D9", - "uni21D9.v1" - ], - "uni22C1" : [ - "uni22C1", - "uni22C1.v1" - ], - "radical" : [ - "radical", - "radical.v1", - "radical.v2", - "radical.v3", - "radical.v4" - ], - "uni27EA" : [ - "uni27EA", - "uni27EA.v1", - "uni27EA.v2", - "uni27EA.v3", - "uni27EA.v4", - "uni27EA.v5", - "uni27EA.v6", - "uni27EA.v7" - ], - "uni222D" : [ - "uni222D", - "uni222D.v1" - ], - "uni2B0D" : [ - "uni2B0D", - "uni2B0D.v1" - ], - "uni21F3" : [ - "uni21F3", - "uni21F3.v1" - ], - "arrowdblup" : [ - "arrowdblup", - "arrowdblup.v1" - ], - "uni21B2" : [ - "uni21B2", - "uni21B2.v1" - ], - "uni2230" : [ - "uni2230", - "uni2230.v1" - ], - "bracketright" : [ - "bracketright", - "bracketright.v1", - "bracketright.v2", - "bracketright.v3", - "bracketright.v4", - "bracketright.v5", - "bracketright.v6", - "bracketright.v7" - ], - "integral" : [ - "integral", - "integral.v1" - ], - "slash" : [ - "slash", - "slash.v1", - "slash.v2", - "slash.v3", - "slash.v4", - "slash.v5", - "slash.v6", - "slash.v7" - ], - "uni2233" : [ - "uni2233", - "uni2233.v1" - ], - "uni21E7" : [ - "uni21E7", - "uni21E7.v1" - ], - "uni22A3" : [ - "uni22A3", - "uni27DE" - ], - "uni2A01" : [ - "uni2A01", - "uni2A01.v1" - ], - "backslash" : [ - "backslash", - "backslash.v1", - "backslash.v2", - "backslash.v3", - "backslash.v4", - "backslash.v5", - "backslash.v6", - "backslash.v7" - ], - "uni2A04" : [ - "uni2A04", - "uni2A04.v1" - ], - "uni27E7" : [ - "uni27E7", - "uni27E7.v1", - "uni27E7.v2", - "uni27E7.v3", - "uni27E7.v4", - "uni27E7.v5", - "uni27E7.v6", - "uni27E7.v7" - ], - "uni21D5" : [ - "uni21D5", - "uni21D5.v1" - ], - "uni2B07" : [ - "uni2B07", - "uni2B07.v1" - ], - "uni2197" : [ - "uni2197", - "uni2197.v1" - ], - "angleright" : [ - "angleright", - "uni27E9.v1", - "uni27E9.v2", - "uni27E9.v3", - "uni27E9.v4", - "uni27E9.v5", - "uni27E9.v6", - "uni27E9.v7" - ], - "uni21D8" : [ - "uni21D8", - "uni21D8.v1" - ], - "uni22C0" : [ - "uni22C0", - "uni22C0.v1" - ], - "contourintegral" : [ - "contourintegral", - "contourintegral.v1" - ], - "parallel" : [ - "parallel", - "parallel.v1", - "parallel.v2", - "parallel.v3", - "parallel.v4", - "parallel.v5", - "parallel.v6", - "parallel.v7" - ], - "uni21C3" : [ - "uni21C3", - "uni21C3.v1" - ], - "uni22C3" : [ - "uni22C3", - "uni22C3.v1" - ], - "uni222C" : [ - "uni222C", - "uni222C.v1" - ], - "bracketleft" : [ - "bracketleft", - "bracketleft.v1", - "bracketleft.v2", - "bracketleft.v3", - "bracketleft.v4", - "bracketleft.v5", - "bracketleft.v6", - "bracketleft.v7" - ], - "uni2A0C" : [ - "uni2A0C", - "uni2A0C.v1" - ], - "uni27EF" : [ - "uni27EF", - "uni27EF.v1", - "uni27EF.v2", - "uni27EF.v3", - "uni27EF.v4", - "uni27EF.v5", - "uni27EF.v6", - "uni27EF.v7" - ], - "uni222F" : [ - "uni222F", - "uni222F.v1" - ], - "uni219F" : [ - "uni219F", - "uni219F.v1" - ], - "uni21B1" : [ - "uni21B1", - "uni21B1.v1" - ], - "uni21F5" : [ - "uni21F5", - "uni21F5.v1" - ], - "uni2232" : [ - "uni2232", - "uni2232.v1" - ], - "uni2309" : [ - "uni2309", - "uni2309.v1", - "uni2309.v2", - "uni2309.v3", - "uni2309.v4", - "uni2309.v5", - "uni2309.v6", - "uni2309.v7" - ], - "parenright" : [ - "parenright", - "parenright.v1", - "parenright.v2", - "parenright.v3", - "parenright.v4", - "parenright.v5", - "parenright.v6", - "parenright.v7" - ], - "arrowdbldown" : [ - "arrowdbldown", - "arrowdbldown.v1" - ], - "arrowupdn" : [ - "arrowupdn", - "arrowupdn.v1" - ], - "uni22A2" : [ - "uni22A2", - "uni27DD" - ], - "uni2A00" : [ - "uni2A00", - "uni2A00.v1" - ], - "uni21A5" : [ - "uni21A5", - "uni21A5.v1" - ], - "uni230B" : [ - "uni230B", - "uni230B.v1", - "uni230B.v2", - "uni230B.v3", - "uni230B.v4", - "uni230B.v5", - "uni230B.v6", - "uni230B.v7" - ], - "uni22A5" : [ - "uni22A5", - "uni27D8" - ], - "uni21E9" : [ - "uni21E9", - "uni21E9.v1" - ], - "uni2A03" : [ - "uni2A03", - "uni2A03.v1" - ], - "uni27E6" : [ - "uni27E6", - "uni27E6.v1", - "uni27E6.v2", - "uni27E6.v3", - "uni27E6.v4", - "uni27E6.v5", - "uni27E6.v6", - "uni27E6.v7" - ], - "uni2A06" : [ - "uni2A06", - "uni2A06.v1" - ], - "uni21BF" : [ - "uni21BF", - "uni21BF.v1" - ], - "uni2B06" : [ - "uni2B06", - "uni2B06.v1" - ], - "uni2196" : [ - "uni2196", - "uni2196.v1" - ], - "uni27E9" : [ - "uni27E9", - "uni27E9.v1", - "uni27E9.v2", - "uni27E9.v3", - "uni27E9.v4", - "uni27E9.v5", - "uni27E9.v6", - "uni27E9.v7" - ], - "summation" : [ - "summation", - "summation.v1" - ], - "braceleft" : [ - "braceleft", - "braceleft.v1", - "braceleft.v2", - "braceleft.v3", - "braceleft.v4", - "braceleft.v5", - "braceleft.v6", - "braceleft.v7" - ], - "uni21D7" : [ - "uni21D7", - "uni21D7.v1" - ], - "uni2199" : [ - "uni2199", - "uni2199.v1" - ], - "fraction" : [ - "fraction", - "fraction.v1", - "fraction.v2", - "fraction.v3", - "fraction.v4", - "fraction.v5", - "fraction.v6", - "fraction.v7" - ], - "uni2A09" : [ - "uni2A09", - "uni2A09.v1" - ], - "product" : [ - "product", - "product.v1" - ], - "uni21C2" : [ - "uni21C2", - "uni21C2.v1" - ], - "uni22C2" : [ - "uni22C2", - "uni22C2.v1" - ], - "uni27EB" : [ - "uni27EB", - "uni27EB.v1", - "uni27EB.v2", - "uni27EB.v3", - "uni27EB.v4", - "uni27EB.v5", - "uni27EB.v6", - "uni27EB.v7" - ], - "uni21C5" : [ - "uni21C5", - "uni21C5.v1" - ], - "uni27EE" : [ - "uni27EE", - "uni27EE.v1", - "uni27EE.v2", - "uni27EE.v3", - "uni27EE.v4", - "uni27EE.v5", - "uni27EE.v6", - "uni27EE.v7" - ], - "uni21C8" : [ - "uni21C8", - "uni21C8.v1" - ], - "uni21B0" : [ - "uni21B0", - "uni21B0.v1" - ], - "arrowup" : [ - "arrowup", - "arrowup.v1" - ], - "braceright" : [ - "braceright", - "braceright.v1", - "braceright.v2", - "braceright.v3", - "braceright.v4", - "braceright.v5", - "braceright.v6", - "braceright.v7" - ], - "uni21B3" : [ - "uni21B3", - "uni21B3.v1" - ], - "dblverticalbar" : [ - "dblverticalbar", - "parallel.v1", - "parallel.v2", - "parallel.v3", - "parallel.v4", - "parallel.v5", - "parallel.v6", - "parallel.v7" - ], - "uni2231" : [ - "uni2231", - "uni2231.v1" - ], - "uni2A11" : [ - "uni2A11", - "uni2A11.v1" - ], - "uni2308" : [ - "uni2308", - "uni2308.v1", - "uni2308.v2", - "uni2308.v3", - "uni2308.v4", - "uni2308.v5", - "uni2308.v6", - "uni2308.v7" - ], - "uni21CA" : [ - "uni21CA", - "uni21CA.v1" - ], - "bar" : [ - "bar", - "divides.v1", - "divides.v2", - "divides.v3", - "divides.v4", - "divides.v5", - "divides.v6", - "divides.v7" - ], - "divides" : [ - "divides", - "divides.v1", - "divides.v2", - "divides.v3", - "divides.v4", - "divides.v5", - "divides.v6", - "divides.v7" - ] - }, - "accents" : { - "u1D688" : 262, - "u1D753.sts" : 599, - "u1D726" : 570, - "u1D430.st" : 465, - "u1D403" : 283, - "u1D570" : 598, - "u1D537.sts" : 319, - "J.st" : 363, - "u1D7CE" : 287, - "u1D429.sts" : 339, - "u1D4AB" : 480, - "u1D76F" : 458, - "u1D44C" : 399, - "u1D4E6.st" : 671, - "Mu.sts" : 594, - "u1D5A5" : 310, - "u1D40C.st" : 607, - "u1D6AA.st" : 371, - "u1D526.st" : 187, - "u1D435.sts" : 543, - "u1D546" : 333, - "u1D70E.sts" : 408, - "u1D749.st" : 362, - "u1D751" : 465, - "u1D7B0" : 459, - "Rho" : 283, - "u1D49F.st" : 532, - "u1D5EE" : 264, - "u1D6CE.sts" : 360, - "u1D58F" : 159, - "uni20ED" : -264, - "u1D71A.sts" : 469, - "u1D441.sts" : 684, - "u1D62D" : 267, - "u1D79A" : 474, - "u1D451.st" : 496, - "u1D6E8" : 542, - "u1D689" : 268, - "zeta.st" : 270, - "u1D6DA.sts" : 508, - "u1D727" : 711, - "u1D5D0" : 341, - "u1D59D.sts" : 385, - "u1D404" : 350, - "u1D571" : 292, - "u1D48F.sts" : 428, - "u1D7CF" : 295, - "u1D50A.sts" : 719, - "u1D4AC" : 482, - "u1D6CB.st" : 318, - "u1D42D.st" : 214, - "u1D44D" : 485, - "u1D739.sts" : 460, - "uni03F1" : 249, - "u1D49B.sts" : 472, - "u1D70B.st" : 384, - "u1D5A6" : 407, - "u1D7B1" : 423, - "u1D6F9.sts" : 536, - "u1D752" : 415, - "u1D57B.st" : 544, - "acute.st" : 319, - "u1D745.sts" : 527, - "u1D472.st" : 663, - "M.sts" : 594, - "u1D5EF" : 128, - "r.st" : 213, - "u1D7FA" : 323, - "u1D6B8.st" : 375, - "u1D529.sts" : 330, - "u1D62E" : 454, - "u1D750.st" : 352, - "u1D79B" : 627, - "u1D6E9" : 498, - "u1D751.sts" : 612, - "u1D4E9.sts" : 575, - "u1D5D1" : 225, - "u1D728" : 615, - "omicron.st" : 285, - "u1D535.sts" : 342, - "u1D405" : 342, - "u1D44E.st" : 325, - "Z.sts" : 424, - "u1D572" : 633, - "u1D610" : 287, - "u1D427.sts" : 354, - "u1D6EC.st" : 568, - "u1D72C.st" : 545, - "uni2131.st" : 785, - "u1D7CE.sts" : 379, - "u1D44E" : 287, - "u1D400.st" : 484, - "Mu" : 458, - "uni2128.st" : 211, - "Zeta" : 316, - "u1D59C.st" : 197, - "u1D433.sts" : 343, - "u1D5A7" : 354, - "u1D70C.sts" : 467, - "u1D493.st" : 337, - "u1D7B2" : 231, - "g.sts" : 441, - "u1D753" : 482, - "u1D6D9.st" : 458, - "u1D6CC.sts" : 187, - "u1D430" : 415, - "u1D58F.sts" : 280, - "eight" : 261, - "u1D719.st" : 471, - "u1D7FB" : 262, - "uni20EE" : -264, - "u1D62F" : 315, - "u1D79C" : 535, - "u1D46F.st" : 671, - "u1D59B.sts" : 282, - "u1D589.st" : 225, - "Theta.sts" : 513, - "uni2017" : 252, - "t.sts" : 225, - "u1D5D2" : 230, - "u1D48D.sts" : 241, - "u1D729" : 544, - "u1D74D.st" : 592, - "u1D406" : 579, - "u1D52A.st" : 389, - "u1D573" : 496, - "u1D611" : 493, - "u1D421.st" : 158, - "caron.st" : 285, - "u1D4AE" : 451, - "u1D737.sts" : 575, - "u1D44F" : 165, - "Phi.st" : 404, - "u1D65A" : 365, - "u1D4D7.st" : 814, - "u1D5A8" : 139, - "u1D6F7.sts" : 553, - "hungarumlaut.sts" : 370, - "u1D743.sts" : 409, - "u1D7B3" : 369, - "u1D754" : 400, - "u1D517.st" : 756, - "u1D431" : 296, - "u1D527.sts" : 253, - "u1D7FC" : 317, - "u1D419.sts" : 475, - "u1D79D" : 503, - "u1D47A" : 561, - "Q.st" : 438, - "u1D4E7.sts" : 663, - "dotlessj.fra" : 135, - "u1D442.st" : 552, - "u1D6E0.st" : 335, - "u1D533.sts" : 258, - "u1D5D3" : 221, - "u1D407" : 450, - "u1D574" : 400, - "u1D425.sts" : 200, - "u1D720.st" : 562, - "u1D612" : 515, - "uni03C2" : 237, - "uni2111.st" : 399, - "rho.sts" : 371, - "u1D4AF" : 500, - "u1D6BE.sts" : 537, - "u1D590.st" : 251, - "u1D6BA" : 401, - "u1D70A.sts" : 352, - "u1D431.sts" : 392, - "u1D6BC.st" : 501, - "u1D41E.st" : 309, - "u1D65B" : 437, - "u1D7D6.st" : 331, - "uni2124" : 333, - "u1D5A9" : 345, - "u1D7B4" : 307, - "u1D6CA.sts" : 181, - "u1D755" : 530, - "u1D58D.sts" : 336, - "u1D432" : 303, - "e.st" : 272, - "u1D47F.sts" : 718, - "u1D56C.st" : 547, - "uni20EF" : -264, - "u1D4AE.sts" : 502, - "space_uni0326.sts" : 332, - "u1D463.st" : 337, - "u1D7FD" : 78, - "u1D79E" : 536, - "u1D4DA" : 745, - "uni03D6.st" : 471, - "u1D47B" : 434, - "u1D6A9.st" : 378, - "u1D729.sts" : 672, - "u1D741.st" : 430, - "u1D48B.sts" : 486, - "u1D5D4" : 366, - "u1D408" : 218, - "u1D575" : 267, - "space_uni0323" : 138, - "u1D6E9.sts" : 634, - "u1D613" : 287, - "u1D780" : 283, - "u1D735.sts" : 640, - "u1D6DD.st" : 391, - "u1D43F.st" : 395, - "grave.st" : 250, - "u1D6BB" : 400, - "u1D71D.st" : 552, - "u1D519.sts" : 619, - "u1D65C" : 437, - "dotlessj.frab" : 150, - "u1D6F5.sts" : 539, - "u1D741.sts" : 485, - "y.st" : 300, - "u1D7B5" : 362, - "u1D58D.st" : 247, - "u1D4D9.sts" : 698, - "u1D484.st" : 404, - "u1D756" : 366, - "u1D525.sts" : 299, - "u1D433" : 259, - "u1D417.sts" : 537, - "u1D7FE" : 262, - "u1D79F" : 535, - "u1D4DB" : 689, - "u1D4E5.sts" : 472, - "u1D47C" : 473, - "u1D531.sts" : 372, - "u1D51A" : 540, - "u1D423.sts" : 268, - "u1D5D5" : 297, - "u1D4DB.st" : 722, - "circumflexbelowcmb" : -264, - "u1D6FE.st" : 300, - "u1D409" : 348, - "u1D576" : 538, - "u1D7E0" : 277, - "u1D614" : 585, - "u1D73E.st" : 216, - "eight.sts" : 354, - "u1D51B.st" : 468, - "u1D6BC.sts" : 581, - "u1D781" : 278, - "u1D6B0.st" : 240, - "u1D412.st" : 417, - "u1D57F.sts" : 715, - "nabla.sts" : 577, - "u1D6BC" : 447, - "u1D65D" : 273, - "dbloverlinecmb" : -264, - "u1D58B.sts" : 398, - "u1D7B6" : 376, - "Omicron" : 389, - "u1D757" : 327, - "u1D47D.sts" : 628, - "dotlessi.sso" : 211, - "u1D4AC.sts" : 536, - "u1D434" : 550, - "alpha" : 356, - "u1D508.st" : 594, - "u1D7FF" : 262, - "u1D4DC" : 757, - "u1D727.sts" : 876, - "D.st" : 282, - "u1D47D" : 476, - "I.sts" : 247, - "u1D51B" : 408, - "u1D5D6" : 433, - "u1D6E7.sts" : 616, - "u1D6D1.st" : 379, - "u1D433.st" : 291, - "u1D577" : 519, - "u1D733.sts" : 585, - "u1D7E1" : 276, - "u1D615" : 502, - "u1D782" : 375, - "u1D711.st" : 405, - "Delta.st" : 469, - "uni211A" : 333, - "u1D517.sts" : 903, - "u1D6BD" : 410, - "V.sts" : 490, - "u1D6F3.sts" : 634, - "uni03F4" : 389, - "u1D4E9.st" : 556, - "u1D581.st" : 542, - "u1D409.sts" : 477, - "u1D65E" : 269, - "u1D6AD.st" : 409, - "u1D40F.st" : 334, - "u1D4D7.sts" : 848, - "u1D529.st" : 251, - "u1D7B7" : 406, - "u1D523.sts" : 363, - "u1D758" : 313, - "u1D415.sts" : 557, - "X.st" : 406, - "u1D435" : 420, - "uni20D0" : -264, - "u1D640" : 481, - "brevebelowcmb" : -264, - "u1D4E3.sts" : 651, - "c.sts" : 358, - "partialdiff" : 291, - "u1D4DD" : 686, - "u1D6AE.sts" : 577, - "u1D6F2.st" : 504, - "dotlessi.mrmb" : 160, - "u1D47E" : 637, - "Sigma" : 350, - "u1D421.sts" : 196, - "dotlessi.mitb.sts" : 277, - "u1D51C" : 406, - "u1D454.st" : 361, - "zeta.sts" : 346, - "u1D5D7" : 301, - "u1D732.st" : 634, - "u1D578" : 658, - "mu.sts" : 358, - "u1D7E2" : 256, - "u1D6BA.sts" : 525, - "u1D616" : 519, - "u1D57D.sts" : 655, - "u1D783" : 387, - "u1D460" : 296, - "p.sts" : 289, - "u1D46F.sts" : 758, - "Psi.sts" : 510, - "u1D6CE.st" : 296, - "u1D6BE" : 418, - "pi.st" : 333, - "u1D4AB.st" : 516, - "u1D65F" : 292, - "uni2126" : 360, - "Alpha.st" : 421, - "l.st" : 131, - "u1D70E.st" : 331, - "u1D719.sts" : 550, - "u1D7B8" : 391, - "u1D47B.sts" : 569, - "uni03F1.st" : 292, - "u1D759" : 458, - "u1D4AA.sts" : 586, - "u1D57E.st" : 532, - "u1D436" : 596, - "tilde.st" : 285, - "dotlessj.frab.sts" : 270, - "u1D475.st" : 670, - "u1D641" : 473, - "Iota.sts" : 247, - "mu" : 237, - "u1D6A0" : 262, - "u1D6D9.sts" : 545, - "u1D725.sts" : 749, - "u1D4DE" : 594, - "u1D753.st" : 526, - "u1D530.st" : 282, - "u1D47F" : 584, - "u1D509.sts" : 402, - "u1D68A" : 215, - "u1D6E5.sts" : 746, - "u1D5D8" : 336, - "u1D731.sts" : 594, - "six.st" : 360, - "u1D579" : 515, - "u1D6EF.st" : 545, - "u1D7E3" : 260, - "u1D617" : 406, - "u1D784" : 376, - "u1D461" : 225, - "u1D6F1.sts" : 682, - "uni211B" : 532, - "u1D72F.st" : 481, - "u1D407.sts" : 577, - "u1D6BF" : 442, - "uni03F5" : 242, - "Nu.sts" : 490, - "u1D403.st" : 324, - "u1D4D5.sts" : 713, - "u1D59F.st" : 266, - "u1D521.sts" : 295, - "u1D496.st" : 391, - "u1D7B9" : 506, - "u1D413.sts" : 521, - "u1D437" : 427, - "u1D6A1" : 258, - "uni20D1" : -264, - "u1D4E1.sts" : 644, - "u1D642" : 575, - "uni210C.sts" : 604, - "u1D6AC.sts" : 471, - "u1D56F.sts" : 618, - "u1D4DF" : 566, - "dotlessj.mitb" : 282, - "u1D6EA" : 347, - "u1D51E" : 329, - "u1D68B" : 90, - "u1D5D9" : 328, - "Phi" : 358, - "u1D57B.sts" : 657, - "u1D7E4" : 242, - "u1D52D.st" : 175, - "Xi" : 333, - "u1D618" : 519, - "u1D6C2.st" : 343, - "u1D46D.sts" : 630, - "u1D424.st" : 149, - "Kappa" : 378, - "u1D462" : 305, - "u1D785" : 337, - "uni2130.sts" : 503, - "Tau.sts" : 479, - "u1D702.st" : 318, - "uni2127" : 362, - "dotlessi.st" : 162, - "u1D717.sts" : 558, - "uni03D1.st" : 338, - "u1D572.st" : 677, - "u1D6D7.sts" : 470, - "K.st" : 430, - "u1D438" : 483, - "u1D6A2" : 263, - "u1D723.sts" : 677, - "u1D643" : 543, - "u1D507.sts" : 585, - "u1D6E3.sts" : 588, - "u1D6EB" : 545, - "u1D51F" : 189, - "u1D68C" : 306, - "u1D6E3.st" : 508, - "u1D445.st" : 444, - "u1D498.sts" : 598, - "u1D72A" : 529, - "phi.st" : 356, - "u1D7E5" : 243, - "u1D513.sts" : 620, - "u1D619" : 404, - "u1D723.st" : 598, - "u1D786" : 395, - "u1D463" : 294, - "u1D405.sts" : 457, - "uni211C" : 430, - "three.sts" : 322, - "u1D593.st" : 292, - "u1D4D3.sts" : 592, - "u1D6BF.st" : 494, - "hungarumlaut" : 274, - "u1D411.sts" : 378, - "u1D54A" : 291, - "breve.sts" : 340, - "circumflex" : 250, - "u1D439" : 475, - "u1D6A3" : 260, - "uni20D2" : -264, - "u1D6AA.sts" : 441, - "u1D644" : 312, - "u1D56D.sts" : 680, - "u1D56F.st" : 499, - "u1D466.st" : 340, - "u1D45F.sts" : 382, - "u1D4E1.st" : 622, - "u1D6EC" : 517, - "u1D68D" : 351, - "u1D744.st" : 329, - "u1D521.st" : 216, - "macron" : 251, - "u1D72B" : 614, - "two" : 240, - "u1D709.sts" : 384, - "uni211C.st" : 486, - "u1D7E6" : 323, - "acute.sts" : 379, - "u1D49A.st" : 391, - "u1D46B.sts" : 588, - "E.sts" : 426, - "u1D787" : 500, - "u1D7D7.sts" : 349, - "s.st" : 264, - "u1D464" : 405, - "u1D6C9.sts" : 396, - "u1D715.sts" : 482, - "uni2128" : 164, - "u1D5AA" : 367, - "u1D54B" : 305, - "u1D6D5.sts" : 372, - "R.sts" : 323, - "u1D598.sts" : 397, - "u1D721.sts" : 656, - "u1D487.st" : 553, - "u1D6A4" : 168, - "u1D645" : 501, - "uni03D1.sts" : 433, - "u1D505.sts" : 627, - "u1D6E1.sts" : 634, - "u1D6ED" : 625, - "u1D496.sts" : 465, - "u1D68E" : 271, - "u1D72C" : 495, - "u1D511.sts" : 640, - "u1D4DE.st" : 625, - "u1D7E7" : 249, - "u1D403.sts" : 389, - "u1D788" : 366, - "u1D465" : 329, - "u1D51E.st" : 390, - "uni211D" : 247, - "u1D4D1.sts" : 604, - "u1D670" : 262, - "u1D6B3.st" : 607, - "breve.st" : 285, - "u1D415.st" : 484, - "nabla" : 416, - "dotlessj.tt" : 263, - "l.sts" : 167, - "u1D5AB" : 139, - "u1D54C" : 361, - "u1D6A5" : 275, - "uni20D3" : -264, - "u1D646" : 543, - "u1D45D.sts" : 362, - "u1D490" : 367, - "u1D6EE" : 542, - "y.sts" : 357, - "u1D68F" : 340, - "u1D707.sts" : 454, - "u1D72D" : 542, - "dotlessi.fra.st" : 174, - "u1D40A" : 438, - "u1D436.st" : 661, - "u1D4B1.st" : 438, - "u1D6D4.st" : 397, - "u1D789" : 290, - "u1D7D5.sts" : 185, - "u1D6C7.sts" : 387, - "u1D7E8" : 334, - "Upsilon" : 389, - "u1D466" : 304, - "u1D6D0" : 288, - "u1D713.sts" : 623, - "u1D504" : 443, - "u1D671" : 189, - "u1D714.st" : 394, - "R.st" : 271, - "u1D46A.st" : 723, - "u1D584.st" : 531, - "u1D5AC" : 437, - "u1D6D3.sts" : 386, - "u1D596.sts" : 555, - "u1D54D" : 305, - "u1D488.sts" : 444, - "u1D647" : 311, - "u1D491" : 296, - "A" : 375, - "u1D494.sts" : 422, - "B" : 256, - "u1D6EF" : 494, - "C" : 507, - "u1D457.st" : 398, - "u1D4D2.st" : 548, - "D" : 243, - "u1D6F5.st" : 447, - "E" : 315, - "u1D72E" : 565, - "F" : 308, - "u1D735.st" : 543, - "u1D401.sts" : 408, - "kappa.sts" : 370, - "G" : 507, - "u1D512.st" : 393, - "H" : 375, - "u1D40B" : 232, - "f.st" : 293, - "I" : 181, - "dotlessi.fra.sts" : 241, - "eta" : 218, - "u1D467" : 336, - "J" : 317, - "u1D48B.st" : 433, - "K" : 378, - "u1D505" : 442, - "u1D672" : 362, - "L" : 193, - "u1D6D1" : 329, - "u1D710" : 306, - "M" : 458, - "u1D4AE.st" : 484, - "u1D44F.sts" : 230, - "N" : 375, - "u1D7E9" : 250, - "uni030A" : -264, - "O" : 388, - "u1D5AD" : 354, - "P" : 250, - "u1D54E" : 416, - "Q" : 388, - "R" : 234, - "S" : 330, - "uni20D4" : -264, - "u1D45B.sts" : 398, - "T" : 361, - "Alpha.sts" : 490, - "u1D648" : 635, - "U" : 375, - "u1D478.st" : 582, - "V" : 375, - "u1D492" : 410, - "u1D6B9.sts" : 580, - "W" : 514, - "u1D530" : 223, - "X" : 361, - "gamma.sts" : 428, - "u1D533.st" : 180, - "Y" : 375, - "u1D705.sts" : 445, - "u1D7D1.st" : 319, - "Z" : 317, - "z.st" : 258, - "u1D72F" : 430, - "u1D7D3.sts" : 376, - "u1D40C" : 546, - "u1D6C5.sts" : 362, - "u1D588.sts" : 448, - "u1D711.sts" : 484, - "u1D468" : 608, - "u1D6D2" : 284, - "u1D673" : 165, - "a" : 214, - "u1D4A9.sts" : 708, - "u1D50F.st" : 502, - "b" : 100, - "u1D711" : 355, - "u1D6A4.st" : 188, - "c" : 249, - "Omega.sts" : 478, - "u1D594.sts" : 473, - "d" : 377, - "u1D406.st" : 644, - "e" : 236, - "u1D5AE" : 367, - "u1D486.sts" : 471, - "u1D54F" : 333, - "f" : 262, - "u1D499.st" : 393, - "u1D4B5.sts" : 434, - "grave.sts" : 302, - "g" : 332, - "h" : 104, - "Mu.st" : 514, - "beta" : 280, - "u1D6A8" : 433, - "i" : 138, - "u1D43A.st" : 661, - "j" : 156, - "u1D649" : 543, - "u1D6D1.sts" : 453, - "k" : 100, - "u1D75A" : 336, - "u1D492.sts" : 519, - "u1D493" : 282, - "l" : 105, - "xi" : 196, - "m" : 350, - "u1D531" : 229, - "n" : 211, - "o" : 249, - "chi" : 267, - "p" : 202, - "theta.st" : 291, - "q" : 318, - "nu.sts" : 328, - "r" : 181, - "u1D57A" : 401, - "u1D40D" : 450, - "s" : 232, - "u1D7CE.st" : 323, - "t" : 161, - "u1D6C5.st" : 301, - "u1D427.st" : 291, - "u1D469" : 477, - "u" : 245, - "u1D4A2.st" : 544, - "delta" : 232, - "u1D507" : 407, - "u1D674" : 254, - "A.sts" : 489, - "three.st" : 282, - "E.st" : 362, - "u1D44D.sts" : 620, - "u1D6D3" : 276, - "u1D705.st" : 371, - "u1D712" : 331, - "uni030B" : -240, - "uni2127.st" : 409, - "u1D5AF" : 259, - "dotlessi.ssbo" : 223, - "uni2130.st" : 484, - "u1D45B.st" : 313, - "u1D7BA" : 373, - "u1D575.st" : 305, - "uni03D6.sts" : 572, - "v" : 264, - "u1D75B" : 343, - "w" : 361, - "x" : 258, - "uni20D5" : -264, - "uni210E.st" : 238, - "u1D6A9" : 334, - "y" : 264, - "z" : 226, - "Iota.st" : 207, - "u1D6B7.sts" : 577, - "N.sts" : 490, - "u1D494" : 324, - "u1D703.sts" : 422, - "u1D532" : 268, - "Epsilon.st" : 365, - "u1D7D1.sts" : 375, - "uni03F5.st" : 291, - "u1D6E6.st" : 536, - "u1D6C3.sts" : 432, - "u1D5DA" : 428, - "u1D448.st" : 469, - "u1D586.sts" : 531, - "u1D57B" : 502, - "u1D40E" : 431, - "Y.st" : 421, - "u1D478.sts" : 670, - "u1D726.st" : 618, - "u1D6D4" : 348, - "u1D508" : 524, - "u1D675" : 260, - "u1D47C.st" : 521, - "u1D592.sts" : 550, - "nine" : 242, - "u1D596.st" : 449, - "u1D713" : 469, - "u1D484.sts" : 467, - "u1D4B3.sts" : 627, - "Eta.st" : 421, - "u1D7BB" : 370, - "u1D75C" : 397, - "uni212D.sts" : 693, - "h.sts" : 166, - "u1D490.sts" : 475, - "asteriskmath" : 250, - "u1D495" : 254, - "u1D469.st" : 526, - "u1D4E4.st" : 523, - "u1D533" : 134, - "m.st" : 403, - "u1D43F.sts" : 455, - "u1D40A.st" : 492, - "u1D747.st" : 247, - "u1D524.st" : 404, - "u1D5DB" : 397, - "two.sts" : 328, - "u1D57C" : 401, - "u.sts" : 341, - "u1D40F" : 293, - "beta.sts" : 407, - "u1D61A" : 442, - "uni2110.st" : 505, - "u1D6D5" : 272, - "u1D44B.sts" : 667, - "u1D509" : 254, - "u1D676" : 335, - "u1D714" : 345, - "u1D6A9.sts" : 450, - "uni2130" : 450, - "u1D7BC" : 462, - "u1D75D" : 429, - "uni20D6" : -264, - "three" : 258, - "u1D43A" : 596, - "u1D6B5.sts" : 500, - "dotaccent.sts" : 201, - "u1D578.sts" : 829, - "u1D701.sts" : 419, - "u1D496" : 345, - "u1D42B.st" : 242, - "u1D534" : 127, - "dieresis" : 253, - "uni03D5.st" : 374, - "u1D6C1.sts" : 637, - "u1D584.sts" : 644, - "u1D5DC" : 166, - "u1D74F.sts" : 524, - "u1D476.sts" : 670, - "u1D57D" : 500, - "u1D4A5.sts" : 636, - "u1D61B" : 484, - "u1D470.st" : 407, - "u1D6D6" : 288, - "u1D590.sts" : 341, - "u1D677" : 262, - "u1D6B6.st" : 483, - "u1D418.st" : 484, - "u1D482.sts" : 433, - "u1D715" : 361, - "u1D4B1.sts" : 461, - "Tau" : 361, - "u1D7BD" : 475, - "u1D75E" : 166, - "u1D6EA.st" : 381, - "u1D44C.st" : 456, - "uni211C.sts" : 613, - "u1D43B" : 542, - "u1D72A.st" : 584, - "u1D497" : 332, - "ring.sts" : 489, - "u1D535" : 204, - "u1D43D.sts" : 627, - "u1D740" : 263, - "u1D59A.st" : 355, - "u1D491.st" : 354, - "u1D5DD" : 356, - "u1D57E" : 490, - "L.st" : 220, - "u1D6D7.st" : 402, - "u1D439.st" : 528, - "u1D4B4.st" : 418, - "u1D61C" : 490, - "u1D6D7" : 356, - "u1D717.st" : 461, - "u1D678" : 263, - "sigma.st" : 351, - "u1D716" : 269, - "u1D46D.st" : 555, - "u1D560" : 235, - "u1D587.st" : 336, - "dieresis.st" : 285, - "gamma" : 293, - "uni2131" : 718, - "u1D7BE" : 468, - "u1D74B.st" : 447, - "u1D75F" : 394, - "u1D6B3.sts" : 697, - "uni20D7" : -264, - "u1D576.sts" : 697, - "u1D43C" : 347, - "u1D468.sts" : 748, - "dotlessi.ds" : 139, - "u1D498" : 460, - "u1D536" : 128, - "dotlessj.ss" : 147, - "u1D7A0" : 457, - "u1D582.sts" : 812, - "u1D741" : 396, - "u1D6F8.st" : 580, - "u1D4D5.st" : 686, - "u1D74D.sts" : 688, - "u1D474.sts" : 878, - "u1D5DE" : 398, - "u1D57F" : 554, - "u1D738.st" : 334, - "Nu" : 375, - "u1D61D" : 481, - "u1D78A" : 269, - "u1D6D8" : 311, - "u1D48E.st" : 543, - "dotlessi.ssb" : 128, - "u1D679" : 347, - "u1D480.sts" : 606, - "u1D717" : 411, - "u1D5C0" : 324, - "u1D561" : 391, - "u1D440.st" : 688, - "u1D7BF" : 428, - "u1D42F.sts" : 400, - "u1D43D" : 487, - "t.st" : 184, - "uni210B.sts" : 795, - "Theta" : 389, - "u1D499" : 359, - "u1D43B.sts" : 684, - "u1D537" : 185, - "u1D7A1" : 573, - "u1D6BA.st" : 450, - "u1D41C.st" : 357, - "u1D742" : 336, - "u1D536.st" : 174, - "u1D7D4.st" : 374, - "J.sts" : 432, - "u1D5DF" : 165, - "u1D7EA" : 249, - "u1D61E" : 620, - "u1D78B" : 475, - "u1D6D9" : 403, - "u1D6A5.sts" : 346, - "u1D461.st" : 260, - "u1D718" : 365, - "u1D5C1" : 119, - "W.sts" : 664, - "u1D409.st" : 399, - "overlinecmb" : -264, - "u1D562" : 236, - "u1D600" : 226, - "u1D6B1.sts" : 574, - "Kappa.st" : 430, - "u1D574.sts" : 545, - "uni03F0.st" : 350, - "uni20D8" : -264, - "u1D73F.sts" : 460, - "u1D466.sts" : 420, - "u1D43E" : 545, - "u1D6DB.st" : 389, - "u1D43D.st" : 539, - "breveinvertedcmb" : -264, - "gamma.st" : 344, - "u1D580.sts" : 704, - "u1D538" : 305, - "d.sts" : 506, - "u1D6FF.sts" : 437, - "u1D71B.st" : 522, - "u1D472.sts" : 751, - "u1D743" : 315, - "u1D74B.sts" : 512, - "u1D7A2" : 535, - "u1D420" : 358, - "u1D58B.st" : 303, - "lambda.sts" : 177, - "u1D52F.sts" : 337, - "u1D482.st" : 373, - "u1D7EB" : 244, - "uni2102" : 335, - "u1D61F" : 467, - "u1D6C8.st" : 303, - "u1D4A5.st" : 613, - "q.sts" : 424, - "u1D719" : 423, - "u1D5C2" : 120, - "u1D708.st" : 338, - "u1D563" : 346, - "u1D42D.sts" : 244, - "u1D601" : 155, - "u1D6FC.st" : 446, - "u1D45E.st" : 396, - "u1D578.st" : 703, - "u1D43F" : 360, - "u1D73C.st" : 374, - "u1D64A" : 546, - "six.sts" : 428, - "u1D410.st" : 483, - "u1D539" : 247, - "S.st" : 372, - "u1D7A3" : 501, - "space_uni0331.st" : 285, - "u1D744" : 293, - "u1D421" : 134, - "u1D6E9.st" : 539, - "uni03D1" : 291, - "u1D7EC" : 275, - "u1D78D" : 365, - "uni030F" : -288, - "u1D729.st" : 593, - "u1D46A" : 658, - "u1D458.sts" : 283, - "Omega.st" : 407, - "u1D47F.st" : 636, - "u1D5C3" : 140, - "u1D599.st" : 330, - "uni2133" : 702, - "u1D564" : 187, - "u1D572.sts" : 799, - "u1D602" : 281, - "chi.sts" : 397, - "four" : 353, - "u1D464.sts" : 542, - "u1D431.st" : 334, - "u1D73D.sts" : 449, - "g.st" : 374, - "u1D6AA" : 327, - "u1D64B" : 434, - "u1D6FD.sts" : 549, - "dotlessi.mitb.st" : 221, - "u1D470.sts" : 456, - "u1D7A4" : 570, - "u1D4E7.st" : 638, - "u1D745" : 387, - "u1D422" : 160, - "u1D6AB.st" : 536, - "u1D52D.sts" : 250, - "u1D527.st" : 189, - "u1D40D.st" : 501, - "u1D7ED" : 282, - "u1D41F.sts" : 404, - "u1D78E" : 283, - "eta.st" : 263, - "u1D46B" : 465, - "dieresis.sts" : 340, - "dotlessi.frab" : 141, - "Chi.st" : 406, - "Omicron.st" : 438, - "u1D5C4" : 120, - "u1D42B.sts" : 290, - "u1D452.st" : 340, - "u1D6F0.st" : 539, - "u1D565" : 139, - "tilde" : 251, - "u1D603" : 250, - "u1D770" : 388, - "u1D730.st" : 497, - "dotaccent.st" : 162, - "dotlessi.mrmb.st" : 182, - "u1D6AB" : 479, - "u1D64C" : 546, - "u1D6CC.st" : 144, - "u1D42E.st" : 338, - "u1D7A5" : 532, - "u1D746" : 406, - "u1D70C.st" : 397, - "uni211B.st" : 575, - "four.st" : 394, - "u1D423" : 189, - "u1D590" : 215, - "u1D7EE" : 259, - "u1D57C.st" : 441, - "u1D78F" : 566, - "u1D72F.sts" : 564, - "u1D456.sts" : 351, - "u1D46C" : 515, - "u1D473.st" : 421, - "u1D50A" : 518, - "Psi.st" : 435, - "u1D6B9.st" : 500, - "u1D751.st" : 523, - "u1D5C5" : 119, - "u1D570.sts" : 762, - "u1D6EF.sts" : 632, - "u1D566" : 263, - "u1D7D0" : 277, - "u1D73B.sts" : 450, - "u1D462.sts" : 421, - "u1D604" : 372, - "u1D771" : 306, - "u1D6ED.st" : 688, - "u1D44F.st" : 189, - "u1D51F.sts" : 324, - "u1D6AC" : 351, - "u1D6FB.sts" : 579, - "u1D64D" : 441, - "u1D72D.st" : 598, - "u1D50A.st" : 586, - "F.st" : 354, - "u1D7A6" : 514, - "u1D4DF.sts" : 613, - "u1D401.st" : 340, - "u1D747" : 212, - "u1D5F0" : 285, - "u1D52B.sts" : 368, - "u1D59D.st" : 292, - "u1D424" : 126, - "u1D591" : 293, - "u1D494.st" : 386, - "u1D41D.sts" : 585, - "u1D7EF" : 279, - "F.sts" : 417, - "u1D46D" : 507, - "u1D5C6" : 359, - "hungarumlaut.st" : 310, - "u1D567" : 235, - "u1D7D1" : 282, - "nu" : 209, - "u1D605" : 244, - "u1D772" : 395, - "psi" : 348, - "u1D74E.st" : 447, - "Z.st" : 359, - "u1D52B.st" : 279, - "S.sts" : 439, - "u1D6AD" : 364, - "u1D6C0.st" : 465, - "u1D422.st" : 182, - "u1D64E" : 460, - "u1D700.st" : 325, - "u1D448.sts" : 552, - "u1D7A7" : 571, - "u1D748" : 343, - "u1D5F1" : 433, - "u1D425" : 136, - "u1D570.st" : 642, - "u1D592" : 405, - "u1D4D8.st" : 581, - "u1D630" : 345, - "dotlessj.fra.sts" : 259, - "beta.st" : 331, - "u1D454.sts" : 419, - "u1D518.st" : 453, - "one" : 257, - "u1D72D.sts" : 677, - "tilde.sts" : 340, - "u1D46E" : 658, - "Beta" : 286, - "u1D6ED.sts" : 787, - "u1D5C7" : 220, - "n.st" : 249, - "u1D460.sts" : 404, - "u1D568" : 333, - "u1D7D2" : 414, - "u1D606" : 251, - "u1D443.st" : 462, - "u1D6E1.st" : 540, - "m.sts" : 476, - "u1D773" : 269, - "u1D450" : 317, - "grave" : 219, - "u1D721.st" : 579, - "u1D6AE" : 450, - "space_uni030F" : 226, - "u1D40F.sts" : 398, - "sigma.sts" : 437, - "u1D64F" : 511, - "u1D4DD.sts" : 748, - "u1D591.st" : 330, - "u1D7A8" : 535, - "u1D6BD.st" : 459, - "u1D5F2" : 266, - "u1D41B.sts" : 183, - "u1D41F.st" : 347, - "u1D749" : 318, - "u1D426" : 418, - "u1D593" : 255, - "u1D7D7.st" : 310, - "z.sts" : 309, - "u1D631" : 322, - "space_uni0331.sts" : 340, - "circumflexcmb" : -264, - "u1D46F" : 616, - "uni212A" : 378, - "u1D56D.st" : 566, - "eta.sts" : 339, - "u1D50D" : 222, - "u1D67A" : 255, - "u1D464.st" : 461, - "u1D5C8" : 249, - "Phi.sts" : 475, - "u1D569" : 236, - "u1D7D3" : 290, - "u1D742.st" : 373, - "u1D607" : 242, - "u1D4B0" : 432, - "u1D774" : 272, - "uni03D5.sts" : 462, - "u1D451" : 442, - "u1D6AF" : 445, - "dotlessi.mitb" : 185, - "u1D6DE.st" : 395, - "u1D71F.sts" : 800, - "u1D446.sts" : 635, - "u1D49A" : 345, - "uni212D.st" : 567, - "u1D7A9" : 529, - "u1D71E.st" : 536, - "u1D5F3" : 289, - "u1D6DF.sts" : 505, - "u1D427" : 257, - "u1D594" : 334, - "u1D72B.sts" : 754, - "u1D632" : 395, - "u1D452.sts" : 415, - "u1D58E.st" : 202, - "u1D485.st" : 565, - "uni03C2.st" : 282, - "u1D50F.sts" : 622, - "u1D6DA" : 373, - "u1D6EB.sts" : 695, - "u1D50E" : 465, - "u1D67B" : 153, - "u1D5C9" : 228, - "u1D7D4" : 335, - "u1D608" : 481, - "u1D51B.sts" : 587, - "u1D4B1" : 397, - "u1D775" : 297, - "u1D6FF.st" : 373, - "u1D452" : 300, - "M.st" : 514, - "u1D4DC.st" : 795, - "u1D40D.sts" : 577, - "dotlessj.fra.st" : 195, - "uni212C.sts" : 532, - "u1D73F.st" : 395, - "u1D4DB.sts" : 751, - "u1D51C.st" : 464, - "u1D6B1.st" : 492, - "u1D49B" : 379, - "u1D413.st" : 448, - "u1D5F4" : 340, - "u1D428" : 287, - "Tau.st" : 407, - "u1D595" : 177, - "u1D633" : 301, - "uni2112.sts" : 720, - "u1D6DB" : 339, - "u1D509.st" : 305, - "u1D50F" : 437, - "u1D67C" : 262, - "five.sts" : 347, - "a.st" : 244, - "one.sts" : 352, - "u1D71A" : 361, - "u1D438.sts" : 621, - "u1D7D5" : 124, - "uni2126.st" : 407, - "u1D609" : 403, - "u1D4B2" : 549, - "u1D776" : 369, - "u1D453" : 464, - "u1D6D2.st" : 329, - "eight.st" : 296, - "u1D434.st" : 604, - "uni20E1" : -264, - "u1D71D.sts" : 629, - "Nu.st" : 421, - "u1D444.sts" : 648, - "tildebelowcmb" : -264, - "u1D712.st" : 367, - "u1D49C" : 702, - "u1D6DD.sts" : 469, - "u1D5F5" : 127, - "u1D582.st" : 687, - "u1D450.sts" : 437, - "Epsilon" : 318, - "u1D429" : 241, - "u1D6AE.st" : 501, - "u1D596" : 409, - "u1D634" : 310, - "uni03D5" : 320, - "uni03F4.st" : 438, - "u.st" : 285, - "u1D50D.sts" : 363, - "u1D6DC" : 295, - "macron.st" : 285, - "u1D67D" : 262, - "u1D49E.sts" : 523, - "Kappa.sts" : 500, - "four.sts" : 462, - "u1D71B" : 453, - "uni0323" : -265, - "B.sts" : 351, - "u1D6F3.st" : 539, - "u1D4D0.st" : 807, - "u1D7D6" : 299, - "u1D777" : 283, - "u1D4B3" : 556, - "u1D40B.sts" : 289, - "u1D748.sts" : 454, - "u1D454" : 316, - "u1D733.st" : 498, - "u1D510.st" : 624, - "uni211B.sts" : 598, - "u1D754.sts" : 486, - "u1D6CF.st" : 278, - "O.sts" : 514, - "u1D53B" : 247, - "u1D4AC.st" : 516, - "u1D5F6" : 128, - "u1D597" : 242, - "u1D70F.st" : 314, - "chi.st" : 314, - "u1D635" : 260, - "omicron.sts" : 341, - "Gamma.sts" : 402, - "u1D57F.st" : 597, - "delta.sts" : 348, - "uni212C" : 479, - "u1D6DD" : 340, - "u1D476.st" : 582, - "u1D67E" : 262, - "u1D70F.sts" : 391, - "u1D436.sts" : 768, - "u1D71C" : 609, - "u1D754.st" : 452, - "u1D531.st" : 289, - "u1D7D7" : 281, - "u1D778" : 141, - "u1D4B4" : 397, - "u1D6CF.sts" : 347, - "uni03F1.sts" : 372, - "u1D71B.sts" : 625, - "u1D660" : 274, - "u1D442.sts" : 648, - "i.sts" : 201, - "u1D49E" : 462, - "u1D6DB.sts" : 469, - "u1D50D.st" : 275, - "u1D53C" : 334, - "u1D59E.sts" : 289, - "uni2128.sts" : 294, - "u1D404.st" : 396, - "u1D5F7" : 151, - "uni03D6" : 404, - "psi.st" : 405, - "u1D598" : 266, - "u1D497.st" : 364, - "u1D636" : 351, - "u1D480" : 460, - "v.sts" : 357, - "u1D49C.sts" : 806, - "u1D6DE" : 344, - "u1D67F" : 193, - "T.st" : 407, - "space_uni0326" : 246, - "u1D71D" : 502, - "u1D7D8" : 277, - "u1D746.sts" : 485, - "u1D779" : 278, - "u1D4B5" : 396, - "u1D456" : 247, - "lambda.st" : 121, - "u1D6C0" : 415, - "u1D661" : 274, - "u1D52E.st" : 397, - "u1D6C3.st" : 360, - "u1D425.st" : 161, - "dotlessi.sts" : 202, - "u1D752.sts" : 546, - "sigma" : 300, - "u1D49F" : 496, - "u1D53D" : 334, - "u1D703.st" : 349, - "u1D536.sts" : 251, - "u1D5F8" : 128, - "u1D599" : 292, - "u1D428.sts" : 378, - "u1D573.st" : 539, - "u1D637" : 324, - "u1D4E0" : 557, - "u1D7CF.sts" : 392, - "h.st" : 129, - "u1D481" : 533, - "uni212D" : 497, - "u1D6DF" : 371, - "u1D70D.sts" : 289, - "u1D434.sts" : 693, - "u1D71E" : 490, - "dotlessj.mrmb.sts" : 238, - "u1D7D9" : 277, - "u1D6CD.sts" : 382, - "u1D6E4.st" : 512, - "u1D446.st" : 547, - "u1D440.sts" : 788, - "u1D457" : 359, - "u1D6C1" : 479, - "space_uni0326.st" : 278, - "u1D662" : 503, - "u1D724.st" : 406, - "u1D700" : 284, - "seven.sts" : 158, - "u1D59C.sts" : 283, - "seven.st" : 123, - "u1D47A.st" : 610, - "u1D594.st" : 373, - "u1D53E" : 335, - "u1D48E.sts" : 630, - "u1D5F9" : 128, - "u1D638" : 435, - "u1D4E1" : 594, - "five.st" : 291, - "u1D738.sts" : 399, - "u1D482" : 336, - "u1D49A.sts" : 464, - "u1D520" : 269, - "u1D6F8.sts" : 666, - "u1D467.st" : 376, - "u1D4E2.st" : 523, - "u1D71F" : 647, - "u1D744.sts" : 390, - "upsilon.sts" : 367, - "u1D745.st" : 444, - "u1D522.st" : 301, - "u1D528.sts" : 317, - "u1D458" : 213, - "u1D6C2" : 392, - "u1D663" : 350, - "u1D49B.st" : 415, - "u1D750.sts" : 408, - "u1D701" : 313, - "u1D4E8.sts" : 476, - "u1D534.sts" : 250, - "u1D426.sts" : 556, - "u1D74A" : 353, - "u1D639" : 319, - "kappa" : 247, - "u1D4E2" : 502, - "u1D6BF.sts" : 573, - "u1D483" : 225, - "u1D488.st" : 379, - "u1D70B.sts" : 462, - "u1D521" : 165, - "u1D432.sts" : 402, - "Omega" : 360, - "G.st" : 568, - "u1D6CB.sts" : 388, - "u1D56A" : 235, - "u1D58E.sts" : 288, - "Zeta.st" : 358, - "u1D459" : 184, - "u1D6C3" : 329, - "u1D4AF.sts" : 566, - "u1D4DF.st" : 591, - "u1D664" : 373, - "omicron" : 250, - "space_uni0323.st" : 162, - "u1D702" : 272, - "u1D59A.sts" : 453, - "u1D51F.st" : 239, - "u1D48C.sts" : 282, - "u1D6B4.st" : 501, - "u1D416.st" : 661, - "u1D7AA" : 478, - "u1D74B" : 406, - "u1D736.sts" : 451, - "u1D4E3" : 599, - "K.sts" : 500, - "u1D44A.st" : 625, - "u1D484" : 365, - "u1D522" : 243, - "u1D6F6.sts" : 535, - "u1D742.sts" : 432, - "uni0326" : -268, - "u1D5CA" : 299, - "u1D56B" : 236, - "u1D526.sts" : 255, - "X.sts" : 473, - "circumflex.st" : 285, - "u1D418.sts" : 557, - "u1D6C4" : 340, - "u1D665" : 335, - "Xi.st" : 377, - "u1D4B2.st" : 609, - "u1D437.st" : 477, - "u1D4E6.sts" : 704, - "dotlessj.sso" : 239, - "dotlessj.mitb.st" : 304, - "dotlessi.frab.sts" : 260, - "u1D532.sts" : 419, - "tau.st" : 275, - "delta.st" : 275, - "u1D6D5.st" : 311, - "u1D703" : 310, - "u1D715.st" : 405, - "u1D424.sts" : 183, - "u1D7AB" : 446, - "o.st" : 284, - "u1D74C" : 370, - "u1D46B.st" : 509, - "u1D585.st" : 230, - "e.sts" : 329, - "dotlessi.tt" : 263, - "u1D6BD.sts" : 533, - "u1D4E4" : 497, - "Eta" : 375, - "u1D430.sts" : 541, - "u1D485" : 512, - "u1D690" : 332, - "u1D523" : 222, - "psi.sts" : 498, - "u1D58C.sts" : 554, - "u1D5CB" : 205, - "epsilon.sts" : 373, - "r.sts" : 260, - "u1D56C" : 505, - "u1D47E.sts" : 829, - "u1D458.st" : 238, - "u1D4D3.st" : 573, - "u1D60A" : 559, - "dotlessj.mrmb.st" : 200, - "dotlessi.fra" : 120, - "u1D6F6.st" : 443, - "u1D6C5" : 264, - "uni20E5" : -263, - "u1D736.st" : 385, - "u1D666" : 440, - "u1D513.st" : 494, - "u1D728.sts" : 756, - "u1D704" : 184, - "u1D48A.sts" : 383, - "u1D48C.st" : 248, - "u1D7AC" : 489, - "u1D6E8.sts" : 683, - "u1D4AF.st" : 541, - "u1D74D" : 530, - "alpha.st" : 416, - "u1D734.sts" : 710, - "u1D42A" : 369, - "uni2133.sts" : 802, - "u1D4E5" : 427, - "u1D518.sts" : 566, - "u1D486" : 340, - "u1D6F0" : 498, - "u1D6F4.sts" : 656, - "u1D691" : 90, - "u1D524" : 339, - "u1D740.sts" : 321, - "iota.sts" : 184, - "u1D479.st" : 499, - "u1D4D8.sts" : 602, - "u1D5CC" : 214, - "u1D524.sts" : 504, - "u1D41A.st" : 264, - "u1D56D" : 523, - "u1D534.st" : 161, - "u1D7D2.st" : 451, - "u1D416.sts" : 759, - "space_uni0309.st" : 290, - "u1D60B" : 400, - "u1D6C6" : 273, - "u1D4E4.sts" : 548, - "u1D667" : 313, - "partialdiff.st" : 343, - "u1D6AF.sts" : 580, - "u1D530.sts" : 364, - "u1D705" : 331, - "u1D422.sts" : 218, - "Rho.sts" : 384, - "dotlessi" : 139, - "uni2133.st" : 766, - "u1D7AD" : 415, - "u1D6A5.st" : 289, - "u1D407.st" : 501, - "u1D74E" : 398, - "Chi" : 361, - "u1D6BB.sts" : 521, - "u1D57E.sts" : 644, - "u1D42B" : 216, - "N.st" : 421, - "u1D4E6" : 632, - "six" : 318, - "u1D487" : 516, - "u1D6F1" : 541, - "Lambda" : 347, - "u1D692" : 263, - "u1D525" : 168, - "u1D43B.st" : 596, - "u1D730" : 443, - "u1D58A.sts" : 416, - "tau.sts" : 350, - "u1D5CD" : 141, - "u1D47C.sts" : 599, - "uni2140" : 333, - "u1D56E" : 584, - "u1D4AB.sts" : 535, - "u1D60C" : 464, - "u1D6C7" : 267, - "u1D726.sts" : 699, - "uni20E6" : -264, - "u1D480.st" : 518, - "u1D668" : 325, - "caronbelowcmb" : -264, - "u1D7CF.st" : 332, - "u1D706" : 238, - "u1D6C6.st" : 314, - "u1D428.st" : 323, - "u1D550" : 305, - "u1D6E6.sts" : 620, - "b.st" : 124, - "u1D732.sts" : 716, - "u1D7AE" : 365, - "u1D706.st" : 266, - "u1D74F" : 415, - "u1D42C" : 265, - "u1D6FA.st" : 588, - "u1D45C.st" : 356, - "u1D516.sts" : 583, - "u1D4E7" : 610, - "u1D576.st" : 581, - "u1D6F2.sts" : 583, - "uni2110" : 469, - "u1D488" : 339, - "u1D408.sts" : 275, - "u1D6F2" : 454, - "u1D73A.st" : 356, - "u1D693" : 319, - "u1D526" : 132, - "u1D4D6.sts" : 617, - "u1D731" : 463, - "u1D522.sts" : 388, - "u1D5CE" : 258, - "u1D414.sts" : 567, - "u1D56F" : 458, - "uni20DB" : -264, - "u1D60D" : 457, - "breveinvertedbelowcmb" : -264, - "u1D77A" : 169, - "u1D4E2.sts" : 542, - "u1D6E7.st" : 531, - "u1D449.st" : 471, - "u1D6C8" : 256, - "u1D6AD.sts" : 476, - "u1D669" : 278, - "v.st" : 300, - "u1D420.sts" : 481, - "u1D5B0" : 367, - "u1D707" : 349, - "u1D504.st" : 507, - "u1D727.st" : 776, - "u1D47D.st" : 536, - "u1D7AF" : 447, - "u1D597.st" : 279, - "u1D57C.sts" : 546, - "u1D42D" : 194, - "u1D46E.sts" : 825, - "u1D59A" : 317, - "u1D4E8" : 448, - "dotlessi.frab.st" : 176, - "u1D489" : 228, - "u1D6F3" : 498, - "u1D527" : 130, - "u1D694" : 94, - "u1D718.sts" : 491, - "u1D732" : 584, - "G.sts" : 658, - "u1D47A.sts" : 692, - "u1D5CF" : 230, - "u1D4E5.st" : 451, - "u1D7DA" : 287, - "u1D6D8.sts" : 429, - "mu.st" : 281, - "u1D60E" : 554, - "u1D724.sts" : 454, - "u1D40B.st" : 253, - "u1D748.st" : 386, - "u1D525.st" : 216, - "u1D6C9" : 275, - "u1D77B" : 271, - "u1D49E.st" : 503, - "u1D508.sts" : 726, - "u1D5B1" : 257, - "u1D6E4.sts" : 594, - "T.sts" : 479, - "u1D708" : 297, - "u1D552" : 236, - "u1D730.sts" : 580, - "u1D499.sts" : 449, - "u1D450.st" : 364, - "u1D5FA" : 406, - "u1D514.sts" : 502, - "u1D42E" : 296, - "u1D59B" : 160, - "A.st" : 421, - "Zeta.sts" : 424, - "u1D406.sts" : 738, - "u1D4E9" : 533, - "u1D6F0.sts" : 634, - "uni2111" : 337, - "seven" : 103, - "u1D6F4" : 514, - "uni2111.sts" : 501, - "u1D4D4.sts" : 546, - "u1D528" : 183, - "u1D695" : 178, - "a.sts" : 284, - "u1D520.sts" : 419, - "rho" : 243, - "space_uni0309.sts" : 339, - "u1D733" : 444, - "u1D6CA.st" : 140, - "u1D410" : 431, - "u1D412.sts" : 484, - "u1D42C.st" : 287, - "uni20DC" : -264, - "u1D7DB" : 289, - "u1D4E0.sts" : 601, - "u1D70A.st" : 282, - "u1D60F" : 502, - "u1D77C" : 285, - "u1D6AB.sts" : 621, - "u1D56E.sts" : 747, - "macron.sts" : 340, - "n.sts" : 296, - "u1D57A.st" : 441, - "u1D709" : 285, - "u1D5B2" : 293, - "dotlessj" : 153, - "u1D471.st" : 570, - "u1D553" : 139, - "uni212C.st" : 514, - "U.st" : 421, - "u1D57A.sts" : 546, - "u1D419.st" : 408, - "u1D6B7.st" : 501, - "u1D5FB" : 253, - "u1D46C.sts" : 640, - "u1D59C" : 162, - "u1D42F" : 303, - "u1D63A" : 324, - "u1D6EB.st" : 605, - "u1D44D.st" : 534, - "u1D6F5" : 394, - "u1D716.sts" : 380, - "u1D529" : 195, - "u1D696" : 210, - "u1D734" : 580, - "upsilon" : 251, - "u1D72B.st" : 667, - "u1D411" : 281, - "u1D6D6.sts" : 384, - "u1D599.sts" : 427, - "u1D722.sts" : 756, - "u1D7DC" : 396, - "u1D59B.st" : 196, - "dotlessj.mitb.sts" : 347, - "u1D77D" : 256, - "u1D492.st" : 452, - "asterisk" : 398, - "u1D45A" : 404, - "uni20E8" : -264, - "i.st" : 162, - "u1D6E2.sts" : 696, - "u1D6D8.st" : 358, - "u1D4B5.st" : 421, - "u1D5B3" : 340, - "u1D554" : 238, - "u1D497.sts" : 436, - "u1D718.st" : 418, - "u1D512.sts" : 505, - "u1D5FC" : 274, - "u1D46E.st" : 723, - "u1D404.sts" : 467, - "u1D59D" : 255, - "u1D588.st" : 350, - "u1D63B" : 314, - "uni2112" : 634, - "u1D4D2.sts" : 571, - "u1D74C.st" : 409, - "u1D6F6" : 385, - "u1D697" : 191, - "u1D420.st" : 419, - "u1D410.sts" : 561, - "u1D735" : 483, - "u1D412" : 374, - "u1D7DD" : 278, - "u1D6F9.st" : 446, - "u1D56C.sts" : 661, - "u1D4D6.st" : 596, - "u1D77E" : 299, - "uni03F0.sts" : 422, - "u1D45B" : 265, - "u1D45E.sts" : 474, - "u1D739.st" : 407, - "u1D516.st" : 461, - "u1D5B4" : 344, - "uni210C.st" : 487, - "u1D555" : 424, - "u1D48F.st" : 365, - "u1D708.sts" : 405, - "u1D760" : 336, - "uni2127.sts" : 480, - "u1D46A.sts" : 825, - "u1D7D6.sts" : 393, - "u1D5FD" : 237, - "Sigma.sts" : 464, - "u1D59E" : 168, - "u1D441.st" : 596, - "u1D6C8.sts" : 369, - "u1D63C" : 511, - "u1D714.sts" : 484, - "u1D6F7" : 415, - "u1D698" : 262, - "u1D736" : 439, - "u1D6D4.sts" : 476, - "u1D597.sts" : 371, - "u1D413" : 400, - "Lambda.sts" : 455, - "u1D580" : 545, - "u1D720.sts" : 640, - "Alpha" : 374, - "u1D489.sts" : 282, - "u1D6BB.st" : 448, - "u1D41D.st" : 502, - "dotlessi.ss" : 119, - "u1D537.st" : 244, - "u1D77F" : 418, - "u1D7D5.st" : 146, - "u1D7DE" : 266, - "u1D504.sts" : 629, - "uni20E9" : -264, - "u1D45C" : 315, - "u1D6E0.sts" : 380, - "u1D495.sts" : 336, - "u1D5B5" : 333, - "u1D556" : 236, - "H.st" : 421, - "u1D7C0" : 487, - "u1D510.sts" : 776, - "u1D462.st" : 340, - "u1D761" : 489, - "u1D402.sts" : 738, - "u1D5FE" : 342, - "u1D6A8.st" : 484, - "u1D740.st" : 284, - "u1D59F" : 229, - "u1D4D0.sts" : 842, - "u1D63D" : 443, - "u1D6F8" : 528, - "u1D699" : 188, - "u1D6DC.st" : 339, - "u1D43E.st" : 606, - "u1D5E0" : 489, - "u1D737" : 483, - "u1D414" : 442, - "u1D581" : 500, - "caron" : 250, - "u1D71C.st" : 664, - "u1D7DF" : 277, - "u1D45C.sts" : 433, - "C.sts" : 659, - "tildecomb" : -264, - "u1D45D" : 246, - "u1D58C.st" : 449, - "u1D483.st" : 242, - "u1D5B6" : 472, - "u1D706.sts" : 317, - "u1D6C9.st" : 328, - "iota.st" : 128, - "u1D4A6.st" : 730, - "u1D557" : 225, - "u1D762" : 397, - "u1D7C1" : 643, - "u1D7D4.sts" : 465, - "lambda" : 86, - "u1D709.st" : 321, - "u1D5FF" : 216, - "P.sts" : 344, - "u1D589.sts" : 313, - "u1D6C6.sts" : 386, - "u1D712.sts" : 438, - "Pi.st" : 421, - "u1D45F.st" : 290, - "u1D63E" : 580, - "u1D579.st" : 557, - "u1D4DA.st" : 783, - "u1D6F9" : 392, - "u1D6FD.st" : 480, - "u1D6D2.sts" : 380, - "u1D73D.st" : 391, - "u1D51A.st" : 597, - "u1D595.sts" : 299, - "u1D5E1" : 397, - "u1D738" : 295, - "u1D411.st" : 317, - "u1D487.sts" : 608, - "u1D415" : 434, - "p.st" : 238, - "u1D582" : 643, - "u1D620" : 481, - "u1D45E" : 349, - "theta" : 247, - "u1D493.sts" : 395, - "u1D5B7" : 319, - "u1D507.st" : 465, - "u1D558" : 236, - "u1D7C2" : 472, - "u1D400.sts" : 557, - "j.sts" : 233, - "u1D763" : 366, - "u1D440" : 625, - "u1D63F" : 447, - "uni0300" : -295, - "u1D6D0.st" : 324, - "u1D432.st" : 341, - "u1D44E.sts" : 397, - "u1D710.st" : 353, - "u1D5E2" : 395, - "u1D739" : 376, - "w.sts" : 479, - "u1D416" : 594, - "u1D583" : 488, - "u1D621" : 458, - "u1D4E8.st" : 464, - "u1D580.st" : 588, - "u1D45A.sts" : 572, - "u1D6AC.st" : 397, - "u1D40E.st" : 483, - "u1D45F" : 247, - "u1D528.st" : 238, - "u1D6B8.sts" : 444, - "zero.sts" : 340, - "u1D66A" : 376, - "u1D704.sts" : 260, - "u1D5B8" : 333, - "Pi.sts" : 490, - "u1D559" : 139, - "u1D7C3" : 411, - "u1D7D2.sts" : 494, - "u1D764" : 394, - "u1D6C4.sts" : 466, - "u1D587.sts" : 432, - "u1D441" : 542, - "two.st" : 273, - "u1D453.st" : 506, - "u1D6F1.st" : 595, - "u1D710.sts" : 425, - "u1D479.sts" : 570, - "u1D731.st" : 513, - "nine.sts" : 335, - "u1D48A" : 282, - "u1D6D0.sts" : 379, - "u1D593.sts" : 386, - "u1D485.sts" : 642, - "u1D5E3" : 288, - "u1D4B4.sts" : 430, - "u1D417" : 418, - "u1D584" : 490, - "u1D42F.st" : 341, - "u1D4AA.st" : 562, - "u1D622" : 324, - "u1D6CD.st" : 315, - "uni0331" : -263, - "uni03F5.sts" : 371, - "Delta.sts" : 548, - "u1D70D.st" : 220, - "u1D491.sts" : 400, - "O.st" : 438, - "u1D6CA" : 115, - "u1D66B" : 343, - "u1D57D.st" : 542, - "u1D5B9" : 312, - "u1D474.st" : 777, - "caroncmb" : -264, - "u1D7C4" : 358, - "u1D765" : 397, - "u1D752.st" : 467, - "u1D442" : 495, - "uni2115" : 361, - "u1D44C.sts" : 548, - "uni0301" : -233, - "u1D48B" : 398, - "u1D6EE.st" : 596, - "u1D5E4" : 395, - "c.st" : 295, - "u1D418" : 434, - "u1D585" : 194, - "u1D72E.st" : 616, - "dotlessj.st" : 177, - "u1D402.st" : 644, - "u1D623" : 268, - "u1D790" : 513, - "uni210E.sts" : 283, - "u1D6B6.sts" : 561, - "u1D59E.st" : 203, - "u1D579.sts" : 672, - "u1D6CB" : 277, - "Psi" : 386, - "u1D495.st" : 282, - "u1D702.sts" : 397, - "u1D66C" : 466, - "Xi.sts" : 444, - "uni20F0" : -264, - "u1D70A" : 243, - "u1D7D0.sts" : 354, - "space_uni0323.sts" : 201, - "u1D7C5" : 615, - "u1D6C2.sts" : 420, - "u1D585.sts" : 319, - "Lambda.st" : 391, - "u1D4A2" : 506, - "u1D766" : 318, - "u1D443" : 416, - "u1D477.sts" : 570, - "u1D4A6.sts" : 763, - "Theta.st" : 438, - "u1D591.sts" : 427, - "w.st" : 407, - "u1D48C" : 228, - "u1D74F.st" : 456, - "u1D52C.st" : 316, - "u1D483.sts" : 273, - "u1D52A" : 337, - "u1D6C1.st" : 540, - "u1D423.st" : 222, - "u1D4B2.sts" : 643, - "u1D5E5" : 296, - "theta.sts" : 373, - "u1D419" : 364, - "u1D586" : 388, - "u1D701.st" : 352, - "u1D7F0" : 343, - "u1D624" : 359, - "u1D791" : 465, - "circumflex.sts" : 340, - "u1D4D9.st" : 674, - "u1D571.st" : 330, - "u1D6CC" : 118, - "phi" : 302, - "u1D66D" : 339, - "u1D519.st" : 492, - "u1D70B" : 328, - "u1D43E.sts" : 695, - "five" : 256, - "u1D767" : 429, - "u1D444" : 495, - "iota" : 98, - "u1D44A.sts" : 739, - "u1D6E2.st" : 606, - "u1D444.st" : 552, - "u1D48D" : 196, - "u1D6A8.sts" : 555, - "L.sts" : 261, - "u1D722.st" : 669, - "u1D52B" : 226, - "u1D5E6" : 310, - "dotlessj.ssb" : 158, - "u1D587" : 298, - "u1D7F1" : 269, - "u1D592.st" : 445, - "u1D625" : 544, - "u1D792" : 451, - "u1D6B4.sts" : 577, - "u1D6BE.st" : 465, - "u1D577.sts" : 676, - "u1D700.sts" : 397, - "B.st" : 296, - "u1D469.sts" : 599, - "u1D6CD" : 274, - "Y.sts" : 490, - "u1D66E" : 345, - "u1D70C" : 354, - "u1D6C0.sts" : 540, - "u1D583.sts" : 641, - "space_uni030F.st" : 260, - "u1D7C7" : 508, - "u1D56E.st" : 627, - "u1D74E.sts" : 525, - "u1D475.sts" : 757, - "nine.st" : 286, - "u1D465.st" : 359, - "u1D4E0.st" : 581, - "u1D768" : 397, - "u1D445" : 398, - "uni210B" : 695, - "u1D650" : 528, - "u1D743.st" : 350, - "u1D520.st" : 329, - "kappa.st" : 292, - "f.sts" : 358, - "u1D481.sts" : 662, - "u1D48E" : 478, - "u1D4B0.sts" : 501, - "u1D52C" : 258, - "Beta.sts" : 388, - "u1D5E7" : 367, - "V.st" : 421, - "u1D6DF.st" : 423, - "u1D588" : 312, - "u1D7F2" : 331, - "u1D626" : 333, - "u1D793" : 597, - "dbllowlinecmb" : -264, - "u1D71F.st" : 707, - "u1D470" : 383, - "s.sts" : 316, - "dotlessj.mrmb" : 176, - "u1D6CE" : 252, - "u1D58F.st" : 194, - "u1D66F" : 336, - "u1D43C.sts" : 441, - "u1D486.st" : 377, - "u1D70D" : 182, - "u1D7C8" : 373, - "u1D4A9.st" : 678, - "u1D4A5" : 568, - "u1D769" : 366, - "u1D446" : 498, - "u1D6B0" : 218, - "Rho.st" : 325, - "u1D651" : 511, - "j.st" : 186, - "u1D4DD.st" : 720, - "u1D48F" : 318, - "uni213C" : 258, - "u1D52D" : 128, - "u1D69A" : 316, - "u1D5E8" : 382, - "u1D6B2.st" : 449, - "u1D414.st" : 492, - "u1D6B2.sts" : 517, - "u1D589" : 189, - "u1D575.sts" : 399, - "u1D627" : 428, - "u1D4D0" : 768, - "u1D794" : 474, - "u1D7F3" : 275, - "u1D471" : 516, - "u1D467.sts" : 449, - "u1D6CF" : 235, - "u1D581.sts" : 655, - "u1D70E" : 286, - "u1D74C.sts" : 469, - "u1D473.sts" : 470, - "u1D7C9" : 672, - "u1D4A2.sts" : 564, - "omega.st" : 375, - "u1D4A6" : 668, - "uni210C" : 422, - "u1D447" : 398, - "u1D6B1" : 438, - "u1D652" : 663, - "dotlessj.frab.st" : 185, - "uni2110.sts" : 524, - "u1D6D3.st" : 317, - "u1D435.st" : 468, - "u1D4B0.st" : 476, - "u1D6FA" : 533, - "u1D52E" : 333, - "u1D69B" : 245, - "u1D5E9" : 366, - "u1D42E.sts" : 401, - "u1D713.st" : 527, - "u1D7F4" : 277, - "u1D628" : 419, - "u1D4D1" : 559, - "Sigma.st" : 395, - "u1D795" : 482, - "uni03C2.sts" : 359, - "u1D472" : 604, - "u1D583.st" : 529, - "u1D510" : 566, - "u1D43A.sts" : 767, - "u1D6AF.st" : 500, - "ring.st" : 421, - "u1D70F" : 269, - "uni2112.st" : 690, - "one.st" : 295, - "u1D448" : 421, - "u1D6B2" : 403, - "u1D6F4.st" : 566, - "u1D653" : 497, - "u1D4D1.st" : 584, - "u1D6A4.sts" : 249, - "u1D456.st" : 284, - "Delta" : 416, - "uni0304" : -263, - "u1D734.st" : 636, - "u1D459.sts" : 248, - "u1D511.st" : 511, - "u1D6FB" : 420, - "uni213D" : 236, - "u1D52F" : 200, - "u1D69C" : 302, - "I.st" : 207, - "u1D6B0.sts" : 275, - "u1D48A.st" : 323, - "u1D573.sts" : 651, - "u1D73A" : 322, - "u1D7F5" : 259, - "zeta" : 224, - "u1D73E.sts" : 253, - "u1D465.sts" : 431, - "pi.sts" : 410, - "u1D4D2" : 523, - "u1D629" : 267, - "u1D796" : 535, - "u1D473" : 396, - "breve" : 251, - "u1D511" : 453, - "u1D6FE.sts" : 374, - "u1D74A.sts" : 465, - "u1D471.sts" : 658, - "u1D55A" : 139, - "u1D477.st" : 499, - "u1D52E.sts" : 496, - "uni210D" : 361, - "u1D449" : 413, - "u1D6B3" : 546, - "u1D755.st" : 604, - "u1D532.st" : 324, - "u1D654" : 511, - "u1D7D0.st" : 295, - "u1D6FC" : 392, - "u1D69D" : 188, - "u1D42C.sts" : 338, - "u1D73B" : 347, - "u1D7F6" : 262, - "H.sts" : 490, - "u1D50E.st" : 531, - "u1D4D3" : 549, - "u1D797" : 573, - "u1D405.st" : 387, - "u1D474" : 712, - "u1D512" : 340, - "nu.st" : 255, - "u1D498.st" : 506, - "u1D5BA" : 228, - "Pi" : 375, - "u1D55B" : 249, - "ring" : 375, - "uni2126.sts" : 478, - "q.st" : 360, - "U.sts" : 490, - "u1D4A9" : 625, - "zero.st" : 286, - "Gamma.st" : 342, - "u1D6B4" : 450, - "u1D655" : 489, - "uni2119" : 247, - "u1D457.sts" : 464, - "space_uni0309" : 251, - "uni213E" : 333, - "u1D6FD" : 437, - "u1D52F.st" : 255, - "u1D69E" : 220, - "u1D571.sts" : 419, - "u1D6C4.st" : 388, - "u1D426.st" : 468, - "b.sts" : 160, - "u1D73C" : 319, - "u1D73C.sts" : 451, - "u1D463.sts" : 404, - "u1D7F7" : 277, - "xi.sts" : 311, - "u1D704.st" : 208, - "u1D4D4" : 504, - "u1D798" : 304, - "u1D475" : 616, - "u1D6FC.sts" : 531, - "u1D680" : 262, - "u1D45A.st" : 465, - "u1D513" : 436, - "u1D574.st" : 440, - "u1D5BB" : 120, - "o.sts" : 340, - "u1D55C" : 139, - "u1D52C.sts" : 407, - "uni210E" : 213, - "u1D41E.sts" : 358, - "u1D6B5" : 383, - "u1D656" : 363, - "u1D6E5.st" : 646, - "u1D447.st" : 452, - "u1D42A.sts" : 472, - "u1D6FE" : 259, - "Omicron.sts" : 513, - "upsilon.st" : 296, - "u1D69F" : 262, - "u1D725.st" : 661, - "u1D73D" : 343, - "u1D41A" : 231, - "u1D7F8" : 251, - "u1D47B.st" : 486, - "u1D595.st" : 213, - "u1D4D5" : 654, - "u1D799" : 534, - "phi.sts" : 441, - "u1D476" : 528, - "u1D6E0" : 278, - "u1D681" : 166, - "u1D514" : 338, - "u1D449.sts" : 565, - "u1D5BC" : 264, - "uni210B.st" : 761, - "u1D55D" : 139, - "brevecmb" : -264, - "u1D468.st" : 660, - "u1D4E3.st" : 627, - "u1D6B6" : 430, - "u1D72E.sts" : 700, - "u1D657" : 274, - "P.st" : 290, - "u1D746.st" : 444, - "u1D523.st" : 282, - "Chi.sts" : 473, - "uni213F" : 333, - "u1D6FF" : 335, - "Gamma" : 297, - "u1D6EE.sts" : 683, - "u1D49C.st" : 769, - "dotaccent" : 138, - "epsilon.st" : 292, - "u1D461.sts" : 324, - "u1D73A.sts" : 418, - "u1D73E" : 197, - "u1D41B" : 126, - "u1D7F9" : 248, - "u1D51E.sts" : 492, - "u1D4D6" : 572, - "u1D6FA.sts" : 684, - "u1D477" : 468, - "u1D6E1" : 473, - "u1D682" : 309, - "u1D720" : 514, - "u1D4DE.sts" : 650, - "u1D52A.sts" : 502, - "u1D489.st" : 248, - "u1D5BD" : 397, - "u1D55E" : 420, - "u1D41C.sts" : 417, - "d.st" : 431, - "u1D42A.st" : 411, - "u1D6B7" : 450, - "u1D658" : 384, - "u1D540" : 167, - "u1D73F" : 359, - "Upsilon.st" : 438, - "u1D41C" : 298, - "partialdiff.sts" : 430, - "u1D6B5.st" : 430, - "u1D417.st" : 465, - "uni20EA" : -264, - "u1D4D7" : 774, - "u1D478" : 528, - "u1D6E2" : 552, - "u1D516" : 405, - "u1D683" : 262, - "x.st" : 293, - "u1D721" : 528, - "u1D447.sts" : 544, - "rho.st" : 292, - "u1D44B.st" : 580, - "u1D5BE" : 238, - "dotlessj.ds" : 249, - "u1D55F" : 346, - "u1D76A" : 428, - "u1D72C.sts" : 623, - "u1D453.sts" : 576, - "u1D6B8" : 330, - "u1D659" : 578, - "uni0307" : -265, - "space_uni030F.sts" : 312, - "tau" : 232, - "u1D5A0" : 333, - "epsilon" : 244, - "u1D490.st" : 407, - "u1D6EC.sts" : 654, - "u1D541" : 471, - "u1D6D6.st" : 319, - "u1D438.st" : 536, - "u1D4B3.st" : 602, - "uni03F4.sts" : 513, - "u1D716.st" : 310, - "u1D58A" : 283, - "u1D51C.sts" : 585, - "u1D41D" : 444, - "u1D4D8" : 556, - "u1D40E.sts" : 561, - "u1D479" : 457, - "Upsilon.sts" : 514, - "u1D586.st" : 427, - "u1D46C.st" : 564, - "u1D517" : 672, - "u1D684" : 262, - "u1D4DC.sts" : 828, - "u1D6E3" : 457, - "D.sts" : 336, - "u1D722" : 615, - "u1D74A.st" : 389, - "u1D41A.sts" : 312, - "u1D5BF" : 280, - "u1D76B" : 394, - "u1D6B9" : 445, - "acute" : 281, - "C.st" : 567, - "u1D459.st" : 207, - "u1D4D4.st" : 528, - "u1D6F7.st" : 466, - "u1D5A1" : 256, - "Q.sts" : 514, - "u1D542" : 333, - "omega" : 322, - "dotlessj.ssbo" : 253, - "u1D737.st" : 507, - "u1D514.st" : 389, - "uni0338" : -263, - "u1D439.sts" : 612, - "u1D5EA" : 519, - "u1D48D.st" : 212, - "u1D58B" : 266, - "u1D41E" : 281, - "uni20EB" : -264, - "u1D4D9" : 645, - "u1D6E4" : 461, - "u1D71E.sts" : 609, - "u1D518" : 391, - "u1D685" : 262, - "u1D445.sts" : 515, - "u1D723" : 542, - "Beta.st" : 330, - "u1D400" : 434, - "u1D6DE.sts" : 474, - "W.st" : 575, - "u1D72A.sts" : 674, - "u1D451.sts" : 577, - "u1D76C" : 352, - "uni2131.sts" : 822, - "k.sts" : 160, - "u1D41B.st" : 149, - "u1D7D3.st" : 323, - "u1D50E.sts" : 654, - "alpha.sts" : 509, - "u1D535.st" : 262, - "u1D6EA.sts" : 441, - "u1D5A2" : 411, - "uni0308" : -261, - "pi" : 279, - "u1D543" : 167, - "u1D49F.sts" : 552, - "u1D51A.sts" : 745, - "u1D5EB" : 351, - "u1D460.st" : 334, - "u1D58C" : 408, - "u1D40C.sts" : 697, - "u1D41F" : 309, - "u1D62A" : 258, - "u1D749.sts" : 433, - "x.sts" : 350, - "dotlessi.mrmb.sts" : 218, - "u1D408.st" : 240, - "u1D4DA.sts" : 816, - "u1D6E5" : 586, - "xi.st" : 238, - "u1D519" : 435, - "u1D686" : 262, - "Iota" : 181, - "nabla.st" : 477, - "k.st" : 124, - "u1D724" : 382, - "u1D755.sts" : 708, - "u1D401" : 300, - "zero" : 254, - "omega.sts" : 469, - "u1D6DA.st" : 427, - "u1D43C.st" : 382, - "Eta.sts" : 490, - "u1D76D" : 425, - "u1D44A" : 552, - "u1D71A.st" : 398, - "u1D5A3" : 252, - "u1D58A.st" : 321, - "u1D544" : 361, - "u1D481.st" : 582, - "u1D437.sts" : 551, - "u1D6C7.st" : 313, - "u1D5EC" : 366, - "u1D429.st" : 280, - "u1D58D" : 211, - "uni20EC" : -264, - "space_uni0331" : 251, - "Epsilon.sts" : 428, - "u1D62B" : 278, - "u1D707.st" : 386, - "u1D71C.sts" : 752, - "u1D443.sts" : 535, - "u1D6E6" : 482, - "u1D687" : 253, - "u1D6FB.st" : 480, - "caron.sts" : 340, - "u1D45D.st" : 296, - "u1D577.st" : 562, - "u1D725" : 603, - "u1D6DC.sts" : 405, - "u1D402" : 580, - "u1D59F.sts" : 357, - "u1D73B.st" : 385, - "dotlessj.sts" : 219, - "lowlinecmb" : -264, - "u1D76E" : 392, - "u1D4AA" : 515, - "u1D44B" : 528, - "uni0309" : -263, - "uni03F0" : 297, - "u1D5A4" : 317, - "u1D6E8.st" : 596, - "u1D750" : 316, - "u1D728.st" : 669, - "u1D505.st" : 498, - "u1D5ED" : 344, - "u1D40A.sts" : 574, - "u1D747.sts" : 308, - "u1D58E" : 166, - "u1D47E.st" : 713, - "u1D62C" : 268, - "u1D598.st" : 303, - "u1D6E7" : 481 - }, - "v_assembly" : { - "divides" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "divides.bt", - "endConnector" : 601, - "startConnector" : 0, - "advance" : 1202, - "extender" : false - }, - { - "glyph" : "divides.ex", - "endConnector" : 1202, - "startConnector" : 1202, - "advance" : 1202, - "extender" : true - }, - { - "glyph" : "divides.tp", - "endConnector" : 0, - "startConnector" : 601, - "advance" : 1202, - "extender" : false - } - ] - }, - "uni230B" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni23A6", - "endConnector" : 500, - "startConnector" : 0, - "advance" : 1500, - "extender" : false - }, - { - "glyph" : "uni23A5", - "endConnector" : 1000, - "startConnector" : 1000, - "advance" : 1000, - "extender" : true - } - ] - }, - "uni21A7" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21A7.bt", - "endConnector" : 166, - "startConnector" : 0, - "advance" : 498, - "extender" : false - }, - { - "glyph" : "uni21A7.ex", - "endConnector" : 332, - "startConnector" : 332, - "advance" : 332, - "extender" : true - }, - { - "glyph" : "uni21A7.tp", - "endConnector" : 0, - "startConnector" : 166, - "advance" : 498, - "extender" : false - } - ] - }, - "bracketright" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni23A6", - "endConnector" : 500, - "startConnector" : 0, - "advance" : 1500, - "extender" : false - }, - { - "glyph" : "uni23A5", - "endConnector" : 1000, - "startConnector" : 1000, - "advance" : 1000, - "extender" : true - }, - { - "glyph" : "uni23A4", - "endConnector" : 0, - "startConnector" : 500, - "advance" : 1500, - "extender" : false - } - ] - }, - "uni2B06" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni2B06.bt", - "endConnector" : 164, - "startConnector" : 0, - "advance" : 492, - "extender" : false - }, - { - "glyph" : "uni2B06.ex", - "endConnector" : 327, - "startConnector" : 327, - "advance" : 327, - "extender" : true - }, - { - "glyph" : "uni2B06.tp", - "endConnector" : 0, - "startConnector" : 164, - "advance" : 492, - "extender" : false - } - ] - }, - "arrowup" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "arrowup.bt", - "endConnector" : 169, - "startConnector" : 0, - "advance" : 506, - "extender" : false - }, - { - "glyph" : "arrowup.ex", - "endConnector" : 337, - "startConnector" : 337, - "advance" : 337, - "extender" : true - }, - { - "glyph" : "arrowup.tp", - "endConnector" : 0, - "startConnector" : 169, - "advance" : 505, - "extender" : false - } - ] - }, - "uni21CA" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21CA.bt", - "endConnector" : 169, - "startConnector" : 0, - "advance" : 505, - "extender" : false - }, - { - "glyph" : "uni21CA.ex", - "endConnector" : 337, - "startConnector" : 337, - "advance" : 337, - "extender" : true - }, - { - "glyph" : "uni21CA.tp", - "endConnector" : 0, - "startConnector" : 169, - "advance" : 506, - "extender" : false - } - ] - }, - "uni21F5" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21F5.bt", - "endConnector" : 172, - "startConnector" : 0, - "advance" : 514, - "extender" : false - }, - { - "glyph" : "uni21F5.ex", - "endConnector" : 343, - "startConnector" : 343, - "advance" : 343, - "extender" : true - }, - { - "glyph" : "uni21F5.tp", - "endConnector" : 0, - "startConnector" : 172, - "advance" : 515, - "extender" : false - } - ] - }, - "dblverticalbar" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "parallel.bt", - "endConnector" : 601, - "startConnector" : 0, - "advance" : 1202, - "extender" : false - }, - { - "glyph" : "parallel.ex", - "endConnector" : 1202, - "startConnector" : 1202, - "advance" : 1202, - "extender" : true - }, - { - "glyph" : "parallel.tp", - "endConnector" : 0, - "startConnector" : 601, - "advance" : 1202, - "extender" : false - } - ] - }, - "uni21A1" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21A1.bt", - "endConnector" : 169, - "startConnector" : 0, - "advance" : 505, - "extender" : false - }, - { - "glyph" : "uni21A1.ex", - "endConnector" : 337, - "startConnector" : 337, - "advance" : 337, - "extender" : true - }, - { - "glyph" : "uni21A1.tp", - "endConnector" : 0, - "startConnector" : 169, - "advance" : 506, - "extender" : false - } - ] - }, - "uni27E6" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni27E6.bt", - "endConnector" : 500, - "startConnector" : 0, - "advance" : 1000, - "extender" : false - }, - { - "glyph" : "uni27E6.ex", - "endConnector" : 1000, - "startConnector" : 1000, - "advance" : 1000, - "extender" : true - }, - { - "glyph" : "uni27E6.tp", - "endConnector" : 0, - "startConnector" : 500, - "advance" : 1000, - "extender" : false - } - ] - }, - "uni27EF" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni27EF.bt", - "endConnector" : 499, - "startConnector" : 0, - "advance" : 1526, - "extender" : false - }, - { - "glyph" : "uni27EF.ex", - "endConnector" : 998, - "startConnector" : 998, - "advance" : 998, - "extender" : true - }, - { - "glyph" : "uni27EF.tp", - "endConnector" : 0, - "startConnector" : 499, - "advance" : 1526, - "extender" : false - } - ] - }, - "braceleft" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni23A9", - "endConnector" : 374, - "startConnector" : 0, - "advance" : 750, - "extender" : false - }, - { - "glyph" : "braceleft.ex", - "endConnector" : 748, - "startConnector" : 748, - "advance" : 748, - "extender" : true - }, - { - "glyph" : "uni23A8", - "endConnector" : 374, - "startConnector" : 374, - "advance" : 1500, - "extender" : false - }, - { - "glyph" : "braceleft.ex", - "endConnector" : 748, - "startConnector" : 748, - "advance" : 748, - "extender" : true - }, - { - "glyph" : "uni23A7", - "endConnector" : 0, - "startConnector" : 374, - "advance" : 750, - "extender" : false - } - ] - }, - "radical" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni23B7", - "endConnector" : 320, - "startConnector" : 0, - "advance" : 1820, - "extender" : false - }, - { - "glyph" : "radical.ex", - "endConnector" : 640, - "startConnector" : 640, - "advance" : 640, - "extender" : true - }, - { - "glyph" : "radical.tp", - "endConnector" : 0, - "startConnector" : 320, - "advance" : 620, - "extender" : false - } - ] - }, - "uni21D5" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21D5.bt", - "endConnector" : 178, - "startConnector" : 0, - "advance" : 533, - "extender" : false - }, - { - "glyph" : "uni21D5.ex", - "endConnector" : 356, - "startConnector" : 356, - "advance" : 356, - "extender" : true - }, - { - "glyph" : "uni21D5.tp", - "endConnector" : 0, - "startConnector" : 178, - "advance" : 533, - "extender" : false - } - ] - }, - "uni21BF" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21BF.bt", - "endConnector" : 171, - "startConnector" : 0, - "advance" : 512, - "extender" : false - }, - { - "glyph" : "uni21BF.ex", - "endConnector" : 341, - "startConnector" : 341, - "advance" : 341, - "extender" : true - }, - { - "glyph" : "uni21BF.tp", - "endConnector" : 0, - "startConnector" : 171, - "advance" : 513, - "extender" : false - } - ] - }, - "uni230A" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni23A3", - "endConnector" : 500, - "startConnector" : 0, - "advance" : 1500, - "extender" : false - }, - { - "glyph" : "uni23A2", - "endConnector" : 1000, - "startConnector" : 1000, - "advance" : 1000, - "extender" : true - } - ] - }, - "arrowdown" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "arrowdown.bt", - "endConnector" : 169, - "startConnector" : 0, - "advance" : 505, - "extender" : false - }, - { - "glyph" : "arrowdown.ex", - "endConnector" : 337, - "startConnector" : 337, - "advance" : 337, - "extender" : true - }, - { - "glyph" : "arrowdown.tp", - "endConnector" : 0, - "startConnector" : 169, - "advance" : 506, - "extender" : false - } - ] - }, - "uni21C5" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21C5.bt", - "endConnector" : 172, - "startConnector" : 0, - "advance" : 515, - "extender" : false - }, - { - "glyph" : "uni21C5.ex", - "endConnector" : 343, - "startConnector" : 343, - "advance" : 343, - "extender" : true - }, - { - "glyph" : "uni21C5.tp", - "endConnector" : 0, - "startConnector" : 172, - "advance" : 514, - "extender" : false - } - ] - }, - "uni27EE" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni27EE.bt", - "endConnector" : 499, - "startConnector" : 0, - "advance" : 1526, - "extender" : false - }, - { - "glyph" : "uni27EE.ex", - "endConnector" : 998, - "startConnector" : 998, - "advance" : 998, - "extender" : true - }, - { - "glyph" : "uni27EE.tp", - "endConnector" : 0, - "startConnector" : 499, - "advance" : 1526, - "extender" : false - } - ] - }, - "bar" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "divides.bt", - "endConnector" : 601, - "startConnector" : 0, - "advance" : 1202, - "extender" : false - }, - { - "glyph" : "divides.ex", - "endConnector" : 1202, - "startConnector" : 1202, - "advance" : 1202, - "extender" : true - }, - { - "glyph" : "divides.tp", - "endConnector" : 0, - "startConnector" : 601, - "advance" : 1202, - "extender" : false - } - ] - }, - "uni21A5" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21A5.bt", - "endConnector" : 166, - "startConnector" : 0, - "advance" : 498, - "extender" : false - }, - { - "glyph" : "uni21A5.ex", - "endConnector" : 332, - "startConnector" : 332, - "advance" : 332, - "extender" : true - }, - { - "glyph" : "uni21A5.tp", - "endConnector" : 0, - "startConnector" : 166, - "advance" : 498, - "extender" : false - } - ] - }, - "uni21BE" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21BE.bt", - "endConnector" : 171, - "startConnector" : 0, - "advance" : 512, - "extender" : false - }, - { - "glyph" : "uni21BE.ex", - "endConnector" : 341, - "startConnector" : 341, - "advance" : 341, - "extender" : true - }, - { - "glyph" : "uni21BE.tp", - "endConnector" : 0, - "startConnector" : 171, - "advance" : 513, - "extender" : false - } - ] - }, - "parallel" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "parallel.bt", - "endConnector" : 601, - "startConnector" : 0, - "advance" : 1202, - "extender" : false - }, - { - "glyph" : "parallel.ex", - "endConnector" : 1202, - "startConnector" : 1202, - "advance" : 1202, - "extender" : true - }, - { - "glyph" : "parallel.tp", - "endConnector" : 0, - "startConnector" : 601, - "advance" : 1202, - "extender" : false - } - ] - }, - "uni21E9" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21E9.bt", - "endConnector" : 173, - "startConnector" : 0, - "advance" : 519, - "extender" : false - }, - { - "glyph" : "uni21E9.ex", - "endConnector" : 346, - "startConnector" : 346, - "advance" : 346, - "extender" : true - }, - { - "glyph" : "uni21E9.tp", - "endConnector" : 0, - "startConnector" : 173, - "advance" : 519, - "extender" : false - } - ] - }, - "braceright" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni23AD", - "endConnector" : 374, - "startConnector" : 0, - "advance" : 750, - "extender" : false - }, - { - "glyph" : "braceright.ex", - "endConnector" : 748, - "startConnector" : 748, - "advance" : 748, - "extender" : true - }, - { - "glyph" : "uni23AC", - "endConnector" : 374, - "startConnector" : 374, - "advance" : 1500, - "extender" : false - }, - { - "glyph" : "braceright.ex", - "endConnector" : 748, - "startConnector" : 748, - "advance" : 748, - "extender" : true - }, - { - "glyph" : "uni23AB", - "endConnector" : 0, - "startConnector" : 374, - "advance" : 750, - "extender" : false - } - ] - }, - "uni2B0D" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni2B0D.bt", - "endConnector" : 161, - "startConnector" : 0, - "advance" : 484, - "extender" : false - }, - { - "glyph" : "uni2B0D.ex", - "endConnector" : 322, - "startConnector" : 322, - "advance" : 322, - "extender" : true - }, - { - "glyph" : "uni2B0D.tp", - "endConnector" : 0, - "startConnector" : 161, - "advance" : 484, - "extender" : false - } - ] - }, - "uni21F3" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21F3.bt", - "endConnector" : 175, - "startConnector" : 0, - "advance" : 524, - "extender" : false - }, - { - "glyph" : "uni21F3.ex", - "endConnector" : 349, - "startConnector" : 349, - "advance" : 349, - "extender" : true - }, - { - "glyph" : "uni21F3.tp", - "endConnector" : 0, - "startConnector" : 175, - "advance" : 523, - "extender" : false - } - ] - }, - "uni21C3" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21C3.bt", - "endConnector" : 171, - "startConnector" : 0, - "advance" : 513, - "extender" : false - }, - { - "glyph" : "uni21C3.ex", - "endConnector" : 341, - "startConnector" : 341, - "advance" : 341, - "extender" : true - }, - { - "glyph" : "uni21C3.tp", - "endConnector" : 0, - "startConnector" : 171, - "advance" : 512, - "extender" : false - } - ] - }, - "arrowdblup" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "arrowdblup.bt", - "endConnector" : 168, - "startConnector" : 0, - "advance" : 505, - "extender" : false - }, - { - "glyph" : "arrowdblup.ex", - "endConnector" : 336, - "startConnector" : 336, - "advance" : 336, - "extender" : true - }, - { - "glyph" : "arrowdblup.tp", - "endConnector" : 0, - "startConnector" : 168, - "advance" : 504, - "extender" : false - } - ] - }, - "uni2309" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni23A5", - "endConnector" : 1000, - "startConnector" : 1000, - "advance" : 1000, - "extender" : true - }, - { - "glyph" : "uni23A4", - "endConnector" : 0, - "startConnector" : 500, - "advance" : 1500, - "extender" : false - } - ] - }, - "uni219F" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni219F.bt", - "endConnector" : 169, - "startConnector" : 0, - "advance" : 506, - "extender" : false - }, - { - "glyph" : "uni219F.ex", - "endConnector" : 337, - "startConnector" : 337, - "advance" : 337, - "extender" : true - }, - { - "glyph" : "uni219F.tp", - "endConnector" : 0, - "startConnector" : 169, - "advance" : 505, - "extender" : false - } - ] - }, - "uni21C8" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21C8.bt", - "endConnector" : 169, - "startConnector" : 0, - "advance" : 506, - "extender" : false - }, - { - "glyph" : "uni21C8.ex", - "endConnector" : 337, - "startConnector" : 337, - "advance" : 337, - "extender" : true - }, - { - "glyph" : "uni21C8.tp", - "endConnector" : 0, - "startConnector" : 169, - "advance" : 505, - "extender" : false - } - ] - }, - "parenright" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni23A0", - "endConnector" : 249, - "startConnector" : 0, - "advance" : 1495, - "extender" : false - }, - { - "glyph" : "uni239F", - "endConnector" : 498, - "startConnector" : 498, - "advance" : 498, - "extender" : true - }, - { - "glyph" : "uni239E", - "endConnector" : 0, - "startConnector" : 249, - "advance" : 1495, - "extender" : false - } - ] - }, - "parenleft" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni239D", - "endConnector" : 249, - "startConnector" : 0, - "advance" : 1495, - "extender" : false - }, - { - "glyph" : "uni239C", - "endConnector" : 498, - "startConnector" : 498, - "advance" : 498, - "extender" : true - }, - { - "glyph" : "uni239B", - "endConnector" : 0, - "startConnector" : 249, - "advance" : 1495, - "extender" : false - } - ] - }, - "uni21E7" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21E7.bt", - "endConnector" : 173, - "startConnector" : 0, - "advance" : 519, - "extender" : false - }, - { - "glyph" : "uni21E7.ex", - "endConnector" : 346, - "startConnector" : 346, - "advance" : 346, - "extender" : true - }, - { - "glyph" : "uni21E7.tp", - "endConnector" : 0, - "startConnector" : 173, - "advance" : 519, - "extender" : false - } - ] - }, - "uni21C2" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni21C2.bt", - "endConnector" : 171, - "startConnector" : 0, - "advance" : 513, - "extender" : false - }, - { - "glyph" : "uni21C2.ex", - "endConnector" : 341, - "startConnector" : 341, - "advance" : 341, - "extender" : true - }, - { - "glyph" : "uni21C2.tp", - "endConnector" : 0, - "startConnector" : 171, - "advance" : 512, - "extender" : false - } - ] - }, - "uni2308" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni23A2", - "endConnector" : 1000, - "startConnector" : 1000, - "advance" : 1000, - "extender" : true - }, - { - "glyph" : "uni23A1", - "endConnector" : 0, - "startConnector" : 500, - "advance" : 1500, - "extender" : false - } - ] - }, - "arrowupdn" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "arrowupdn.bt", - "endConnector" : 127, - "startConnector" : 0, - "advance" : 380, - "extender" : false - }, - { - "glyph" : "arrowupdn.ex", - "endConnector" : 254, - "startConnector" : 254, - "advance" : 254, - "extender" : true - }, - { - "glyph" : "arrowupdn.tp", - "endConnector" : 0, - "startConnector" : 127, - "advance" : 380, - "extender" : false - } - ] - }, - "uni2B07" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni2B07.bt", - "endConnector" : 164, - "startConnector" : 0, - "advance" : 492, - "extender" : false - }, - { - "glyph" : "uni2B07.ex", - "endConnector" : 327, - "startConnector" : 327, - "advance" : 327, - "extender" : true - }, - { - "glyph" : "uni2B07.tp", - "endConnector" : 0, - "startConnector" : 164, - "advance" : 492, - "extender" : false - } - ] - }, - "bracketleft" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni23A3", - "endConnector" : 500, - "startConnector" : 0, - "advance" : 1500, - "extender" : false - }, - { - "glyph" : "uni23A2", - "endConnector" : 1000, - "startConnector" : 1000, - "advance" : 1000, - "extender" : true - }, - { - "glyph" : "uni23A1", - "endConnector" : 0, - "startConnector" : 500, - "advance" : 1500, - "extender" : false - } - ] - }, - "arrowdbldown" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "arrowdbldown.bt", - "endConnector" : 168, - "startConnector" : 0, - "advance" : 504, - "extender" : false - }, - { - "glyph" : "arrowdbldown.ex", - "endConnector" : 336, - "startConnector" : 336, - "advance" : 336, - "extender" : true - }, - { - "glyph" : "arrowdbldown.tp", - "endConnector" : 0, - "startConnector" : 168, - "advance" : 505, - "extender" : false - } - ] - }, - "uni27E7" : { - "italic" : 0, - "parts" : [ - { - "glyph" : "uni27E7.bt", - "endConnector" : 500, - "startConnector" : 0, - "advance" : 1000, - "extender" : false - }, - { - "glyph" : "uni27E7.ex", - "endConnector" : 1000, - "startConnector" : 1000, - "advance" : 1000, - "extender" : true - }, - { - "glyph" : "uni27E7.tp", - "endConnector" : 0, - "startConnector" : 500, - "advance" : 1000, - "extender" : false - } - ] - } - }, - "h_variants" : { - "uni21CD" : [ - "uni21CD", - "uni21CD.h1" - ], - "uni2263" : [ - - ], - "caronbelowcmb" : [ - "caronbelowcmb", - "caronbelowcmb.h1", - "caronbelowcmb.h2", - "caronbelowcmb.h3", - "caronbelowcmb.h4", - "caronbelowcmb.h5", - "caronbelowcmb.h6", - "caronbelowcmb.h7" - ], - "uni21A4" : [ - "uni21A4", - "uni27FB" - ], - "uni20D0" : [ - "uni20D0", - "uni20D0.h1" - ], - "caroncmb" : [ - "caroncmb", - "caroncmb.h1", - "caroncmb.h2", - "caroncmb.h3", - "caroncmb.h4", - "caroncmb.h5", - "caroncmb.h6", - "caroncmb.h7" - ], - "uni21E8" : [ - "uni21E8", - "uni21E8.h1" - ], - "uni27A1" : [ - "uni27A1", - "uni27A1.h1" - ], - "uni2B05" : [ - "uni2B05", - "uni2B05.h1" - ], - "uni20D6" : [ - "uni20D6", - "uni20D6.h1" - ], - "uni2B31" : [ - "uni2B31", - "uni2B31.h1" - ], - "overlinecmb" : [ - "overlinecmb", - "overlinecmb.h1" - ], - "uni20ED" : [ - "uni20ED", - "uni20ED.h1" - ], - "uni21C1" : [ - "uni21C1", - "uni21C1.h1" - ], - "uni21AC" : [ - "uni21AC", - "uni21AC.h1" - ], - "circumflexbelowcmb" : [ - "circumflexbelowcmb", - "circumflexbelowcmb.h1", - "circumflexbelowcmb.h2", - "circumflexbelowcmb.h3", - "circumflexbelowcmb.h4", - "circumflexbelowcmb.h5", - "circumflexbelowcmb.h6", - "circumflexbelowcmb.h7" - ], - "uni21C4" : [ - "uni21C4", - "uni21C4.h1" - ], - "uni219A" : [ - "uni219A", - "uni219A.h1" - ], - "lowlinecmb" : [ - "lowlinecmb", - "lowlinecmb.h1" - ], - "uni21DB" : [ - "uni21DB", - "uni21DB.h1" - ], - "uni21C7" : [ - "uni21C7", - "uni21C7.h1" - ], - "brevebelowcmb" : [ - "brevebelowcmb", - "brevebelowcmb.h1", - "brevebelowcmb.h2", - "brevebelowcmb.h3", - "brevebelowcmb.h4", - "brevebelowcmb.h5", - "brevebelowcmb.h6", - "brevebelowcmb.h7" - ], - "dbloverlinecmb" : [ - "dbloverlinecmb", - "dbloverlinecmb.h1" - ], - "uni23DE" : [ - "uni23DE", - "uni23DE.h1", - "uni23DE.h2", - "uni23DE.h3", - "uni23DE.h4", - "uni23DE.h5", - "uni23DE.h6", - "uni23DE.h7" - ], - "uni21F6" : [ - "uni21F6", - "uni21F6.h1" - ], - "circumflexcmb" : [ - "circumflexcmb", - "circumflexcmb.h1", - "circumflexcmb.h2", - "circumflexcmb.h3", - "circumflexcmb.h4", - "circumflexcmb.h5", - "circumflexcmb.h6", - "circumflexcmb.h7" - ], - "uni20E1" : [ - "uni20E1", - "uni20E1.h1" - ], - "uni23B5" : [ - "uni23B5", - "uni23B5.h1", - "uni23B5.h2", - "uni23B5.h3", - "uni23B5.h4", - "uni23B5.h5", - "uni23B5.h6", - "uni23B5.h7" - ], - "uni21CC" : [ - "uni21CC", - "uni21CC.h1" - ], - "uni23E1" : [ - "uni23E1", - "uni23E1.h1", - "uni23E1.h2", - "uni23E1.h3", - "uni23E1.h4", - "uni23E1.h5", - "uni23E1.h6", - "uni23E1.h7" - ], - "uni21A0" : [ - "uni21A0", - "uni21A0.h1" - ], - "uni21CF" : [ - "uni21CF", - "uni21CF.h1" - ], - "uni2907" : [ - "uni2907", - "uni27FE" - ], - "uni21A3" : [ - "uni21A3", - "uni21A3.h1" - ], - "brevecmb" : [ - "brevecmb", - "brevecmb.h1", - "brevecmb.h2", - "brevecmb.h3", - "brevecmb.h4", - "brevecmb.h5", - "brevecmb.h6", - "brevecmb.h7" - ], - "uni21A6" : [ - "uni21A6", - "uni27FC" - ], - "arrowleft" : [ - "arrowleft", - "uni27F5" - ], - "uni21A9" : [ - "uni21A9", - "uni21A9.h1" - ], - "uni21BD" : [ - "uni21BD", - "uni21BD.h1" - ], - "uni2B04" : [ - "uni2B04", - "uni2B04.h1" - ], - "arrowright" : [ - "arrowright", - "uni27F6" - ], - "breveinvertedcmb" : [ - "breveinvertedcmb", - "breveinvertedcmb.h1", - "breveinvertedcmb.h2", - "breveinvertedcmb.h3", - "breveinvertedcmb.h4", - "breveinvertedcmb.h5", - "breveinvertedcmb.h6", - "breveinvertedcmb.h7" - ], - "uni20EC" : [ - "uni20EC", - "uni20EC.h1" - ], - "minus" : [ - - ], - "arrowdblleft" : [ - "arrowdblleft", - "uni27F8" - ], - "uni21C0" : [ - "uni21C0", - "uni21C0.h1" - ], - "uni21AB" : [ - "uni21AB", - "uni21AB.h1" - ], - "uni20EF" : [ - "uni20EF", - "uni20EF.h1" - ], - "uni21AE" : [ - "uni21AE", - "uni21AE.h1" - ], - "uni21C6" : [ - "uni21C6", - "uni21C6.h1" - ], - "uni21DA" : [ - "uni21DA", - "uni21DA.h1" - ], - "uni2B0C" : [ - "uni2B0C", - "uni2B0C.h1" - ], - "breveinvertedbelowcmb" : [ - "breveinvertedbelowcmb", - "breveinvertedbelowcmb.h1", - "breveinvertedbelowcmb.h2", - "breveinvertedbelowcmb.h3", - "breveinvertedbelowcmb.h4", - "breveinvertedbelowcmb.h5", - "breveinvertedbelowcmb.h6", - "breveinvertedbelowcmb.h7" - ], - "uni21C9" : [ - "uni21C9", - "uni21C9.h1" - ], - "uni21DD" : [ - "uni21DD", - "uni27FF" - ], - "uni23DD" : [ - "uni23DD", - "uni23DD.h1", - "uni23DD.h2", - "uni23DD.h3", - "uni23DD.h4", - "uni23DD.h5", - "uni23DD.h6", - "uni23DD.h7" - ], - "tildecomb" : [ - "tildecomb", - "tildecomb.h1", - "tildecomb.h2", - "tildecomb.h3", - "tildecomb.h4", - "tildecomb.h5", - "tildecomb.h6", - "tildecomb.h7" - ], - "uni23B4" : [ - "uni23B4", - "uni23B4.h1", - "uni23B4.h2", - "uni23B4.h3", - "uni23B4.h4", - "uni23B4.h5", - "uni23B4.h6", - "uni23B4.h7" - ], - "uni21B7" : [ - "uni21B7", - "uni21B7.h1" - ], - "uni21CB" : [ - "uni21CB", - "uni21CB.h1" - ], - "uni23E0" : [ - "uni23E0", - "uni23E0.h1", - "uni23E0.h2", - "uni23E0.h3", - "uni23E0.h4", - "uni23E0.h5", - "uni23E0.h6", - "uni23E0.h7" - ], - "uni21CE" : [ - "uni21CE", - "uni21CE.h1" - ], - "uni2906" : [ - "uni2906", - "uni27FD" - ], - "uni21A2" : [ - "uni21A2", - "uni21A2.h1" - ], - "dbllowlinecmb" : [ - "dbllowlinecmb", - "dbllowlinecmb.h1" - ], - "uni21E6" : [ - "uni21E6", - "uni21E6.h1" - ], - "uni20E9" : [ - "uni20E9", - "uni23B4.h1", - "uni23B4.h2", - "uni23B4.h3", - "uni23B4.h4", - "uni23B4.h5", - "uni23B4.h6", - "uni23B4.h7" - ], - "uni20D1" : [ - "uni20D1", - "uni20D1.h1" - ], - "arrowdblright" : [ - "arrowdblright", - "uni27F9" - ], - "uni21BC" : [ - "uni21BC", - "uni21BC.h1" - ], - "uni20D7" : [ - "uni20D7", - "uni20D7.h1" - ], - "uni20EE" : [ - "uni20EE", - "uni20EE.h1" - ], - "uni21AA" : [ - "uni21AA", - "uni21AA.h1" - ], - "uni21AD" : [ - "uni21AD", - "uni21AD.h1" - ], - "uni219B" : [ - "uni219B", - "uni219B.h1" - ], - "equal" : [ - - ], - "uni21DC" : [ - "uni21DC", - "uni2B33" - ], - "equivalence" : [ - - ], - "uni219E" : [ - "uni219E", - "uni219E.h1" - ], - "arrowdblboth" : [ - "arrowdblboth", - "uni27FA" - ], - "uni23DC" : [ - "uni23DC", - "uni23DC.h1", - "uni23DC.h2", - "uni23DC.h3", - "uni23DC.h4", - "uni23DC.h5", - "uni23DC.h6", - "uni23DC.h7" - ], - "tildebelowcmb" : [ - "tildebelowcmb", - "tildebelowcmb.h1", - "tildebelowcmb.h2", - "tildebelowcmb.h3", - "tildebelowcmb.h4", - "tildebelowcmb.h5", - "tildebelowcmb.h6", - "tildebelowcmb.h7" - ], - "uni23DF" : [ - "uni23DF", - "uni23DF.h1", - "uni23DF.h2", - "uni23DF.h3", - "uni23DF.h4", - "uni23DF.h5", - "uni23DF.h6", - "uni23DF.h7" - ], - "arrowboth" : [ - "arrowboth", - "uni27F7" - ], - "uni21B6" : [ - "uni21B6", - "uni21B6.h1" - ], - "uni034D" : [ - "uni034D", - "uni034D.h1" - ] - }, - "version" : "1.3", - "constants" : { - "FlattenedAccentBaseHeight" : 664, - "UpperLimitBaselineRiseMin" : 111, - "SubSuperscriptGapMin" : 160, - "OverbarExtraAscender" : 40, - "RadicalExtraAscender" : 40, - "FractionRuleThickness" : 40, - "DisplayOperatorMinHeight" : 1300, - "StackGapMin" : 120, - "LowerLimitBaselineDropMin" : 600, - "StretchStackGapBelowMin" : 167, - "FractionNumeratorDisplayStyleShiftUp" : 677, - "StretchStackGapAboveMin" : 200, - "FractionNumeratorShiftUp" : 394, - "AccentBaseHeight" : 450, - "SkewedFractionVerticalGap" : 96, - "FractionDenominatorDisplayStyleShiftDown" : 686, - "LowerLimitGapMin" : 167, - "MinConnectorOverlap" : 20, - "AxisHeight" : 250, - "SuperscriptBottomMin" : 108, - "RadicalKernBeforeDegree" : 278, - "StretchStackTopShiftUp" : 111, - "RadicalDisplayStyleVerticalGap" : 148, - "StackBottomDisplayStyleShiftDown" : 686, - "RadicalVerticalGap" : 50, - "RadicalKernAfterDegree" : -556, - "ScriptScriptPercentScaleDown" : 50, - "MathLeading" : 154, - "StretchStackBottomShiftDown" : 600, - "RadicalDegreeBottomRaisePercent" : 60, - "UnderbarExtraDescender" : 40, - "StackTopShiftUp" : 444, - "DelimitedSubFormulaMinHeight" : 1300, - "StackDisplayStyleGapMin" : 280, - "SubscriptTopMax" : 344, - "SuperscriptShiftUp" : 363, - "SuperscriptBottomMaxWithSubscript" : 344, - "ScriptPercentScaleDown" : 70, - "UnderbarVerticalGap" : 120, - "SpaceAfterScript" : 56, - "StackTopDisplayStyleShiftUp" : 677, - "FractionDenomDisplayStyleGapMin" : 120, - "UpperLimitGapMin" : 200, - "SuperscriptShiftUpCramped" : 289, - "SubscriptShiftDown" : 247, - "SuperscriptBaselineDropMax" : 250, - "OverbarVerticalGap" : 120, - "FractionNumeratorGapMin" : 40, - "SkewedFractionHorizontalGap" : 350, - "FractionDenominatorGapMin" : 40, - "UnderbarRuleThickness" : 40, - "SubscriptBaselineDropMin" : 200, - "OverbarRuleThickness" : 40, - "FractionNumDisplayStyleGapMin" : 120, - "FractionDenominatorShiftDown" : 345, - "RadicalRuleThickness" : 40, - "StackBottomShiftDown" : 345 - } -} \ No newline at end of file diff --git a/CSharpMath.Apple/Resources/latinmodern-math.otf b/CSharpMath.Apple/Resources/latinmodern-math.otf deleted file mode 100644 index 0e4642e91..000000000 Binary files a/CSharpMath.Apple/Resources/latinmodern-math.otf and /dev/null differ diff --git a/CSharpMath.Avalonia.Example/App.xaml b/CSharpMath.Avalonia.Example/App.xaml index 3c327353f..018f7856d 100644 --- a/CSharpMath.Avalonia.Example/App.xaml +++ b/CSharpMath.Avalonia.Example/App.xaml @@ -4,7 +4,7 @@ - + diff --git a/CSharpMath.Avalonia.Example/CSharpMath.Avalonia.Example.csproj b/CSharpMath.Avalonia.Example/CSharpMath.Avalonia.Example.csproj index 42e47464b..93dae7a4e 100644 --- a/CSharpMath.Avalonia.Example/CSharpMath.Avalonia.Example.csproj +++ b/CSharpMath.Avalonia.Example/CSharpMath.Avalonia.Example.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net10.0 WinExe @@ -11,6 +11,7 @@ + diff --git a/CSharpMath.Avalonia.Example/MainView.xaml b/CSharpMath.Avalonia.Example/MainView.xaml index a78add00b..e88a7c73c 100644 --- a/CSharpMath.Avalonia.Example/MainView.xaml +++ b/CSharpMath.Avalonia.Example/MainView.xaml @@ -18,9 +18,9 @@ Margin="2,8" Padding="8,0" VerticalContentAlignment="Center" - Content="Light" - IsChecked="true" /> - + ("lightThemeRbn"); - themes.Checked += (sender, e) => Application.Current.Styles[0] = light; - themes.Unchecked += (sender, e) => Application.Current.Styles[0] = dark; + var light = this.Find("lightThemeRbn")!; + var dark = this.Find("darkThemeRbn")!; + if ((string)Application.Current!.ActualThemeVariant.Key == "Dark") + dark.IsChecked = true; + else light.IsChecked = true; + light.IsCheckedChanged += (sender, e) => { + Application.Current!.RequestedThemeVariant = + light.IsChecked == true ? ThemeVariant.Light : ThemeVariant.Dark; + }; + dark.IsCheckedChanged += (sender, e) => { + Application.Current!.RequestedThemeVariant = + dark.IsChecked == false ? ThemeVariant.Light : ThemeVariant.Dark; + }; } private void InitializeComponent() { diff --git a/CSharpMath.Avalonia.Example/MainWindow.xaml.cs b/CSharpMath.Avalonia.Example/MainWindow.xaml.cs index 51be11dda..2c0c03efe 100644 --- a/CSharpMath.Avalonia.Example/MainWindow.xaml.cs +++ b/CSharpMath.Avalonia.Example/MainWindow.xaml.cs @@ -6,17 +6,16 @@ namespace CSharpMath.Avalonia.Example { public class MainWindow : Window { public MainWindow() { InitializeComponent(); - Icon = new WindowIcon(System.Reflection.Assembly.GetExecutingAssembly() - .GetManifestResourceStream("CSharpMath.Avalonia.Example.Icon.png")); + var stream = System.Reflection.Assembly.GetExecutingAssembly() + .GetManifestResourceStream("CSharpMath.Avalonia.Example.Icon.png"); + if (stream != null) + Icon = new WindowIcon(stream); +#if DEBUG this.AttachDevTools(); +#endif } private void InitializeComponent() { - // TODO: iOS does not support dynamically loading assemblies - // so we must refer to this resource DLL statically. For - // now I am doing that here. But we need a better solution!! - var theme = new global::Avalonia.Themes.Default.DefaultTheme(); - theme.TryGetResource("Button", out _); AvaloniaXamlLoader.Load(this); } } diff --git a/CSharpMath.Avalonia.Example/Pages/CalculatorPage.xaml.cs b/CSharpMath.Avalonia.Example/Pages/CalculatorPage.xaml.cs index e9acb8734..c582b1dc7 100644 --- a/CSharpMath.Avalonia.Example/Pages/CalculatorPage.xaml.cs +++ b/CSharpMath.Avalonia.Example/Pages/CalculatorPage.xaml.cs @@ -9,13 +9,13 @@ public class CalculatorPage : UserControl { public CalculatorPage() => AvaloniaXamlLoader.Load(this); } class CalculatorPageConverter : IValueConverter { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => value is string latex ? Atom.LaTeXParser.MathListFromLaTeX(latex) .Bind(list => Evaluation.Interpret(list)) .Match(success => success, error => latex) : value; - object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => + object? IValueConverter.ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => throw new NotImplementedException(); public static CalculatorPageConverter Singleton { get; } = new CalculatorPageConverter(); } diff --git a/CSharpMath.Avalonia/AvaloniaCanvas.cs b/CSharpMath.Avalonia/AvaloniaCanvas.cs index 0e6e276a0..445b2faeb 100644 --- a/CSharpMath.Avalonia/AvaloniaCanvas.cs +++ b/CSharpMath.Avalonia/AvaloniaCanvas.cs @@ -54,11 +54,11 @@ public void Restore() { } public void Save() => _states.Push(new Stack()); public void Scale(float sx, float sy) => - PushState(DrawingContext.PushPreTransform(new Matrix(sx, 0, 0, sy, 0, 0))); + PushState(DrawingContext.PushTransform(Matrix.CreateScale(sx, sy))); public void StrokeRect(float left, float top, float width, float height) => DrawingContext.DrawRectangle(new Pen(CurrentBrush), new Rect(left, top, width, height)); public void Translate(float dx, float dy) => - PushState(DrawingContext.PushPreTransform(new Matrix(1, 0, 0, 1, dx, dy))); + PushState(DrawingContext.PushTransform(Matrix.CreateTranslation(dx, dy))); private void PushState(DrawingContext.PushedState state) => _states.Peek().Push(state); } } diff --git a/CSharpMath.Avalonia/Extensions.cs b/CSharpMath.Avalonia/Extensions.cs index ae54f1e5e..8b26ecbf5 100644 --- a/CSharpMath.Avalonia/Extensions.cs +++ b/CSharpMath.Avalonia/Extensions.cs @@ -47,15 +47,15 @@ public static void DrawAsPng (this Painter painter, System.IO.Stream target, float textPainterCanvasWidth = TextPainter.DefaultCanvasWidth, - CSharpMathTextAlignment alignment = CSharpMathTextAlignment.TopLeft) where TContent : class { + int? quality = null) where TContent : class { if (!(painter.Measure(textPainterCanvasWidth) is { } size)) return; // RenderTargetBitmap does not support zero width/height. ArgumentException will be thrown. if (size.Width is 0) size.Width = 1; if (size.Height is 0) size.Height = 1; using var bitmap = new RenderTargetBitmap(new PixelSize((int)size.Width, (int)size.Height)); - bitmap.Render(new DrawVisual(painter, size, alignment)); - bitmap.Save(target); + bitmap.Render(new DrawVisual(painter, size, CSharpMathTextAlignment.TopLeft)); + bitmap.Save(target, quality); } } } diff --git a/CSharpMath.CoreTests/CSharpMath.CoreTests.csproj b/CSharpMath.CoreTests/CSharpMath.CoreTests.csproj index 705b8174f..abe3d53e9 100644 --- a/CSharpMath.CoreTests/CSharpMath.CoreTests.csproj +++ b/CSharpMath.CoreTests/CSharpMath.CoreTests.csproj @@ -1,13 +1,20 @@  - - - - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + \ No newline at end of file diff --git a/CSharpMath.CoreTests/LaTeXSettingsTests.cs b/CSharpMath.CoreTests/LaTeXSettingsTests.cs index d87d8465c..2cf97a8bc 100644 --- a/CSharpMath.CoreTests/LaTeXSettingsTests.cs +++ b/CSharpMath.CoreTests/LaTeXSettingsTests.cs @@ -30,10 +30,10 @@ public void CommandForAtomIgnoresInnerLists() { [Fact] public void AtomForCommandGeneratesACopy() { var atom = LaTeXSettings.AtomForCommand(@"\int"); - if (atom == null) throw new Xunit.Sdk.NotNullException(); + Assert.NotNull(atom); atom.IndexRange = Range.NotFound; var atom2 = LaTeXSettings.AtomForCommand(@"\int"); - if (atom2 == null) throw new Xunit.Sdk.NotNullException(); + Assert.NotNull(atom2); Assert.Equal(Range.Zero, atom2.IndexRange); } } diff --git a/CSharpMath.CoreTests/MathListTest.cs b/CSharpMath.CoreTests/MathListTest.cs index bfbb81df5..8c19445bf 100644 --- a/CSharpMath.CoreTests/MathListTest.cs +++ b/CSharpMath.CoreTests/MathListTest.cs @@ -159,7 +159,7 @@ static Action Assert.Equal(new Range(rangeIndex, rangeLength), a.IndexRange); }; static void CheckListContents(MathList? list) { - if (list == null) throw new Xunit.Sdk.NotNullException(); + Assert.NotNull(list); Assert.Collection(list.Atoms, CheckAtomNucleusAndRange("\u2212", 0, 1), CheckAtomNucleusAndRange("52", 1, 2), diff --git a/CSharpMath.CoreTests/MockTests.cs b/CSharpMath.CoreTests/MockTests.cs index 6031d5124..a2c9cbed1 100644 --- a/CSharpMath.CoreTests/MockTests.cs +++ b/CSharpMath.CoreTests/MockTests.cs @@ -1,4 +1,5 @@ -using CSharpMath.CoreTests.FrontEnd; +using CSharpMath.TestUtils; +using CSharpMath.CoreTests; using Xunit; using TGlyph = System.Text.Rune; using CSharpMath.Display; @@ -28,9 +29,6 @@ public void TestGlyphBoundsWithM() { } [Fact] public void ResourceProviderFindsResource() => - Assert.NotNull(Resources.ManifestResources.LatinMathContent); - [Fact] - public void ResourceProviderFindsMathConfiguration() => - Assert.IsType(Resources.ManifestResources.LatinMath["constants"]); + Assert.NotNull(TestUtils.Resources.ManifestResources.LatinMath); } } diff --git a/CSharpMath.CoreTests/_Helpers/ApproximateAssertions.cs b/CSharpMath.CoreTests/_Helpers/ApproximateAssertions.cs index d9a6226cc..793e9590a 100644 --- a/CSharpMath.CoreTests/_Helpers/ApproximateAssertions.cs +++ b/CSharpMath.CoreTests/_Helpers/ApproximateAssertions.cs @@ -22,9 +22,7 @@ public static void At Equal(x, actual.X, tolerance); Equal(y, actual.Y, tolerance); } catch (Xunit.Sdk.InRangeException) { - throw new Xunit.Sdk.InRangeException(actual, - new PointF((float)(x - tolerance), (float)(y - tolerance)), - new PointF((float)(x + tolerance), (float)(y + tolerance))); + Assert.Fail($"Expected point at ({x}, {y}) ± {tolerance}, but was ({actual.X}, {actual.Y})"); } } public static void Equal @@ -42,11 +40,7 @@ public static void Congruent(double x, double y, double width, double height, Equal(width, actual.Width, tolerance); Equal(height, actual.Height, tolerance); } catch (Xunit.Sdk.InRangeException) { - throw new Xunit.Sdk.InRangeException(actual, - new RectangleF((float)(x - tolerance), (float)(y - tolerance), - (float)(width - tolerance), (float)(height - tolerance)), - new RectangleF((float)(x + tolerance), (float)(y + tolerance), - (float)(width + tolerance), (float)(height + tolerance))); + Assert.Fail($"Expected rectangle at ({x}, {y}) with size ({width}, {height}) ± {tolerance}, but was at ({actual.X}, {actual.Y}) with size ({actual.Width}, {actual.Height})"); } } diff --git a/CSharpMath.CoreTests/_Helpers/FrontEnd/TestFontMeasurer.cs b/CSharpMath.CoreTests/_Helpers/FrontEnd/TestFontMeasurer.cs index 246e11917..9f9eac110 100644 --- a/CSharpMath.CoreTests/_Helpers/FrontEnd/TestFontMeasurer.cs +++ b/CSharpMath.CoreTests/_Helpers/FrontEnd/TestFontMeasurer.cs @@ -1,5 +1,5 @@ namespace CSharpMath.CoreTests.FrontEnd { - class TestFontMeasurer : Display.FrontEnd.IFontMeasurer { + class TestFontMeasurer : TestUtils.IFontMeasurer { TestFontMeasurer() { } public static TestFontMeasurer Instance { get; } = new TestFontMeasurer(); public int GetUnitsPerEm(TestFont font) => 1000; diff --git a/CSharpMath.CoreTests/_Helpers/FrontEnd/TestGlyphNameProvider.cs b/CSharpMath.CoreTests/_Helpers/FrontEnd/TestGlyphNameProvider.cs index a927ef846..71ee987bc 100644 --- a/CSharpMath.CoreTests/_Helpers/FrontEnd/TestGlyphNameProvider.cs +++ b/CSharpMath.CoreTests/_Helpers/FrontEnd/TestGlyphNameProvider.cs @@ -2,7 +2,7 @@ namespace CSharpMath.CoreTests.FrontEnd { using System.Linq; using TGlyph = System.Text.Rune; /// Looks up a name in latinmodern-math.json - class TestGlyphNameProvider : Display.FrontEnd.IGlyphNameProvider { + class TestGlyphNameProvider : TestUtils.IGlyphNameProvider { TestGlyphNameProvider() { } public static TestGlyphNameProvider Instance { get; } = new TestGlyphNameProvider(); static readonly TGlyph italic_a = "𝑎".EnumerateRunes().Single(); diff --git a/CSharpMath.CoreTests/_Helpers/FrontEnd/TestInterfaces.cs b/CSharpMath.CoreTests/_Helpers/FrontEnd/TestInterfaces.cs new file mode 100644 index 000000000..2154801d4 --- /dev/null +++ b/CSharpMath.CoreTests/_Helpers/FrontEnd/TestInterfaces.cs @@ -0,0 +1,18 @@ +namespace CSharpMath.Editor.Tests; + +using System.Text; +using CSharpMath.CoreTests.FrontEnd; + +/// +/// The names provided by this class are used to lookup spacings in JsonMathTable.cs. +/// +public interface IGlyphNameProvider{ + string GetGlyphName(Rune glyph); + Rune GetGlyph(string glyphName); +} + +public interface IFontMeasurer { + /// A proportionality constant that is applied when + /// reading from the Json table. + int GetUnitsPerEm(TestFont font); +} \ No newline at end of file diff --git a/CSharpMath.CoreTests/_Helpers/FrontEnd/TestTypesettingContext.cs b/CSharpMath.CoreTests/_Helpers/FrontEnd/TestTypesettingContext.cs index 51447bb05..142fd2d9f 100644 --- a/CSharpMath.CoreTests/_Helpers/FrontEnd/TestTypesettingContext.cs +++ b/CSharpMath.CoreTests/_Helpers/FrontEnd/TestTypesettingContext.cs @@ -6,9 +6,9 @@ public static class TestTypesettingContexts { (font, size) => new TestFont(size), TestGlyphBoundsProvider.Instance, TestGlyphFinder.Instance, - new Apple.JsonMathTable( + new TestUtils.JsonMathTable( TestFontMeasurer.Instance, - Resources.ManifestResources.LatinMath, + TestUtils.Resources.ManifestResources.LatinMath, TestGlyphNameProvider.Instance, TestGlyphBoundsProvider.Instance ) diff --git a/CSharpMath.CrossPlatform.slnf b/CSharpMath.CrossPlatform.slnf index bd27cd963..9a85c0a4a 100644 --- a/CSharpMath.CrossPlatform.slnf +++ b/CSharpMath.CrossPlatform.slnf @@ -15,6 +15,7 @@ "CSharpMath.Rendering.Tests.FSharp/CSharpMath.Rendering.Tests.FSharp.fsproj", "CSharpMath.Rendering.Text.Tests/CSharpMath.Rendering.Text.Tests.csproj", "CSharpMath.Rendering/CSharpMath.Rendering.csproj", + "CSharpMath.TestUtils/CSharpMath.TestUtils.csproj", "CSharpMath.Xaml/CSharpMath.Xaml.shproj", "CSharpMath.Xaml.Tests/CSharpMath.Xaml.Tests.csproj", "CSharpMath.Xaml.Tests.NuGet/CSharpMath.Xaml.Tests.NuGet.csproj", @@ -22,7 +23,6 @@ "Typography/Typography.OpenFont/Typography.OpenFont.shproj", "Typography/Typography.GlyphLayout/Typography.GlyphLayout.shproj", "Typography/Typography.TextBreak/Typography.TextBreak/Typography.TextBreak.shproj", - "Typography/Typography.TextBreak/Typography.TextBreak.UnitTests/TextBreakTests.csproj", "CSharpMath.Playground/CSharpMath.Playground.csproj", "CSharpMath.Avalonia/CSharpMath.Avalonia.csproj", "CSharpMath.Avalonia.Example/CSharpMath.Avalonia.Example.csproj", diff --git a/CSharpMath.Editor.Tests.Visualizer/CSharpMath.Editor.Tests.Visualizer.csproj b/CSharpMath.Editor.Tests.Visualizer/CSharpMath.Editor.Tests.Visualizer.csproj index e7c725a25..ff84a473d 100644 --- a/CSharpMath.Editor.Tests.Visualizer/CSharpMath.Editor.Tests.Visualizer.csproj +++ b/CSharpMath.Editor.Tests.Visualizer/CSharpMath.Editor.Tests.Visualizer.csproj @@ -1,7 +1,7 @@  Exe - netcoreapp3.1 + net10.0 CSharpMath.Editor.Tests.Visualizer.Checker diff --git a/CSharpMath.Editor.Tests.Visualizer/Checker.cs b/CSharpMath.Editor.Tests.Visualizer/Checker.cs index e6ae66b2b..49854da13 100644 --- a/CSharpMath.Editor.Tests.Visualizer/Checker.cs +++ b/CSharpMath.Editor.Tests.Visualizer/Checker.cs @@ -1,7 +1,7 @@ using System; using System.Drawing; using System.Text; -using ListDisplay = CSharpMath.Display.Displays.ListDisplay; +using ListDisplay = CSharpMath.Display.Displays.ListDisplay; namespace CSharpMath.Editor.Tests.Visualizer { using Structures; @@ -11,7 +11,7 @@ public class Checker { public static readonly bool OutputLines = true; public static void Main() { static int ReadInt(string message) { - string input; + string? input; int value; do { Console.Write(message); @@ -27,7 +27,7 @@ static int ReadInt(string message) { try { Console.Title = "CSharpMath.Editor.Tests Visualizer"; Console.Clear(); - if (Environment.OSVersion.Platform == PlatformID.Win32NT) + if (OperatingSystem.IsWindows()) Console.SetBufferSize(Console.WindowWidth, Console.BufferHeight); // line wrapping Console.ResetColor(); Console.WriteLine("Welcome to the CSharpMath.Editor.Tests Visualizer!"); @@ -46,7 +46,7 @@ static int ReadInt(string message) { ListDisplay? display = null; void AssignDisplay() { Console.Write("Input LaTeX: "); - if (latex is null) latex = Console.ReadLine(); + if (latex is null) latex = Console.ReadLine()!; else Console.WriteLine(latex); // The P-key case IndexForPointTests.CreateDisplay(latex) .Match(listDisplay => display = listDisplay, error => { @@ -61,7 +61,7 @@ void AssignDisplay() { var y = ReadInt("Input Touch Y (integer): "); Console.Clear(); - if(Environment.OSVersion.Platform == PlatformID.Win32NT) + if(OperatingSystem.IsWindows()) Console.SetBufferSize(10000, Console.BufferHeight); // no line wrapping display.Draw(context); moveCursor:var pos = Adjust(new Rectangle(x, y, 0, 0)); @@ -91,7 +91,7 @@ public static void SetConsoleColor(Color? col) { ConsoleColor ret = 0; double rr = color.R, gg = color.G, bb = color.B, delta = double.MaxValue; foreach (var cc in System.Linq.Enumerable.Cast(Enum.GetValues(typeof(ConsoleColor)))) { - var n = Enum.GetName(typeof(ConsoleColor), cc); + var n = Enum.GetName(typeof(ConsoleColor), cc)!; // There's no "DarkYellow" in System.Drawing.Color var c = cc is ConsoleColor.DarkYellow ? System.Drawing.Color.Orange : System.Drawing.Color.FromName(n); var t = Math.Pow(c.R - rr, 2.0) + Math.Pow(c.G - gg, 2.0) + Math.Pow(c.B - bb, 2.0); diff --git a/CSharpMath.Editor.Tests.Visualizer/GraphicsContext.cs b/CSharpMath.Editor.Tests.Visualizer/GraphicsContext.cs index 4d9a38e4f..5902c2b22 100644 --- a/CSharpMath.Editor.Tests.Visualizer/GraphicsContext.cs +++ b/CSharpMath.Editor.Tests.Visualizer/GraphicsContext.cs @@ -3,7 +3,7 @@ using System.Drawing; using System.Linq; using CSharpMath.Display; -using CSharpMath.CoreTests.FrontEnd; +using CSharpMath.TestUtils; using TGlyph = System.Text.Rune; namespace CSharpMath.Editor.Tests.Visualizer { diff --git a/CSharpMath.Editor.Tests/CSharpMath.Editor.Tests.csproj b/CSharpMath.Editor.Tests/CSharpMath.Editor.Tests.csproj index 9f96b5a61..315c3d4d4 100644 --- a/CSharpMath.Editor.Tests/CSharpMath.Editor.Tests.csproj +++ b/CSharpMath.Editor.Tests/CSharpMath.Editor.Tests.csproj @@ -1,19 +1,19 @@  - - - - - - - - - - - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + \ No newline at end of file diff --git a/CSharpMath.Editor.Tests/CaretTests.cs b/CSharpMath.Editor.Tests/CaretTests.cs index 9efbf5db7..9b48a0de2 100644 --- a/CSharpMath.Editor.Tests/CaretTests.cs +++ b/CSharpMath.Editor.Tests/CaretTests.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; using CSharpMath.Atom; -using CSharpMath.CoreTests.FrontEnd; +using CSharpMath.TestUtils; using Xunit; using TGlyph = System.Text.Rune; diff --git a/CSharpMath.Editor.Tests/IndexForPointTests.cs b/CSharpMath.Editor.Tests/IndexForPointTests.cs index f3627d955..e7e258cc4 100644 --- a/CSharpMath.Editor.Tests/IndexForPointTests.cs +++ b/CSharpMath.Editor.Tests/IndexForPointTests.cs @@ -1,13 +1,13 @@ using System.Drawing; using CSharpMath.Atom; -using CSharpMath.CoreTests.FrontEnd; +using CSharpMath.TestUtils; using Xunit; namespace CSharpMath.Editor.Tests { // Use the "CSharpMath.Editor Test Checker" project in the _Utils folder to visualize the test cases using SubIndex = MathListSubIndexType; public class IndexForPointTests { - public class TestData : TheoryData { + public class TestData : TheoryData { // Format of test data public void Add((double x, double y) point, int index, params (SubIndex subType, int subIndex)[] subIndexRecursive) { @@ -787,4 +787,4 @@ public void Complex(PointF point, MathListIndex expected) => [Theory, MemberData(nameof(InnerData))] public void Inner(PointF point, MathListIndex expected) => Test(@"\int a\left(bb\left[cc\right]dd\right)e\sum ", point, expected); } -} \ No newline at end of file +} diff --git a/CSharpMath.Editor.Tests/KeyPressTests.cs b/CSharpMath.Editor.Tests/KeyPressTests.cs index 5f633a60f..d84ac2e56 100644 --- a/CSharpMath.Editor.Tests/KeyPressTests.cs +++ b/CSharpMath.Editor.Tests/KeyPressTests.cs @@ -1,14 +1,14 @@ using System; using System.Linq; using CSharpMath.Display.FrontEnd; -using CSharpMath.CoreTests.FrontEnd; +using CSharpMath.TestUtils; using Xunit; using TGlyph = System.Text.Rune; -using T = Xunit.InlineDataAttribute; // 'T'est -using K = CSharpMath.Editor.MathKeyboardInput; // 'K'ey +using T = Xunit.InlineDataAttribute; +using K = CSharpMath.Editor.MathKeyboardInput; +using EventInteractor = System.Action, System.EventHandler>; namespace CSharpMath.Editor.Tests { - using EventInteractor = Action, EventHandler>; public class KeyPressTests { private static readonly TypesettingContext context = TestTypesettingContexts.Instance; static void Test(string latex, K[] inputs) { @@ -402,4 +402,4 @@ public void Return(params K[] inputs) => ] public void Slash(string latex, params K[] inputs) => Test(latex, inputs); } -} \ No newline at end of file +} diff --git a/CSharpMath.Editor.Tests/PointForIndexTests.cs b/CSharpMath.Editor.Tests/PointForIndexTests.cs index 0de0e5181..24b16860b 100644 --- a/CSharpMath.Editor.Tests/PointForIndexTests.cs +++ b/CSharpMath.Editor.Tests/PointForIndexTests.cs @@ -1,6 +1,8 @@ using System.Drawing; -using CSharpMath.CoreTests.FrontEnd; +using CSharpMath.Atom; +using CSharpMath.TestUtils; using Xunit; +using SubIndex = CSharpMath.Editor.MathListSubIndexType; namespace CSharpMath.Editor.Tests { using static IndexForPointTests; @@ -9,7 +11,7 @@ namespace CSharpMath.Editor.Tests { public class PointForIndexTests { void Test(string latex, PointF expected, MathListIndex index) => CreateDisplay(latex).Match( - display => CSharpMath.CoreTests.Approximately.Equal + display => CSharpMath.TestUtils.Approximately.Equal (expected, display.PointForIndex(TestTypesettingContexts.Instance, index)), s => throw new Xunit.Sdk.XunitException(s) ); diff --git a/CSharpMath.Evaluation.Tests/CSharpMath.Evaluation.Tests.csproj b/CSharpMath.Evaluation.Tests/CSharpMath.Evaluation.Tests.csproj index 709cdef75..20310f4ea 100644 --- a/CSharpMath.Evaluation.Tests/CSharpMath.Evaluation.Tests.csproj +++ b/CSharpMath.Evaluation.Tests/CSharpMath.Evaluation.Tests.csproj @@ -2,4 +2,17 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + \ No newline at end of file diff --git a/CSharpMath.Evaluation.Tests/EvaluationTests.cs b/CSharpMath.Evaluation.Tests/EvaluationTests.cs index b98e20f73..e06143074 100644 --- a/CSharpMath.Evaluation.Tests/EvaluationTests.cs +++ b/CSharpMath.Evaluation.Tests/EvaluationTests.cs @@ -52,82 +52,86 @@ void Test(string input) { [InlineData(".9876543210", "0.9876543210", "0.9876543210")] [InlineData("1234.5678", @"\frac{6172839}{5000}", @"\frac{6172839}{5000}")] [InlineData(@"\infty", @"\infty ", @"\infty ")] + [InlineData(@"1_2", @"1", @"1")] + [InlineData(@"10_2", @"2", @"2")] + [InlineData(@"1._2", @"1", @"1")] + [InlineData(@"1.1_2", @"\frac{3}{2}", @"\frac{3}{2}")] + [InlineData(@".1_3", @"\frac{1}{3}", @"\frac{1}{3}")] + [InlineData(@"10_3", @"3", @"3")] + [InlineData(@"10.1_3", @"\frac{10}{3}", @"\frac{10}{3}")] public void Numbers(string input, string converted, string output) => Test(input, converted, output); [Theory] [InlineData("a", "a", "a")] - [InlineData("ab", @"a\times b", @"a\times b")] - [InlineData("abc", @"a\times b\times c", @"a\times b\times c")] - [InlineData("3a", @"3\times a", @"3\times a")] - [InlineData("3ab", @"3\times a\times b", @"3\times a\times b")] - [InlineData("3a3", @"3\times a\times 3", @"9\times a")] - [InlineData("3aa", @"3\times a\times a", @"3\times a^2")] + [InlineData("ab", @"ab", @"ab")] + [InlineData("abc", @"abc", @"abc")] + [InlineData("3a", @"3a", @"3a")] + [InlineData("3ab", @"3ab", @"3ab")] + [InlineData("3a3", @"3a3", @"9a")] + [InlineData("3aa", @"3aa", @"3a^2")] [InlineData(@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", - @"a\times b\times c\times d\times e\times f\times g\times h\times i\times j\times k\times l\times m\times " + - @"n\times o\times p\times q\times r\times s\times t\times u\times v\times w\times x\times y\times z\times " + - @"A\times B\times C\times D\times E\times F\times G\times H\times I\times J\times K\times L\times M\times " + - @"N\times O\times P\times Q\times R\times S\times T\times U\times V\times W\times X\times Y\times Z", + @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", // i is considered as a number instead of a variable like other alphabets, so it is sorted to the front - @"i\times a\times A\times b\times B\times c\times C\times d\times D\times e\times E\times f\times F\times " + - @"g\times G\times h\times H\times I\times j\times J\times k\times K\times l\times L\times m\times M\times " + - @"n\times N\times o\times O\times p\times P\times q\times Q\times r\times R\times s\times S\times t\times " + - @"T\times u\times U\times v\times V\times w\times W\times x\times X\times y\times Y\times z\times Z")] + @"iaAbBcCdDeEfFgGhHIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ")] [InlineData(@"\alpha\beta\gamma\delta\epsilon\varepsilon\zeta\eta\theta\iota\kappa\varkappa" + @"\lambda\mu\nu\xi\omicron\pi\varpi\rho\varrho\sigma\varsigma\tau\upsilon\phi\varphi\chi" + @"\psi\omega\Gamma\Delta\Theta\Lambda\Xi\Pi\Sigma\Upsilon\Phi\Psi\Omega", - @"\alpha \times \beta \times \gamma \times \delta \times \epsilon \times \varepsilon \times \zeta " + - @"\times \eta \times \theta \times \iota \times \kappa \times \varkappa \times \lambda \times \mu " + - @"\times \nu \times \xi \times \omicron \times \pi \times \varpi \times \rho \times \varrho " + - @"\times \sigma \times \varsigma \times \tau \times \upsilon \times \phi \times \varphi \times \chi " + - @"\times \psi \times \omega \times \Gamma \times \Delta \times \Theta \times \Lambda \times \Xi " + - @"\times \Pi \times \Sigma \times \Upsilon \times \Phi \times \Psi \times \Omega ", - @"\alpha \times \beta \times \chi \times \delta \times \Delta \times \epsilon \times \eta " + - @"\times \gamma \times \Gamma \times \iota \times \kappa \times \lambda \times \Lambda \times \mu " + - @"\times \nu \times \omega \times \Omega \times \omicron \times \phi \times \Phi \times \Pi " + - @"\times \psi \times \Psi \times \rho \times \sigma \times \Sigma \times \tau \times \theta " + - @"\times \Theta \times \upsilon \times \Upsilon \times \varepsilon \times \varkappa \times \varphi " + - @"\times \varpi \times \varrho \times \varsigma \times \xi \times \Xi \times \zeta \times \pi ")] + @"\alpha \beta \gamma \delta \epsilon \varepsilon \zeta " + + @"\eta \theta \iota \kappa \varkappa \lambda \mu " + + @"\nu \xi \omicron \pi \varpi \rho \varrho " + + @"\sigma \varsigma \tau \upsilon \phi \varphi \chi " + + @"\psi \omega \Gamma \Delta \Theta \Lambda \Xi " + + @"\Pi \Sigma \Upsilon \Phi \Psi \Omega ", + @"\alpha \beta \chi \delta \Delta \epsilon \eta " + + @"\gamma \Gamma \iota \kappa \lambda \Lambda \mu " + + @"\nu \omega \Omega \omicron \phi \Phi \pi \Pi " + + @"\psi \Psi \rho \sigma \Sigma \tau \theta " + + @"\Theta \upsilon \Upsilon \varepsilon \varkappa \varphi " + + @"\varpi \varrho \varsigma \xi \Xi \zeta ")] [InlineData(@"a_2", @"a_2", @"a_2")] - [InlineData(@"a_2+a_2", @"a_2+a_2", @"2\times a_2")] + [InlineData(@"a_2+a_2", @"a_2+a_2", @"2a_2")] [InlineData(@"a_{23}", @"a_{23}", @"a_{23}")] [InlineData(@"\pi_a", @"\pi _a", @"\pi _a")] - [InlineData(@"ii", @"i\times i", @"-1")] - [InlineData(@"i\infty", @"i\times \infty ", @"\infty i")] - [InlineData(@"\infty\infty", @"\infty \times \infty ", @"\infty ")] + [InlineData(@"\pi_\kappa", @"\pi _{\kappa }", @"\pi _{\kappa }")] + [InlineData(@"\pi_{\kappa23}", @"\pi _{\kappa 23}", @"\pi _{\kappa 23}")] + [InlineData(@"\pi_{1a\kappa23}", @"\pi _{1a\kappa 23}", @"\pi _{1a\kappa 23}")] + [InlineData(@"ii", @"i\cdot i", @"-1")] + [InlineData(@"i\infty", @"i\cdot \infty ", @"\infty i")] + [InlineData(@"\infty\infty", @"\infty \cdot \infty ", @"\infty ")] public void Variables(string input, string converted, string result) => Test(input, converted, result); [Theory] [InlineData("a + b", @"a+b", "a+b")] [InlineData("a - b", @"a-b", "a-b")] - [InlineData("a * b", @"a\times b", @"a\times b")] - [InlineData(@"a\times b", @"a\times b", @"a\times b")] - [InlineData(@"a\cdot b", @"a\times b", @"a\times b")] + [InlineData("a * b", @"ab", @"ab")] + [InlineData(@"a\times b", @"ab", @"ab")] + [InlineData(@"a\cdot b", @"ab", @"ab")] [InlineData(@"a / b", @"\frac{a}{b}", @"\frac{a}{b}")] [InlineData(@"a\div b", @"\frac{a}{b}", @"\frac{a}{b}")] [InlineData(@"\frac ab", @"\frac{a}{b}", @"\frac{a}{b}")] [InlineData("a + b + c", @"a+b+c", "a+b+c")] [InlineData("a + b - c", @"a+b-c", "a+b-c")] - [InlineData("a + b * c", @"a+b\times c", @"a+b\times c")] + [InlineData("a + b * c", @"a+bc", @"a+bc")] [InlineData("a + b / c", @"a+\frac{b}{c}", @"a+\frac{b}{c}")] [InlineData("a - b + c", @"a-b+c", "a-b+c")] [InlineData("a - b - c", @"a-b-c", @"a-b-c")] - [InlineData("a - b * c", @"a-b\times c", @"a-b\times c")] + [InlineData("a - b * c", @"a-bc", @"a-bc")] [InlineData("a - b / c", @"a-\frac{b}{c}", @"a-\frac{b}{c}")] - [InlineData("a * b + c", @"a\times b+c", @"a\times b+c")] - [InlineData("a * b - c", @"a\times b-c", @"a\times b-c")] - [InlineData("a * b * c", @"a\times b\times c", @"a\times b\times c")] - [InlineData("a * b / c", @"\frac{a\times b}{c}", @"\frac{a\times b}{c}")] + [InlineData("a * b + c", @"ab+c", @"ab+c")] + [InlineData("a * b - c", @"ab-c", @"ab-c")] + [InlineData("a * b * c", @"abc", @"abc")] + [InlineData("a * b / c", @"\frac{ab}{c}", @"\frac{ab}{c}")] [InlineData("a / b + c", @"\frac{a}{b}+c", @"\frac{a}{b}+c")] [InlineData("a / b - c", @"\frac{a}{b}-c", @"\frac{a}{b}-c")] - [InlineData("a / b * c", @"\frac{a}{b}\times c", @"\frac{a}{b}\times c")] - [InlineData("a / b / c", @"\frac{\frac{a}{b}}{c}", @"\frac{a}{b\times c}")] + [InlineData("a / b * c", @"\frac{a}{b}\cdot c", @"\frac{a}{b}\cdot c")] + [InlineData("a / b / c", @"\frac{\frac{a}{b}}{c}", @"\frac{a}{bc}")] [InlineData(@"2+\frac ab", @"2+\frac{a}{b}", @"2+\frac{a}{b}")] [InlineData(@"\frac ab+2", @"\frac{a}{b}+2", @"\frac{a}{b}+2")] [InlineData(@"2-\frac ab", @"2-\frac{a}{b}", @"2-\frac{a}{b}")] [InlineData(@"\frac ab-2", @"\frac{a}{b}-2", @"\frac{a}{b}-2")] - [InlineData(@"2*\frac ab", @"2\times \frac{a}{b}", @"2\times \frac{a}{b}")] - [InlineData(@"\frac ab*2", @"\frac{a}{b}\times 2", @"\frac{a}{b}\times 2")] - [InlineData(@"2/\frac ab", @"\frac{2}{\frac{a}{b}}", @"2\times \frac{b}{a}")] - [InlineData(@"\frac ab/2", @"\frac{\frac{a}{b}}{2}", @"\frac{\frac{1}{2}\times a}{b}")] + [InlineData(@"2*\frac ab", @"2\frac{a}{b}", @"2\frac{a}{b}")] + [InlineData(@"\frac ab*2", @"\frac{a}{b}\cdot 2", @"\frac{a}{b}\cdot 2")] + [InlineData(@"2/\frac ab", @"\frac{2}{\frac{a}{b}}", @"\frac{2b}{a}")] + [InlineData(@"\frac ab/2", @"\frac{\frac{a}{b}}{2}", @"\frac{a}{2b}")] [InlineData(@"1+i", @"1+i", @"1+i")] [InlineData(@"1-i", @"1-i", @"1-i")] [InlineData(@"i+1", @"i+1", @"1+i")] @@ -135,11 +139,13 @@ public void Numbers(string input, string converted, string output) => [InlineData(@"\infty+1", @"\infty +1", @"\infty ")] [InlineData(@"\infty+i", @"\infty +i", @"\infty +i")] [InlineData(@"\infty+\infty", @"\infty +\infty ", @"\infty ")] - [InlineData(@"\infty\times \infty", @"\infty \times \infty ", @"\infty ")] - [InlineData(@"i\times \infty", @"i\times \infty ", @"\infty i")] - [InlineData(@"\infty\times i", @"\infty \times i", @"\infty i")] - [InlineData(@"i\times i", @"i\times i", @"-1")] - [InlineData(@"\frac00", @"\frac{0}{0}", @"\mathrm{undefined}")] + [InlineData(@"\infty\times \infty", @"\infty \cdot \infty ", @"\infty ")] + [InlineData(@"\infty\cdot \infty", @"\infty \cdot \infty ", @"\infty ")] + [InlineData(@"i\times \infty", @"i\cdot \infty ", @"\infty i")] + [InlineData(@"i\cdot \infty", @"i\cdot \infty ", @"\infty i")] + [InlineData(@"\infty\times i", @"\infty \cdot i", @"\infty i")] + [InlineData(@"i\times i", @"i\cdot i", @"-1")] + [InlineData(@"\frac00", @"\frac{0}{0}", @"0")] // BUG? [InlineData(@"\frac0\infty", @"\frac{0}{\infty }", @"0")] [InlineData(@"\frac2\infty", @"\frac{2}{\infty }", @"0")] [InlineData(@"\frac{-2}\infty", @"\frac{-2}{\infty }", @"0")] @@ -158,65 +164,80 @@ public void Numbers(string input, string converted, string output) => [InlineData("++a", "a", "a")] [InlineData("+-a", "-a", "-a")] [InlineData("-+a", "-a", "-a")] - [InlineData("--a", "--a", "a")] + [InlineData("--a", @"\left( -1\right) \left( -1\right) \cdot a", "a")] [InlineData("+++a", "a", "a")] - [InlineData("---a", "---a", "-a")] - [InlineData("a++a", "a+a", @"2\times a")] + [InlineData("---a", @"\left( -1\right) \left( -1\right) \left( -1\right) \cdot a", "-a")] + [InlineData("a++a", "a+a", @"2a")] [InlineData("a+-a", "a-a", "0")] [InlineData("a-+a", "a-a", "0")] - [InlineData("a--a", "a--a", @"2\times a")] - [InlineData("a+++a", "a+a", @"2\times a")] - [InlineData("a---a", "a---a", "0")] - [InlineData("a*+a", @"a\times a", "a^2")] - [InlineData("a*-a", @"a\times -a", "-a^2")] - [InlineData("+a*+a", @"a\times a", "a^2")] - [InlineData("-a*-a", @"-a\times -a", "a^2")] + [InlineData("a--a", @"a--a", @"2a")] + [InlineData("a+++a", "a+a", @"2a")] + [InlineData("a---a", @"a-\left( -1\right) \left( -1\right) \cdot a", "0")] + [InlineData("a*+a", @"aa", "a^2")] + [InlineData("a*-a", @"a\cdot \left( -1\right) \cdot a", "-a^2")] + [InlineData("+a*+a", @"aa", "a^2")] + [InlineData("-a*-a", @"\left( -1\right) \cdot a\cdot \left( -1\right) \cdot a", "a^2")] [InlineData("a/+a", @"\frac{a}{a}", "1")] [InlineData("a/-a", @"\frac{a}{-a}", "-1")] [InlineData("+a/+a", @"\frac{a}{a}", "1")] [InlineData("-a/-a", @"\frac{-a}{-a}", "1")] - [InlineData("-2+-2+-2", @"-2-2-2", "-6")] - [InlineData("-2--2--2", @"-2--2--2", "2")] - [InlineData("-2*-2*-2", @"-2\times -2\times -2", "-8")] - [InlineData("-2/-2/-2", @"\frac{\frac{-2}{-2}}{-2}", @"\frac{-1}{2}")] + [InlineData(@"-2+-2+-2", @"-2-2-2", "-6")] + [InlineData(@"-2--2--2", @"-2--2--2", "2")] + [InlineData(@"-2*-2*-2", @"\left( -1\right) \cdot 2\cdot \left( -1\right) \cdot 2\cdot \left( -1\right) \cdot 2", "-8")] + [InlineData(@"-2/-2/-2", @"\frac{\frac{-2}{-2}}{-2}", @"\frac{-1}{2}")] public void UnaryOperators(string latex, string converted, string result) => Test(latex, converted, result); [Theory] [InlineData(@"9\%", @"\frac{9}{100}", @"\frac{9}{100}")] - [InlineData(@"a\%", @"\frac{a}{100}", @"\frac{1}{100}\times a")] - [InlineData(@"\pi\%", @"\frac{\pi }{100}", @"\frac{1}{100}\times \pi ")] - [InlineData(@"a\%\%", @"\frac{\frac{a}{100}}{100}", @"\frac{1}{10000}\times a")] + [InlineData(@"a\%", @"\frac{a}{100}", @"\frac{a}{100}")] + [InlineData(@"\pi\%", @"\frac{\pi }{100}", @"\frac{\pi }{100}")] + [InlineData(@"a\%\%", @"\frac{\frac{a}{100}}{100}", @"\frac{a}{10000}")] [InlineData(@"9\%+3", @"\frac{9}{100}+3", @"\frac{309}{100}")] [InlineData(@"-9\%+3", @"-\frac{9}{100}+3", @"\frac{291}{100}")] [InlineData(@"2^2\%", @"\frac{2^2}{100}", @"\frac{1}{25}")] [InlineData(@"2\%^2", @"\left( \frac{2}{100}\right) ^2", @"\frac{1}{2500}")] - [InlineData(@"2\%2", @"\frac{2}{100}\times 2", @"\frac{1}{25}")] + [InlineData(@"2\%2", @"\frac{2}{100}\cdot 2", @"\frac{1}{25}")] [InlineData(@"1+2\%^2", @"1+\left( \frac{2}{100}\right) ^2", @"\frac{2501}{2500}")] - [InlineData(@"9\degree", @"\frac{9\times \pi }{180}", @"\frac{1}{20}\times \pi ")] - [InlineData(@"a\degree", @"\frac{a\times \pi }{180}", @"\frac{1}{180}\times a\times \pi ")] - [InlineData(@"\pi\degree", @"\frac{\pi \times \pi }{180}", @"\frac{1}{180}\times \pi ^2")] - [InlineData(@"a\%\degree", @"\frac{\frac{a}{100}\times \pi }{180}", @"\frac{1}{18000}\times a\times \pi ")] - [InlineData(@"a\degree\degree", @"\frac{\frac{a\times \pi }{180}\times \pi }{180}", @"\frac{1}{32400}\times a\times \pi ^2")] - [InlineData(@"9\degree+3", @"\frac{9\times \pi }{180}+3", @"3+\frac{1}{20}\times \pi ")] - [InlineData(@"-9\degree+3", @"-\frac{9\times \pi }{180}+3", @"3+\frac{-1}{20}\times \pi ")] - [InlineData(@"2^2\degree", @"\frac{2^2\times \pi }{180}", @"\frac{1}{45}\times \pi ")] - [InlineData(@"2\degree^2", @"\left( \frac{2\times \pi }{180}\right) ^2", @"\left( \frac{1}{90}\times \pi \right) ^2")] - [InlineData(@"2\degree2", @"\frac{2\times \pi }{180}\times 2", @"\frac{1}{45}\times \pi ")] - [InlineData(@"1+2\degree^2", @"1+\left( \frac{2\times \pi }{180}\right) ^2", @"1+\left( \frac{1}{90}\times \pi \right) ^2")] + [InlineData(@"9\degree", @"\frac{9\pi }{180}", @"\frac{\pi }{20}")] + [InlineData(@"a\degree", @"\frac{a\pi }{180}", @"\frac{a\pi }{180}")] + [InlineData(@"\pi\degree", @"\frac{\pi \pi }{180}", @"\frac{\pi ^2}{180}")] + [InlineData(@"a\%\degree", @"\frac{\frac{a}{100}\cdot \pi }{180}", @"\frac{a\pi }{18000}")] + [InlineData(@"a\degree\degree", @"\frac{\frac{a\pi }{180}\cdot \pi }{180}", @"\frac{a\pi ^2}{32400}")] + [InlineData(@"9\degree+3", @"\frac{9\pi }{180}+3", @"3+\frac{\pi }{20}")] + [InlineData(@"-9\degree+3", @"-\frac{9\pi }{180}+3", @"3+\frac{-1}{20}\cdot \pi ")] + [InlineData(@"2^2\degree", @"\frac{2^2\cdot \pi }{180}", @"\frac{\pi }{45}")] + [InlineData(@"2\degree^2", @"\left( \frac{2\pi }{180}\right) ^2", @"\frac{\pi ^2}{8100}")] + [InlineData(@"2\degree2", @"\frac{2\pi }{180}\cdot 2", @"\frac{\pi }{45}")] + [InlineData(@"1+2\degree^2", @"1+\left( \frac{2\pi }{180}\right) ^2", @"1+\frac{\pi ^2}{8100}")] + [InlineData(@"0!", @"0!", @"1")] + [InlineData(@"2.5!", @"\left( \frac{5}{2}\right) !", @"\frac{15}{8}\cdot \sqrt{\pi }")] + [InlineData(@"-1!", @"-1!", @"-1")] + [InlineData(@"(-1)!", @"\left( -1\right) !", @"\mathrm{undefined}")] + [InlineData(@"(-1)!!", @"2^{\frac{-1}{2}}\left( \frac{2}{\pi }\right) ^{\frac{1-\cos \left( \pi \cdot \left( -1\right) \cdot 1\right) }{4}}\cdot \left( \frac{-1}{2}\right) !", @"1")] + [InlineData(@"(-1)!!!", @"\left( 2^{\frac{-1}{2}}\left( \frac{2}{\pi }\right) ^{\frac{1-\cos \left( \pi \cdot \left( -1\right) \cdot 1\right) }{4}}\cdot \left( \frac{-1}{2}\right) !\right) !", @"1")] public void PostfixOperators(string latex, string converted, string result) => Test(latex, converted, result); [Theory] + [InlineData("0", "1")] + [InlineData("1", "1")] + [InlineData("2", "2")] + [InlineData("3", "3")] + [InlineData("30", "42849873690624000")] + [InlineData("31", "191898783962510625")] + [InlineData(@"\frac{25}{2}", @"\sqrt[4]{2}^{25}\sqrt[4]{\frac{2}{\pi }}\cdot \left( \frac{25}{4}\right) !")] + public void DoubleFactorial(string x, string result) => Test($"{x}!!", $$$"""2^{\frac{{{{x}}}}{2}}\left( \frac{2}{\pi }\right) ^{\frac{1-\cos \left( \pi {{{x}}}\right) }{4}}\cdot \left( \frac{{{{x}}}}{2}\right) !""", result); + [Theory] [InlineData("2^2", "2^2", "4")] [InlineData(".2^2", @"\left( \frac{1}{5}\right) ^2", @"\frac{1}{25}")] [InlineData("2.^2", "2^2", "4")] [InlineData("2.1^2", @"\left( \frac{21}{10}\right) ^2", @"\frac{441}{100}")] [InlineData("a^a", "a^a", "a^a")] [InlineData("a^{a+b}", "a^{a+b}", "a^{a+b}")] - [InlineData("a^{-2}", "a^{-2}", "a^{-2}")] + [InlineData("a^{-2}", "a^{-2}", @"\frac{1}{a^2}")] [InlineData("2^{3^4}", "2^{3^4}", "2417851639229258349412352")] [InlineData("4^{3^2}", "4^{3^2}", "262144")] [InlineData("4^3+2", "4^3+2", "66")] [InlineData("2+3^4", "2+3^4", "83")] - [InlineData("4^3*2", @"4^3\times 2", "128")] - [InlineData("2*3^4", @"2\times 3^4", "162")] + [InlineData("4^3*2", @"4^3\cdot 2", "128")] + [InlineData("2*3^4", @"23^4", "162")] // BUG in AngouriMath! [InlineData("1/x", @"\frac{1}{x}", @"\frac{1}{x}")] [InlineData("2/x", @"\frac{2}{x}", @"\frac{2}{x}")] [InlineData("0^x", @"0^x", @"0")] @@ -249,14 +270,14 @@ public void Numbers(string input, string converted, string output) => [InlineData(@"\cos x", @"\cos \left( x\right) ", @"\cos \left( x\right) ")] [InlineData(@"\tan x", @"\tan \left( x\right) ", @"\tan \left( x\right) ")] [InlineData(@"\cot x", @"\cot \left( x\right) ", @"\cot \left( x\right) ")] - [InlineData(@"\sec x", @"\frac{1}{\cos \left( x\right) }", @"\frac{1}{\cos \left( x\right) }")] - [InlineData(@"\csc x", @"\frac{1}{\sin \left( x\right) }", @"\frac{1}{\sin \left( x\right) }")] + [InlineData(@"\sec x", @"\sec \left( x\right) ", @"\sec \left( x\right) ")] + [InlineData(@"\csc x", @"\csc \left( x\right) ", @"\csc \left( x\right) ")] [InlineData(@"\arcsin x", @"\arcsin \left( x\right) ", @"\arcsin \left( x\right) ")] [InlineData(@"\arccos x", @"\arccos \left( x\right) ", @"\arccos \left( x\right) ")] [InlineData(@"\arctan x", @"\arctan \left( x\right) ", @"\arctan \left( x\right) ")] [InlineData(@"\arccot x", @"\arccot \left( x\right) ", @"\arccot \left( x\right) ")] - [InlineData(@"\arcsec x", @"\arccos \left( \frac{1}{x}\right) ", @"\arccos \left( \frac{1}{x}\right) ")] - [InlineData(@"\arccsc x", @"\arcsin \left( \frac{1}{x}\right) ", @"\arcsin \left( \frac{1}{x}\right) ")] + [InlineData(@"\arcsec x", @"\arcsec \left( x\right) ", @"\arcsec \left( x\right) ")] + [InlineData(@"\arccsc x", @"\arccsc \left( x\right) ", @"\arccsc \left( x\right) ")] [InlineData(@"\ln x", @"\ln \left( x\right) ", @"\ln \left( x\right) ")] [InlineData(@"\log x", @"\log \left( x\right) ", @"\log \left( x\right) ")] [InlineData(@"\log_3 x", @"\log _3\left( x\right) ", @"\log _3\left( x\right) ")] @@ -272,20 +293,22 @@ public void Numbers(string input, string converted, string output) => [InlineData(@"\log_{10} x^{-1}", @"\log \left( x^{-1}\right) ", @"\log \left( \frac{1}{x}\right) ")] [InlineData(@"\log_3 x^{-1}", @"\log _3\left( x^{-1}\right) ", @"\log _3\left( \frac{1}{x}\right) ")] [InlineData(@"\log_e x^{-1}", @"\ln \left( x^{-1}\right) ", @"\ln \left( \frac{1}{x}\right) ")] - [InlineData(@"2\sin x", @"2\times \sin \left( x\right) ", @"2\times \sin \left( x\right) ")] - [InlineData(@"\sin 2x", @"\sin \left( 2\times x\right) ", @"\sin \left( 2\times x\right) ")] - [InlineData(@"\sin xy", @"\sin \left( x\times y\right) ", @"\sin \left( x\times y\right) ")] + [InlineData(@"2\sin x", @"2\sin \left( x\right) ", @"2\sin \left( x\right) ")] + [InlineData(@"\sin 2x", @"\sin \left( 2x\right) ", @"\sin \left( 2x\right) ")] + [InlineData(@"\sin x2", @"\sin \left( x2\right) ", @"\sin \left( 2x\right) ")] + [InlineData(@"\sin x2^2", @"\sin \left( x2^2\right) ", @"\sin \left( 4x\right) ")] + [InlineData(@"\sin xy", @"\sin \left( xy\right) ", @"\sin \left( xy\right) ")] [InlineData(@"\sin \frac\pi2", @"\sin \left( \frac{\pi }{2}\right) ", @"1")] [InlineData(@"\sin \frac\pi2+1", @"\sin \left( \frac{\pi }{2}\right) +1", @"2")] [InlineData(@"\cos +x", @"\cos \left( x\right) ", @"\cos \left( x\right) ")] [InlineData(@"\cos -x", @"\cos \left( -x\right) ", @"\cos \left( -x\right) ")] - [InlineData(@"\tan x\%", @"\tan \left( \frac{x}{100}\right) ", @"\tan \left( \frac{1}{100}\times x\right) ")] - [InlineData(@"\tan x\%^2", @"\tan \left( \left( \frac{x}{100}\right) ^2\right) ", @"\tan \left( \left( \frac{1}{100}\times x\right) ^2\right) ")] - [InlineData(@"\cot x*y", @"\cot \left( x\right) \times y", @"\cot \left( x\right) \times y")] + [InlineData(@"\tan x\%", @"\tan \left( \frac{x}{100}\right) ", @"\tan \left( \frac{x}{100}\right) ")] + [InlineData(@"\tan x\%^2", @"\tan \left( \left( \frac{x}{100}\right) ^2\right) ", @"\tan \left( \left( \frac{x}{100}\right) ^2\right) ")] + [InlineData(@"\cot x*y", @"\cot \left( x\right) \cdot y", @"\cot \left( x\right) \cdot y")] [InlineData(@"\cot x/y", @"\frac{\cot \left( x\right) }{y}", @"\frac{\cot \left( x\right) }{y}")] [InlineData(@"\cos \arccos x", @"\cos \left( \arccos \left( x\right) \right) ", @"x")] [InlineData(@"\sin^2 x", @"\sin \left( x\right) ^2", @"\sin \left( x\right) ^2")] - [InlineData(@"\sin^2 xy+\cos^2 yx", @"\sin \left( x\times y\right) ^2+\cos \left( y\times x\right) ^2", @"1")] + [InlineData(@"\sin^2 xy+\cos^2 yx", @"\sin \left( xy\right) ^2+\cos \left( yx\right) ^2", @"1")] [InlineData(@"\log^2 x", @"\log \left( x\right) ^2", @"\log \left( x\right) ^2")] [InlineData(@"\ln^2 x", @"\ln \left( x\right) ^2", @"\ln \left( x\right) ^2")] [InlineData(@"\log_{10}^2 x", @"\log \left( x\right) ^2", @"\log \left( x\right) ^2")] @@ -296,14 +319,14 @@ public void Numbers(string input, string converted, string output) => [InlineData(@"\cos^{-1} x", @"\arccos \left( x\right) ", @"\arccos \left( x\right) ")] [InlineData(@"\tan^{-1} x", @"\arctan \left( x\right) ", @"\arctan \left( x\right) ")] [InlineData(@"\cot^{-1} x", @"\arccot \left( x\right) ", @"\arccot \left( x\right) ")] - [InlineData(@"\sec^{-1} x", @"\arccos \left( \frac{1}{x}\right) ", @"\arccos \left( \frac{1}{x}\right) ")] - [InlineData(@"\csc^{-1} x", @"\arcsin \left( \frac{1}{x}\right) ", @"\arcsin \left( \frac{1}{x}\right) ")] + [InlineData(@"\sec^{-1} x", @"\arcsec \left( x\right) ", @"\arcsec \left( x\right) ")] + [InlineData(@"\csc^{-1} x", @"\arccsc \left( x\right) ", @"\arccsc \left( x\right) ")] [InlineData(@"\arcsin^{-1} x", @"\sin \left( x\right) ", @"\sin \left( x\right) ")] [InlineData(@"\arccos^{-1} x", @"\cos \left( x\right) ", @"\cos \left( x\right) ")] [InlineData(@"\arctan^{-1} x", @"\tan \left( x\right) ", @"\tan \left( x\right) ")] [InlineData(@"\arccot^{-1} x", @"\cot \left( x\right) ", @"\cot \left( x\right) ")] - [InlineData(@"\arcsec^{-1} x", @"\frac{1}{\cos \left( x\right) }", @"\frac{1}{\cos \left( x\right) }")] - [InlineData(@"\arccsc^{-1} x", @"\frac{1}{\sin \left( x\right) }", @"\frac{1}{\sin \left( x\right) }")] + [InlineData(@"\arcsec^{-1} x", @"\sec \left( x\right) ", @"\sec \left( x\right) ")] + [InlineData(@"\arccsc^{-1} x", @"\csc \left( x\right) ", @"\csc \left( x\right) ")] [InlineData(@"\ln^{-1} x", @"e^x", @"e^x")] [InlineData(@"\log^{-1} x", @"10^x", @"10^x")] [InlineData(@"\log_3^{-1} x", @"3^x", @"3^x")] @@ -319,68 +342,68 @@ public void Numbers(string input, string converted, string output) => [InlineData(@"\log_{10}^{-1} x^{-1}", @"10^{x^{-1}}", @"10^{\frac{1}{x}}")] [InlineData(@"\log_3^{-1} x^{-1}", @"3^{x^{-1}}", @"3^{\frac{1}{x}}")] [InlineData(@"\log_e^{-1} x^{-1}", @"e^{x^{-1}}", @"e^{\frac{1}{x}}")] - [InlineData(@"2\sin^{-1} x", @"2\times \arcsin \left( x\right) ", @"2\times \arcsin \left( x\right) ")] - [InlineData(@"\sin^{-1} 2x", @"\arcsin \left( 2\times x\right) ", @"\arcsin \left( 2\times x\right) ")] - [InlineData(@"\sin^{-1} xy", @"\arcsin \left( x\times y\right) ", @"\arcsin \left( x\times y\right) ")] + [InlineData(@"2\sin^{-1} x", @"2\arcsin \left( x\right) ", @"2\arcsin \left( x\right) ")] + [InlineData(@"\sin^{-1} 2x", @"\arcsin \left( 2x\right) ", @"\arcsin \left( 2x\right) ")] + [InlineData(@"\sin^{-1} xy", @"\arcsin \left( xy\right) ", @"\arcsin \left( xy\right) ")] [InlineData(@"\cos^{-1} +x", @"\arccos \left( x\right) ", @"\arccos \left( x\right) ")] [InlineData(@"\cos^{-1} -x", @"\arccos \left( -x\right) ", @"\arccos \left( -x\right) ")] - [InlineData(@"\tan^{-1} x\%", @"\arctan \left( \frac{x}{100}\right) ", @"\arctan \left( \frac{1}{100}\times x\right) ")] - [InlineData(@"\tan^{-1} x\%^2", @"\arctan \left( \left( \frac{x}{100}\right) ^2\right) ", @"\arctan \left( \left( \frac{1}{100}\times x\right) ^2\right) ")] - [InlineData(@"\cot^{-1} x*y", @"\arccot \left( x\right) \times y", @"\arccot \left( x\right) \times y")] + [InlineData(@"\tan^{-1} x\%", @"\arctan \left( \frac{x}{100}\right) ", @"\arctan \left( \frac{x}{100}\right) ")] + [InlineData(@"\tan^{-1} x\%^2", @"\arctan \left( \left( \frac{x}{100}\right) ^2\right) ", @"\arctan \left( \left( \frac{x}{100}\right) ^2\right) ")] + [InlineData(@"\cot^{-1} x*y", @"\arccot \left( x\right) \cdot y", @"\arccot \left( x\right) \cdot y")] [InlineData(@"\cot^{-1} x/y", @"\frac{\arccot \left( x\right) }{y}", @"\frac{\arccot \left( x\right) }{y}")] [InlineData(@"\cos^{-1} \arccos^{-1} x", @"\arccos \left( \cos \left( x\right) \right) ", @"x")] [InlineData(@"\sin^1 x", @"\sin \left( x\right) ^1", @"\sin \left( x\right) ")] [InlineData(@"\sin^{+1} x", @"\sin \left( x\right) ^1", @"\sin \left( x\right) ")] - [InlineData(@"\sin^{+-1} x", @"\sin \left( x\right) ^{-1}", @"\frac{1}{\sin \left( x\right) }")] - [InlineData(@"\sin^{-+1} x", @"\sin \left( x\right) ^{-1}", @"\frac{1}{\sin \left( x\right) }")] - [InlineData(@"\sin^{--1} x", @"\sin \left( x\right) ^{--1}", @"\sin \left( x\right) ")] - [InlineData(@"\sin^{-1^2} x", @"\sin \left( x\right) ^{-1^2}", @"\frac{1}{\sin \left( x\right) }")] - [InlineData(@"\sin^{-1+3} xy+\cos^{-1+3} yx", @"\sin \left( x\times y\right) ^{-1+3}+\cos \left( y\times x\right) ^{-1+3}", @"1")] + [InlineData(@"\sin^{+-1} x", @"\sin \left( x\right) ^{-1}", @"\csc \left( x\right) ")] + [InlineData(@"\sin^{-+1} x", @"\sin \left( x\right) ^{-1}", @"\csc \left( x\right) ")] + [InlineData(@"\sin^{--1} x", @"\sin \left( x\right) ^{\left( -1\right) \left( -1\right) \cdot 1}", @"\sin \left( x\right) ")] + [InlineData(@"\sin^{-1^2} x", @"\sin \left( x\right) ^{-1^2}", @"\csc \left( x\right) ")] + [InlineData(@"\sin^{-1+3} xy+\cos^{-1+3} yx", @"\sin \left( xy\right) ^{-1+3}+\cos \left( yx\right) ^{-1+3}", @"1")] [InlineData(@"\log^{-a_2} x", @"\log \left( x\right) ^{-a_2}", @"\log \left( x\right) ^{-a_2}")] [InlineData(@"\ln^{3-1} x", @"\ln \left( x\right) ^{3-1}", @"\ln \left( x\right) ^2")] public void FunctionInverses(string latex, string converted, string result) => Test(latex, converted, result); [Theory] [InlineData(@"1+(2+3)", @"1+2+3", @"6")] [InlineData(@"1+((2+3))", @"1+2+3", @"6")] - [InlineData(@"2*(3+4)", @"2\times \left( 3+4\right) ", @"14")] - [InlineData(@"(3+4)*2", @"\left( 3+4\right) \times 2", @"14")] + [InlineData(@"2*(3+4)", @"2\left( 3+4\right) ", @"14")] + [InlineData(@"(3+4)*2", @"\left( 3+4\right) \cdot 2", @"14")] [InlineData(@"(5+6)^2", @"\left( 5+6\right) ^2", @"121")] [InlineData(@"(5+6)", @"5+6", @"11")] [InlineData(@"((5+6))", @"5+6", @"11")] - [InlineData(@"(5+6)2", @"\left( 5+6\right) \times 2", @"22")] - [InlineData(@"2(5+6)", @"2\times \left( 5+6\right) ", @"22")] - [InlineData(@"2(5+6)2", @"2\times \left( 5+6\right) \times 2", @"44")] - [InlineData(@"(5+6)x", @"\left( 5+6\right) \times x", @"11\times x")] - [InlineData(@"x(5+6)", @"x\times \left( 5+6\right) ", @"11\times x")] - [InlineData(@"x(5+6)x", @"x\times \left( 5+6\right) \times x", @"11\times x^2")] - [InlineData(@"(5+6).2", @"\left( 5+6\right) \times \frac{1}{5}", @"\frac{11}{5}")] - [InlineData(@".2(5+6)", @"\frac{1}{5}\times \left( 5+6\right) ", @"\frac{11}{5}")] - [InlineData(@".2(5+6).2", @"\frac{1}{5}\times \left( 5+6\right) \times \frac{1}{5}", @"\frac{11}{25}")] - [InlineData(@"(5+6)2.", @"\left( 5+6\right) \times 2", @"22")] - [InlineData(@"2.(5+6)", @"2\times \left( 5+6\right) ", @"22")] - [InlineData(@"2.(5+6)2.", @"2\times \left( 5+6\right) \times 2", @"44")] - [InlineData(@"(5+6)(2)", @"\left( 5+6\right) \times 2", @"22")] - [InlineData(@"(5+6)(1+1)", @"\left( 5+6\right) \times \left( 1+1\right) ", @"22")] - [InlineData(@"(5+6)(-(-2))", @"\left( 5+6\right) \times --2", @"22")] - [InlineData(@"(5+6)(--2)", @"\left( 5+6\right) \times --2", @"22")] + [InlineData(@"(5+6)2", @"\left( 5+6\right) \cdot 2", @"22")] + [InlineData(@"2(5+6)", @"2\left( 5+6\right) ", @"22")] + [InlineData(@"2(5+6)2", @"2\cdot \left( 5+6\right) \cdot 2", @"44")] + [InlineData(@"(5+6)x", @"\left( 5+6\right) \cdot x", @"11x")] + [InlineData(@"x(5+6)", @"x\left( 5+6\right) ", @"11x")] + [InlineData(@"x(5+6)x", @"x\cdot \left( 5+6\right) \cdot x", @"11x^2")] + [InlineData(@"(5+6).2", @"\left( 5+6\right) \cdot \frac{1}{5}", @"\frac{11}{5}")] + [InlineData(@".2(5+6)", @"\frac{1}{5}\left( 5+6\right) ", @"\frac{11}{5}")] + [InlineData(@".2(5+6).2", @"\frac{1}{5}\cdot \left( 5+6\right) \cdot \frac{1}{5}", @"\frac{11}{25}")] + [InlineData(@"(5+6)2.", @"\left( 5+6\right) \cdot 2", @"22")] + [InlineData(@"2.(5+6)", @"2\left( 5+6\right) ", @"22")] + [InlineData(@"2.(5+6)2.", @"2\cdot \left( 5+6\right) \cdot 2", @"44")] + [InlineData(@"(5+6)(2)", @"\left( 5+6\right) \cdot 2", @"22")] + [InlineData(@"(5+6)(1+1)", @"\left( 5+6\right) \left( 1+1\right) ", @"22")] + [InlineData(@"(5+6)(-(-2))", @"\left( 5+6\right) \left( -1\right) \left( -1\right) \cdot 2", @"22")] + [InlineData(@"(5+6)(--2)", @"\left( 5+6\right) \left( -1\right) \left( -1\right) \cdot 2", @"22")] [InlineData(@"+(1)", @"1", @"1")] [InlineData(@"+(1)\%", @"\frac{1}{100}", @"\frac{1}{100}")] [InlineData(@"+(-1)", @"-1", @"-1")] [InlineData(@"-(+1)", @"-1", @"-1")] - [InlineData(@"-(-1)", @"--1", @"1")] - [InlineData(@"--(--1)", @"----1", @"1")] + [InlineData(@"-(-1)", @"\left( -1\right) \left( -1\right) \cdot 1", @"1")] + [InlineData(@"--(--1)", @"\left( -1\right) \left( -1\right) \left( -1\right) \left( -1\right) \cdot 1", @"1")] [InlineData(@"(2+3)^{(4+5)}", @"\left( 2+3\right) ^{4+5}", @"1953125")] [InlineData(@"(2+3)^{((4)+5)}", @"\left( 2+3\right) ^{4+5}", @"1953125")] - [InlineData(@"(1+i)\infty", @"\left( 1+i\right) \times \infty ", @"\infty +\infty i")] - [InlineData(@"2\sin(x)", @"2\times \sin \left( x\right) ", @"2\times \sin \left( x\right) ")] - [InlineData(@"(2)\sin(x)", @"2\times \sin \left( x\right) ", @"2\times \sin \left( x\right) ")] + [InlineData(@"(1+i)\infty", @"\left( 1+i\right) \cdot \infty ", @"\infty +\infty i")] + [InlineData(@"2\sin(x)", @"2\sin \left( x\right) ", @"2\sin \left( x\right) ")] + [InlineData(@"(2)\sin(x)", @"2\sin \left( x\right) ", @"2\sin \left( x\right) ")] [InlineData(@"\sin(x+1)", @"\sin \left( x+1\right) ", @"\sin \left( 1+x\right) ")] [InlineData(@"\sin((x+1))", @"\sin \left( x+1\right) ", @"\sin \left( 1+x\right) ")] - [InlineData(@"\sin(2(x+1))", @"\sin \left( 2\times \left( x+1\right) \right) ", @"\sin \left( 2\times \left( 1+x\right) \right) ")] + [InlineData(@"\sin(2(x+1))", @"\sin \left( 2\left( x+1\right) \right) ", @"\sin \left( 2\left( 1+x\right) \right) ")] [InlineData(@"\sin((x+1)+2)", @"\sin \left( x+1+2\right) ", @"\sin \left( 3+x\right) ")] - [InlineData(@"\sin(x)2", @"\sin \left( x\right) \times 2", @"2\times \sin \left( x\right) ")] - [InlineData(@"\sin(x)(x+1)", @"\sin \left( x\right) \times \left( x+1\right) ", @"\sin \left( x\right) \times \left( 1+x\right) ")] - [InlineData(@"\sin(x)(x+1)(x)", @"\sin \left( x\right) \times \left( x+1\right) \times x", @"\sin \left( x\right) \times \left( 1+x\right) \times x")] + [InlineData(@"\sin(x)2", @"\sin \left( x\right) \cdot 2", @"2\sin \left( x\right) ")] + [InlineData(@"\sin(x)(x+1)", @"\sin \left( x\right) \left( x+1\right) ", @"\sin \left( x\right) \left( 1+x\right) ")] + [InlineData(@"\sin(x)(x+1)(x)", @"\sin \left( x\right) \cdot \left( x+1\right) \cdot x", @"\sin \left( x\right) \cdot \left( 1+x\right) \cdot x")] [InlineData(@"\sin(x^2)", @"\sin \left( x^2\right) ", @"\sin \left( x^2\right) ")] [InlineData(@"\sin\ (x^2)", @"\sin \left( x^2\right) ", @"\sin \left( x^2\right) ")] [InlineData(@"\sin\; (x^2)", @"\sin \left( x^2\right) ", @"\sin \left( x^2\right) ")] @@ -397,31 +420,31 @@ public void Numbers(string input, string converted, string output) => [InlineData(@"\sin\ (x)^2", @"\sin \left( x\right) ^2", @"\sin \left( x\right) ^2")] [InlineData(@"\sin\; (x)^2", @"\sin \left( x\right) ^2", @"\sin \left( x\right) ^2")] [InlineData(@"\sin\ \; (x)^2", @"\sin \left( x\right) ^2", @"\sin \left( x\right) ^2")] - [InlineData(@"\sin(x)^{-1}", @"\sin \left( x\right) ^{-1}", @"\frac{1}{\sin \left( x\right) }")] - [InlineData(@"\sin\ (x)^{-1}", @"\sin \left( x\right) ^{-1}", @"\frac{1}{\sin \left( x\right) }")] - [InlineData(@"\sin\; (x)^{-1}", @"\sin \left( x\right) ^{-1}", @"\frac{1}{\sin \left( x\right) }")] - [InlineData(@"\sin\ \; (x)^{-1}", @"\sin \left( x\right) ^{-1}", @"\frac{1}{\sin \left( x\right) }")] - [InlineData(@"\sin^3(x)^{-1}", @"\sin \left( x\right) ^{3\times -1}", @"\sin \left( x\right) ^{-3}")] - [InlineData(@"\sin^3\ (x)^{-1}", @"\sin \left( x\right) ^{3\times -1}", @"\sin \left( x\right) ^{-3}")] - [InlineData(@"\sin^3\; (x)^{-1}", @"\sin \left( x\right) ^{3\times -1}", @"\sin \left( x\right) ^{-3}")] - [InlineData(@"\sin^3\ \; (x)^{-1}", @"\sin \left( x\right) ^{3\times -1}", @"\sin \left( x\right) ^{-3}")] + [InlineData(@"\sin(x)^{-1}", @"\sin \left( x\right) ^{-1}", @"\csc \left( x\right) ")] + [InlineData(@"\sin\ (x)^{-1}", @"\sin \left( x\right) ^{-1}", @"\csc \left( x\right) ")] + [InlineData(@"\sin\; (x)^{-1}", @"\sin \left( x\right) ^{-1}", @"\csc \left( x\right) ")] + [InlineData(@"\sin\ \; (x)^{-1}", @"\sin \left( x\right) ^{-1}", @"\csc \left( x\right) ")] + [InlineData(@"\sin^3(x)^{-1}", @"\sin \left( x\right) ^{3\cdot \left( -1\right) \cdot 1}", @"\frac{1}{\sin \left( x\right) ^3}")] + [InlineData(@"\sin^3\ (x)^{-1}", @"\sin \left( x\right) ^{3\cdot \left( -1\right) \cdot 1}", @"\frac{1}{\sin \left( x\right) ^3}")] + [InlineData(@"\sin^3\; (x)^{-1}", @"\sin \left( x\right) ^{3\cdot \left( -1\right) \cdot 1}", @"\frac{1}{\sin \left( x\right) ^3}")] + [InlineData(@"\sin^3\ \; (x)^{-1}", @"\sin \left( x\right) ^{3\cdot \left( -1\right) \cdot 1}", @"\frac{1}{\sin \left( x\right) ^3}")] [InlineData(@"\sin^{-1}(x)^{-1}", @"\arcsin \left( x\right) ^{-1}", @"\frac{1}{\arcsin \left( x\right) }")] [InlineData(@"\sin^{-1}\ (x)^{-1}", @"\arcsin \left( x\right) ^{-1}", @"\frac{1}{\arcsin \left( x\right) }")] [InlineData(@"\sin^{-1}\; (x)^{-1}", @"\arcsin \left( x\right) ^{-1}", @"\frac{1}{\arcsin \left( x\right) }")] [InlineData(@"\sin^{-1}\ \; (x)^{-1}", @"\arcsin \left( x\right) ^{-1}", @"\frac{1}{\arcsin \left( x\right) }")] [InlineData(@"\sin^a(x)", @"\sin \left( x\right) ^a", @"\sin \left( x\right) ^a")] - [InlineData(@"\sin^a(x)^2", @"\sin \left( x\right) ^{a\times 2}", @"\sin \left( x\right) ^{2\times a}")] - [InlineData(@"\sin^a\ (x)^2", @"\sin \left( x\right) ^{a\times 2}", @"\sin \left( x\right) ^{2\times a}")] - [InlineData(@"\sin^a\; (x)^2", @"\sin \left( x\right) ^{a\times 2}", @"\sin \left( x\right) ^{2\times a}")] - [InlineData(@"\sin^a\ \; (x)^2", @"\sin \left( x\right) ^{a\times 2}", @"\sin \left( x\right) ^{2\times a}")] - [InlineData(@"\sin(x)^2(x)", @"\sin \left( x\right) ^2\times x", @"\sin \left( x\right) ^2\times x")] - [InlineData(@"\sin\ (x)^2(x)", @"\sin \left( x\right) ^2\times x", @"\sin \left( x\right) ^2\times x")] - [InlineData(@"\sin\; (x)^2(x)", @"\sin \left( x\right) ^2\times x", @"\sin \left( x\right) ^2\times x")] - [InlineData(@"\sin\ \; (x)^2(x)", @"\sin \left( x\right) ^2\times x", @"\sin \left( x\right) ^2\times x")] - [InlineData(@"\sin^a(x)^2(x)", @"\sin \left( x\right) ^{a\times 2}\times x", @"\sin \left( x\right) ^{2\times a}\times x")] - [InlineData(@"\sin^a\ (x)^2(x)", @"\sin \left( x\right) ^{a\times 2}\times x", @"\sin \left( x\right) ^{2\times a}\times x")] - [InlineData(@"\sin^a\; (x)^2(x)", @"\sin \left( x\right) ^{a\times 2}\times x", @"\sin \left( x\right) ^{2\times a}\times x")] - [InlineData(@"\sin^a\ \; (x)^2(x)", @"\sin \left( x\right) ^{a\times 2}\times x", @"\sin \left( x\right) ^{2\times a}\times x")] + [InlineData(@"\sin^a(x)^2", @"\sin \left( x\right) ^{a2}", @"\sin \left( x\right) ^{2a}")] + [InlineData(@"\sin^a\ (x)^2", @"\sin \left( x\right) ^{a2}", @"\sin \left( x\right) ^{2a}")] + [InlineData(@"\sin^a\; (x)^2", @"\sin \left( x\right) ^{a2}", @"\sin \left( x\right) ^{2a}")] + [InlineData(@"\sin^a\ \; (x)^2", @"\sin \left( x\right) ^{a2}", @"\sin \left( x\right) ^{2a}")] + [InlineData(@"\sin(x)^2(x)", @"\sin \left( x\right) ^2\cdot x", @"\sin \left( x\right) ^2\cdot x")] + [InlineData(@"\sin\ (x)^2(x)", @"\sin \left( x\right) ^2\cdot x", @"\sin \left( x\right) ^2\cdot x")] + [InlineData(@"\sin\; (x)^2(x)", @"\sin \left( x\right) ^2\cdot x", @"\sin \left( x\right) ^2\cdot x")] + [InlineData(@"\sin\ \; (x)^2(x)", @"\sin \left( x\right) ^2\cdot x", @"\sin \left( x\right) ^2\cdot x")] + [InlineData(@"\sin^a(x)^2(x)", @"\sin \left( x\right) ^{a2}\cdot x", @"\sin \left( x\right) ^{2a}\cdot x")] + [InlineData(@"\sin^a\ (x)^2(x)", @"\sin \left( x\right) ^{a2}\cdot x", @"\sin \left( x\right) ^{2a}\cdot x")] + [InlineData(@"\sin^a\; (x)^2(x)", @"\sin \left( x\right) ^{a2}\cdot x", @"\sin \left( x\right) ^{2a}\cdot x")] + [InlineData(@"\sin^a\ \; (x)^2(x)", @"\sin \left( x\right) ^{a2}\cdot x", @"\sin \left( x\right) ^{2a}\cdot x")] [InlineData(@"\sin (\frac\pi2)", @"\sin \left( \frac{\pi }{2}\right) ", @"1")] [InlineData(@"\sin (\frac\pi2)+1", @"\sin \left( \frac{\pi }{2}\right) +1", @"2")] public void Parentheses(string latex, string converted, string result) { @@ -429,75 +452,86 @@ public void Parentheses(string latex, string converted, string result) { Test(latex.Replace('(', '[').Replace(')', ']'), converted, result); } [Theory] - [InlineData(@"\begin{matrix}1\end{matrix}", @"\left( \begin{matrix}1\end{matrix}\right) ", @"\left( \begin{matrix}1\end{matrix}\right) ")] - [InlineData(@"\begin{pmatrix}1\end{pmatrix}", @"\left( \begin{matrix}1\end{matrix}\right) ", @"\left( \begin{matrix}1\end{matrix}\right) ")] - [InlineData(@"\begin{bmatrix}1\end{bmatrix}", @"\left( \begin{matrix}1\end{matrix}\right) ", @"\left( \begin{matrix}1\end{matrix}\right) ")] - [InlineData(@"\begin{pmatrix}1\end{pmatrix}^2", @"\left( \begin{matrix}1\end{matrix}\right) ^2", @"\left( \begin{matrix}1\end{matrix}\right) ^2")] - [InlineData(@"\begin{bmatrix}1\end{bmatrix}^2", @"\left( \begin{matrix}1\end{matrix}\right) ^2", @"\left( \begin{matrix}1\end{matrix}\right) ^2")] - public void Vectors(string latex, string converted, string result) => Test(latex, converted, result); - [Theory] - [InlineData(@"\begin{matrix}1&2\\3&4\end{matrix}", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) ", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) ")] - [InlineData(@"\begin{pmatrix}1&2\\3&4\end{pmatrix}", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) ", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) ")] - [InlineData(@"\begin{bmatrix}1&2\\3&4\end{bmatrix}", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) ", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) ")] - [InlineData(@"\begin{pmatrix}1&2\\3&4\end{pmatrix}^2", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) ^2", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) ^2")] - [InlineData(@"\begin{bmatrix}1&2\\3&4\end{bmatrix}^2", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) ^2", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) ^2")] - [InlineData(@"\begin{matrix}1&2\\3&4\end{matrix}+\begin{bmatrix}1&2\\3&5\end{bmatrix}", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) +\left( \begin{matrix}1&2\\ 3&5\end{matrix}\right) ", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) +\left( \begin{matrix}1&2\\ 3&5\end{matrix}\right) ")] - [InlineData(@"\begin{pmatrix}1&2\\3&4\end{pmatrix}+\begin{matrix}1&2\\3&5\end{matrix}", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) +\left( \begin{matrix}1&2\\ 3&5\end{matrix}\right) ", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) +\left( \begin{matrix}1&2\\ 3&5\end{matrix}\right) ")] - [InlineData(@"\begin{bmatrix}1&2\\3&4\end{bmatrix}+\begin{pmatrix}1&2\\3&5\end{pmatrix}", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) +\left( \begin{matrix}1&2\\ 3&5\end{matrix}\right) ", @"\left( \begin{matrix}1&2\\ 3&4\end{matrix}\right) +\left( \begin{matrix}1&2\\ 3&5\end{matrix}\right) ")] - public void Matrices(string latex, string converted, string result) => Test(latex, converted, result); + [InlineData(@"\begin{matrix}1\end{matrix}", @"\left[ \begin{matrix}1\end{matrix}\right] ", @"1")] + [InlineData(@"\begin{matrix}1&2\\3&4\end{matrix}", @"\left[ \begin{matrix}1&2\\ 3&4\end{matrix}\right] ", @"\left[ \begin{matrix}1&2\\ 3&4\end{matrix}\right] ")] + [InlineData(@"(\begin{matrix}1\end{matrix})^2", @"\left[ \begin{matrix}1\end{matrix}\right] ^2", @"1")] + [InlineData(@"[\begin{matrix}1&2\end{matrix}]^2", @"\left[ \begin{matrix}1&2\end{matrix}\right] ^2", @"\left[ \begin{matrix}1&4\end{matrix}\right] ")] + [InlineData(@"[\begin{matrix}3\\4\end{matrix}]^2", @"\left[ \begin{matrix}3\\ 4\end{matrix}\right] ^2", @"\left[ \begin{matrix}9\\ 16\end{matrix}\right] ")] + [InlineData(@"[\begin{matrix}1&2\\3&4\end{matrix}]^2", @"\left[ \begin{matrix}1&2\\ 3&4\end{matrix}\right] ^2", @"\left[ \begin{matrix}7&10\\ 15&22\end{matrix}\right] ")] + [InlineData(@"\begin{matrix}1&2\\3&4\end{matrix}+\begin{matrix}1&2\\3&5\end{matrix}", @"\left[ \begin{matrix}1&2\\ 3&4\end{matrix}\right] +\left[ \begin{matrix}1&2\\ 3&5\end{matrix}\right] ", @"\left[ \begin{matrix}2&4\\ 6&9\end{matrix}\right] ")] + public void Matrices(string latex, string converted, string result) { + Test(latex, converted, result); + Test(latex.Replace("matrix", "pmatrix"), converted, result); + Test(latex.Replace("matrix", "bmatrix"), converted, result); + } [Theory] [InlineData(@"1,2", @"1,2")] [InlineData(@"1,2,3", @"1,2,3")] [InlineData(@"a,b,c,d", @"a,b,c,d")] [InlineData(@"\sqrt2,\sqrt[3]2,\frac34", @"\sqrt{2},2^{\frac{1}{3}},\frac{3}{4}")] [InlineData(@"\sin a,\cos b^2,\tan c_3,\cot de,\sec 12f,\csc g+h", - @"\sin \left( a\right) ,\cos \left( b^2\right) ,\tan \left( c_3\right) ,\cot \left( d\times e\right) ,\frac{1}{\cos \left( 12\times f\right) },\frac{1}{\sin \left( g\right) }+h")] + @"\sin \left( a\right) ,\cos \left( b^2\right) ,\tan \left( c_3\right) ,\cot \left( de\right) ,\sec \left( 12f\right) ,\csc \left( g\right) +h")] public void Comma(string latex, string converted) => Test(latex, converted, null); [Theory] [InlineData(@"\emptyset", @"\emptyset ")] - [InlineData(@"\mathbb R", @"\left\{ \left( -\infty ,\infty \right) \right\} ")] - [InlineData(@"\mathbb C", @"\left\{ \left\{ z\in \mathbb{C}:\Re \left( z\right) \in \left( -\infty ,\infty \right) \wedge \Im \left( z\right) \in \left( -\infty ,\infty \right) \right\} \right\} ")] + [InlineData(@"\mathbb Z", @"\mathbb{Z}")] + [InlineData(@"\mathbb Q", @"\mathbb{Q}")] + [InlineData(@"\mathbb R", @"\mathbb{R}")] + [InlineData(@"\mathbb C", @"\mathbb{C}")] [InlineData(@"\{\}", @"\emptyset ")] + [InlineData(@"\left\{\right\}", @"\emptyset ")] + [InlineData(@"\left\{1\right\}", @"\left\{ 1\right\} ")] [InlineData(@"\{1\}", @"\left\{ 1\right\} ")] [InlineData(@"\{1,2\}", @"\left\{ 1,2\right\} ")] [InlineData(@"\{x,y\}", @"\left\{ x,y\right\} ")] [InlineData(@"\{\sqrt[3]2,\frac34,\sin^2x\}", @"\left\{ 2^{\frac{1}{3}},\frac{3}{4},\sin \left( x\right) ^2\right\} ")] + [InlineData(@"\{\{\}\}", @"\left\{ \emptyset \right\} ")] + [InlineData(@"\{\left\{\right\}\}", @"\left\{ \emptyset \right\} ")] public void Sets(string latex, string converted) => Test(latex, converted, null); [Theory] - [InlineData(@"\emptyset\cup\{2\}", @"\left\{ 2\right\} ")] - [InlineData(@"\{1\}\cup\{2\}", @"\left\{ 1,2\right\} ")] - [InlineData(@"\{3,4\}\cap\emptyset", @"\left( \left\{ 3,4\right\} \cap \right) \left( \emptyset \right) ")] - [InlineData(@"\{3,4\}\cap\{4,5\}", @"\left\{ 4\right\} ")] - [InlineData(@"\{2,3,4\}\setminus\{4\}", @"\left\{ 2,3\right\} ")] - [InlineData(@"\{3\}^\complement", @"\left\{ \left\{ z\in \mathbb{C}:\Re \left( z\right) \in \left( -\infty ,3\right] \wedge \Im \left( z\right) \in \left( -\infty ,0\right) \right\} ,\left\{ z\in \mathbb{C}:\Re \left( z\right) \in \left( -\infty ,3\right) \wedge \Im \left( z\right) \in \left[ 0,\infty \right) \right\} ,\left\{ z\in \mathbb{C}:\Re \left( z\right) \in \left[ 3,\infty \right) \wedge \Im \left( z\right) \in \left( 0,\infty \right) \right\} ,\left\{ z\in \mathbb{C}:\Re \left( z\right) \in \left( 3,\infty \right) \wedge \Im \left( z\right) \in \left( -\infty ,0\right] \right\} \right\} ")] - public void SetOperations(string latex, string converted) => Test(latex, converted, null); + [InlineData(@"\emptyset\cup\{2\}", @"\emptyset \cup \left\{ 2\right\} ", @"\left\{ 2\right\} ")] + [InlineData(@"\{1\}\cup\{2\}", @"\left\{ 1\right\} \cup \left\{ 2\right\} ", @"\left\{ 1,2\right\} ")] + [InlineData(@"\{3,4\}\cap\emptyset", @"\left\{ 3,4\right\} \cap \emptyset ", @"\emptyset ")] + [InlineData(@"\{3,4\}\cap\{4,5\}", @"\left\{ 3,4\right\} \cap \left\{ 4,5\right\} ", @"\left\{ 4\right\} ")] + [InlineData(@"\{2,3,4\}\setminus\{4\}", @"\left\{ 2,3,4\right\} \setminus \left\{ 4\right\} ", @"\left\{ 2,3\right\} ")] + [InlineData(@"\emptyset^\complement", @"\mathbb{C}\setminus \emptyset ", @"\mathbb{C}")] + [InlineData(@"\{3\}^\complement", @"\mathbb{C}\setminus \left\{ 3\right\} ", @"\mathbb{C}\setminus \left\{ 3\right\} ")] + [InlineData(@"\mathbb R+1", @"\mathbb{R}+1", @"\mathbb{R}+1")] + [InlineData(@"\sin^\complement x", @"\mathbb{C}\setminus \sin \left( x\right) ", @"\mathbb{C}\setminus \sin \left( x\right) ")] + [InlineData(@"1^\complement", @"\mathbb{C}\setminus 1", @"\mathbb{C}\setminus 1")] + public void SetOperations(string latex, string converted, string result) => Test(latex, converted, result); [Theory] - [InlineData(@"(1,2)", @"\left\{ \left( 1,2\right) \right\} ")] - [InlineData(@"[1,2)", @"\left\{ \left[ 1,2\right) \right\} ")] - [InlineData(@"(1,2]", @"\left\{ \left( 1,2\right] \right\} ")] - [InlineData(@"[1,2]", @"\left\{ \left[ 1,2\right] \right\} ")] - [InlineData(@"(2,1)", @"\left\{ \left( 2,1\right) \right\} ")] - [InlineData(@"[2,1)", @"\left\{ \left[ 2,1\right) \right\} ")] - [InlineData(@"(2,1]", @"\left\{ \left( 2,1\right] \right\} ")] - [InlineData(@"[2,1]", @"\left\{ \left[ 2,1\right] \right\} ")] - [InlineData(@"[1,2]\setminus\{1\}", @"\left\{ \left( 1,2\right] \right\} ")] - [InlineData(@"[1,2]\setminus\{2\}", @"\left\{ \left[ 1,2\right) \right\} ")] - [InlineData(@"[1,2]\cup(2,3)", @"\left\{ \left[ 1,2\right] ,\left( 2,3\right) \right\} ")] - [InlineData(@"[1,2]\cap[1.5,1.6]", @"\left\{ \left[ \frac{3}{2},\frac{8}{5}\right] \right\} ")] - [InlineData(@"[1.5,1.5]", @"\left\{ \frac{3}{2}\right\} ")] - [InlineData(@"(1.5,1.5]", @"\emptyset ")] - [InlineData(@"[1.5,1.5)", @"\emptyset ")] - [InlineData(@"(1.5,1.5)", @"\emptyset ")] - [InlineData(@"[xy,xy]", @"\left\{ x\times y\right\} ")] - [InlineData(@"(xy,xy]", @"\emptyset ")] - [InlineData(@"[xy,xy)", @"\emptyset ")] - [InlineData(@"(xy,xy)", @"\emptyset ")] - public void Intervals(string latex, string converted) => Test(latex, converted, null); + [InlineData(@"(1,2)", @"\left( 1;2\right) ", @"\left( 1;2\right) ")] + [InlineData(@"[1,2)", @"\left[ 1;2\right) ", @"\left[ 1;2\right) ")] + [InlineData(@"(1,2]", @"\left( 1;2\right] ", @"\left( 1;2\right] ")] + [InlineData(@"[1,2]", @"\left[ 1;2\right] ", @"\left[ 1;2\right] ")] + [InlineData(@"(2,1)", @"\left( 2;1\right) ", @"\left( 2;1\right) ")] + [InlineData(@"[2,1)", @"\left[ 2;1\right) ", @"\left[ 2;1\right) ")] + [InlineData(@"(2,1]", @"\left( 2;1\right] ", @"\left( 2;1\right] ")] + [InlineData(@"[2,1]", @"\left[ 2;1\right] ", @"\left[ 2;1\right] ")] + [InlineData(@"[1,2]\setminus\{1\}", @"\left[ 1;2\right] \setminus \left\{ 1\right\} ", @"\left[ 1;2\right] \setminus \left\{ 1\right\} ")] + [InlineData(@"[1,2]\setminus\{2\}", @"\left[ 1;2\right] \setminus \left\{ 2\right\} ", @"\left[ 1;2\right] \setminus \left\{ 2\right\} ")] + [InlineData(@"[1,2]\cup(2,3)", @"\left[ 1;2\right] \cup \left( 2;3\right) ", @"\left[ 1;3\right) ")] + [InlineData(@"[1,2]\cap[1.5,1.6]", @"\left[ 1;2\right] \cap \left[ \frac{3}{2};\frac{8}{5}\right] ", @"\left[ \frac{3}{2};\frac{8}{5}\right] ")] + [InlineData(@"[1.5,1.5]", @"\left\{ \frac{3}{2}\right\} ", @"\left\{ \frac{3}{2}\right\} ")] + [InlineData(@"(1.5,1.5]", @"\emptyset ", @"\emptyset ")] + [InlineData(@"[1.5,1.5)", @"\emptyset ", @"\emptyset ")] + [InlineData(@"(1.5,1.5)", @"\emptyset ", @"\emptyset ")] + [InlineData(@"[xy,xy]", @"\left\{ xy\right\} ", @"\left\{ xy\right\} ")] + [InlineData(@"(xy,xy]", @"\emptyset ", @"\emptyset ")] + [InlineData(@"[xy,xy)", @"\emptyset ", @"\emptyset ")] + [InlineData(@"(xy,xy)", @"\emptyset ", @"\emptyset ")] + [InlineData(@"\frac{[7, 8]}{9}", @"\frac{\left[ 7;8\right] }{9}", @"\frac{\left[ 7;8\right] }{9}")] + [InlineData(@"+(3,4]", @"\left( 3;4\right] ", @"\left( 3;4\right] ")] + public void Intervals(string latex, string converted, string result) { + Test(latex, converted, result); + Test(latex.Replace(",", ";"), converted, result); + } [Theory] [InlineData(@"\>\:\pi", @"\pi ", @"\pi ")] - [InlineData(@"3\quad 2", @"3\times 2", "6")] - [InlineData(@"a\textstyle b\displaystyle", @"a\times b", @"a\times b")] - [InlineData(@"a^6+2a^6 % should be 3a^6", @"a^6+2\times a^6", @"3\times a^6")] + [InlineData(@"3\quad 2", @"3\cdot 2", "6")] + [InlineData(@"a\textstyle b\displaystyle", @"ab", @"ab")] + [InlineData(@"a^6+2a^6 % should be 3a^6", @"a^6+2a^6", @"3a^6")] [InlineData(@"4+\ \mkern1.5mu3", @"4+3", "7")] public void SkipInvisible(string latex, string converted, string output) => Test(latex, converted, output); [Theory] @@ -529,7 +563,6 @@ public void Parentheses(string latex, string converted, string result) { [InlineData(@"1\degree_7", "Subscripts are unsupported for Ordinary °")] [InlineData(@"\dagger_8", "Unsupported Unary Operator †")] [InlineData(@".", "Invalid number: .")] - [InlineData(@"1._2", "Subscripts are unsupported for Number 1.")] [InlineData(@"..", "Invalid number: ..")] [InlineData(@"1..", "Invalid number: 1..")] [InlineData(@"..1", "Invalid number: ..1")] @@ -603,6 +636,7 @@ public void Parentheses(string latex, string converted, string result) { [InlineData(@"\{x\}\}", "Missing {")] [InlineData(@"+\}", "Missing right operand for +")] [InlineData(@"\left\{1+\right\}", "Missing right operand for +")] + [InlineData(@"\left\{\{\right\}\}", @"Missing }")] [InlineData(@"\{2,3\}^\square", "Placeholders should be filled")] [InlineData(@"\left\{2,3\right\}^\square", "Placeholders should be filled")] [InlineData(@"\frac{}{x}", "Missing numerator")] @@ -634,29 +668,29 @@ public void Parentheses(string latex, string converted, string result) { [InlineData(@"1,,2,", "Missing left operand for comma")] [InlineData(@"1,2,,", "Missing left operand for comma")] [InlineData(@"\arcsin(1,2)", "Comma cannot be argument for arcsin")] - [InlineData(@"+(3,4]", "Set cannot be right operand for +")] - [InlineData(@"[5,6)\times", "Set cannot be left operand for ×")] - [InlineData(@"\frac{[7,8]}{9}", "Set cannot be numerator")] + [InlineData(@"[5,6)\times", "Missing right operand for ×")] [InlineData(@"\sqrt[{[)}]{}", "Unrecognized bracket pair [ )")] - [InlineData(@"\sqrt[{[a,b]}]{}", "Set cannot be degree")] - [InlineData(@"\{\{\}\}", "Set cannot be set element")] + [InlineData(@"\sqrt[{[a,b]}]{}", "Missing radicand")] [InlineData(@"\cap", "Unsupported Unary Operator ∩")] [InlineData(@"\cap1", "Unsupported Unary Operator ∩")] - [InlineData(@"1\cap", "Entity cannot be left operand for ∩")] + [InlineData(@"1\cap", "Missing right operand for ∩")] [InlineData(@"\cup", "Unsupported Unary Operator ∪")] [InlineData(@"\cup1", "Unsupported Unary Operator ∪")] - [InlineData(@"1\cup", "Entity cannot be left operand for ∪")] + [InlineData(@"1\cup", "Missing right operand for ∪")] [InlineData(@"\setminus", "Unsupported Unary Operator ∖")] [InlineData(@"\setminus1", "Unsupported Unary Operator ∖")] - [InlineData(@"1\setminus", "Entity cannot be left operand for ∖")] + [InlineData(@"1\setminus", "Missing right operand for ∖")] [InlineData(@"^\complement", "Exponentiation is unsupported for Ordinary")] [InlineData(@"_\complement", "Subscripts are unsupported for Ordinary")] - [InlineData(@"1^\complement", "Entity cannot be target of set inversion")] [InlineData(@"1_\complement", "Subscripts are unsupported for Number 1")] - [InlineData(@"x^\complement", "Entity cannot be target of set inversion")] [InlineData(@"x_\complement", "Unsupported Ordinary ∁ in subscript")] - [InlineData(@"\sin^\complement x", "Entity cannot be target of set inversion")] [InlineData(@"\sin_\complement x", "Subscripts are unsupported for Large Operator sin")] + [InlineData(@",\cap", "Missing left operand for comma")] + [InlineData(@";\cap", "Missing left operand for comma")] + [InlineData(@"1,\cap", "Unsupported Unary Operator ∩")] + [InlineData(@"1;\cap", "Unsupported Unary Operator ∩")] + [InlineData(@"\cap,", "Unsupported Unary Operator ∩")] + [InlineData(@"\cap;", "Unsupported Unary Operator ∩")] public void Error(string badLaTeX, string error) => Evaluation.Evaluate(ParseLaTeX(badLaTeX)) .Match(entity => throw new Xunit.Sdk.XunitException(entity.Latexise()), e => Assert.Equal(error, e)); @@ -664,14 +698,46 @@ public void Error(string badLaTeX, string error) => [Theory] [InlineData("1 + 1 - 1", @"1+1-1")] [InlineData("3 / 2", @"\frac{3}{2}")] - [InlineData("2 * 3 / 5", @"\frac{2\times 3}{5}")] + [InlineData("2 * 3 / 5", @"\frac{2\cdot 3}{5}")] [InlineData("sin(x+pi)", @"\sin \left( x+\pi \right) ")] + [InlineData("sin(aaa)", @"\sin \left( aaa\right) ")] [InlineData("log(3,alpha)", @"\log _3\left( \alpha \right) ")] + [InlineData("a_2k", @"a_{2k}")] [InlineData("2e9", @"2000000000")] [InlineData("-3e4^x", @"-30000^x")] [InlineData("(-3e4)^x", @"\left( -30000\right) ^x")] [InlineData("i+2i", @"i+2i")] public void SimpleArithmeticSyntax(string simpleSyntax, string latex) => Assert.Equal(latex, LaTeXParser.MathListToLaTeX(Evaluation.Visualize((Entity)simpleSyntax)).ToString()); + [Theory] + [InlineData(@"\operatorname{true}", @"\operatorname{True} ", @"\operatorname{True} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{false}", @"\operatorname{False} ", @"\operatorname{False} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\neg\operatorname{true}", @"\neg \operatorname{True} ", @"\operatorname{False} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\neg\operatorname{false}", @"\neg \operatorname{False} ", @"\operatorname{True} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{true}\land\operatorname{true}", @"\operatorname{True} \land \operatorname{True} ", @"\operatorname{True} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{true}\land\operatorname{false}", @"\operatorname{True} \land \operatorname{False} ", @"\operatorname{False} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{false}\land\operatorname{true}", @"\operatorname{False} \land \operatorname{True} ", @"\operatorname{False} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{false}\land\operatorname{false}", @"\operatorname{False} \land \operatorname{False} ", @"\operatorname{False} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{true}\lor\operatorname{true}", @"\operatorname{True} \lor \operatorname{True} ", @"\operatorname{True} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{true}\lor\operatorname{false}", @"\operatorname{True} \lor \operatorname{False} ", @"\operatorname{True} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{false}\lor\operatorname{true}", @"\operatorname{False} \lor \operatorname{True} ", @"\operatorname{True} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{false}\lor\operatorname{false}", @"\operatorname{False} \lor \operatorname{False} ", @"\operatorname{False} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{true}\oplus\operatorname{true}", @"\operatorname{True} \oplus \operatorname{True} ", @"\operatorname{False} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{true}\oplus\operatorname{false}", @"\operatorname{True} \oplus \operatorname{False} ", @"\operatorname{True} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{false}\oplus\operatorname{true}", @"\operatorname{False} \oplus \operatorname{True} ", @"\operatorname{True} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"\operatorname{false}\oplus\operatorname{false}", @"\operatorname{False} \oplus \operatorname{False} ", @"\operatorname{False} ", Skip = "Awaiting AngouriMath update")] + [InlineData(@"x=x", @"x=x", @"\operatorname{True} ")] + [InlineData(@"x\leq x", @"x\leqslant x", @"\operatorname{True} ")] + [InlineData(@"x\neq y", @"\neg x=y", @"\neg x=y")] + [InlineData(@"1<2", @"1<2", @"\operatorname{True} ")] + [InlineData(@"2<1", @"2<1", @"\operatorname{False} ")] + [InlineData(@"1\le1", @"1\leqslant 1", @"\operatorname{True} ")] + [InlineData(@"2>1", @"2>1", @"\operatorname{True} ")] + [InlineData(@"1>2", @"1>2", @"\operatorname{False} ")] + [InlineData(@"1\ge1", @"1\geqslant 1", @"\operatorname{True} ")] + [InlineData(@"x\in\{x,y\}", @"x\in \left\{ x,y\right\} ", @"\operatorname{True} ")] + [InlineData(@"z\notin\{x,y\}", @"\neg z\in \left\{ x,y\right\} ", @"\operatorname{True} ")] + [InlineData(@"\{x,y\}\ni x", @"x\in \left\{ x,y\right\} ", @"\operatorname{True} ")] + public void LogicalAndRelationalOperators(string latex, string converted, string result) => Test(latex, converted, result); } } diff --git a/CSharpMath.Evaluation.Tests/InterpretTests.cs b/CSharpMath.Evaluation.Tests/InterpretTests.cs index 10a24b5ae..f4675fceb 100644 --- a/CSharpMath.Evaluation.Tests/InterpretTests.cs +++ b/CSharpMath.Evaluation.Tests/InterpretTests.cs @@ -10,11 +10,11 @@ public class InterpretTests { [InlineData(@"1+2", @"\underline\mathrm{Input}\\1+2\\\\\underline\mathrm{Simplified}\\3\\\\\underline\mathrm{Value\ (100\ digits)}\\3")] [InlineData(@"1+\sqrt", @"\color{red}\text{Missing radicand}")] [InlineData(@"1+\sqrt2", @"\underline\mathrm{Input}\\1+\sqrt{2}\\\\\underline\mathrm{Simplified}\\1+\sqrt{2}\\\\\underline\mathrm{Value\ (100\ digits)}\\2.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573")] - [InlineData(@"1+\sqrt{2x}", @"\underline\mathrm{Input}\\1+\sqrt{2\times x_{}}\\\\\underline\mathrm{Simplified}\\1+\sqrt{2\times x_{}}\\\\\underline\mathrm{Expanded}\\1+\sqrt{2\times x_{}}\\\\\underline\mathrm{Factorized}\\1+\sqrt{2\times x_{}}")] - [InlineData(@"1+\sqrt{2xy}", @"\underline\mathrm{Input}\\1+\sqrt{2\times x_{}\times y_{}}\\\\\underline\mathrm{Simplified}\\1+\sqrt{2\times x_{}\times y_{}}\\\\\underline\mathrm{Expanded}\\1+\sqrt{2\times x_{}\times y_{}}\\\\\underline\mathrm{Factorized}\\1+\sqrt{2\times x_{}\times y_{}}")] + [InlineData(@"1+\sqrt{2x}", @"\underline\mathrm{Input}\\1+\sqrt{2 x}\\\\\underline\mathrm{Simplified}\\1+\sqrt{2 x}\\\\\underline\mathrm{Expanded}\\1+\sqrt{2 x}\\\\\underline\mathrm{Factorized}\\1+\sqrt{2 x}")] + [InlineData(@"1+\sqrt{2xy}", @"\underline\mathrm{Input}\\1+\sqrt{2 x y}\\\\\underline\mathrm{Simplified}\\1+\sqrt{2 x y}\\\\\underline\mathrm{Expanded}\\1+\sqrt{2 x y}\\\\\underline\mathrm{Factorized}\\1+\sqrt{2 x y}")] [InlineData(@"=1+\sqrt{2xy}", @"\color{red}\text{Missing left side of equation}")] [InlineData(@"1+\sqrt{2xy}=", @"\color{red}\text{Missing right side of equation}")] - [InlineData(@"1+\sqrt{2xy}=3", @"\underline\mathrm{Input}\\1+\sqrt{2\times x_{}\times y_{}}=3\\\\\underline\mathrm{Solutions}\\x_{}\in \left\{\frac{--\frac{4}{y_{}}}{2}\right\}\\y_{}\in \left\{\frac{4}{2\times x_{}}\right\}\\")] + [InlineData(@"1+\sqrt{2xy}=3", @"\underline\mathrm{Input}\\1+\sqrt{2 x y}=3\\\\\underline\mathrm{Solutions}\\x\in \left\{ \frac{\frac{4}{y}}{2} \right\}\\y\in \left\{ \frac{4}{2 x} \right\}\\")] [InlineData(@"1=3", @"\underline\mathrm{Input}\\1=3\\\\\underline\mathrm{Result}\\\text{False}")] [InlineData(@"1=1", @"\underline\mathrm{Input}\\1=1\\\\\underline\mathrm{Result}\\\text{True}")] public void Interpret(string input, string expected) { diff --git a/CSharpMath.Evaluation.Tests/LogicalOperatorPrecedenceTests.cs b/CSharpMath.Evaluation.Tests/LogicalOperatorPrecedenceTests.cs new file mode 100644 index 000000000..c53c0fa85 --- /dev/null +++ b/CSharpMath.Evaluation.Tests/LogicalOperatorPrecedenceTests.cs @@ -0,0 +1,44 @@ +using Xunit; +using AngouriMath; + +namespace CSharpMath.EvaluationTests { + using Atom; + + public class LogicalOperatorPrecedenceTests { + static MathList ParseLaTeX(string latex) => + LaTeXParser.MathListFromLaTeX(latex).Match(list => list, e => throw new Xunit.Sdk.XunitException(e)); + + static Evaluation.MathItem ParseMath(string latex) => + Evaluation.Evaluate(ParseLaTeX(latex)).Match(entity => entity, e => throw new Xunit.Sdk.XunitException(e)); + + static void AssertConversion(string input, string expectedConverted) { + var math = ParseMath(input); + Assert.NotNull(math); + var actual = LaTeXParser.MathListToLaTeX(Evaluation.Visualize(math)).ToString(); + Assert.Equal(expectedConverted, actual); + } + + [Theory(Skip = "Awaiting AngouriMath update")] + // Test that ∧ binds tighter than ∨ + [InlineData(@"a\land b\lor c", @"\left( a\land b\right) \lor c")] + [InlineData(@"a\lor b\land c", @"a\lor \left( b\land c\right) ")] + // Test that ∨ binds tighter than ⊕ + [InlineData(@"a\oplus b\land c", @"a\oplus \left( b\land c\right) ")] + [InlineData(@"a\land b\oplus c", @"\left( a\land b\right) \oplus c")] + // Test that → is right associative and lowest precedence + [InlineData(@"a\to b\lor c", @"a\to \left( b\lor c\right) ")] + [InlineData(@"a\lor b\to c", @"\left( a\lor b\right) \to c")] + [InlineData(@"a\to b\to c", @"a\to \left( b\to c\right) ")] + // Complex expression + [InlineData(@"a\to b\land c\lor d", @"a\to \left( \left( b\land c\right) \lor d\right) ")] + // Test ¬ has highest precedence + [InlineData(@"\neg a\land b", @"\left( \neg a\right) \land b")] + [InlineData(@"\neg a\lor\neg b", @"\left( \neg a\right) \lor \left( \neg b\right) ")] + // Test relational operators bind tighter than logical + [InlineData(@"a=b\land c=d", @"\left( a=b\right) \land \left( c=d\right) ")] + [InlineData(@"ad", @"\left( ad\right) ")] + public void LogicalOperatorPrecedence(string input, string expectedOutput) { + AssertConversion(input, expectedOutput); + } + } +} diff --git a/CSharpMath.Evaluation/CSharpMath.Evaluation.csproj b/CSharpMath.Evaluation/CSharpMath.Evaluation.csproj index f8304b4d7..aa2e5ef69 100644 --- a/CSharpMath.Evaluation/CSharpMath.Evaluation.csproj +++ b/CSharpMath.Evaluation/CSharpMath.Evaluation.csproj @@ -13,7 +13,7 @@ - + diff --git a/CSharpMath.Evaluation/Evaluation.cs b/CSharpMath.Evaluation/Evaluation.cs index 6d8d21e19..d1b451538 100644 --- a/CSharpMath.Evaluation/Evaluation.cs +++ b/CSharpMath.Evaluation/Evaluation.cs @@ -18,22 +18,25 @@ enum Precedence { ParenthesisContext, // Lowest Comma, + Implication, + Disjunction, + Conjunction, + Negation, + Relation, SetOperation, AddSubtract, MultiplyDivide, FunctionApplication, UnaryPlusMinus, - PercentDegree + Postfix // Highest } - public abstract class MathItem : AngouriMath.Core.Sys.Interfaces.ILatexiseable { + public abstract class MathItem : AngouriMath.Core.ILatexiseable { private protected MathItem() { } public abstract string Latexise(); public static implicit operator MathItem(AngouriMath.Entity content) => new Entity(content); public static explicit operator AngouriMath.Entity(MathItem item) => ((Entity)item).Content; - public static implicit operator MathItem(SetNode content) => new Set(content); - public static explicit operator SetNode(MathItem item) => ((Set)item).Content; - /// A real number, complex number, variable, function call, vector, matrix or higher-dimensional tensor + /// A real number, complex number, variable, function call, vector, matrix, higher-dimensional tensor, or set public sealed class Entity : MathItem { public Entity(AngouriMath.Entity content) => Content = content; public AngouriMath.Entity Content { get; } @@ -57,19 +60,12 @@ public IEnumerator GetEnumerator() { } } } - /// A set or a combination of set operations - public sealed class Set : MathItem { - public Set(SetNode content) => Content = content; - public SetNode Content { get; } - public override string Latexise() => Content.Latexise(); - } } public static MathList Visualize(MathItem entity) => LaTeXParser.MathListFromLaTeX(entity.Latexise()) // CSharpMath must handle all LaTeX coming from AngouriMath or a bug is present! .Match(list => list, e => throw new InvalidCodePathException(e)); public static Result Evaluate(MathList mathList) { - MathS.pi.ToString(); // Call into MathS's static initializer to ensure Entity methods work return Transform(mathList.Clone(true)) .Bind(result => result is { } r @@ -105,19 +101,6 @@ static Result ExpectEntity(this Result result, string itemNam }); static Result AsEntity(this MathItem? item, string itemName) => Result.Ok(item).ExpectEntity(itemName); - static Result ExpectSetOrNull(this Result result, string itemName) => - result.Bind(item => item switch { - null => Result.Ok((SetNode?)null), - MathItem.Set entity => Result.Ok((SetNode?)entity.Content), - var notEntity => Result.Err(item.GetType().Name + " cannot be " + itemName) - }); - static Result ExpectSet(this Result result, string itemName) => - result.ExpectSetOrNull(itemName).Bind(item => item switch { - null => Result.Err("Missing " + itemName), - { } entity => Result.Ok(entity) - }); - static Result AsSet(this MathItem? item, string itemName) => - Result.Ok(item).ExpectSet(itemName); static Result ExpectNotNull(this Result result, string itemName) => result.Bind(item => item switch { null => Result.Err("Missing " + itemName), @@ -132,11 +115,11 @@ static Result TryMakeSet(MathItem.Comma c, bool leftClosed, bool right (MathItem)( left == right // MathS.Sets.Interval throws when both edges are equal ? leftClosed && rightClosed - ? new Set(MathS.Sets.Element(left)) - : MathS.Sets.Empty() - : new Set(MathS.Sets.Interval(left, right).SetLeftClosed(leftClosed).SetRightClosed(rightClosed)) + ? MathS.Sets.Finite(left) + : MathS.Sets.Empty + : MathS.Sets.Interval(left, leftClosed, right, rightClosed)) ) - )), + ), _ => "Unrecognized comma-delimited collection of " + c.Count() + " items" }; static readonly Dictionary ContextInfo = @@ -179,20 +162,16 @@ static Result TryMakeSet(MathItem.Comma c, bool leftClosed, bool right string? error; Precedence handlePrecendence; Func handlePrefix, handlePostfix, handleFunction, handleFunctionInverse; - Func handleFunctionN, handleFunctionInverseN; Func handleBinary; - Func handlePrefixSet, handlePostfixSet, handleFunctionSet, handleFunctionInverseSet; - Func handleBinarySet; - Func> handlePrefixInner, handlePostfixInner, handleFunctionInner, handleFunctionInverseInner; - Func> handleBinaryInner; for (; i < mathList.Count; i++) { var atom = mathList[i]; MathItem? @this; + bool subscriptAllowed = false; Result HandleSuperscript(ref MathItem? @this, MathList superscript) { switch(superscript) { case { Count: 1 } when superscript[0] is Atoms.Ordinary { Nucleus: "∁" }: (@this, error) = - @this.AsSet("target of set inversion").Bind(target => (MathItem?)!target); + @this.AsEntity("target of set inversion").Bind(target => (MathItem?)MathS.SetSubtraction(MathS.Sets.C, target)); // we don't support domains yet if (error != null) return error; break; default: @@ -211,13 +190,19 @@ Result HandleSuperscript(ref MathItem? @this, MathList superscript) { switch (atom) { case Atoms.Placeholder _: return "Placeholders should be filled"; + case Atoms.Number { Subscript: [Atoms.Number numericBase] } n: + if (int.TryParse(numericBase.Nucleus, out var @base)) { + try { @this = MathS.FromBaseN(atom.Nucleus, @base); } catch (Exception e) { return e.Message; } + subscriptAllowed = true; + goto handleThis; + } else return "Invalid numeric base: " + numericBase.Nucleus; case Atoms.Number n: - if (AngouriMath.Core.Numerix.ComplexNumber.TryParse(n.Nucleus, out var number)) { - @this = new NumberEntity(number); + if (Entity.Number.Complex.TryParse(n.Nucleus, out var number)) { + @this = number; goto handleThis; } else return "Invalid number: " + n.Nucleus; case Atoms.Variable v: - var subscript = new System.Text.StringBuilder("_"); + var subscript = new System.Text.StringBuilder(); foreach (var subAtom in v.Subscript) switch (subAtom) { case Atoms.Placeholder _: @@ -235,24 +220,27 @@ Result HandleSuperscript(ref MathItem? @this, MathList superscript) { default: return $"Unsupported {subAtom.TypeName} {subAtom.Nucleus} in subscript"; } + var underscore = subscript.Length > 0 ? "_" : ""; @this = (v.Nucleus, v.Subscript.Count) switch { - ("R", 0) when v.FontStyle == FontStyle.Blackboard => MathS.Sets.R(), - ("C", 0) when v.FontStyle == FontStyle.Blackboard => MathS.Sets.C(), + ("C", 0) when v.FontStyle == FontStyle.Blackboard => MathS.Sets.C, + ("R", 0) when v.FontStyle == FontStyle.Blackboard => MathS.Sets.R, + ("Q", 0) when v.FontStyle == FontStyle.Blackboard => MathS.Sets.Q, + ("Z", 0) when v.FontStyle == FontStyle.Blackboard => MathS.Sets.Z, ("e", 0) => MathS.e, ("π", 0) => MathS.pi, - ("i", 0) => new NumberEntity(MathS.i), + ("i", 0) => MathS.i, // Convert θ to theta - _ when LaTeXSettings.CommandForAtom(atom) is string s => MathS.Var(s + subscript.ToString()), - (var name, _) => MathS.Var(name + subscript.ToString()) + _ when LaTeXSettings.CommandForAtom(atom) is string s => MathS.Var(string.Concat(s.TrimStart('\\'), underscore, subscript)), + (var name, _) => MathS.Var(name + underscore + subscript.ToString()) }; - v.Subscript.Clear(); + subscriptAllowed = true; goto handleThis; case Atoms.Ordinary { Nucleus: "∞" }: - @this = new NumberEntity(AngouriMath.Core.Numerix.RealNumber.PositiveInfinity); + @this = Entity.Number.Real.PositiveInfinity; goto handleThis; case Atoms.Ordinary { Nucleus: "∅" }: - @this = MathS.Sets.Empty(); + @this = MathS.Sets.Empty; goto handleThis; case Atoms.Fraction f: Entity numerator, denominator; @@ -327,19 +315,23 @@ _ when LaTeXSettings.CommandForAtom(atom) is string s => MathS.Var(s + subscript handleFunction = MathS.Arccosec; handleFunctionInverse = MathS.Cosec; goto handleFunction; - case Atoms.LargeOperator { Nucleus: "log", Subscript: var @base }: + case Atoms.LargeOperator { Nucleus: "log", Subscript: var logBaseList }: Entity? logBase; - (logBase, error) = Transform(@base).ExpectEntityOrNull(nameof(logBase)); + (logBase, error) = Transform(logBaseList).ExpectEntityOrNull(nameof(logBase)); if (error != null) return error; - @base.Clear(); - logBase ??= new NumberEntity(10); + logBase ??= 10; handleFunction = arg => MathS.Log(logBase, arg); handleFunctionInverse = arg => MathS.Pow(logBase, arg); + subscriptAllowed = true; goto handleFunction; case Atoms.LargeOperator { Nucleus: "ln" }: handleFunction = MathS.Ln; handleFunctionInverse = arg => MathS.Pow(MathS.e, arg); goto handleFunction; + case Atoms.LargeOperator { Nucleus: "sgn" }: + handleFunction = MathS.Signum; + handleFunctionInverse = arg => MathS.NaN; + goto handleFunction; case Atoms.BinaryOperator { Nucleus: "+" }: handlePrecendence = Precedence.AddSubtract; handleBinary = (a, b) => a + b; @@ -360,14 +352,23 @@ _ when LaTeXSettings.CommandForAtom(atom) is string s => MathS.Var(s + subscript handleBinary = (a, b) => a / b; goto handleBinary; case Atoms.Ordinary { Nucleus: "%" }: - handlePrecendence = Precedence.PercentDegree; handlePostfix = x => x / 100; goto handlePostfix; case Atoms.Ordinary { Nucleus: "°" }: - handlePrecendence = Precedence.PercentDegree; handlePostfix = x => x * MathS.pi / 180; goto handlePostfix; + case Atoms.Punctuation { Nucleus: "!" }: + if (i + 1 < mathList.Count && mathList[i + 1] is Atoms.Punctuation { Nucleus: "!" }) { + i++; + // z!! = 2^(z/2) (2/π)^((1-cos(πz))/4) Γ(z/2+1) + handlePostfix = z => MathS.Pow(2, z / 2) * + MathS.Pow(2 / MathS.pi, (1 - MathS.Cos(MathS.pi * z)) / 4) * + MathS.Factorial(z / 2); + } else + handlePostfix = MathS.Factorial; + goto handlePostfix; case Atoms.Punctuation { Nucleus: "," }: + case Atoms.Punctuation { Nucleus: ";" }: // ; is interpreted as an alias of , if (prec <= Precedence.Comma) { if (prev is null) return "Missing left operand for comma"; i++; @@ -383,16 +384,82 @@ _ when LaTeXSettings.CommandForAtom(atom) is string s => MathS.Var(s + subscript } case Atoms.BinaryOperator { Nucleus: "∩" }: handlePrecendence = Precedence.SetOperation; - handleBinarySet = (l, r) => l & r; - goto handleBinarySet; + handleBinary = MathS.Intersection; + goto handleBinary; case Atoms.BinaryOperator { Nucleus: "∪" }: handlePrecendence = Precedence.SetOperation; - handleBinarySet = (l, r) => l | r; - goto handleBinarySet; + handleBinary = MathS.Union; + goto handleBinary; case Atoms.BinaryOperator { Nucleus: "∖" }: handlePrecendence = Precedence.SetOperation; - handleBinarySet = (l, r) => l - r; - goto handleBinarySet; + handleBinary = MathS.SetSubtraction; + goto handleBinary; + case Atoms.LargeOperator { Nucleus: "true" or "True" }: + @this = MathS.Boolean.Create(true); + goto handleThis; + case Atoms.LargeOperator { Nucleus: "false" or "False" }: + @this = MathS.Boolean.Create(false); + goto handleThis; + case Atoms.Ordinary { Nucleus: "¬" }: + handlePrecendence = Precedence.Negation; + handlePrefix = MathS.Negation; + goto handlePrefix; + case Atoms.BinaryOperator { Nucleus: "∧" }: + handlePrecendence = Precedence.Conjunction; + handleBinary = MathS.Conjunction; + goto handleBinary; + case Atoms.BinaryOperator { Nucleus: "∨" }: + handlePrecendence = Precedence.Disjunction; + handleBinary = MathS.Disjunction; + goto handleBinary; + case Atoms.BinaryOperator { Nucleus: "⊕" }: + handlePrecendence = Precedence.Disjunction; + handleBinary = MathS.ExclusiveDisjunction; + goto handleBinary; + case Atoms.Relation { Nucleus: "→" }: + handlePrecendence = Precedence.Implication; + handleBinary = MathS.Implication; + goto handleBinary; + case Atoms.Relation { Nucleus: "↛" }: + handlePrecendence = Precedence.Implication; + handleBinary = (x, y) => MathS.Negation(MathS.Implication(x, y)); + goto handleBinary; + case Atoms.Relation { Nucleus: "∈" }: + handlePrecendence = Precedence.Relation; + handleBinary = MathS.Sets.ElementInSet; + goto handleBinary; + case Atoms.Relation { Nucleus: "∉" }: + handlePrecendence = Precedence.Relation; + handleBinary = (element, set) => MathS.Negation(MathS.Sets.ElementInSet(element, set)); + goto handleBinary; + case Atoms.Relation { Nucleus: "∋" }: + handlePrecendence = Precedence.Relation; + handleBinary = (set, element) => MathS.Sets.ElementInSet(element, set); + goto handleBinary; + case Atoms.Relation { Nucleus: "=" }: + handlePrecendence = Precedence.Relation; + handleBinary = MathS.Equality; + goto handleBinary; + case Atoms.Relation { Nucleus: "≠" }: + handlePrecendence = Precedence.Relation; + handleBinary = (element, set) => MathS.Negation(MathS.Equality(element, set)); + goto handleBinary; + case Atoms.Relation { Nucleus: "<" }: + handlePrecendence = Precedence.Relation; + handleBinary = MathS.LessThan; + goto handleBinary; + case Atoms.Relation { Nucleus: "≤" }: + handlePrecendence = Precedence.Relation; + handleBinary = MathS.LessOrEqualThan; + goto handleBinary; + case Atoms.Relation { Nucleus: ">" }: + handlePrecendence = Precedence.Relation; + handleBinary = MathS.GreaterThan; + goto handleBinary; + case Atoms.Relation { Nucleus: "≥" }: + handlePrecendence = Precedence.Relation; + handleBinary = MathS.GreaterOrEqualThan; + goto handleBinary; case Atoms.Table { Environment: "matrix" } matrix: var (rows, cols, cells) = (matrix.NRows, matrix.NColumns, matrix.Cells); var matrixElements = new Entity[rows * cols]; @@ -468,30 +535,10 @@ _ when LaTeXSettings.CommandForAtom(atom) is string s => MathS.Var(s + subscript return $"Unsupported table environment {table.Environment}"; default: return $"Unsupported {atom.TypeName} {atom.Nucleus}"; -#pragma warning disable CS0162 // Unreachable code detected -#pragma warning disable CS0164 // This label has not been referenced handleFunction: - handleFunctionInner = (itemName, item) => - item.AsEntity(itemName).Bind(e => (MathItem)handleFunction(e)); - handleFunctionInverseInner = (itemName, item) => - item.AsEntity(itemName).Bind(e => (MathItem)handleFunctionInverse(e)); - goto handleFunctionInner; - handleFunctionN: - handleFunctionInner = (itemName, item) => - item.AsEntities(itemName).Bind(e => (MathItem)handleFunctionN(e)); - handleFunctionInverseInner = (itemName, item) => - item.AsEntities(itemName).Bind(e => (MathItem)handleFunctionInverseN(e)); - goto handleFunctionInner; - handleFunctionSet: - handleFunctionInner = (itemName, item) => - item.AsSet(itemName).Bind(set => (MathItem)handleFunctionSet(set)); - handleFunctionInverseInner = (itemName, item) => - item.AsSet(itemName).Bind(set => (MathItem)handleFunctionInverseSet(set)); - goto handleFunctionInner; - handleFunctionInner: if (atom.Superscript.EqualsList(new MathList(new Atoms.UnaryOperator("\u2212"), new Atoms.Number("1")))) { atom.Superscript.Clear(); - handleFunctionInner = handleFunctionInverseInner; + handleFunction = handleFunctionInverse; } i++; MathList? bracketArgument = null; @@ -552,45 +599,19 @@ _ when LaTeXSettings.CommandForAtom(atom) is string s => MathS.Var(s + subscript ? Transform(mathList, ref i, Precedence.FunctionApplication) : Transform(bracketArgument); if (error != null) return error; - (@this, error) = handleFunctionInner("argument for " + atom.Nucleus, next); + (@this, error) = next.AsEntity("argument for " + atom.Nucleus).Bind(e => (MathItem)handleFunction(e)); if (error != null) return error; goto handleThis; handlePrefix: - handlePrefixInner = (itemName, item) => item.AsEntity(itemName).Bind(e => (MathItem)handlePrefix(e)); - goto handlePrefixInner; - handlePrefixSet: - handlePrefixInner = (itemName, item) => item.AsSet(itemName).Bind(set => (MathItem)handlePrefixSet(set)); - goto handlePrefixInner; - handlePrefixInner: i++; (next, error) = Transform(mathList, ref i, handlePrecendence); if (error != null) return error; - (@this, error) = handlePrefixInner("right operand for " + atom.Nucleus, next); + (@this, error) = next.AsEntity("right operand for " + atom.Nucleus).Bind(e => (MathItem)handlePrefix(e)); if (error != null) return error; goto handleThis; handleBinary: - handleBinaryInner = (leftName, left, rightName, right) => { - Entity l, r; - (l, error) = left.AsEntity(leftName); - if (error != null) return error; - (r, error) = right.AsEntity(rightName); - if (error != null) return error; - return (MathItem)handleBinary(l, r); - }; - goto handleBinaryInner; - handleBinarySet: - handleBinaryInner = (leftName, left, rightName, right) => { - SetNode l, r; - (l, error) = left.AsSet(leftName); - if (error != null) return error; - (r, error) = right.AsSet(rightName); - if (error != null) return error; - return (MathItem)handleBinarySet(l, r); - }; - goto handleBinaryInner; - handleBinaryInner: if (prev is null) { // No previous entity, treat as unary operator (happens for 1---2) if (atom is Atoms.BinaryOperator b) { @@ -607,9 +628,11 @@ _ when LaTeXSettings.CommandForAtom(atom) is string s => MathS.Var(s + subscript i++; (next, error) = Transform(mathList, ref i, handlePrecendence); if (error != null) return error; - (@this, error) = - handleBinaryInner("left operand for " + atom.Nucleus, prev, - "right operand for " + atom.Nucleus, next); + (var l, error) = prev.AsEntity("left operand for " + atom.Nucleus); + if (error != null) return error; + (var r, error) = next.AsEntity("right operand for " + atom.Nucleus); + if (error != null) return error; + @this = (MathItem)handleBinary(l, r); if (error != null) return error; prev = null; // We used up prev, don't keep it goto handleThis; @@ -619,28 +642,14 @@ _ when LaTeXSettings.CommandForAtom(atom) is string s => MathS.Var(s + subscript } handlePostfix: - handlePostfixInner = (itemName, item) => item.AsEntity(itemName).Bind(e => (MathItem)handlePostfix(e)); - goto handlePostfixInner; - handlePostfixSet: - handlePostfixInner = (itemName, item) => item.AsSet(itemName).Bind(set => (MathItem)handlePostfixSet(set)); - goto handlePostfixInner; - handlePostfixInner: - if (prev == null) return "Missing left operand for " + atom.Nucleus; - if (prec < handlePrecendence) { - (@this, error) = - handlePostfixInner("left operand for " + atom.Nucleus, prev); - if (error != null) return error; - prev = null; // We used up prev, don't keep it - goto handleThis; - } else { - i--; - return prev; - } -#pragma warning restore CS0162 // Unreachable code detected -#pragma warning restore CS0164 // This label has not been referenced + (@this, error) = + prev.AsEntity("left operand for " + atom.Nucleus).Bind(e => (MathItem)handlePostfix(e)); + if (error != null) return error; + prev = null; // We used up prev, don't keep it + goto handleThis; handleThis: - if (atom.Subscript.Count > 0) + if (!subscriptAllowed && atom.Subscript.Count > 0) return $"Subscripts are unsupported for {atom.TypeName} {atom.Nucleus}"; error = HandleSuperscript(ref @this, atom.Superscript).Error; if (error != null) return error; diff --git a/CSharpMath.Evaluation/Interpret.cs b/CSharpMath.Evaluation/Interpret.cs index 8ada8f4c4..7d036de7f 100644 --- a/CSharpMath.Evaluation/Interpret.cs +++ b/CSharpMath.Evaluation/Interpret.cs @@ -3,7 +3,7 @@ namespace CSharpMath { static partial class Evaluation { - static StringBuilder AppendLaTeX(this StringBuilder sb, AngouriMath.Core.Sys.Interfaces.ILatexiseable latex) => + static StringBuilder AppendLaTeX(this StringBuilder sb, AngouriMath.Core.ILatexiseable latex) => sb.Append(latex.Latexise()); static StringBuilder AppendLaTeXHeader(this StringBuilder sb, string header, bool includeNewlineBefore = true) { if (includeNewlineBefore) sb.Append(@"\\\\"); @@ -30,12 +30,12 @@ public static string Interpret(Atom.MathList mathList, System.Func (MathItem?)x).ExpectEntity("right side of equation").Bind(right => { latex.AppendLaTeXHeader("Input", false).AppendLaTeX(left).Append("=").AppendLaTeX(right); var entity = left - right; - var variables = AngouriMath.MathS.Utils.GetUniqueVariables(entity).FiniteSet(); - if (variables.Count == 0) - latex.AppendLaTeXHeader("Result").Append($@"\text{{{entity.Eval() == 0}}}"); + var variables = entity.Vars; + if (variables.IsEmpty()) + latex.AppendLaTeXHeader("Result").Append($@"\text{{{entity.Evaled == 0}}}"); else { latex.AppendLaTeXHeader("Solutions"); - foreach (AngouriMath.VariableEntity variable in variables) + foreach (AngouriMath.Entity.Variable variable in variables) latex.AppendLaTeX(variable).Append(@"\in ").AppendLaTeX(entity.SolveEquation(variable)).Append(@"\\"); } return latex.ToString(); @@ -47,14 +47,13 @@ public static string Interpret(Atom.MathList mathList, System.Func - - - - - - - - - - - - - - - - - - - - - diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/App.xaml b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/App.xaml deleted file mode 100644 index 2b0b675a7..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/App.xaml +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/App.xaml.cs b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/App.xaml.cs deleted file mode 100644 index f8158b7c1..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/App.xaml.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace CSharpMath.Forms.Example.WPF { - /// Interaction logic for App.xaml - public partial class App : System.Windows.Application { } -} \ No newline at end of file diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/CSharpMath.Forms.Example.WPF.csproj b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/CSharpMath.Forms.Example.WPF.csproj deleted file mode 100644 index 25df500db..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/CSharpMath.Forms.Example.WPF.csproj +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - Debug - AnyCPU - {60549250-61D2-40E0-82C5-7B829193D694} - WinExe - CSharpMath.Forms.Example.WPF - CSharpMath.Forms.Example.WPF - v4.7.2 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - true - - - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\packages\OpenTK.3.1.0\lib\net20\OpenTK.dll - - - ..\..\packages\OpenTK.GLControl.3.1.0\lib\net20\OpenTK.GLControl.dll - - - ..\..\packages\SkiaSharp.1.68.1.1\lib\net45\SkiaSharp.dll - - - ..\..\packages\SkiaSharp.Views.Desktop.Common.1.68.1.1\lib\net45\SkiaSharp.Views.Desktop.Common.dll - - - ..\..\packages\SkiaSharp.Views.Forms.WPF.1.68.1.1\lib\net45\SkiaSharp.Views.Forms.dll - - - ..\..\packages\SkiaSharp.Views.WindowsForms.1.68.1.1\lib\net45\SkiaSharp.Views.WindowsForms.dll - - - ..\..\packages\SkiaSharp.Views.WPF.1.68.1.1\lib\net45\SkiaSharp.Views.WPF.dll - - - - ..\..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll - - - - - ..\..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll - - - - ..\..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll - - - ..\..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll - - - - - - - - - 4.0 - - - - - - ..\..\packages\WpfLightToolkit.1.0.3\lib\net45\WpfLightToolkit.dll - - - ..\..\packages\Xamarin.Forms.4.3.0.908675\lib\netstandard2.0\Xamarin.Forms.Core.dll - - - ..\..\packages\Xamarin.Forms.4.3.0.908675\lib\netstandard2.0\Xamarin.Forms.Platform.dll - - - ..\..\packages\Xamarin.Forms.Platform.WPF.4.3.0.908675\lib\net45\Xamarin.Forms.Platform.WPF.dll - - - ..\..\packages\Xamarin.Forms.4.3.0.908675\lib\netstandard2.0\Xamarin.Forms.Xaml.dll - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - MainWindow.xaml - Code - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - Designer - - - Designer - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - - - {b3fa77b8-c6e9-4a78-8bd4-9a167da36637} - CSharpMath.Forms.Example - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - \ No newline at end of file diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/MainWindow.xaml b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/MainWindow.xaml deleted file mode 100644 index d45532ac4..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/MainWindow.xaml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/MainWindow.xaml.cs b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/MainWindow.xaml.cs deleted file mode 100644 index 9b76fbece..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/MainWindow.xaml.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace CSharpMath.Forms.Example.WPF { - /// Interaction logic for MainWindow.xaml - public partial class MainWindow : Xamarin.Forms.Platform.WPF.FormsApplicationPage { - public MainWindow() { - InitializeComponent(); - Xamarin.Forms.Forms.Init(); - LoadApplication(new Example.App()); - } - } -} \ No newline at end of file diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/OpenTK.dll.config b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/OpenTK.dll.config deleted file mode 100644 index 7098d39e9..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/OpenTK.dll.config +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/AssemblyInfo.cs b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/AssemblyInfo.cs deleted file mode 100644 index 7c43ee382..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; -using System.Windows; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("CSharpMath.Forms.Example.WPF")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("CSWCSS")] -[assembly: AssemblyProduct("CSharpMath.Forms.Example.WPF")] -[assembly: AssemblyCopyright("Copyright © CSWCSS 2018")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -//In order to begin building localizable applications, set -//CultureYouAreCodingWith in your .csproj file -//inside a . For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - - -[assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] - - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Resources.Designer.cs b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Resources.Designer.cs deleted file mode 100644 index f2d4c47d7..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Resources.Designer.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace CSharpMath.Forms.Example.WPF.Properties { - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CSharpMath.Forms.Example.WPF.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Resources.resx b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Resources.resx deleted file mode 100644 index af7dbebba..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Settings.Designer.cs b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Settings.Designer.cs deleted file mode 100644 index f212577c4..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Settings.Designer.cs +++ /dev/null @@ -1,25 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace CSharpMath.Forms.Example.WPF.Properties { - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Settings.settings b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Settings.settings deleted file mode 100644 index 033d7a5e9..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/packages.config b/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/packages.config deleted file mode 100644 index 799cf3ffd..000000000 --- a/CSharpMath.Forms.Example/CSharpMath.Forms.Example.WPF/packages.config +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/CSharpMath.Forms.Tests/ButtonTests.cs b/CSharpMath.Forms.Tests/ButtonTests.cs index 03aa103b2..6da084a8c 100644 --- a/CSharpMath.Forms.Tests/ButtonTests.cs +++ b/CSharpMath.Forms.Tests/ButtonTests.cs @@ -277,6 +277,9 @@ void TestTwoButtonDisplayPlaceholders(MathInputButton mathInputButton, string ex }.Select(input => new object[] { input }); } public static class NotNullExtension { - public static T NotNull(this T? obj) where T : class => obj ?? throw new Xunit.Sdk.NotNullException(); + public static T NotNull(this T? obj) where T : class { + Assert.NotNull(obj); + return obj; + } } } diff --git a/CSharpMath.Forms.Tests/CSharpMath.Forms.Tests.csproj b/CSharpMath.Forms.Tests/CSharpMath.Forms.Tests.csproj index d6f504579..c4e201e33 100644 --- a/CSharpMath.Forms.Tests/CSharpMath.Forms.Tests.csproj +++ b/CSharpMath.Forms.Tests/CSharpMath.Forms.Tests.csproj @@ -11,4 +11,17 @@ Always + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + \ No newline at end of file diff --git a/CSharpMath.Forms/MathKeyboardExtensions.cs b/CSharpMath.Forms/MathKeyboardExtensions.cs index 68ef86ec3..295d3ef13 100644 --- a/CSharpMath.Forms/MathKeyboardExtensions.cs +++ b/CSharpMath.Forms/MathKeyboardExtensions.cs @@ -19,7 +19,7 @@ public static void BindDisplay(this MathKeyboard keyboard, (sender, e) => { var c = e.Surface.Canvas; c.Clear(); - MathPainter.DrawDisplay(settings, keyboard.Display, c); + settings.DrawDisplay(keyboard.Display, c); if (keyboard.ShouldDrawCaret) keyboard.DrawCaret(new SkiaCanvas(c, settings.AntiAlias), caretColor.FromNative(), caretShape); }; diff --git a/CSharpMath.Ios.Example/AppDelegate.cs b/CSharpMath.Ios.Example/AppDelegate.cs deleted file mode 100644 index 9b29b8b88..000000000 --- a/CSharpMath.Ios.Example/AppDelegate.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Foundation; -using UIKit; - -namespace CSharpMath.Ios.Example { - // The UIApplicationDelegate for the application. - // This class is responsible for launching the User Interface of the application, - // as well as listening (and optionally responding) to application events from iOS. - [Register("AppDelegate")] - public class AppDelegate : UIApplicationDelegate { - public override bool FinishedLaunching - (UIApplication application, NSDictionary launchOptions) { - Window = new UIWindow { RootViewController = new IosMathViewController() }; - return true; - } - public override void OnResignActivation(UIApplication application) { - // Invoked when the application is about to move from active to inactive state. - // This can occur for certain types of temporary interruptions - // (such as an incoming phone call or SMS message) or when the user - // quits the application and it begins the transition to the background state. - // Games should use this method to pause the game. - } - public override void DidEnterBackground(UIApplication application) { - // Use this method to release shared resources, save user data, - // invalidate timers and store the application state. - // If your application supports background exection this method - // is called instead of WillTerminate when the user quits. - } - public override void WillEnterForeground(UIApplication application) { - // Called as part of the transiton from background to active state. - // Here you can undo many of the changes made on entering the background. - } - public override void OnActivated(UIApplication application) { - // Restart any tasks that were paused (or not yet started) - // while the application was inactive. - // If the application was previously in the background, - // optionally refresh the user interface. - } - public override void WillTerminate(UIApplication application) { - // Called when the application is about to terminate. - // Save data, if needed. See also DidEnterBackground. - } - } -} \ No newline at end of file diff --git a/CSharpMath.Ios.Example/Assets.xcassets/AppIcon.appiconset/Contents.json b/CSharpMath.Ios.Example/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 64d0e3ddf..000000000 --- a/CSharpMath.Ios.Example/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,202 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "20x20", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "20x20", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "83.5x83.5", - "scale" : "2x" - }, - { - "idiom" : "ios-marketing", - "size" : "1024x1024", - "scale" : "1x" - }, - { - "size" : "24x24", - "idiom" : "watch", - "scale" : "2x", - "role" : "notificationCenter", - "subtype" : "38mm" - }, - { - "size" : "27.5x27.5", - "idiom" : "watch", - "scale" : "2x", - "role" : "notificationCenter", - "subtype" : "42mm" - }, - { - "size" : "29x29", - "idiom" : "watch", - "role" : "companionSettings", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "watch", - "role" : "companionSettings", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "watch", - "scale" : "2x", - "role" : "appLauncher", - "subtype" : "38mm" - }, - { - "size" : "44x44", - "idiom" : "watch", - "scale" : "2x", - "role" : "longLook", - "subtype" : "42mm" - }, - { - "size" : "86x86", - "idiom" : "watch", - "scale" : "2x", - "role" : "quickLook", - "subtype" : "38mm" - }, - { - "size" : "98x98", - "idiom" : "watch", - "scale" : "2x", - "role" : "quickLook", - "subtype" : "42mm" - }, - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/CSharpMath.Ios.Example/Assets.xcassets/Contents.json b/CSharpMath.Ios.Example/Assets.xcassets/Contents.json deleted file mode 100644 index 4caf392f9..000000000 --- a/CSharpMath.Ios.Example/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/CSharpMath.Ios.Example/CSharpMath.Ios.Example.csproj b/CSharpMath.Ios.Example/CSharpMath.Ios.Example.csproj deleted file mode 100644 index 843f3c79f..000000000 --- a/CSharpMath.Ios.Example/CSharpMath.Ios.Example.csproj +++ /dev/null @@ -1,148 +0,0 @@ - - - - Debug - iPhoneSimulator - {664EAD44-C19D-462B-9127-FD1106B4F3C6} - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Exe - CSharpMath.Ios.Example - CSharpMath.Ios.Example - Resources - - - - - true - full - false - bin\iPhoneSimulator\Debug - DEBUG;ENABLE_TEST_CLOUD; - prompt - 4 - iPhone Developer - true - true - true - true - 64941 - None - x86_64 - HttpClientHandler - false - - - west - latest - - - pdbonly - true - bin\iPhone\Release - - - prompt - 4 - iPhone Developer - true - Entitlements.plist - SdkOnly - ARM64 - NSUrlSessionHandler - - - - - pdbonly - true - bin\iPhoneSimulator\Release - - - prompt - 4 - iPhone Developer - true - None - x86_64 - HttpClientHandler - - - - - true - full - false - bin\iPhone\Debug - DEBUG;ENABLE_TEST_CLOUD; - prompt - 4 - iPhone Developer - true - true - true - true - true - true - Entitlements.plist - 64569 - SdkOnly - ARM64 - NSUrlSessionHandler - - - - - - - ..\packages\Newtonsoft.Json.12.0.2\lib\netstandard2.0\Newtonsoft.Json.dll - - - - - - - - - - - false - - - false - - - - - - - - - - - - - - - TestRenderingMathData.cs - - - TestRenderingSharedData.cs - - - - - - - - {11d4e6c7-c8e2-449c-a1e7-18bbbce4e6f3} - CSharpMath.Ios - false - false - - - {5157367B-F03E-4ACB-83A1-0DE414A3BFCA} - CSharpMath - - - - \ No newline at end of file diff --git a/CSharpMath.Ios.Example/Entitlements.plist b/CSharpMath.Ios.Example/Entitlements.plist deleted file mode 100644 index 9ae599370..000000000 --- a/CSharpMath.Ios.Example/Entitlements.plist +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/CSharpMath.Ios.Example/IosMathViewController.cs b/CSharpMath.Ios.Example/IosMathViewController.cs deleted file mode 100644 index 9a9f72027..000000000 --- a/CSharpMath.Ios.Example/IosMathViewController.cs +++ /dev/null @@ -1,21 +0,0 @@ -using UIKit; - -namespace CSharpMath.Ios.Example { - public class IosMathViewController : UIViewController { - public override void ViewDidLoad() { - var scrollView = new UIScrollView { BackgroundColor = UIColor.White, ScrollEnabled = true }; - System.nfloat y = 0, w = 0; - foreach (var latex in Rendering.Tests.TestRenderingMathData.AllConstants.Values) { - var latexView = IosMathLabels.MathView(latex, 50); // WJWJWJ latex here - var size = latexView.SizeThatFits(new CoreGraphics.CGSize(370, 280)); - latexView.Frame = new CoreGraphics.CGRect(0, y, size.Width, size.Height); - scrollView.Add(latexView); - y += size.Height; - w = size.Width > w ? size.Width : w; - y += 10; - } - scrollView.ContentSize = new CoreGraphics.CGSize(w, y); - View = scrollView; - } - } -} diff --git a/CSharpMath.Ios.Example/LaunchScreen.storyboard b/CSharpMath.Ios.Example/LaunchScreen.storyboard deleted file mode 100644 index 7981a14b7..000000000 --- a/CSharpMath.Ios.Example/LaunchScreen.storyboard +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CSharpMath.Ios.Example/Main.cs b/CSharpMath.Ios.Example/Main.cs deleted file mode 100644 index 48d9a80d2..000000000 --- a/CSharpMath.Ios.Example/Main.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace CSharpMath.Ios.Example { - public class Application { - // This is the main entry point of the application. - static void Main(string[] args) => - // if you want to use a different Application Delegate class from "AppDelegate" - // you can specify it here. - UIKit.UIApplication.Main(args, null, "AppDelegate"); - } -} \ No newline at end of file diff --git a/CSharpMath.Ios.Example/Main.storyboard b/CSharpMath.Ios.Example/Main.storyboard deleted file mode 100644 index b5474cad7..000000000 --- a/CSharpMath.Ios.Example/Main.storyboard +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/CSharpMath.Ios.Example/packages.config b/CSharpMath.Ios.Example/packages.config deleted file mode 100644 index c42689034..000000000 --- a/CSharpMath.Ios.Example/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/CSharpMath.Ios.Tests/AppDelegate.cs b/CSharpMath.Ios.Tests/AppDelegate.cs deleted file mode 100644 index b379f4dd4..000000000 --- a/CSharpMath.Ios.Tests/AppDelegate.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Foundation; -using UIKit; - -using Xunit.Runner; -using Xunit.Sdk; - - -namespace CSharpMath.Ios.Tests { - // The UIApplicationDelegate for the application. This class is responsible for launching the - // User Interface of the application, as well as listening (and optionally responding) to - // application events from iOS. - [Register("AppDelegate")] - public partial class AppDelegate : RunnerAppDelegate { - // - // This method is invoked when the application has loaded and is ready to run. In this - // method you should instantiate the window, load the UI into it and then make the window - // visible. - // - // You have 17 seconds to return from this method, or iOS will terminate your application. - // - public override bool FinishedLaunching(UIApplication app, NSDictionary options) { - - // We need this to ensure the execution assembly is part of the app bundle - AddExecutionAssembly(typeof(ExtensibilityPointFactory).Assembly); - - - // tests can be inside the main assembly - AddTestAssembly(Assembly.GetExecutingAssembly()); - // otherwise you need to ensure that the test assemblies will - // become part of the app bundle - // AddTestAssembly(typeof(PortableTests).Assembly); - - // start running the test suites as soon as the application is loaded - AutoStart = true; - // crash the application (to ensure it's ended) and return to springboard -#if CI - TerminateAfterExecution = true; -#endif - return base.FinishedLaunching(app, options); - } - } -} \ No newline at end of file diff --git a/CSharpMath.Ios.Tests/CSharpMath.Ios.Tests.csproj b/CSharpMath.Ios.Tests/CSharpMath.Ios.Tests.csproj deleted file mode 100644 index 6ea6090e4..000000000 --- a/CSharpMath.Ios.Tests/CSharpMath.Ios.Tests.csproj +++ /dev/null @@ -1,151 +0,0 @@ - - - - Debug - iPhoneSimulator - {30C91103-12E5-47AE-85FE-41B0218A8997} - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Exe - CSharpMath.Ios.Tests - CSharpMath.Ios.Tests - Resources - - - true - full - false - bin\iPhoneSimulator\Debug - DEBUG; - prompt - 4 - iPhone Developer - true - true - true - 23322 - None - x86_64 - NSUrlSessionHandler - false - - - - - Default - - - - - pdbonly - true - bin\iPhone\Release - - - prompt - 4 - iPhone Developer - true - true - Entitlements.plist - SdkOnly - ARM64 - NSUrlSessionHandler - - - - - Default - - - - - pdbonly - true - bin\iPhoneSimulator\Release - - - prompt - 4 - iPhone Developer - true - None - x86_64 - NSUrlSessionHandler - - - - - Default - - - - - true - full - false - bin\iPhone\Debug - DEBUG; - prompt - 4 - iPhone Developer - true - true - true - true - true - Entitlements.plist - 41866 - SdkOnly - ARM64 - NSUrlSessionHandler - - - - - Default - - - - - $(DefineConstants);CI - - - - - - - - - - - - - - - - - - - - - - TestRenderingMathData.cs - - - TestRenderingSharedData.cs - - - - - - - {5157367B-F03E-4ACB-83A1-0DE414A3BFCA} - CSharpMath - - - {11D4E6C7-C8E2-449C-A1E7-18BBBCE4E6F3} - CSharpMath.Ios - - - - \ No newline at end of file diff --git a/CSharpMath.Ios.Tests/Entitlements.plist b/CSharpMath.Ios.Tests/Entitlements.plist deleted file mode 100644 index 9ae599370..000000000 --- a/CSharpMath.Ios.Tests/Entitlements.plist +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/CSharpMath.Ios.Tests/Info.plist b/CSharpMath.Ios.Tests/Info.plist deleted file mode 100644 index f36e99281..000000000 --- a/CSharpMath.Ios.Tests/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleName - Unit Tests - CFBundleIdentifier - CSharpMath.Ios.Unit-Tests - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1.0 - LSRequiresIPhoneOS - - MinimumOSVersion - 13.5 - UIDeviceFamily - - 1 - 2 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UILaunchStoryboardName - LaunchScreen - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - - diff --git a/CSharpMath.Ios.Tests/LaunchScreen.storyboard b/CSharpMath.Ios.Tests/LaunchScreen.storyboard deleted file mode 100644 index 5d2e905aa..000000000 --- a/CSharpMath.Ios.Tests/LaunchScreen.storyboard +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CSharpMath.Ios.Tests/Main.cs b/CSharpMath.Ios.Tests/Main.cs deleted file mode 100644 index ae01bae5f..000000000 --- a/CSharpMath.Ios.Tests/Main.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; - -using Foundation; -using UIKit; - -namespace CSharpMath.Ios.Tests { - public class Application { - // This is the main entry point of the application. - static void Main(string[] args) { - // Write Debug.WriteLine to StdErr: https://github.com/dotnet/runtime/blob/1cfa461bbf071fbc71ceb5e105e1d39d0c077f25/src/libraries/System.Private.CoreLib/src/System/Diagnostics/DebugProvider.Unix.cs#L9 - Environment.SetEnvironmentVariable("COMPlus_DebugWriteToStdErr", "1"); - - // if you want to use a different Application Delegate class from "AppDelegate" - // you can specify it here. - UIApplication.Main(args, null, "AppDelegate"); - } - } -} diff --git a/CSharpMath.Ios.Tests/Tests.cs b/CSharpMath.Ios.Tests/Tests.cs deleted file mode 100644 index 04d8e1afa..000000000 --- a/CSharpMath.Ios.Tests/Tests.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Threading.Tasks; -using Xunit; -using TestData = CSharpMath.Rendering.Tests.TestRenderingMathData; - -namespace CSharpMath.Ios.Tests { - public class Tests { - /// Maximum percentage change from expected file size to actual file size / 100 - /// Same idea as CSharpMath.Rendering.Tests.TestRendering.FileSizeTolerance. - const double FileSizeTolerance = 1.75; // This is too large... (should be <0.01) We need to devise an alternative test mechanism - static readonly Func GetManifestResourceStream = - System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream; - async Task Test(string directory, Action init, string file, string latex) { - var source = new TaskCompletionSource(); - Foundation.NSRunLoop.Main.BeginInvokeOnMainThread(() => { - try { - using var v = IosMathLabels.MathView(latex, 50); - init(v); - var size = v.SizeThatFits(default); - // BeginImageContext does not support zero width/height. GetCurrentContext will return null. - if (size.Width < 1) size.Width = 1; - if (size.Height < 1) size.Height = 1; - v.Frame = new CoreGraphics.CGRect(default, size); - UIKit.UIGraphics.BeginImageContext(size); - var context = UIKit.UIGraphics.GetCurrentContext(); - context.ScaleCTM(1, -1); - context.TranslateCTM(0, -size.Height); - if (!v.DrawViewHierarchy(v.Frame, true)) - throw new Exception(nameof(v.DrawViewHierarchy) + " has failed."); - source.SetResult(UIKit.UIGraphics.GetImageFromCurrentImageContext()); - UIKit.UIGraphics.EndImageContext(); - } catch (Exception e) { - source.SetException(e); - } - }); - - using var expected = GetManifestResourceStream($"CSharpMath.Ios.Tests.{directory}.{file}.png"); - using var actual = (await source.Task).AsPNG().AsStream(); - - // Save the generated image - var documents = Foundation.NSSearchPath.GetDirectories(Foundation.NSSearchPathDirectory.DocumentDirectory, Foundation.NSSearchPathDomain.User, true)[0]; - var dir = new System.IO.DirectoryInfo(documents).CreateSubdirectory(directory).FullName; - using var save = System.IO.File.Create(System.IO.Path.Combine(dir, $"{file}.ios.png")); - actual.CopyTo(save); - - switch (file) { - // The following are produced by inherently different implementations, so they are not comparable - case nameof(TestData.Cyrillic): - case nameof(TestData.ErrorInvalidColor): - case nameof(TestData.ErrorMissingArgument): - case nameof(TestData.ErrorMissingBrace): - break; - default: - Assert.InRange(actual.Length, expected.Length * (1 - FileSizeTolerance), expected.Length * (1 + FileSizeTolerance)); - break; - } - } - [Theory] - [ClassData(typeof(TestData))] - public Task MathInline(string file, string latex) => - Test(nameof(MathInline), v => v.LineStyle = Atom.LineStyle.Text, file, latex); - [Theory] - [ClassData(typeof(TestData))] - public Task MathDisplay(string file, string latex) => - Test(nameof(MathDisplay), v => { }, file, latex); - } -} diff --git a/CSharpMath.Ios/CSharpMath.Ios.csproj b/CSharpMath.Ios/CSharpMath.Ios.csproj deleted file mode 100644 index 47322bc7f..000000000 --- a/CSharpMath.Ios/CSharpMath.Ios.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - xamarin.ios1.0 - Library - The iOS front end for CSharpMath. - $(PackageTags) ios xamarin - - - - - - - \ No newline at end of file diff --git a/CSharpMath.Ios/IosMathLabels.cs b/CSharpMath.Ios/IosMathLabels.cs deleted file mode 100644 index 4fdaceeb7..000000000 --- a/CSharpMath.Ios/IosMathLabels.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace CSharpMath.Ios { - using Apple; - public static class IosMathLabels { - public static AppleMathView MathView(string latex, float fontSize) => - new AppleMathView(AppleTypesetters.LatinMath, fontSize) { LaTeX = latex }; - } -} \ No newline at end of file diff --git a/CSharpMath.Maui.Example/App.xaml b/CSharpMath.Maui.Example/App.xaml new file mode 100644 index 000000000..e2c2b676b --- /dev/null +++ b/CSharpMath.Maui.Example/App.xaml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/CSharpMath.Maui.Example/App.xaml.cs b/CSharpMath.Maui.Example/App.xaml.cs new file mode 100644 index 000000000..5b2daff81 --- /dev/null +++ b/CSharpMath.Maui.Example/App.xaml.cs @@ -0,0 +1,13 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace CSharpMath.Maui.Example { + public partial class App : Application { + public App() { + InitializeComponent(); + } + + protected override Window CreateWindow(IActivationState? activationState) { + return new Window(new AppShell()); + } + } +} \ No newline at end of file diff --git a/CSharpMath.Maui.Example/AppShell.xaml b/CSharpMath.Maui.Example/AppShell.xaml new file mode 100644 index 000000000..45fe7bfa7 --- /dev/null +++ b/CSharpMath.Maui.Example/AppShell.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/CSharpMath.Maui.Example/AppShell.xaml.cs b/CSharpMath.Maui.Example/AppShell.xaml.cs new file mode 100644 index 000000000..24d300a93 --- /dev/null +++ b/CSharpMath.Maui.Example/AppShell.xaml.cs @@ -0,0 +1,10 @@ +namespace CSharpMath.Maui.Example { + public partial class AppShell : Shell { + public AppShell() { + InitializeComponent(); + } + private void ThemeChange(object sender, EventArgs e) { + Application.Current!.UserAppTheme = Application.Current.RequestedTheme == AppTheme.Dark ? AppTheme.Light : AppTheme.Dark; + } + } +} diff --git a/CSharpMath.Maui.Example/CSharpMath.Maui.Example.csproj b/CSharpMath.Maui.Example/CSharpMath.Maui.Example.csproj new file mode 100644 index 000000000..c59160f06 --- /dev/null +++ b/CSharpMath.Maui.Example/CSharpMath.Maui.Example.csproj @@ -0,0 +1,84 @@ + + + + net10.0-android;net10.0-ios;net10.0-maccatalyst + $(TargetFrameworks);net10.0-windows10.0.19041.0 + + + + + Exe + CSharpMath.Maui.Example + true + true + enable + enable + + + CSharpMath.Maui.Example + + + com.companyname.csharpmath.maui.example + + + 1.0 + 1 + + + None + + 15.0 + 15.0 + 21.0 + 10.0.17763.0 + 10.0.17763.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ExamplesPage.xaml + + + + + + MSBuild:Compile + + + \ No newline at end of file diff --git a/CSharpMath.Maui.Example/ClockPage.xaml b/CSharpMath.Maui.Example/ClockPage.xaml new file mode 100644 index 000000000..4b93dfece --- /dev/null +++ b/CSharpMath.Maui.Example/ClockPage.xaml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/CSharpMath.Maui.Example/ClockPage.xaml.cs b/CSharpMath.Maui.Example/ClockPage.xaml.cs new file mode 100644 index 000000000..cee1d18b7 --- /dev/null +++ b/CSharpMath.Maui.Example/ClockPage.xaml.cs @@ -0,0 +1,91 @@ +namespace CSharpMath.Maui.Example { + /// + /// Credits to https://github.com/sadqiang + /// at https://github.com/verybadcat/CSharpMath/issues/27 + /// + public partial class ClockPage : ContentPage, IDrawable { + readonly string[] labels = { + // Four 4s make 1 to 12 using different operations + @"$\frac{44+4}{4}$", + @"$\frac{44}{44}$", + @"$\frac{4}{4}+\frac{4}{4}$", + @"$\frac{4+4+4}{4}$", + @"$4+\frac{4-4}{4}$", + @"$4+4^{4-4}$", + @"$4+\frac{4+4}{4}$", + @"$\frac{44}{4}-4$", + @"$\sqrt{4}^{4-\frac{4}{4}}$", + @"$\:\:(4-\frac{4}{4})^{\sqrt{4}}$", + @"$\frac{44-4}{4}$", + @"$\frac{4!}{\sqrt{4}}-\frac{4}{4}$" + }; + public ClockPage() { + InitializeComponent(); + + Dispatcher.StartTimer(TimeSpan.FromMilliseconds(20), () => { + canvasView.Invalidate(); + return true; + }); + canvasView.Drawable = this; + } + public void Draw(ICanvas canvas, RectF dirtyRect) { + canvas.SaveState(); + canvas.FillColor = Colors.CornflowerBlue; + canvas.FillRectangle(dirtyRect); + canvas.RestoreState(); + canvas.Translate(dirtyRect.Width / 2, dirtyRect.Height / 2); + var minWidthHeight = Math.Min(dirtyRect.Width, dirtyRect.Height); + canvas.Scale(minWidthHeight / 210f, minWidthHeight / 210f); + canvas.SaveState(); + canvas.FillColor = Colors.Black; + canvas.FillCircle(0, 0, 100); + canvas.RestoreState(); + var painter = new TextPainter { FontSize = 8, TextColor = Colors.White }; + for (int i = 0; i < 60; i++) { + // Dots + canvas.SaveState(); + canvas.Rotate(6 * i); + canvas.FillColor = Colors.White; + canvas.FillCircle(0, -90, i % 5 == 0 ? 4 : 2); + canvas.RestoreState(); + // Maths + if (i % 5 == 0) { + painter.LaTeX = labels[i / 5]; + if (!(painter.Measure(dirtyRect.Width) is { } measure)) + throw new Structures.InvalidCodePathException("Invalid LaTeX"); + var θ = (90 - 6 * i) / 180f * MathF.PI; + var (sinθ, cosθ) = MathF.SinCos(θ); + painter.Draw((canvas, dirtyRect.Size), + new System.Drawing.PointF(75 * cosθ - measure.Width / 2, + -75 * sinθ - measure.Height / 2), + float.PositiveInfinity); + } + } + var dateTime = DateTime.Now; + // H + canvas.SaveState(); + canvas.Rotate(30 * dateTime.Hour + dateTime.Minute / 2f); + canvas.StrokeColor = Colors.White; + canvas.StrokeLineCap = LineCap.Round; + canvas.StrokeSize = 12; + canvas.DrawLine(0, 0, 0, -50); + canvas.RestoreState(); + // M + canvas.SaveState(); + canvas.Rotate(6 * dateTime.Minute + dateTime.Second / 10f); + canvas.StrokeColor = Colors.White; + canvas.StrokeLineCap = LineCap.Round; + canvas.StrokeSize = 6; + canvas.DrawLine(0, 0, 0, -65); + canvas.RestoreState(); + // S + canvas.SaveState(); + canvas.Rotate(6f * (dateTime.Second + dateTime.Millisecond / 1000f)); + canvas.StrokeColor = Colors.Red; + canvas.StrokeLineCap = LineCap.Round; + canvas.StrokeSize = 2; + canvas.DrawLine(0, 0, 0, -75); + canvas.RestoreState(); + } + } +} \ No newline at end of file diff --git a/CSharpMath.Maui.Example/EditorPage.xaml b/CSharpMath.Maui.Example/EditorPage.xaml new file mode 100644 index 000000000..503adc72d --- /dev/null +++ b/CSharpMath.Maui.Example/EditorPage.xaml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/CSharpMath.Maui.Example/EditorPage.xaml.cs b/CSharpMath.Maui.Example/EditorPage.xaml.cs new file mode 100644 index 000000000..b60db8a2d --- /dev/null +++ b/CSharpMath.Maui.Example/EditorPage.xaml.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using CommunityToolkit.Maui.Extensions; +using CommunityToolkit.Maui.Views; +using Microsoft.Maui.Controls; +using SharpHook; +using SharpHook.Data; + +namespace CSharpMath.Maui.Example { + [XamlCompilation(XamlCompilationOptions.Compile)] + public partial class EditorPage : ContentPage { + public EditorPage() { + InitializeComponent(); + Content = new EditorView(); + } + } + public class EditorView : ContentView { + public MathPainter OutputMathPainter = new MathPainter { TextColor = Colors.Black }; + public GraphicsView OutputGraphicsView; + readonly MathKeyboard keyboard = new(Rendering.FrontEnd.PainterConstants.LargerFontSize); + public EditorView() { + // Basic functionality + OutputGraphicsView = new GraphicsView(); + var viewModel = keyboard.Keyboard; + viewModel.BindDisplay(OutputGraphicsView, OutputMathPainter, new Color(0, 0, 0, 153)); + + // Input from physical keyboard + var hook = new SimpleGlobalHook(GlobalHookType.Keyboard); + var popupShown = false; + void activatedListener(object? sender, EventArgs e) { if (!hook.IsRunning && IsLoaded && !popupShown) hook.RunAsync(); } + void deactivatedListener(object? sender, EventArgs e) { if (hook.IsRunning) hook.Stop(); } + Window? owningWindow = null; + void unloadedListener(object? sender, EventArgs e) { + if (hook.IsRunning) hook.Stop(); + owningWindow?.Activated -= activatedListener; + owningWindow?.Deactivated -= deactivatedListener; + Unloaded -= unloadedListener; + } + Loaded += (sender, e) => { + owningWindow = Window; + if (!hook.IsRunning && owningWindow.IsActivated && !popupShown) hook.RunAsync(); + owningWindow.Activated += activatedListener; + owningWindow.Deactivated += deactivatedListener; + Unloaded += unloadedListener; + }; + hook.KeyTyped += (sender, e) => viewModel.KeyPress((Editor.MathKeyboardInput)e.Data.KeyChar); + hook.KeyPressed += (sender, e) => { + switch (e.Data.KeyCode) { + case KeyCode.VcBackspace: viewModel.KeyPress(Editor.MathKeyboardInput.Backspace); break; + case KeyCode.VcNumPadEnter or KeyCode.VcEnter: viewModel.KeyPress(Editor.MathKeyboardInput.Return); break; + case KeyCode.VcLeft: viewModel.KeyPress(Editor.MathKeyboardInput.Left); break; + case KeyCode.VcRight: viewModel.KeyPress(Editor.MathKeyboardInput.Right); break; + case KeyCode.VcUp: viewModel.KeyPress(Editor.MathKeyboardInput.Up); break; + case KeyCode.VcDown: viewModel.KeyPress(Editor.MathKeyboardInput.Down); break; + } + }; + + // Evaluation + keyboard.Keyboard.ReturnPressed += delegate { + Dispatcher.Dispatch(async () => { // We may not be on the main thread since SharpHook event handlers are called from its own threads. + if (Parent is Page p) { + popupShown = true; + if (hook.IsRunning) hook.Stop(); + var view = new MathView { FontSize = 32, EnablePanning = true, TextAlignment = Rendering.FrontEnd.TextAlignment.TopLeft, + LaTeX = Evaluation.Interpret(keyboard.Keyboard.MathList) + }; + await p.ShowPopupAsync(new VerticalStackLayout { + new Grid { + ColumnDefinitions = { new() { Width = new GridLength(1, GridUnitType.Star) }, new() { Width = new GridLength(1, GridUnitType.Star) } }, + Children = { + GridItem(0, 0, new Button { Text = "Reset pan", Command = new Command(() => view.DisplacementX = view.DisplacementY = 0) }), + GridItem(0, 1, new Button { Text = "Close", Command = new Command(() => p.ClosePopupAsync()) }) } + }, view }); + popupShown = false; + if (IsLoaded && owningWindow is { IsActivated: true } && !hook.IsRunning) await hook.RunAsync(); + } + }); + }; + + // Debug labels + var latex = new Label { Text = "LaTeX = " }; + var atomTypes = new Label { Text = "Atom Types = " }; + var ranges = new Label { Text = "Ranges = " }; + var index = new Label { Text = "Index = " }; + viewModel.RedrawRequested += (sender, e) => Dispatcher.Dispatch(() => { + latex.Text = "LaTeX = " + viewModel.LaTeX; + atomTypes.Text = "Atom Types = " + string.Join + (", ", viewModel.MathList.Select(x => x.GetType().Name)); + ranges.Text = "Ranges = " + string.Join + (", ", (viewModel.Display ?? throw new Structures.InvalidCodePathException("Invalid LaTeX")) + .Displays.Select(x => x.Range)); + index.Text = "Index = " + viewModel.InsertionIndex; + }); + + static View GridItem(int row, int col, View view) { + Grid.SetRow(view, row); + Grid.SetColumn(view, col); + return view; + } + // Assemble + Content = new Grid { + RowDefinitions = { + new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) }, + new RowDefinition { Height = new GridLength(2, GridUnitType.Star) }, + new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) }, + new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }, + new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) }, + }, + Children = { + GridItem(0, 0, new ScrollView { + Content = new StackLayout { latex, atomTypes, ranges, index } + }), + GridItem(1, 0, OutputGraphicsView), + GridItem(2, 0, new BoxView { Color = Colors.Gray }), + GridItem(3, 0, keyboard), + GridItem(4, 0, new StackLayout { new Button { Text = "Change appearance", Command = new Command(ChangeAppearance), HorizontalOptions = LayoutOptions.Start } }), + } + }; + Themes[0].Invoke(); + } + int CurrentThemeIndex = 0; + public void ChangeAppearance() { + CurrentThemeIndex = (CurrentThemeIndex + 1) % Themes.Count; + Themes[CurrentThemeIndex].Invoke(); + keyboard.Keyboard.InsertionIndex = keyboard.Keyboard.InsertionIndex; // Hack to redraw placeholders in the output. + } + IList Themes => [ + () => { // This theme is the default. + var color = (Color)Application.Current!.Resources[Application.Current!.RequestedTheme == AppTheme.Dark ? "PrimaryDark" : "Primary"]; + OutputMathPainter.TextColor = color; + keyboard.Keyboard.UpdateDisplayCaret(OutputGraphicsView, OutputMathPainter, color); + Atom.LaTeXSettings.PlaceholderBlinks = false; + Atom.LaTeXSettings.PlaceholderActiveColor = null; + Atom.LaTeXSettings.PlaceholderRestingColor = null; + Atom.LaTeXSettings.PlaceholderActiveNucleus = "■"; + Atom.LaTeXSettings.PlaceholderRestingNucleus = "□"; + keyboard.SetButtonsTextColor(color); + keyboard.SetButtonsTextColor(color); + keyboard.SetClearButtonImageSource("recyclebin.png"); + }, + () => { + var color = (Color)Application.Current!.Resources[Application.Current!.RequestedTheme == AppTheme.Dark ? "PrimaryDark" : "Primary"]; + UseMyCustomizedPlaceholderAppearance(); + keyboard.Keyboard.UpdateDisplayCaret(OutputGraphicsView, OutputMathPainter, color); + keyboard.SetButtonsTextColor(color); // Placeholder appearance on the keys is the same as in the output by default. + keyboard.SetClearButtonImageSource("metaltrashcan.png"); + }, + () => { + Atom.LaTeXSettings.PlaceholderBlinks = true; + OutputMathPainter.TextColor = Application.Current!.RequestedTheme == AppTheme.Dark ? Colors.LightGreen : Colors.DarkGreen; + UseMyCustomizedPlaceholderAppearance(); + keyboard.Keyboard.UpdateDisplayCaret(OutputGraphicsView, OutputMathPainter, Colors.Orange); + // If you'd like to use different keyboard colors than output colors and you specified a placeholder color, + // probably you'll not want to use the same placeholder color on the keyboard: + keyboard.SetButtonsTextColor(Colors.Brown, CalculateMyPlaceholderRestingColorFromSurroundingTextColor(Colors.Brown)); + keyboard.SetClearButtonImageSource("flame.png"); + } + ]; + + public void UseMyCustomizedPlaceholderAppearance() { + // You could also customize the "Active" placeholder nucleus and color, but for this example we don't. + Atom.LaTeXSettings.PlaceholderRestingNucleus = "■"; + Atom.LaTeXSettings.PlaceholderRestingColor = CalculateMyPlaceholderRestingColorFromSurroundingTextColor(OutputMathPainter.TextColor).ToCSharpMathColor(); + } + public static Color CalculateMyPlaceholderRestingColorFromSurroundingTextColor(Color textColor) => textColor.WithLuminosity(textColor.GetLuminosity() > 0.5f ? 0.2f : 0.8f); + } +} \ No newline at end of file diff --git a/CSharpMath.Maui.Example/ExamplesPage.xaml b/CSharpMath.Maui.Example/ExamplesPage.xaml new file mode 100644 index 000000000..f56429507 --- /dev/null +++ b/CSharpMath.Maui.Example/ExamplesPage.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + +