Browse Source

Merge branch 'master' into feature/IAddChild

pull/8436/head
Benedikt Stebner 4 years ago
committed by GitHub
parent
commit
14a86320f0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .editorconfig
  2. 2
      native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
  3. 18
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  4. 1
      samples/ControlCatalog.NetCore/Program.cs
  5. 2
      samples/ControlCatalog/MainView.xaml
  6. 235
      samples/ControlCatalog/Pages/PointerCanvas.cs
  7. 109
      samples/ControlCatalog/Pages/PointerContactsTab.cs
  8. 322
      samples/ControlCatalog/Pages/PointersPage.cs
  9. 66
      samples/ControlCatalog/Pages/PointersPage.xaml
  10. 78
      samples/ControlCatalog/Pages/PointersPage.xaml.cs
  11. 21
      samples/IntegrationTestApp/MainWindow.axaml
  12. 66
      samples/IntegrationTestApp/MainWindow.axaml.cs
  13. 35
      samples/IntegrationTestApp/ShowWindowTest.axaml
  14. 40
      samples/IntegrationTestApp/ShowWindowTest.axaml.cs
  15. 119
      src/Avalonia.Base/Controls/ResourceDictionary.cs
  16. 5
      src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs
  17. 4
      src/Avalonia.Base/Input/IInputElement.cs
  18. 7
      src/Avalonia.Base/Input/IKeyboardDevice.cs
  19. 10
      src/Avalonia.Base/Input/IPenDevice.cs
  20. 43
      src/Avalonia.Base/Input/IPointer.cs
  21. 58
      src/Avalonia.Base/Input/InputElement.cs
  22. 174
      src/Avalonia.Base/Input/PenDevice.cs
  23. 22
      src/Avalonia.Base/Input/PointerEventArgs.cs
  24. 6
      src/Avalonia.Base/Input/PointerOverPreProcessor.cs
  25. 125
      src/Avalonia.Base/Input/PointerPoint.cs
  26. 19
      src/Avalonia.Base/Input/Raw/RawPointerEventArgs.cs
  27. 17
      src/Avalonia.Base/Input/Raw/RawTouchEventArgs.cs
  28. 13
      src/Avalonia.Base/Input/TouchDevice.cs
  29. 71
      src/Avalonia.Base/Layout/LayoutHelper.cs
  30. 24
      src/Avalonia.Base/Layout/Layoutable.cs
  31. 8
      src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs
  32. 498
      src/Avalonia.Base/Media/TextFormatting/Unicode/BiDi.trie.cs
  33. 28
      src/Avalonia.Base/Media/TextFormatting/Unicode/BiDiAlgorithm.cs
  34. 25
      src/Avalonia.Base/Media/TextFormatting/Unicode/BiDiData.cs
  35. 44
      src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs
  36. 7
      src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeBreak.cs
  37. 422
      src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeBreak.trie.cs
  38. 1
      src/Avalonia.Base/Media/TextFormatting/Unicode/LineBreakClass.cs
  39. 14
      src/Avalonia.Base/Media/TextFormatting/Unicode/LineBreakEnumerator.cs
  40. 5
      src/Avalonia.Base/Media/TextFormatting/Unicode/Script.cs
  41. 42
      src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeData.cs
  42. 1192
      src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeData.trie.cs
  43. 156
      src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrie.cs
  44. 14
      src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrieBuilder.cs
  45. 14
      src/Avalonia.Base/Point.cs
  46. 1
      src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs
  47. 2
      src/Avalonia.Base/Utilities/ArrayBuilder.cs
  48. 2
      src/Avalonia.Base/Utilities/ArraySlice.cs
  49. 40
      src/Avalonia.Base/Utilities/BidiDictionary.cs
  50. 6
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  51. 20
      src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs
  52. 12
      src/Avalonia.Controls.DataGrid/DataGridCell.cs
  53. 2
      src/Avalonia.Controls.DataGrid/DataGridColumn.cs
  54. 12
      src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
  55. 8
      src/Avalonia.Controls.DataGrid/DataGridRow.cs
  56. 8
      src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs
  57. 8
      src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs
  58. 12
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  59. 2
      src/Avalonia.Controls/Converters/MenuScrollingVisibilityConverter.cs
  60. 4
      src/Avalonia.Controls/GridSplitter.cs
  61. 52
      src/Avalonia.Controls/MenuItem.cs
  62. 16
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  63. 4
      src/Avalonia.Controls/Presenters/ContentPresenter.cs
  64. 8
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  65. 2
      src/Avalonia.Controls/Selection/InternalSelectionModel.cs
  66. 12
      src/Avalonia.Controls/ToolTipService.cs
  67. 6
      src/Avalonia.Controls/TopLevel.cs
  68. 52
      src/Avalonia.Controls/Window.cs
  69. 10
      src/Avalonia.Controls/WindowBase.cs
  70. 28
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlLayoutViewModel.cs
  71. 4
      src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs
  72. 12
      src/Avalonia.Themes.Fluent/Controls/FocusAdorner.xaml
  73. 12
      src/Shared/RawEventGrouping.cs
  74. 2
      src/Skia/Avalonia.Skia/TextShaperImpl.cs
  75. 2
      src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs
  76. 217
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  77. 1
      src/Windows/Avalonia.Win32/Win32Platform.cs
  78. 429
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
  79. 53
      src/Windows/Avalonia.Win32/WindowImpl.cs
  80. 52
      tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs
  81. 24
      tests/Avalonia.Base.UnitTests/Input/TouchDeviceTests.cs
  82. 31
      tests/Avalonia.Base.UnitTests/Layout/LayoutableTests.cs
  83. 140
      tests/Avalonia.Base.UnitTests/Layout/LayoutableTests_LayoutRounding.cs
  84. 2
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/BiDiAlgorithmTests.cs
  85. 9
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/BiDiClassTests.cs
  86. 2
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/BiDiTestDataGenerator.cs
  87. 9
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakClassTrieGenerator.cs
  88. 84
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakClassTrieGeneratorTests.cs
  89. 108
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakTestDataGenerator.cs
  90. 2
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/LineBreakEnumuratorTests.cs
  91. 85
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/TestDataGenerator.cs
  92. 58
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/UnicodeDataGenerator.cs
  93. 4
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/UnicodeDataGeneratorTests.cs
  94. 10
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/UnicodeEnumsGenerator.cs
  95. 64
      tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs
  96. 65
      tests/Avalonia.Controls.UnitTests/BorderTests.cs
  97. 12
      tests/Avalonia.Controls.UnitTests/ButtonTests.cs
  98. 41
      tests/Avalonia.Controls.UnitTests/DecoratorTests.cs
  99. 64
      tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs
  100. 66
      tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Layout.cs

2
.editorconfig

@ -21,7 +21,7 @@ csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
trim_trailing_whitespace = true
# trim_trailing_whitespace = true
# Indentation preferences
csharp_indent_block_contents = true

2
native/Avalonia.Native/src/OSX/WindowBaseImpl.mm

@ -224,7 +224,7 @@ HRESULT WindowBaseImpl::GetFrameSize(AvnSize *ret) {
if (ret == nullptr)
return E_POINTER;
if(Window != nullptr){
if(Window != nullptr && _shown){
auto frame = [Window frame];
ret->Width = frame.size.width;
ret->Height = frame.size.height;

18
native/Avalonia.Native/src/OSX/WindowImpl.mm

@ -119,13 +119,16 @@ void WindowImpl::BringToFront()
{
if(Window != nullptr)
{
if(IsDialog())
if (![Window isMiniaturized])
{
Activate();
}
else
{
[Window orderFront:nullptr];
if(IsDialog())
{
Activate();
}
else
{
[Window orderFront:nullptr];
}
}
[Window invalidateShadow];
@ -488,6 +491,8 @@ HRESULT WindowImpl::SetWindowState(AvnWindowState state) {
}
if (_shown) {
_actualWindowState = _lastWindowState;
switch (state) {
case Maximized:
if (currentState == FullScreen) {
@ -545,7 +550,6 @@ HRESULT WindowImpl::SetWindowState(AvnWindowState state) {
break;
}
_actualWindowState = _lastWindowState;
WindowEvents->WindowStateChanged(_actualWindowState);
}

1
samples/ControlCatalog.NetCore/Program.cs

@ -115,7 +115,6 @@ namespace ControlCatalog.NetCore
})
.With(new Win32PlatformOptions
{
EnableMultitouch = true
})
.UseSkia()
.AfterSetup(builder =>

2
samples/ControlCatalog/MainView.xaml

@ -109,7 +109,7 @@
<TabItem Header="OpenGL">
<pages:OpenGlPage />
</TabItem>
<TabItem Header="Pointers (Touch)">
<TabItem Header="Pointers">
<pages:PointersPage />
</TabItem>
<TabItem Header="ProgressBar">

235
samples/ControlCatalog/Pages/PointerCanvas.cs

@ -0,0 +1,235 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Threading;
namespace ControlCatalog.Pages;
public class PointerCanvas : Control
{
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
private int _events;
private IDisposable? _statusUpdated;
private Dictionary<int, PointerPoints> _pointers = new();
private PointerPointProperties? _lastProperties;
private PointerUpdateKind? _lastNonOtherUpdateKind;
class PointerPoints
{
struct CanvasPoint
{
public IBrush Brush;
public Point Point;
public double Radius;
public double? Pressure;
}
readonly CanvasPoint[] _points = new CanvasPoint[1000];
int _index;
public void Render(DrawingContext context, bool drawPoints)
{
CanvasPoint? prev = null;
for (var c = 0; c < _points.Length; c++)
{
var i = (c + _index) % _points.Length;
var pt = _points[i];
var pressure = (pt.Pressure ?? prev?.Pressure ?? 0.5);
var thickness = pressure * 10;
var radius = pressure * pt.Radius;
if (drawPoints)
{
if (pt.Brush != null)
{
context.DrawEllipse(pt.Brush, null, pt.Point, radius, radius);
}
}
else
{
if (prev.HasValue && prev.Value.Brush != null && pt.Brush != null
&& prev.Value.Pressure != null && pt.Pressure != null)
{
var linePen = new Pen(Brushes.Black, thickness, null, PenLineCap.Round, PenLineJoin.Round);
context.DrawLine(linePen, prev.Value.Point, pt.Point);
}
}
prev = pt;
}
}
void AddPoint(Point pt, IBrush brush, double radius, float? pressure = null)
{
_points[_index] = new CanvasPoint { Point = pt, Brush = brush, Radius = radius, Pressure = pressure };
_index = (_index + 1) % _points.Length;
}
public void HandleEvent(PointerEventArgs e, Visual v)
{
e.Handled = true;
var currentPoint = e.GetCurrentPoint(v);
if (e.RoutedEvent == PointerPressedEvent)
AddPoint(currentPoint.Position, Brushes.Green, 10);
else if (e.RoutedEvent == PointerReleasedEvent)
AddPoint(currentPoint.Position, Brushes.Red, 10);
else
{
var pts = e.GetIntermediatePoints(v);
for (var c = 0; c < pts.Count; c++)
{
var pt = pts[c];
AddPoint(pt.Position, c == pts.Count - 1 ? Brushes.Blue : Brushes.Black,
c == pts.Count - 1 ? 5 : 2, pt.Properties.Pressure);
}
}
}
}
private int _threadSleep;
public static DirectProperty<PointerCanvas, int> ThreadSleepProperty =
AvaloniaProperty.RegisterDirect<PointerCanvas, int>(nameof(ThreadSleep), c => c.ThreadSleep, (c, v) => c.ThreadSleep = v);
public int ThreadSleep
{
get => _threadSleep;
set => SetAndRaise(ThreadSleepProperty, ref _threadSleep, value);
}
private bool _drawOnlyPoints;
public static DirectProperty<PointerCanvas, bool> DrawOnlyPointsProperty =
AvaloniaProperty.RegisterDirect<PointerCanvas, bool>(nameof(DrawOnlyPoints), c => c.DrawOnlyPoints, (c, v) => c.DrawOnlyPoints = v);
public bool DrawOnlyPoints
{
get => _drawOnlyPoints;
set => SetAndRaise(DrawOnlyPointsProperty, ref _drawOnlyPoints, value);
}
private string? _status;
public static DirectProperty<PointerCanvas, string?> StatusProperty =
AvaloniaProperty.RegisterDirect<PointerCanvas, string?>(nameof(DrawOnlyPoints), c => c.Status, (c, v) => c.Status = v,
defaultBindingMode: Avalonia.Data.BindingMode.TwoWay);
public string? Status
{
get => _status;
set => SetAndRaise(StatusProperty, ref _status, value);
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
_statusUpdated = DispatcherTimer.Run(() =>
{
if (_stopwatch.Elapsed.TotalMilliseconds > 250)
{
Status = $@"Events per second: {(_events / _stopwatch.Elapsed.TotalSeconds)}
PointerUpdateKind: {_lastProperties?.PointerUpdateKind}
Last PointerUpdateKind != Other: {_lastNonOtherUpdateKind}
IsLeftButtonPressed: {_lastProperties?.IsLeftButtonPressed}
IsRightButtonPressed: {_lastProperties?.IsRightButtonPressed}
IsMiddleButtonPressed: {_lastProperties?.IsMiddleButtonPressed}
IsXButton1Pressed: {_lastProperties?.IsXButton1Pressed}
IsXButton2Pressed: {_lastProperties?.IsXButton2Pressed}
IsBarrelButtonPressed: {_lastProperties?.IsBarrelButtonPressed}
IsEraser: {_lastProperties?.IsEraser}
IsInverted: {_lastProperties?.IsInverted}
Pressure: {_lastProperties?.Pressure}
XTilt: {_lastProperties?.XTilt}
YTilt: {_lastProperties?.YTilt}
Twist: {_lastProperties?.Twist}";
_stopwatch.Restart();
_events = 0;
}
return true;
}, TimeSpan.FromMilliseconds(10));
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
_statusUpdated?.Dispose();
}
void HandleEvent(PointerEventArgs e)
{
_events++;
if (_threadSleep != 0)
{
Thread.Sleep(_threadSleep);
}
InvalidateVisual();
var lastPointer = e.GetCurrentPoint(this);
_lastProperties = lastPointer.Properties;
if (_lastProperties.PointerUpdateKind != PointerUpdateKind.Other)
{
_lastNonOtherUpdateKind = _lastProperties.PointerUpdateKind;
}
if (e.RoutedEvent == PointerReleasedEvent && e.Pointer.Type == PointerType.Touch)
{
_pointers.Remove(e.Pointer.Id);
return;
}
if (e.Pointer.Type != PointerType.Pen
|| lastPointer.Properties.Pressure > 0)
{
if (!_pointers.TryGetValue(e.Pointer.Id, out var pt))
_pointers[e.Pointer.Id] = pt = new PointerPoints();
pt.HandleEvent(e, this);
}
}
public override void Render(DrawingContext context)
{
context.FillRectangle(Brushes.White, Bounds);
foreach (var pt in _pointers.Values)
pt.Render(context, _drawOnlyPoints);
base.Render(context);
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (e.ClickCount == 2)
{
_pointers.Clear();
InvalidateVisual();
return;
}
HandleEvent(e);
base.OnPointerPressed(e);
}
protected override void OnPointerMoved(PointerEventArgs e)
{
HandleEvent(e);
base.OnPointerMoved(e);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
HandleEvent(e);
base.OnPointerReleased(e);
}
protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e)
{
_lastProperties = null;
base.OnPointerCaptureLost(e);
}
}

109
samples/ControlCatalog/Pages/PointerContactsTab.cs

@ -0,0 +1,109 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Media.Immutable;
namespace ControlCatalog.Pages;
public class PointerContactsTab : Control
{
class PointerInfo
{
public Point Point { get; set; }
public Color Color { get; set; }
}
private static Color[] AllColors = new[]
{
Colors.Aqua,
Colors.Beige,
Colors.Chartreuse,
Colors.Coral,
Colors.Fuchsia,
Colors.Crimson,
Colors.Lavender,
Colors.Orange,
Colors.Orchid,
Colors.ForestGreen,
Colors.SteelBlue,
Colors.PapayaWhip,
Colors.PaleVioletRed,
Colors.Goldenrod,
Colors.Maroon,
Colors.Moccasin,
Colors.Navy,
Colors.Wheat,
Colors.Violet,
Colors.Sienna,
Colors.Indigo,
Colors.Honeydew
};
private Dictionary<IPointer, PointerInfo> _pointers = new Dictionary<IPointer, PointerInfo>();
public PointerContactsTab()
{
ClipToBounds = true;
}
void UpdatePointer(PointerEventArgs e)
{
if (!_pointers.TryGetValue(e.Pointer, out var info))
{
if (e.RoutedEvent == PointerMovedEvent)
return;
var colors = AllColors.Except(_pointers.Values.Select(c => c.Color)).ToArray();
var color = colors[new Random().Next(0, colors.Length - 1)];
_pointers[e.Pointer] = info = new PointerInfo { Color = color };
}
info.Point = e.GetPosition(this);
InvalidateVisual();
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
UpdatePointer(e);
e.Pointer.Capture(this);
e.Handled = true;
base.OnPointerPressed(e);
}
protected override void OnPointerMoved(PointerEventArgs e)
{
UpdatePointer(e);
e.Handled = true;
base.OnPointerMoved(e);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
_pointers.Remove(e.Pointer);
e.Handled = true;
InvalidateVisual();
}
protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e)
{
_pointers.Remove(e.Pointer);
InvalidateVisual();
}
public override void Render(DrawingContext context)
{
context.FillRectangle(Brushes.Transparent, new Rect(default, Bounds.Size));
foreach (var pt in _pointers.Values)
{
var brush = new ImmutableSolidColorBrush(pt.Color);
context.DrawEllipse(brush, null, pt.Point, 75, 75);
}
}
}

322
samples/ControlCatalog/Pages/PointersPage.cs

@ -1,322 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Threading;
using Avalonia.VisualTree;
namespace ControlCatalog.Pages;
public class PointersPage : Decorator
{
public PointersPage()
{
Child = new TabControl
{
Items = new[]
{
new TabItem() { Header = "Contacts", Content = new PointerContactsTab() },
new TabItem() { Header = "IntermediatePoints", Content = new PointerIntermediatePointsTab() }
}
};
}
class PointerContactsTab : Control
{
class PointerInfo
{
public Point Point { get; set; }
public Color Color { get; set; }
}
private static Color[] AllColors = new[]
{
Colors.Aqua,
Colors.Beige,
Colors.Chartreuse,
Colors.Coral,
Colors.Fuchsia,
Colors.Crimson,
Colors.Lavender,
Colors.Orange,
Colors.Orchid,
Colors.ForestGreen,
Colors.SteelBlue,
Colors.PapayaWhip,
Colors.PaleVioletRed,
Colors.Goldenrod,
Colors.Maroon,
Colors.Moccasin,
Colors.Navy,
Colors.Wheat,
Colors.Violet,
Colors.Sienna,
Colors.Indigo,
Colors.Honeydew
};
private Dictionary<IPointer, PointerInfo> _pointers = new Dictionary<IPointer, PointerInfo>();
public PointerContactsTab()
{
ClipToBounds = true;
}
void UpdatePointer(PointerEventArgs e)
{
if (!_pointers.TryGetValue(e.Pointer, out var info))
{
if (e.RoutedEvent == PointerMovedEvent)
return;
var colors = AllColors.Except(_pointers.Values.Select(c => c.Color)).ToArray();
var color = colors[new Random().Next(0, colors.Length - 1)];
_pointers[e.Pointer] = info = new PointerInfo {Color = color};
}
info.Point = e.GetPosition(this);
InvalidateVisual();
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
UpdatePointer(e);
e.Pointer.Capture(this);
e.Handled = true;
base.OnPointerPressed(e);
}
protected override void OnPointerMoved(PointerEventArgs e)
{
UpdatePointer(e);
e.Handled = true;
base.OnPointerMoved(e);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
_pointers.Remove(e.Pointer);
e.Handled = true;
InvalidateVisual();
}
protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e)
{
_pointers.Remove(e.Pointer);
InvalidateVisual();
}
public override void Render(DrawingContext context)
{
context.FillRectangle(Brushes.Transparent, new Rect(default, Bounds.Size));
foreach (var pt in _pointers.Values)
{
var brush = new ImmutableSolidColorBrush(pt.Color);
context.DrawEllipse(brush, null, pt.Point, 75, 75);
}
}
}
public class PointerIntermediatePointsTab : Decorator
{
public PointerIntermediatePointsTab()
{
this[TextElement.ForegroundProperty] = Brushes.Black;
var slider = new Slider
{
Margin = new Thickness(5),
Minimum = 0,
Maximum = 500
};
var status = new TextBlock()
{
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
};
Child = new Grid
{
Children =
{
new PointerCanvas(slider, status),
new Border
{
Background = Brushes.LightYellow,
Child = new StackPanel
{
Children =
{
new StackPanel
{
Orientation = Orientation.Horizontal,
Children =
{
new TextBlock { Text = "Thread sleep:" },
new TextBlock()
{
[!TextBlock.TextProperty] =slider.GetObservable(Slider.ValueProperty)
.Select(x=>x.ToString()).ToBinding()
}
}
},
slider
}
},
HorizontalAlignment = HorizontalAlignment.Right,
VerticalAlignment = VerticalAlignment.Top,
Width = 300,
Height = 60
},
status
}
};
}
class PointerCanvas : Control
{
private readonly Slider _slider;
private readonly TextBlock _status;
private int _events;
private Stopwatch _stopwatch = Stopwatch.StartNew();
private Dictionary<int, PointerPoints> _pointers = new();
class PointerPoints
{
struct CanvasPoint
{
public IBrush Brush;
public Point Point;
public double Radius;
}
readonly CanvasPoint[] _points = new CanvasPoint[1000];
int _index;
public void Render(DrawingContext context)
{
CanvasPoint? prev = null;
for (var c = 0; c < _points.Length; c++)
{
var i = (c + _index) % _points.Length;
var pt = _points[i];
if (prev.HasValue && prev.Value.Brush != null && pt.Brush != null)
context.DrawLine(new Pen(Brushes.Black), prev.Value.Point, pt.Point);
prev = pt;
if (pt.Brush != null)
context.DrawEllipse(pt.Brush, null, pt.Point, pt.Radius, pt.Radius);
}
}
void AddPoint(Point pt, IBrush brush, double radius)
{
_points[_index] = new CanvasPoint { Point = pt, Brush = brush, Radius = radius };
_index = (_index + 1) % _points.Length;
}
public void HandleEvent(PointerEventArgs e, Visual v)
{
e.Handled = true;
if (e.RoutedEvent == PointerPressedEvent)
AddPoint(e.GetPosition(v), Brushes.Green, 10);
else if (e.RoutedEvent == PointerReleasedEvent)
AddPoint(e.GetPosition(v), Brushes.Red, 10);
else
{
var pts = e.GetIntermediatePoints(v);
for (var c = 0; c < pts.Count; c++)
{
var pt = pts[c];
AddPoint(pt.Position, c == pts.Count - 1 ? Brushes.Blue : Brushes.Black,
c == pts.Count - 1 ? 5 : 2);
}
}
}
}
public PointerCanvas(Slider slider, TextBlock status)
{
_slider = slider;
_status = status;
DispatcherTimer.Run(() =>
{
if (_stopwatch.Elapsed.TotalSeconds > 1)
{
_status.Text = "Events per second: " + (_events / _stopwatch.Elapsed.TotalSeconds);
_stopwatch.Restart();
_events = 0;
}
return this.GetVisualRoot() != null;
}, TimeSpan.FromMilliseconds(10));
}
void HandleEvent(PointerEventArgs e)
{
_events++;
Thread.Sleep((int)_slider.Value);
InvalidateVisual();
if (e.RoutedEvent == PointerReleasedEvent && e.Pointer.Type == PointerType.Touch)
{
_pointers.Remove(e.Pointer.Id);
return;
}
if (!_pointers.TryGetValue(e.Pointer.Id, out var pt))
_pointers[e.Pointer.Id] = pt = new PointerPoints();
pt.HandleEvent(e, this);
}
public override void Render(DrawingContext context)
{
context.FillRectangle(Brushes.White, Bounds);
foreach(var pt in _pointers.Values)
pt.Render(context);
base.Render(context);
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (e.ClickCount == 2)
{
_pointers.Clear();
InvalidateVisual();
return;
}
HandleEvent(e);
base.OnPointerPressed(e);
}
protected override void OnPointerMoved(PointerEventArgs e)
{
HandleEvent(e);
base.OnPointerMoved(e);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
HandleEvent(e);
base.OnPointerReleased(e);
}
}
}
}

66
samples/ControlCatalog/Pages/PointersPage.xaml

@ -0,0 +1,66 @@
<UserControl x:Class="ControlCatalog.Pages.PointersPage"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ControlCatalog.Pages">
<TabControl>
<TabItem Header="Contacts">
<local:PointerContactsTab />
</TabItem>
<TabItem Header="IntermediatePoints">
<Panel TextElement.Foreground="Black">
<local:PointerCanvas x:Name="IntermediatePointsCanvas"
DrawOnlyPoints="True"
Status="{Binding #Status1TextBlock.Text, Mode=OneWayToSource}"
ThreadSleep="{Binding #ThreadSleepSlider.Value}" />
<Border Width="300"
Height="60"
HorizontalAlignment="Right"
VerticalAlignment="Top">
<StackPanel Background="LightYellow">
<TextBlock Text="{Binding #ThreadSleepSlider.Value, StringFormat='Thread sleep: {0} / 500'}" />
<Slider x:Name="ThreadSleepSlider"
Value="50"
Maximum="500"
Minimum="0" />
</StackPanel>
</Border>
<TextBlock x:Name="Status1TextBlock"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
</Panel>
</TabItem>
<TabItem Header="Pressure">
<Panel TextElement.Foreground="Black">
<local:PointerCanvas x:Name="PressureCanvas"
DrawOnlyPoints="False"
Status="{Binding #Status2TextBlock.Text, Mode=OneWayToSource}"
ThreadSleep="0" />
<TextBlock x:Name="Status2TextBlock"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
</Panel>
</TabItem>
<TabItem Header="Capture">
<WrapPanel>
<Border Name="BorderCapture1"
MinWidth="250"
MinHeight="170"
Margin="5"
Padding="50"
Background="{DynamicResource SystemAccentColor}"
ToolTip.Placement="Bottom">
<TextBlock>Capture 1</TextBlock>
</Border>
<Border Name="BorderCapture2"
MinWidth="250"
MinHeight="170"
Margin="5"
Padding="50"
Background="{DynamicResource SystemAccentColor}"
ToolTip.Placement="Bottom">
<TextBlock>Capture 2</TextBlock>
</Border>
</WrapPanel>
</TabItem>
</TabControl>
</UserControl>

78
samples/ControlCatalog/Pages/PointersPage.xaml.cs

@ -0,0 +1,78 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace ControlCatalog.Pages;
public class PointersPage : UserControl
{
public PointersPage()
{
this.InitializeComponent();
var border1 = this.Get<Border>("BorderCapture1");
var border2 = this.Get<Border>("BorderCapture2");
border1.PointerPressed += Border_PointerPressed;
border1.PointerReleased += Border_PointerReleased;
border1.PointerCaptureLost += Border_PointerCaptureLost;
border1.PointerMoved += Border_PointerUpdated;
border1.PointerEntered += Border_PointerUpdated;
border1.PointerExited += Border_PointerUpdated;
border2.PointerPressed += Border_PointerPressed;
border2.PointerReleased += Border_PointerReleased;
border2.PointerCaptureLost += Border_PointerCaptureLost;
border2.PointerMoved += Border_PointerUpdated;
border2.PointerEntered += Border_PointerUpdated;
border2.PointerExited += Border_PointerUpdated;
}
private void Border_PointerUpdated(object sender, PointerEventArgs e)
{
var textBlock = (TextBlock)((Border)sender).Child;
var position = e.GetPosition((Border)sender);
textBlock.Text = @$"Type: {e.Pointer.Type}
Captured: {e.Pointer.Captured == sender}
PointerId: {e.Pointer.Id}
Position: {(int)position.X} {(int)position.Y}";
e.Handled = true;
}
private void Border_PointerCaptureLost(object sender, PointerCaptureLostEventArgs e)
{
var textBlock = (TextBlock)((Border)sender).Child;
textBlock.Text = @$"Type: {e.Pointer.Type}
Captured: {e.Pointer.Captured == sender}
PointerId: {e.Pointer.Id}
Position: ??? ???";
e.Handled = true;
}
private void Border_PointerReleased(object sender, PointerReleasedEventArgs e)
{
if (e.Pointer.Captured == sender)
{
e.Pointer.Capture(null);
e.Handled = true;
}
else
{
throw new InvalidOperationException("How?");
}
}
private void Border_PointerPressed(object sender, PointerPressedEventArgs e)
{
e.Pointer.Capture((Border)sender);
e.Handled = true;
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

21
samples/IntegrationTestApp/MainWindow.axaml

@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="IntegrationTestApp.MainWindow"
Name="MainWindow"
Title="IntegrationTestApp">
<NativeMenu.Menu>
<NativeMenu>
@ -94,6 +95,26 @@
</StackPanel>
</DockPanel>
</TabItem>
<TabItem Header="Window">
<StackPanel>
<TextBox Name="ShowWindowSize" Watermark="Window Size"/>
<ComboBox Name="ShowWindowMode" SelectedIndex="0">
<ComboBoxItem>NonOwned</ComboBoxItem>
<ComboBoxItem>Owned</ComboBoxItem>
<ComboBoxItem>Modal</ComboBoxItem>
</ComboBox>
<ComboBox Name="ShowWindowLocation" SelectedIndex="0">
<ComboBoxItem>Manual</ComboBoxItem>
<ComboBoxItem>CenterScreen</ComboBoxItem>
<ComboBoxItem>CenterOwner</ComboBoxItem>
</ComboBox>
<Button Name="ShowWindow">Show Window</Button>
<Button Name="SendToBack">Send to Back</Button>
<Button Name="ExitFullscreen">Exit Fullscreen</Button>
<Button Name="RestoreAll">Restore All</Button>
</StackPanel>
</TabItem>
</TabControl>
</DockPanel>
</Window>

66
samples/IntegrationTestApp/MainWindow.axaml.cs

@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.VisualTree;
namespace IntegrationTestApp
{
@ -46,6 +48,62 @@ namespace IntegrationTestApp
}
}
private void ShowWindow()
{
var sizeTextBox = this.GetControl<TextBox>("ShowWindowSize");
var modeComboBox = this.GetControl<ComboBox>("ShowWindowMode");
var locationComboBox = this.GetControl<ComboBox>("ShowWindowLocation");
var size = !string.IsNullOrWhiteSpace(sizeTextBox.Text) ? Size.Parse(sizeTextBox.Text) : (Size?)null;
var owner = (Window)this.GetVisualRoot()!;
var window = new ShowWindowTest
{
WindowStartupLocation = (WindowStartupLocation)locationComboBox.SelectedIndex,
};
if (size.HasValue)
{
window.Width = size.Value.Width;
window.Height = size.Value.Height;
}
sizeTextBox.Text = string.Empty;
switch (modeComboBox.SelectedIndex)
{
case 0:
window.Show();
break;
case 1:
window.Show(owner);
break;
case 2:
window.ShowDialog(owner);
break;
}
}
private void SendToBack()
{
var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!;
foreach (var window in lifetime.Windows)
{
window.Activate();
}
}
private void RestoreAll()
{
var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!;
foreach (var window in lifetime.Windows)
{
if (window.WindowState == WindowState.Minimized)
window.WindowState = WindowState.Normal;
}
}
private void MenuClicked(object? sender, RoutedEventArgs e)
{
var clickedMenuItemTextBlock = this.FindControl<TextBlock>("ClickedMenuItem");
@ -64,6 +122,14 @@ namespace IntegrationTestApp
this.FindControl<ListBox>("BasicListBox").SelectedIndex = -1;
if (source?.Name == "MenuClickedMenuItemReset")
this.FindControl<TextBlock>("ClickedMenuItem").Text = "None";
if (source?.Name == "ShowWindow")
ShowWindow();
if (source?.Name == "SendToBack")
SendToBack();
if (source?.Name == "ExitFullscreen")
WindowState = WindowState.Normal;
if (source?.Name == "RestoreAll")
RestoreAll();
}
}
}

35
samples/IntegrationTestApp/ShowWindowTest.axaml

@ -0,0 +1,35 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="IntegrationTestApp.ShowWindowTest"
Name="SecondaryWindow"
Title="Show Window Test">
<Grid ColumnDefinitions="Auto,Auto" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<Label Grid.Column="0" Grid.Row="1">Client Size</Label>
<TextBox Name="ClientSize" Grid.Column="1" Grid.Row="1" IsReadOnly="True"
Text="{Binding ClientSize, Mode=OneWay}"/>
<Label Grid.Column="0" Grid.Row="2">Frame Size</Label>
<TextBox Name="FrameSize" Grid.Column="1" Grid.Row="2" IsReadOnly="True"
Text="{Binding FrameSize, Mode=OneWay}"/>
<Label Grid.Column="0" Grid.Row="3">Position</Label>
<TextBox Name="Position" Grid.Column="1" Grid.Row="3" IsReadOnly="True"/>
<Label Grid.Column="0" Grid.Row="4">Owner Rect</Label>
<TextBox Name="OwnerRect" Grid.Column="1" Grid.Row="4" IsReadOnly="True"/>
<Label Grid.Column="0" Grid.Row="5">Screen Rect</Label>
<TextBox Name="ScreenRect" Grid.Column="1" Grid.Row="5" IsReadOnly="True"/>
<Label Grid.Column="0" Grid.Row="6">Scaling</Label>
<TextBox Name="Scaling" Grid.Column="1" Grid.Row="6" IsReadOnly="True"/>
<Label Grid.Column="0" Grid.Row="7">WindowState</Label>
<ComboBox Name="WindowState" Grid.Column="1" Grid.Row="7" SelectedIndex="{Binding WindowState}">
<ComboBoxItem>Normal</ComboBoxItem>
<ComboBoxItem>Minimized</ComboBoxItem>
<ComboBoxItem>Maximized</ComboBoxItem>
<ComboBoxItem>Fullscreen</ComboBoxItem>
</ComboBox>
</Grid>
</Window>

40
samples/IntegrationTestApp/ShowWindowTest.axaml.cs

@ -0,0 +1,40 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Rendering;
namespace IntegrationTestApp
{
public class ShowWindowTest : Window
{
public ShowWindowTest()
{
InitializeComponent();
DataContext = this;
PositionChanged += (s, e) => this.GetControl<TextBox>("Position").Text = $"{Position}";
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
var scaling = PlatformImpl!.DesktopScaling;
this.GetControl<TextBox>("Position").Text = $"{Position}";
this.GetControl<TextBox>("ScreenRect").Text = $"{Screens.ScreenFromVisual(this)?.WorkingArea}";
this.GetControl<TextBox>("Scaling").Text = $"{scaling}";
if (Owner is not null)
{
var ownerRect = this.GetControl<TextBox>("OwnerRect");
var owner = (Window)Owner;
ownerRect.Text = $"{owner.Position}, {PixelSize.FromSize(owner.FrameSize!.Value, scaling)}";
}
}
}
}

119
src/Avalonia.Base/Controls/ResourceDictionary.cs

@ -1,38 +1,45 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using Avalonia.Collections;
using Avalonia.Metadata;
#nullable enable
namespace Avalonia.Controls
{
/// <summary>
/// An indexed dictionary of resources.
/// </summary>
public class ResourceDictionary : AvaloniaDictionary<object, object?>, IResourceDictionary
public class ResourceDictionary : IResourceDictionary
{
private Dictionary<object, object?>? _inner;
private IResourceHost? _owner;
private AvaloniaList<IResourceProvider>? _mergedDictionaries;
/// <summary>
/// Initializes a new instance of the <see cref="ResourceDictionary"/> class.
/// </summary>
public ResourceDictionary()
{
CollectionChanged += OnCollectionChanged;
}
public ResourceDictionary() { }
/// <summary>
/// Initializes a new instance of the <see cref="ResourceDictionary"/> class.
/// </summary>
public ResourceDictionary(IResourceHost owner)
: this()
public ResourceDictionary(IResourceHost owner) => Owner = owner;
public int Count => _inner?.Count ?? 0;
public object? this[object key]
{
Owner = owner;
get => _inner?[key];
set
{
Inner[key] = value;
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
}
}
public ICollection<object> Keys => (ICollection<object>?)_inner?.Keys ?? Array.Empty<object>();
public ICollection<object?> Values => (ICollection<object?>?)_inner?.Values ?? Array.Empty<object?>();
public IResourceHost? Owner
{
get => _owner;
@ -80,7 +87,7 @@ namespace Avalonia.Controls
{
get
{
if (Count > 0)
if (_inner?.Count > 0)
{
return true;
}
@ -100,11 +107,43 @@ namespace Avalonia.Controls
}
}
bool ICollection<KeyValuePair<object, object?>>.IsReadOnly => false;
private Dictionary<object, object?> Inner => _inner ??= new();
public event EventHandler? OwnerChanged;
public void Add(object key, object? value)
{
Inner.Add(key, value);
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
}
public void Clear()
{
if (_inner?.Count > 0)
{
_inner.Clear();
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
}
}
public bool ContainsKey(object key) => _inner?.ContainsKey(key) ?? false;
public bool Remove(object key)
{
if (_inner?.Remove(key) == true)
{
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
return true;
}
return false;
}
public bool TryGetResource(object key, out object? value)
{
if (TryGetValue(key, out value))
if (_inner is not null && _inner.TryGetValue(key, out value))
{
return true;
}
@ -120,9 +159,52 @@ namespace Avalonia.Controls
}
}
value = null;
return false;
}
public bool TryGetValue(object key, out object? value)
{
if (_inner is not null)
return _inner.TryGetValue(key, out value);
value = null;
return false;
}
void ICollection<KeyValuePair<object, object?>>.Add(KeyValuePair<object, object?> item)
{
Add(item.Key, item.Value);
}
bool ICollection<KeyValuePair<object, object?>>.Contains(KeyValuePair<object, object?> item)
{
return (_inner as ICollection<KeyValuePair<object, object?>>)?.Contains(item) ?? false;
}
void ICollection<KeyValuePair<object, object?>>.CopyTo(KeyValuePair<object, object?>[] array, int arrayIndex)
{
(_inner as ICollection<KeyValuePair<object, object?>>)?.CopyTo(array, arrayIndex);
}
bool ICollection<KeyValuePair<object, object?>>.Remove(KeyValuePair<object, object?> item)
{
if ((_inner as ICollection<KeyValuePair<object, object?>>)?.Remove(item) == true)
{
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
return true;
}
return false;
}
public IEnumerator<KeyValuePair<object, object?>> GetEnumerator()
{
return _inner?.GetEnumerator() ?? Enumerable.Empty<KeyValuePair<object, object?>>().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
void IResourceProvider.AddOwner(IResourceHost owner)
{
owner = owner ?? throw new ArgumentNullException(nameof(owner));
@ -134,7 +216,7 @@ namespace Avalonia.Controls
Owner = owner;
var hasResources = Count > 0;
var hasResources = _inner?.Count > 0;
if (_mergedDictionaries is object)
{
@ -159,7 +241,7 @@ namespace Avalonia.Controls
{
Owner = null;
var hasResources = Count > 0;
var hasResources = _inner?.Count > 0;
if (_mergedDictionaries is object)
{
@ -176,10 +258,5 @@ namespace Avalonia.Controls
}
}
}
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
}
}
}

5
src/Avalonia.Base/Input/GestureRecognizers/ScrollGestureRecognizer.cs

@ -66,7 +66,8 @@ namespace Avalonia.Input.GestureRecognizers
public void PointerPressed(PointerPressedEventArgs e)
{
if (e.Pointer.IsPrimary && e.Pointer.Type == PointerType.Touch)
if (e.Pointer.IsPrimary &&
(e.Pointer.Type == PointerType.Touch || e.Pointer.Type == PointerType.Pen))
{
EndGesture();
_tracking = e.Pointer;
@ -101,7 +102,7 @@ namespace Avalonia.Input.GestureRecognizers
if (_scrolling)
{
var vector = _trackedRootPoint - rootPoint;
var elapsed = _lastMoveTimestamp.HasValue ?
var elapsed = _lastMoveTimestamp.HasValue && _lastMoveTimestamp < e.Timestamp ?
TimeSpan.FromMilliseconds(e.Timestamp - _lastMoveTimestamp.Value) :
TimeSpan.Zero;

4
src/Avalonia.Base/Input/IInputElement.cs

@ -42,12 +42,12 @@ namespace Avalonia.Input
/// <summary>
/// Occurs when the pointer enters the control.
/// </summary>
event EventHandler<PointerEventArgs>? PointerEnter;
event EventHandler<PointerEventArgs>? PointerEntered;
/// <summary>
/// Occurs when the pointer leaves the control.
/// </summary>
event EventHandler<PointerEventArgs>? PointerLeave;
event EventHandler<PointerEventArgs>? PointerExited;
/// <summary>
/// Occurs when the pointer is pressed over the control.

7
src/Avalonia.Base/Input/IKeyboardDevice.cs

@ -43,12 +43,17 @@ namespace Avalonia.Input
Control = 2,
Shift = 4,
Meta = 8,
LeftMouseButton = 16,
RightMouseButton = 32,
MiddleMouseButton = 64,
XButton1MouseButton = 128,
XButton2MouseButton = 256,
KeyboardMask = Alt | Control | Shift | Meta
KeyboardMask = Alt | Control | Shift | Meta,
PenInverted = 512,
PenEraser = 1024,
PenBarrelButton = 2048
}
[NotClientImplementable]

10
src/Avalonia.Base/Input/IPenDevice.cs

@ -0,0 +1,10 @@
namespace Avalonia.Input
{
/// <summary>
/// Represents a pen/stylus device.
/// </summary>
public interface IPenDevice : IPointerDevice
{
}
}

43
src/Avalonia.Base/Input/IPointer.cs

@ -2,20 +2,59 @@ using Avalonia.Metadata;
namespace Avalonia.Input
{
/// <summary>
/// Identifies specific pointer generated by input device.
/// </summary>
/// <remarks>
/// Some devices, for instance, touchscreen might generate a pointer on each physical contact.
/// </remarks>
[NotClientImplementable]
public interface IPointer
{
/// <summary>
/// Gets a unique identifier for the input pointer.
/// </summary>
int Id { get; }
/// <summary>
/// Captures pointer input to the specified control.
/// </summary>
/// <param name="control">The control.</param>
/// <remarks>
/// When an element captures the pointer, it receives pointer input whether the cursor is
/// within the control's bounds or not. The current pointer capture control is exposed
/// by the <see cref="Captured"/> property.
/// </remarks>
void Capture(IInputElement? control);
/// <summary>
/// Gets the control that is currently capturing by the pointer, if any.
/// </summary>
/// <remarks>
/// When an element captures the pointer, it receives pointer input whether the cursor is
/// within the control's bounds or not. To set the pointer capture, call the
/// <see cref="Capture"/> method.
/// </remarks>
IInputElement? Captured { get; }
/// <summary>
/// Gets the pointer device type.
/// </summary>
PointerType Type { get; }
/// <summary>
/// Gets a value that indicates whether the input is from the primary pointer when multiple pointers are registered.
/// </summary>
bool IsPrimary { get; }
}
/// <summary>
/// Enumerates pointer device types.
/// </summary>
public enum PointerType
{
Mouse,
Touch
Touch,
Pen
}
}

58
src/Avalonia.Base/Input/InputElement.cs

@ -128,16 +128,20 @@ namespace Avalonia.Input
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="PointerEnter"/> event.
/// Defines the <see cref="PointerEntered"/> event.
/// </summary>
public static readonly RoutedEvent<PointerEventArgs> PointerEnterEvent =
RoutedEvent.Register<InputElement, PointerEventArgs>(nameof(PointerEnter), RoutingStrategies.Direct);
public static readonly RoutedEvent<PointerEventArgs> PointerEnteredEvent =
RoutedEvent.Register<InputElement, PointerEventArgs>(
nameof(PointerEntered),
RoutingStrategies.Direct);
/// <summary>
/// Defines the <see cref="PointerLeave"/> event.
/// Defines the <see cref="PointerExited"/> event.
/// </summary>
public static readonly RoutedEvent<PointerEventArgs> PointerLeaveEvent =
RoutedEvent.Register<InputElement, PointerEventArgs>(nameof(PointerLeave), RoutingStrategies.Direct);
public static readonly RoutedEvent<PointerEventArgs> PointerExitedEvent =
RoutedEvent.Register<InputElement, PointerEventArgs>(
nameof(PointerExited),
RoutingStrategies.Direct);
/// <summary>
/// Defines the <see cref="PointerMoved"/> event.
@ -208,8 +212,8 @@ namespace Avalonia.Input
KeyDownEvent.AddClassHandler<InputElement>((x, e) => x.OnKeyDown(e));
KeyUpEvent.AddClassHandler<InputElement>((x, e) => x.OnKeyUp(e));
TextInputEvent.AddClassHandler<InputElement>((x, e) => x.OnTextInput(e));
PointerEnterEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerEnterCore(e));
PointerLeaveEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerLeaveCore(e));
PointerEnteredEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerEnteredCore(e));
PointerExitedEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerExitedCore(e));
PointerMovedEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerMoved(e));
PointerPressedEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerPressed(e));
PointerReleasedEvent.AddClassHandler<InputElement>((x, e) => x.OnPointerReleased(e));
@ -279,19 +283,19 @@ namespace Avalonia.Input
/// <summary>
/// Occurs when the pointer enters the control.
/// </summary>
public event EventHandler<PointerEventArgs>? PointerEnter
public event EventHandler<PointerEventArgs>? PointerEntered
{
add { AddHandler(PointerEnterEvent, value); }
remove { RemoveHandler(PointerEnterEvent, value); }
add { AddHandler(PointerEnteredEvent, value); }
remove { RemoveHandler(PointerEnteredEvent, value); }
}
/// <summary>
/// Occurs when the pointer leaves the control.
/// </summary>
public event EventHandler<PointerEventArgs>? PointerLeave
public event EventHandler<PointerEventArgs>? PointerExited
{
add { AddHandler(PointerLeaveEvent, value); }
remove { RemoveHandler(PointerLeaveEvent, value); }
add { AddHandler(PointerExitedEvent, value); }
remove { RemoveHandler(PointerExitedEvent, value); }
}
/// <summary>
@ -539,18 +543,18 @@ namespace Avalonia.Input
}
/// <summary>
/// Called before the <see cref="PointerEnter"/> event occurs.
/// Called before the <see cref="PointerEntered"/> event occurs.
/// </summary>
/// <param name="e">The event args.</param>
protected virtual void OnPointerEnter(PointerEventArgs e)
protected virtual void OnPointerEntered(PointerEventArgs e)
{
}
/// <summary>
/// Called before the <see cref="PointerLeave"/> event occurs.
/// Called before the <see cref="PointerExited"/> event occurs.
/// </summary>
/// <param name="e">The event args.</param>
protected virtual void OnPointerLeave(PointerEventArgs e)
protected virtual void OnPointerExited(PointerEventArgs e)
{
}
@ -561,7 +565,9 @@ namespace Avalonia.Input
protected virtual void OnPointerMoved(PointerEventArgs e)
{
if (_gestureRecognizers?.HandlePointerMoved(e) == true)
{
e.Handled = true;
}
}
/// <summary>
@ -571,7 +577,9 @@ namespace Avalonia.Input
protected virtual void OnPointerPressed(PointerPressedEventArgs e)
{
if (_gestureRecognizers?.HandlePointerPressed(e) == true)
{
e.Handled = true;
}
}
/// <summary>
@ -581,7 +589,9 @@ namespace Avalonia.Input
protected virtual void OnPointerReleased(PointerReleasedEventArgs e)
{
if (_gestureRecognizers?.HandlePointerReleased(e) == true)
{
e.Handled = true;
}
}
/// <summary>
@ -634,23 +644,23 @@ namespace Avalonia.Input
}
/// <summary>
/// Called before the <see cref="PointerEnter"/> event occurs.
/// Called before the <see cref="PointerEntered"/> event occurs.
/// </summary>
/// <param name="e">The event args.</param>
private void OnPointerEnterCore(PointerEventArgs e)
private void OnPointerEnteredCore(PointerEventArgs e)
{
IsPointerOver = true;
OnPointerEnter(e);
OnPointerEntered(e);
}
/// <summary>
/// Called before the <see cref="PointerLeave"/> event occurs.
/// Called before the <see cref="PointerExited"/> event occurs.
/// </summary>
/// <param name="e">The event args.</param>
private void OnPointerLeaveCore(PointerEventArgs e)
private void OnPointerExitedCore(PointerEventArgs e)
{
IsPointerOver = false;
OnPointerLeave(e);
OnPointerExited(e);
}
/// <summary>

174
src/Avalonia.Base/Input/PenDevice.cs

@ -0,0 +1,174 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Input.Raw;
using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Input
{
/// <summary>
/// Represents a pen/stylus device.
/// </summary>
public class PenDevice : IPenDevice, IDisposable
{
private readonly Dictionary<long, Pointer> _pointers = new();
private readonly Dictionary<long, PixelPoint> _lastPositions = new();
private int _clickCount;
private Rect _lastClickRect;
private ulong _lastClickTime;
private MouseButton _lastMouseDownButton;
private bool _disposed;
public void ProcessRawEvent(RawInputEventArgs e)
{
if (!e.Handled && e is RawPointerEventArgs margs)
ProcessRawEvent(margs);
}
private void ProcessRawEvent(RawPointerEventArgs e)
{
e = e ?? throw new ArgumentNullException(nameof(e));
if (!_pointers.TryGetValue(e.RawPointerId, out var pointer))
{
if (e.Type == RawPointerEventType.LeftButtonUp
|| e.Type == RawPointerEventType.TouchEnd)
return;
_pointers[e.RawPointerId] = pointer = new Pointer(Pointer.GetNextFreeId(),
PointerType.Pen, _pointers.Count == 0);
}
_lastPositions[e.RawPointerId] = e.Root.PointToScreen(e.Position);
var props = new PointerPointProperties(e.InputModifiers, e.Type.ToUpdateKind(),
e.Point.Twist, e.Point.Pressure, e.Point.XTilt, e.Point.YTilt);
var keyModifiers = e.InputModifiers.ToKeyModifiers();
bool shouldReleasePointer = false;
switch (e.Type)
{
case RawPointerEventType.LeaveWindow:
shouldReleasePointer = true;
break;
case RawPointerEventType.LeftButtonDown:
e.Handled = PenDown(pointer, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult);
break;
case RawPointerEventType.LeftButtonUp:
e.Handled = PenUp(pointer, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult);
break;
case RawPointerEventType.Move:
e.Handled = PenMove(pointer, e.Timestamp, e.Root, e.Position, props, keyModifiers, e.InputHitTestResult, e.IntermediatePoints);
break;
}
if (shouldReleasePointer)
{
pointer.Dispose();
_pointers.Remove(e.RawPointerId);
_lastPositions.Remove(e.RawPointerId);
}
}
private bool PenDown(Pointer pointer, ulong timestamp,
IInputElement root, Point p, PointerPointProperties properties,
KeyModifiers inputModifiers, IInputElement? hitTest)
{
var source = pointer.Captured ?? hitTest;
if (source != null)
{
pointer.Capture(source);
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>();
var doubleClickTime = settings?.DoubleClickTime.TotalMilliseconds ?? 500;
var doubleClickSize = settings?.DoubleClickSize ?? new Size(4, 4);
if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime)
{
_clickCount = 0;
}
++_clickCount;
_lastClickTime = timestamp;
_lastClickRect = new Rect(p, new Size())
.Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
_lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton();
var e = new PointerPressedEventArgs(source, pointer, root, p, timestamp, properties, inputModifiers, _clickCount);
source.RaiseEvent(e);
return e.Handled;
}
return false;
}
private bool PenMove(Pointer pointer, ulong timestamp,
IInputRoot root, Point p, PointerPointProperties properties,
KeyModifiers inputModifiers, IInputElement? hitTest,
Lazy<IReadOnlyList<RawPointerPoint>?>? intermediatePoints)
{
var source = pointer.Captured ?? hitTest;
if (source is not null)
{
var e = new PointerEventArgs(InputElement.PointerMovedEvent, source, pointer, root,
p, timestamp, properties, inputModifiers, intermediatePoints);
source.RaiseEvent(e);
return e.Handled;
}
return false;
}
private bool PenUp(Pointer pointer, ulong timestamp,
IInputElement root, Point p, PointerPointProperties properties,
KeyModifiers inputModifiers, IInputElement? hitTest)
{
var source = pointer.Captured ?? hitTest;
if (source is not null)
{
var e = new PointerReleasedEventArgs(source, pointer, root, p, timestamp, properties, inputModifiers,
_lastMouseDownButton);
source?.RaiseEvent(e);
pointer.Capture(null);
return e.Handled;
}
return false;
}
public void Dispose()
{
if (_disposed)
return;
var values = _pointers.Values.ToList();
_pointers.Clear();
_disposed = true;
foreach (var p in values)
p.Dispose();
}
[Obsolete]
IInputElement? IPointerDevice.Captured => _pointers.Values
.FirstOrDefault(p => p.IsPrimary)?.Captured;
[Obsolete]
void IPointerDevice.Capture(IInputElement? control) => _pointers.Values
.FirstOrDefault(p => p.IsPrimary)?.Capture(control);
[Obsolete]
Point IPointerDevice.GetPosition(IVisual relativeTo) => new Point(-1, -1);
public IPointer? TryGetPointer(RawPointerEventArgs ev)
{
return _pointers.TryGetValue(ev.RawPointerId, out var pointer)
? pointer
: null;
}
}
}

22
src/Avalonia.Base/Input/PointerEventArgs.cs

@ -67,7 +67,14 @@ namespace Avalonia.Input
public IPointer? TryGetPointer(RawPointerEventArgs ev) => _ev.Pointer;
}
/// <summary>
/// Gets specific pointer generated by input device.
/// </summary>
public IPointer Pointer { get; }
/// <summary>
/// Gets the time when the input occurred.
/// </summary>
public ulong Timestamp { get; }
private IPointerDevice? _device;
@ -91,7 +98,10 @@ namespace Avalonia.Input
return mods;
}
}
/// <summary>
/// Gets a value that indicates which key modifiers were active at the time that the pointer event was initiated.
/// </summary>
public KeyModifiers KeyModifiers { get; }
private Point GetPosition(Point pt, IVisual? relativeTo)
@ -102,7 +112,12 @@ namespace Avalonia.Input
return pt;
return pt * _rootVisual.TransformToVisual(relativeTo) ?? default;
}
/// <summary>
/// Gets the pointer position relative to a control.
/// </summary>
/// <param name="relativeTo">The control.</param>
/// <returns>The pointer position in the control's coordinates.</returns>
public Point GetPosition(IVisual? relativeTo) => GetPosition(_rootVisualPosition, relativeTo);
[Obsolete("Use GetCurrentPoint")]
@ -130,7 +145,8 @@ namespace Avalonia.Input
for (var c = 0; c < previousPoints.Count; c++)
{
var pt = previousPoints[c];
points[c] = new PointerPoint(Pointer, GetPosition(pt.Position, relativeTo), _properties);
var pointProperties = new PointerPointProperties(_properties, pt);
points[c] = new PointerPoint(Pointer, GetPosition(pt.Position, relativeTo), pointProperties);
}
points[points.Length - 1] = GetCurrentPoint(relativeTo);

6
src/Avalonia.Base/Input/PointerOverPreProcessor.cs

@ -97,7 +97,7 @@ namespace Avalonia.Input
// Do not pass rootVisual, when we have unknown (negative) position,
// so GetPosition won't return invalid values.
var hasPosition = position.X >= 0 && position.Y >= 0;
var e = new PointerEventArgs(InputElement.PointerLeaveEvent, element, pointer,
var e = new PointerEventArgs(InputElement.PointerExitedEvent, element, pointer,
hasPosition ? root : null, hasPosition ? position : default,
timestamp, properties, inputModifiers);
@ -177,7 +177,7 @@ namespace Avalonia.Input
el = root.PointerOverElement;
var e = new PointerEventArgs(InputElement.PointerLeaveEvent, el, pointer, root, position,
var e = new PointerEventArgs(InputElement.PointerExitedEvent, el, pointer, root, position,
timestamp, properties, inputModifiers);
if (el != null && branch != null && !el.IsAttachedToVisualTree)
{
@ -195,7 +195,7 @@ namespace Avalonia.Input
el = root.PointerOverElement = element;
_lastPointer = (pointer, root.PointToScreen(position));
e.RoutedEvent = InputElement.PointerEnterEvent;
e.RoutedEvent = InputElement.PointerEnteredEvent;
while (el != null && el != branch)
{

125
src/Avalonia.Base/Input/PointerPoint.cs

@ -1,5 +1,10 @@
using Avalonia.Input.Raw;
namespace Avalonia.Input
{
/// <summary>
/// Provides basic properties for the input pointer associated with a single mouse, pen/stylus, or touch contact.
/// </summary>
public sealed class PointerPoint
{
public PointerPoint(IPointer pointer, Point position, PointerPointProperties properties)
@ -8,25 +13,109 @@ namespace Avalonia.Input
Position = position;
Properties = properties;
}
/// <summary>
/// Gets specific pointer generated by input device.
/// </summary>
public IPointer Pointer { get; }
/// <summary>
/// Gets extended information about the input pointer.
/// </summary>
public PointerPointProperties Properties { get; }
/// <summary>
/// Gets the location of the pointer input in client coordinates.
/// </summary>
public Point Position { get; }
}
/// <summary>
/// Provides extended properties for a PointerPoint object.
/// </summary>
public sealed class PointerPointProperties
{
/// <summary>
/// Gets a value that indicates whether the pointer input was triggered by the primary action mode of an input device.
/// </summary>
public bool IsLeftButtonPressed { get; }
/// <summary>
/// Gets a value that indicates whether the pointer input was triggered by the tertiary action mode of an input device.
/// </summary>
public bool IsMiddleButtonPressed { get; }
/// <summary>
/// Gets a value that indicates whether the pointer input was triggered by the secondary action mode (if supported) of an input device.
/// </summary>
public bool IsRightButtonPressed { get; }
/// <summary>
/// Gets a value that indicates whether the pointer input was triggered by the first extended mouse button (XButton1).
/// </summary>
public bool IsXButton1Pressed { get; }
/// <summary>
/// Gets a value that indicates whether the pointer input was triggered by the second extended mouse button (XButton2).
/// </summary>
public bool IsXButton2Pressed { get; }
/// <summary>
/// Gets a value that indicates whether the barrel button of the pen/stylus device is pressed.
/// </summary>
public bool IsBarrelButtonPressed { get; }
/// <summary>
/// Gets a value that indicates whether the input is from a pen eraser.
/// </summary>
public bool IsEraser { get; }
/// <summary>
/// Gets a value that indicates whether the digitizer pen is inverted.
/// </summary>
public bool IsInverted { get; }
/// <summary>
/// Gets the clockwise rotation in degrees of a pen device around its own major axis (such as when the user spins the pen in their fingers).
/// </summary>
/// <returns>
/// A value between 0.0 and 359.0 in degrees of rotation. The default value is 0.0.
/// </returns>
public float Twist { get; }
/// <summary>
/// Gets a value that indicates the force that the pointer device (typically a pen/stylus) exerts on the surface of the digitizer.
/// </summary>
/// <returns>
/// A value from 0 to 1.0. The default value is 0.5.
/// </returns>
public float Pressure { get; } = 0.5f;
/// <summary>
/// Gets the plane angle between the Y-Z plane and the plane that contains the Y axis and the axis of the input device (typically a pen/stylus).
/// </summary>
/// <returns>
/// The value is 0.0 when the finger or pen is perpendicular to the digitizer surface, between 0.0 and 90.0 when tilted to the right of perpendicular, and between 0.0 and -90.0 when tilted to the left of perpendicular. The default value is 0.0.
/// </returns>
public float XTilt { get; }
/// <summary>
/// Gets the plane angle between the X-Z plane and the plane that contains the X axis and the axis of the input device (typically a pen/stylus).
/// </summary>
/// <returns>
/// The value is 0.0 when the finger or pen is perpendicular to the digitizer surface, between 0.0 and 90.0 when tilted towards the user, and between 0.0 and -90.0 when tilted away from the user. The default value is 0.0.
/// </returns>
public float YTilt { get; }
/// <summary>
/// Gets the kind of pointer state change.
/// </summary>
public PointerUpdateKind PointerUpdateKind { get; }
private PointerPointProperties()
{
{
}
public PointerPointProperties(RawInputModifiers modifiers, PointerUpdateKind kind)
{
PointerUpdateKind = kind;
@ -36,10 +125,13 @@ namespace Avalonia.Input
IsRightButtonPressed = modifiers.HasAllFlags(RawInputModifiers.RightMouseButton);
IsXButton1Pressed = modifiers.HasAllFlags(RawInputModifiers.XButton1MouseButton);
IsXButton2Pressed = modifiers.HasAllFlags(RawInputModifiers.XButton2MouseButton);
IsInverted = modifiers.HasAllFlags(RawInputModifiers.PenInverted);
IsEraser = modifiers.HasAllFlags(RawInputModifiers.PenEraser);
IsBarrelButtonPressed = modifiers.HasAllFlags(RawInputModifiers.PenBarrelButton);
// The underlying input source might be reporting the previous state,
// so make sure that we reflect the current state
if (kind == PointerUpdateKind.LeftButtonPressed)
IsLeftButtonPressed = true;
if (kind == PointerUpdateKind.LeftButtonReleased)
@ -62,6 +154,33 @@ namespace Avalonia.Input
IsXButton2Pressed = false;
}
public PointerPointProperties(RawInputModifiers modifiers, PointerUpdateKind kind,
float twist, float pressure, float xTilt, float yTilt
) : this (modifiers, kind)
{
Twist = twist;
Pressure = pressure;
XTilt = xTilt;
YTilt = yTilt;
}
internal PointerPointProperties(PointerPointProperties basedOn, RawPointerPoint rawPoint)
{
IsLeftButtonPressed = basedOn.IsLeftButtonPressed;
IsMiddleButtonPressed = basedOn.IsMiddleButtonPressed;
IsRightButtonPressed = basedOn.IsRightButtonPressed;
IsXButton1Pressed = basedOn.IsXButton1Pressed;
IsXButton2Pressed = basedOn.IsXButton2Pressed;
IsInverted = basedOn.IsInverted;
IsEraser = basedOn.IsEraser;
IsBarrelButtonPressed = basedOn.IsBarrelButtonPressed;
Twist = rawPoint.Twist;
Pressure = rawPoint.Pressure;
XTilt = rawPoint.XTilt;
YTilt = rawPoint.YTilt;
}
public static PointerPointProperties None { get; } = new PointerPointProperties();
}

19
src/Avalonia.Base/Input/Raw/RawPointerEventArgs.cs

@ -56,11 +56,12 @@ namespace Avalonia.Input.Raw
Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null);
Point = new RawPointerPoint();
Position = position;
Type = type;
InputModifiers = inputModifiers;
}
/// <summary>
/// Initializes a new instance of the <see cref="RawPointerEventArgs"/> class.
/// </summary>
@ -87,6 +88,11 @@ namespace Avalonia.Input.Raw
InputModifiers = inputModifiers;
}
/// <summary>
/// Gets the raw pointer identifier.
/// </summary>
public long RawPointerId { get; set; }
/// <summary>
/// Gets the pointer properties and position, in client DIPs.
/// </summary>
@ -130,10 +136,17 @@ namespace Avalonia.Input.Raw
/// Pointer position, in client DIPs.
/// </summary>
public Point Position { get; set; }
public float Twist { get; set; }
public float Pressure { get; set; }
public float XTilt { get; set; }
public float YTilt { get; set; }
public RawPointerPoint()
{
Position = default;
this = default;
Pressure = 0.5f;
}
}
}

17
src/Avalonia.Base/Input/Raw/RawTouchEventArgs.cs

@ -1,15 +1,26 @@
using System;
namespace Avalonia.Input.Raw
{
public class RawTouchEventArgs : RawPointerEventArgs
{
public RawTouchEventArgs(IInputDevice device, ulong timestamp, IInputRoot root,
RawPointerEventType type, Point position, RawInputModifiers inputModifiers,
long touchPointId)
long rawPointerId)
: base(device, timestamp, root, type, position, inputModifiers)
{
TouchPointId = touchPointId;
RawPointerId = rawPointerId;
}
public RawTouchEventArgs(IInputDevice device, ulong timestamp, IInputRoot root,
RawPointerEventType type, RawPointerPoint point, RawInputModifiers inputModifiers,
long rawPointerId)
: base(device, timestamp, root, type, point, inputModifiers)
{
RawPointerId = rawPointerId;
}
public long TouchPointId { get; set; }
[Obsolete("Use RawPointerId")]
public long TouchPointId { get => RawPointerId; set => RawPointerId = value; }
}
}

13
src/Avalonia.Base/Input/TouchDevice.cs

@ -40,14 +40,14 @@ namespace Avalonia.Input
{
if (ev.Handled || _disposed)
return;
var args = (RawTouchEventArgs)ev;
if (!_pointers.TryGetValue(args.TouchPointId, out var pointer))
var args = (RawPointerEventArgs)ev;
if (!_pointers.TryGetValue(args.RawPointerId, out var pointer))
{
if (args.Type == RawPointerEventType.TouchEnd)
return;
var hit = args.InputHitTestResult;
_pointers[args.TouchPointId] = pointer = new Pointer(Pointer.GetNextFreeId(),
_pointers[args.RawPointerId] = pointer = new Pointer(Pointer.GetNextFreeId(),
PointerType.Touch, _pointers.Count == 0);
pointer.Capture(hit);
}
@ -88,7 +88,7 @@ namespace Avalonia.Input
if (args.Type == RawPointerEventType.TouchEnd)
{
_pointers.Remove(args.TouchPointId);
_pointers.Remove(args.RawPointerId);
using (pointer)
{
target.RaiseEvent(new PointerReleasedEventArgs(target, pointer,
@ -101,7 +101,7 @@ namespace Avalonia.Input
if (args.Type == RawPointerEventType.TouchCancel)
{
_pointers.Remove(args.TouchPointId);
_pointers.Remove(args.RawPointerId);
using (pointer)
pointer.Capture(null);
_lastPointer = null;
@ -129,8 +129,7 @@ namespace Avalonia.Input
public IPointer? TryGetPointer(RawPointerEventArgs ev)
{
return ev is RawTouchEventArgs args
&& _pointers.TryGetValue(args.TouchPointId, out var pointer)
return _pointers.TryGetValue(ev.RawPointerId, out var pointer)
? pointer
: null;
}

71
src/Avalonia.Base/Layout/LayoutHelper.cs

@ -36,11 +36,28 @@ namespace Avalonia.Layout
public static Size MeasureChild(ILayoutable? control, Size availableSize, Thickness padding,
Thickness borderThickness)
{
return MeasureChild(control, availableSize, padding + borderThickness);
if (IsParentLayoutRounded(control, out double scale))
{
padding = RoundLayoutThickness(padding, scale, scale);
borderThickness = RoundLayoutThickness(borderThickness, scale, scale);
}
if (control != null)
{
control.Measure(availableSize.Deflate(padding + borderThickness));
return control.DesiredSize.Inflate(padding + borderThickness);
}
return new Size().Inflate(padding + borderThickness);
}
public static Size MeasureChild(ILayoutable? control, Size availableSize, Thickness padding)
{
if (IsParentLayoutRounded(control, out double scale))
{
padding = RoundLayoutThickness(padding, scale, scale);
}
if (control != null)
{
control.Measure(availableSize.Deflate(padding));
@ -137,7 +154,7 @@ namespace Avalonia.Layout
/// <summary>
/// Rounds a size to integer values for layout purposes, compensating for high DPI screen
/// coordinates.
/// coordinates by rounding the size up to the nearest pixel.
/// </summary>
/// <param name="size">Input size.</param>
/// <param name="dpiScaleX">DPI along x-dimension.</param>
@ -149,9 +166,9 @@ namespace Avalonia.Layout
/// associated with the UseLayoutRounding property and should not be used as a general rounding
/// utility.
/// </remarks>
public static Size RoundLayoutSize(Size size, double dpiScaleX, double dpiScaleY)
public static Size RoundLayoutSizeUp(Size size, double dpiScaleX, double dpiScaleY)
{
return new Size(RoundLayoutValue(size.Width, dpiScaleX), RoundLayoutValue(size.Height, dpiScaleY));
return new Size(RoundLayoutValueUp(size.Width, dpiScaleX), RoundLayoutValueUp(size.Height, dpiScaleY));
}
/// <summary>
@ -178,10 +195,9 @@ namespace Avalonia.Layout
);
}
/// <summary>
/// Calculates the value to be used for layout rounding at high DPI.
/// Calculates the value to be used for layout rounding at high DPI by rounding the value
/// up or down to the nearest pixel.
/// </summary>
/// <param name="value">Input value to be rounded.</param>
/// <param name="dpiScale">Ratio of screen's DPI to layout DPI</param>
@ -217,7 +233,46 @@ namespace Avalonia.Layout
return newValue;
}
/// <summary>
/// Calculates the value to be used for layout rounding at high DPI by rounding the value up
/// to the nearest pixel.
/// </summary>
/// <param name="value">Input value to be rounded.</param>
/// <param name="dpiScale">Ratio of screen's DPI to layout DPI</param>
/// <returns>Adjusted value that will produce layout rounding on screen at high dpi.</returns>
/// <remarks>
/// This is a layout helper method. It takes DPI into account and also does not return
/// the rounded value if it is unacceptable for layout, e.g. Infinity or NaN. It's a helper
/// associated with the UseLayoutRounding property and should not be used as a general rounding
/// utility.
/// </remarks>
public static double RoundLayoutValueUp(double value, double dpiScale)
{
double newValue;
// If DPI == 1, don't use DPI-aware rounding.
if (!MathUtilities.IsOne(dpiScale))
{
newValue = Math.Ceiling(value * dpiScale) / dpiScale;
// If rounding produces a value unacceptable to layout (NaN, Infinity or MaxValue),
// use the original value.
if (double.IsNaN(newValue) ||
double.IsInfinity(newValue) ||
MathUtilities.AreClose(newValue, double.MaxValue))
{
newValue = value;
}
}
else
{
newValue = Math.Ceiling(value);
}
return newValue;
}
/// <summary>
/// Calculates the min and max height for a control. Ported from WPF.
/// </summary>

24
src/Avalonia.Base/Layout/Layoutable.cs

@ -548,6 +548,14 @@ namespace Avalonia.Layout
if (IsVisible)
{
var margin = Margin;
var useLayoutRounding = UseLayoutRounding;
var scale = 1.0;
if (useLayoutRounding)
{
scale = LayoutHelper.GetLayoutScale(this);
margin = LayoutHelper.RoundLayoutThickness(margin, scale, scale);
}
ApplyStyling();
ApplyTemplate();
@ -584,16 +592,14 @@ namespace Avalonia.Layout
height = Math.Min(height, MaxHeight);
height = Math.Max(height, MinHeight);
width = Math.Min(width, availableSize.Width);
height = Math.Min(height, availableSize.Height);
if (UseLayoutRounding)
if (useLayoutRounding)
{
var scale = LayoutHelper.GetLayoutScale(this);
width = LayoutHelper.RoundLayoutValue(width, scale);
height = LayoutHelper.RoundLayoutValue(height, scale);
(width, height) = LayoutHelper.RoundLayoutSizeUp(new Size(width, height), scale, scale);
}
width = Math.Min(width, availableSize.Width);
height = Math.Min(height, availableSize.Height);
return NonNegative(new Size(width, height).Inflate(margin));
}
else
@ -678,8 +684,8 @@ namespace Avalonia.Layout
if (useLayoutRounding)
{
size = LayoutHelper.RoundLayoutSize(size, scale, scale);
availableSizeMinusMargins = LayoutHelper.RoundLayoutSize(availableSizeMinusMargins, scale, scale);
size = LayoutHelper.RoundLayoutSizeUp(size, scale, scale);
availableSizeMinusMargins = LayoutHelper.RoundLayoutSizeUp(availableSizeMinusMargins, scale, scale);
}
size = ArrangeOverride(size).Constrain(size);

8
src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs

@ -159,7 +159,6 @@ namespace Avalonia.Media.TextFormatting
{
var flowDirection = paragraphProperties.FlowDirection;
var drawableTextRuns = new List<DrawableTextRun>();
var biDiData = new BidiData((sbyte)flowDirection);
foreach (var textRun in textRuns)
@ -174,10 +173,9 @@ namespace Avalonia.Media.TextFormatting
{
biDiData.Append(textRun.Text);
}
}
var biDi = BidiAlgorithm.Instance.Value!;
var biDi = new BidiAlgorithm();
biDi.Process(biDiData);
@ -290,9 +288,7 @@ namespace Avalonia.Media.TextFormatting
/// <param name="textCharacters">The text characters to form <see cref="ShapeableTextCharacters"/> from.</param>
/// <param name="levels">The bidi levels.</param>
/// <returns></returns>
private static IEnumerable<IReadOnlyList<TextRun>> CoalesceLevels(
IReadOnlyList<TextRun> textCharacters,
ReadOnlySlice<sbyte> levels)
private static IEnumerable<IReadOnlyList<TextRun>> CoalesceLevels(IReadOnlyList<TextRun> textCharacters, ArraySlice<sbyte> levels)
{
if (levels.Length == 0)
{

498
src/Avalonia.Base/Media/TextFormatting/Unicode/BiDi.trie.cs

@ -1,42 +1,472 @@
using System;
namespace Avalonia.Media.TextFormatting.Unicode
{
internal static class BiDiTrie
internal static class BidiTrie
{
public static ReadOnlySpan<byte> Data => new byte[]
{
0,16,0,0,0,0,0,0,0,0,174,224,0,68,12,187,243,236,157,11,176,85,85,25,199,151,115,207,189,247,156,203,227,94,244,132,151,128,58,122,53,184,10,74,112,26,206,61,64,105,130,89,22,163,121,85,12,17,38,26,7,197,72,37,152,166,59,56,142,132,236,64,144,16,196,212,6,26,167,98,34,197,158,71,83,10,134,116,116,236,161,165,4,50,38,61,40,64,137,178,
28,109,6,164,255,102,175,205,93,44,246,99,61,247,62,192,254,102,126,243,173,189,246,218,235,251,214,183,190,253,60,251,156,51,171,129,144,91,193,87,192,157,224,1,176,14,172,7,143,3,7,172,144,208,63,3,191,0,207,130,223,130,109,224,79,224,85,240,23,176,15,188,5,246,131,183,3,182,63,4,26,115,225,253,247,193,186,51,192,96,208,1,206,7,99,64,23,184,24,92,
10,38,131,43,193,117,96,6,152,5,230,128,249,96,30,88,0,22,129,101,224,223,121,66,222,5,7,65,174,64,200,80,212,141,6,99,193,90,44,175,134,94,227,150,115,132,124,15,108,4,143,131,39,192,102,240,28,93,126,17,188,194,44,191,6,118,211,246,251,193,219,116,251,67,57,111,44,141,141,132,20,192,0,112,6,24,12,58,26,123,251,63,191,209,107,127,24,109,47,108,
244,236,249,246,29,212,141,109,244,180,203,4,148,39,49,203,159,68,249,74,186,124,53,244,245,180,252,5,232,91,192,92,112,144,246,227,128,30,44,47,4,75,193,125,76,63,142,65,30,162,253,62,194,245,191,193,176,189,31,115,253,61,133,229,167,192,211,24,239,211,116,204,91,176,252,124,163,231,203,75,92,251,237,88,126,148,137,141,3,118,161,110,15,215,110,31,150,107,200,143,
183,104,253,255,160,79,107,242,202,5,232,211,105,253,155,232,107,64,147,55,239,131,154,188,249,60,139,182,27,78,245,72,170,29,134,49,168,27,23,80,239,80,182,129,223,180,168,197,232,227,232,247,83,96,50,184,6,244,96,28,27,193,13,40,223,8,22,162,188,24,204,199,24,230,96,121,62,184,131,250,114,119,147,55,110,159,217,76,185,22,192,38,112,15,221,118,37,244,55,185,
237,107,224,48,234,182,210,242,90,102,204,223,13,104,91,19,96,67,200,118,47,48,229,223,131,29,133,248,88,241,125,252,153,234,61,224,128,164,95,239,128,67,92,157,19,149,203,77,92,46,55,29,159,3,110,31,141,200,131,45,180,175,124,75,111,223,173,76,185,198,113,38,214,13,5,91,209,231,11,76,191,127,104,234,221,39,55,198,196,229,231,104,187,137,46,239,68,249,175,180,
159,55,160,255,195,249,234,128,119,154,142,221,127,30,51,184,223,59,25,36,139,1,57,101,98,80,19,56,126,56,25,36,139,1,201,98,208,144,197,32,139,1,201,98,208,144,197,32,139,1,201,98,208,144,197,160,94,99,176,179,201,187,174,117,159,9,56,2,237,115,205,189,229,66,179,247,44,205,95,190,150,62,163,217,203,212,13,96,218,59,96,16,150,75,180,110,24,179,110,36,
182,185,144,46,143,133,254,40,45,175,198,115,156,75,104,249,49,250,156,232,114,44,95,213,236,61,183,115,151,175,109,246,158,211,77,231,108,29,224,158,33,221,200,173,119,50,72,22,3,146,197,160,33,139,65,22,3,146,197,160,33,139,65,22,3,146,197,160,225,196,141,193,205,184,198,107,193,53,104,255,130,247,185,178,10,231,182,28,95,247,29,212,141,4,31,1,75,209,247,189,
96,46,103,227,81,172,187,28,117,183,195,135,175,130,187,184,235,205,53,117,240,252,184,212,223,99,6,88,71,203,165,0,182,131,246,86,66,166,128,89,96,61,248,73,107,239,250,255,50,229,18,24,209,134,207,186,193,15,192,223,64,251,0,66,38,130,59,193,19,224,101,80,60,29,109,17,163,85,125,97,31,122,45,88,119,90,60,175,11,182,251,96,159,222,114,55,202,171,192,203,
224,69,216,43,130,182,126,98,253,216,162,27,62,172,203,236,147,180,98,208,157,197,159,100,249,71,82,139,65,119,150,127,36,237,252,187,2,231,128,25,253,78,221,249,143,187,62,88,210,124,236,231,221,43,155,123,223,79,89,207,189,167,229,112,92,197,93,223,60,88,135,207,219,54,98,12,223,134,95,235,221,103,134,205,222,251,97,63,106,238,93,239,62,111,124,146,46,255,146,174,
255,21,244,175,153,54,47,49,101,135,121,87,104,71,115,239,251,131,238,251,104,187,2,218,57,13,158,253,61,204,186,127,161,252,110,72,91,7,28,196,186,92,222,43,187,244,205,123,253,223,79,183,41,230,143,125,239,111,8,179,236,112,156,21,177,206,1,195,177,126,20,215,102,12,181,55,14,250,99,224,19,116,253,228,152,190,156,0,174,102,182,153,134,242,76,174,143,155,176,124,
27,173,155,39,209,255,135,35,222,107,236,65,63,11,21,124,117,100,200,123,122,57,213,78,138,108,166,121,177,138,241,229,225,58,240,203,225,120,30,251,218,79,21,223,169,116,20,120,4,49,216,0,126,200,196,162,70,143,115,19,66,252,168,209,245,155,19,190,119,219,72,245,34,58,151,223,247,215,53,123,250,73,140,97,170,1,159,182,129,45,121,79,63,7,253,59,240,74,130,115,
226,104,242,26,124,221,29,227,239,114,197,220,255,99,29,238,51,14,71,13,57,240,25,238,29,212,207,130,107,90,188,119,78,95,207,247,230,206,110,58,158,197,52,135,28,142,21,1,159,1,214,20,222,7,174,25,96,106,139,119,237,193,214,181,50,227,156,137,242,46,193,207,44,157,147,148,189,121,239,251,19,81,12,44,68,175,255,0,214,159,29,210,230,60,90,63,34,166,143,161,
17,140,118,191,71,81,16,107,91,166,237,198,115,237,251,23,188,239,144,248,223,23,25,26,192,69,220,186,75,4,109,14,213,160,127,193,27,223,104,166,110,52,37,23,98,127,116,4,147,90,226,109,250,251,250,108,170,167,67,207,101,142,127,53,212,213,40,61,45,225,239,232,187,251,210,93,96,9,88,1,86,211,62,106,76,155,26,248,22,237,99,43,152,89,72,63,223,55,193,159,
77,17,108,67,187,109,33,60,19,179,237,166,83,0,66,240,112,54,150,110,128,155,197,35,122,10,45,183,41,210,151,161,155,246,87,161,148,24,42,71,232,36,85,50,156,116,209,229,33,160,200,232,34,104,23,164,200,216,169,112,36,35,211,48,22,2,123,83,143,142,167,66,73,70,22,80,251,61,71,237,183,37,99,184,174,165,45,128,190,33,245,109,22,40,6,228,126,137,214,85,
24,92,241,203,238,118,126,217,109,235,226,231,57,223,214,197,173,231,235,216,126,109,137,237,254,235,221,126,82,34,50,151,65,115,47,130,169,237,101,125,209,177,201,82,62,197,9,139,125,156,196,205,93,84,155,147,81,84,198,42,51,47,39,155,4,29,59,220,243,212,196,58,216,39,202,10,76,228,116,57,164,60,241,36,39,31,66,133,146,163,243,92,162,229,34,213,21,74,89,130,
92,157,83,182,64,94,144,18,83,206,113,62,229,50,8,31,131,184,152,71,229,38,223,71,80,91,191,141,232,253,168,201,57,74,115,206,77,230,254,201,156,183,73,197,33,237,243,131,12,34,177,240,219,250,231,15,31,190,159,160,62,211,20,223,126,144,31,113,99,14,235,75,100,123,25,255,210,138,81,154,115,35,50,31,42,125,232,138,238,124,184,215,3,46,113,109,88,123,166,108,
235,74,84,222,7,249,25,180,63,216,244,69,182,255,176,253,82,116,255,54,33,58,115,26,151,71,108,255,170,199,31,83,194,231,135,175,77,238,207,42,99,59,145,142,173,182,124,229,207,217,62,110,126,185,90,196,151,180,207,227,190,196,229,83,216,190,46,146,59,170,249,101,35,54,97,115,22,54,95,113,146,246,117,134,170,109,209,57,139,186,206,83,149,176,115,94,92,78,197,29,
183,101,175,59,85,69,212,127,157,188,79,235,188,147,132,61,62,167,202,100,92,107,149,84,91,187,200,4,232,241,208,230,237,149,21,8,219,150,173,15,18,19,54,146,68,87,100,198,196,174,227,183,79,66,194,108,217,142,135,74,31,124,127,34,109,117,109,165,33,38,99,31,117,126,23,57,215,171,94,7,152,18,247,125,161,100,228,225,129,85,242,208,64,211,199,90,95,76,206,169,
136,29,222,166,236,62,24,180,191,233,30,59,253,235,21,182,157,104,126,242,207,224,221,119,98,76,73,26,199,219,168,99,174,104,63,42,54,248,253,89,231,90,223,164,36,225,71,208,121,214,166,45,214,102,212,185,159,247,69,117,31,147,221,71,109,156,219,147,190,214,10,242,39,204,47,118,189,106,223,182,198,19,53,71,65,99,50,45,188,141,168,117,54,99,200,183,211,149,160,249,
87,201,81,153,57,143,219,71,131,252,75,83,252,227,174,234,179,31,221,103,70,166,182,119,197,189,94,20,133,125,47,215,149,160,207,29,101,9,123,239,119,4,248,52,56,7,92,20,209,174,157,27,91,123,8,67,40,21,114,71,169,74,22,148,252,235,214,176,246,225,219,47,199,246,203,142,110,175,43,236,92,4,221,99,200,206,179,104,110,70,221,215,132,105,86,68,62,3,9,178,
39,226,135,136,191,81,219,203,32,227,187,168,255,114,156,215,81,37,157,29,252,119,30,76,248,109,90,244,199,26,157,115,21,1,218,13,115,34,141,93,180,63,81,223,121,17,189,94,145,181,159,148,184,126,179,223,151,58,222,167,194,168,42,201,143,234,34,125,160,91,160,251,65,247,133,110,133,238,15,61,0,186,13,154,208,109,223,135,229,34,150,207,132,30,8,61,8,186,29,122,
48,244,251,153,118,68,58,6,101,14,95,226,230,48,106,93,82,241,247,125,182,97,211,70,254,219,20,27,182,147,28,127,146,241,211,57,86,37,57,183,182,108,242,251,188,219,63,95,23,134,168,63,73,30,3,162,150,195,234,76,217,246,251,230,115,68,214,166,200,123,97,58,34,155,195,162,249,16,135,138,68,109,103,195,158,136,63,54,199,43,98,63,204,23,190,94,182,223,168,49,
152,176,225,111,103,162,141,138,77,217,88,233,140,209,244,56,121,159,117,250,178,33,236,59,221,201,157,23,39,28,246,190,31,63,238,112,58,223,207,159,70,237,79,165,246,103,96,121,58,45,207,68,249,243,199,248,149,164,164,121,223,163,123,141,88,175,215,216,73,29,227,69,236,154,56,231,156,8,247,53,186,231,184,176,24,165,113,238,246,237,218,236,219,212,184,162,226,110,82,162,
108,196,249,28,118,30,76,99,94,227,108,199,181,211,181,231,47,219,20,27,253,71,197,43,106,126,249,114,26,34,58,135,105,251,108,211,166,232,254,166,154,163,65,219,201,230,76,84,223,34,231,5,155,34,122,204,78,43,215,69,246,199,164,37,42,199,194,252,17,201,207,36,198,34,234,135,168,63,162,62,203,216,21,21,145,220,77,34,151,69,237,217,222,175,85,226,33,114,92,11,
138,91,82,49,228,219,132,249,97,226,120,172,42,113,190,218,144,184,123,35,255,25,174,143,238,189,150,201,251,45,219,251,130,72,174,155,234,91,71,252,152,166,113,14,243,69,118,44,113,191,77,104,234,88,99,67,146,176,35,179,159,152,122,95,67,245,184,47,115,110,240,197,84,63,65,253,138,74,146,57,162,98,203,100,158,185,199,110,153,92,176,121,220,78,251,51,104,94,252,99,
78,82,191,53,19,246,251,51,124,125,84,187,52,126,39,135,95,167,251,187,68,38,252,115,223,27,181,53,246,122,24,159,42,238,254,20,149,79,162,121,154,86,110,197,249,152,100,28,195,16,253,189,60,27,168,198,218,214,252,37,145,59,174,4,221,151,120,117,5,124,78,153,63,250,57,229,16,250,251,143,67,168,46,74,156,251,138,33,243,93,150,232,163,221,0,188,152,232,211,164,
63,178,162,107,199,196,189,167,159,27,58,247,178,238,246,46,252,181,11,155,151,65,215,51,186,231,147,56,191,252,255,71,24,14,46,3,227,193,40,112,5,205,233,82,0,21,9,74,41,83,214,164,162,73,145,209,174,176,117,30,159,123,175,74,174,123,175,139,92,15,61,21,250,6,232,105,208,36,52,230,37,138,223,95,24,174,136,252,166,127,208,182,252,61,181,123,254,208,141,165,
10,113,191,75,25,151,255,162,231,70,209,253,167,72,46,45,85,201,164,35,223,55,170,88,102,74,2,54,42,145,20,58,112,126,196,119,97,250,64,183,72,127,39,166,34,137,13,137,182,121,211,176,42,153,53,172,139,204,134,190,25,250,139,208,183,64,127,9,122,14,244,109,208,183,66,207,133,190,29,122,30,244,151,161,137,196,184,158,197,54,207,72,110,67,52,249,7,108,254,29,
54,247,66,239,129,126,3,122,31,244,126,232,55,161,15,64,255,211,176,79,95,235,172,146,133,157,93,228,110,232,69,208,14,244,98,232,37,208,95,135,190,7,122,41,244,10,232,123,161,151,67,47,131,94,9,253,13,232,85,208,247,65,223,15,189,26,250,1,232,53,157,102,125,140,99,7,108,110,135,205,157,208,175,38,108,155,128,67,176,123,208,170,93,95,108,143,69,206,70,199,
5,85,114,246,5,93,228,92,232,115,160,135,65,127,8,186,19,122,56,52,73,120,30,236,197,72,86,108,231,129,174,232,218,77,235,247,173,125,127,116,255,15,73,213,182,202,239,108,235,92,159,134,137,191,158,239,51,41,49,53,143,182,238,143,226,226,104,99,159,172,199,227,150,234,113,36,109,31,146,242,223,244,248,249,237,85,37,169,248,155,154,195,184,216,198,197,92,103,174,77,
140,67,39,31,85,164,30,198,171,147,7,186,199,255,52,206,223,166,8,242,39,105,177,241,31,145,50,232,94,255,164,109,95,20,87,100,234,101,250,213,17,21,159,85,125,20,181,21,214,214,190,252,31,0,0,255,255,0,0,0,255,255,99,102,0,0};
0, 0, 16, 0, 0, 0, 0, 0, 64, 180, 0, 0, 116, 3, 0, 0, 124, 3, 0, 0, 132, 3, 0, 0, 140, 3, 0, 0, 164, 3, 0, 0, 172, 3, 0, 0, 180, 3, 0, 0, 188, 3, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 194, 3, 0, 0, 202, 3, 0, 0,
210, 3, 0, 0, 218, 3, 0, 0, 226, 3, 0, 0, 234, 3, 0, 0, 230, 3, 0, 0, 238, 3, 0, 0, 246, 3, 0, 0, 254, 3, 0, 0, 249, 3, 0, 0, 1, 4, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 9, 4, 0, 0, 17, 4, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 148, 3, 0, 0, 156, 3, 0, 0, 23, 4, 0, 0, 31, 4, 0, 0, 39, 4, 0, 0,
47, 4, 0, 0, 55, 4, 0, 0, 63, 4, 0, 0, 69, 4, 0, 0, 77, 4, 0, 0, 82, 4, 0, 0, 90, 4, 0, 0, 93, 4, 0, 0, 101, 4, 0, 0, 108, 4, 0, 0, 116, 4, 0, 0, 122, 4, 0, 0, 130, 4, 0, 0, 129, 4, 0, 0, 137, 4, 0, 0, 145, 4, 0, 0, 153, 4, 0, 0, 24, 9, 0, 0, 31, 9, 0, 0, 35, 9, 0, 0, 62, 4, 0, 0, 199, 9, 0, 0, 62, 4, 0, 0, 22, 11, 0, 0, 207, 9, 0, 0,
161, 4, 0, 0, 163, 4, 0, 0, 171, 4, 0, 0, 179, 4, 0, 0, 187, 4, 0, 0, 188, 4, 0, 0, 196, 4, 0, 0, 204, 4, 0, 0, 212, 4, 0, 0, 188, 4, 0, 0, 220, 4, 0, 0, 225, 4, 0, 0, 212, 4, 0, 0, 188, 4, 0, 0, 233, 4, 0, 0, 241, 4, 0, 0, 187, 4, 0, 0, 249, 4, 0, 0, 1, 5, 0, 0, 179, 4, 0, 0, 9, 5, 0, 0, 148, 3, 0, 0, 17, 5, 0, 0, 21, 5, 0, 0, 29, 5, 0, 0,
31, 5, 0, 0, 39, 5, 0, 0, 47, 5, 0, 0, 187, 4, 0, 0, 188, 4, 0, 0, 55, 5, 0, 0, 179, 4, 0, 0, 11, 4, 0, 0, 59, 5, 0, 0, 196, 4, 0, 0, 179, 4, 0, 0, 187, 4, 0, 0, 148, 3, 0, 0, 67, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 73, 5, 0, 0, 81, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 85, 5, 0, 0, 93, 5, 0, 0, 148, 3, 0, 0, 97, 5, 0, 0, 104, 5, 0, 0,
148, 3, 0, 0, 112, 5, 0, 0, 120, 5, 0, 0, 127, 5, 0, 0, 8, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 135, 5, 0, 0, 143, 5, 0, 0, 151, 5, 0, 0, 159, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 167, 5, 0, 0, 148, 3, 0, 0, 175, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 183, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 191, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 199, 5, 0, 0, 200, 4, 0, 0, 200, 4, 0, 0, 200, 4, 0, 0, 148, 3, 0, 0, 205, 5, 0, 0, 213, 5, 0, 0, 175, 5, 0, 0, 221, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 228, 5, 0, 0,
185, 4, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 236, 5, 0, 0, 244, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 246, 5, 0, 0, 231, 9, 0, 0, 254, 5, 0, 0, 148, 3, 0, 0, 5, 6, 0, 0, 13, 6, 0, 0, 148, 3, 0, 0, 21, 6, 0, 0, 27, 11, 0, 0, 148, 3, 0, 0, 248, 4, 0, 0, 29, 6, 0, 0, 9, 5, 0, 0, 37, 6, 0, 0, 11, 4, 0, 0, 45, 6, 0, 0,
148, 3, 0, 0, 52, 6, 0, 0, 148, 3, 0, 0, 57, 6, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 63, 6, 0, 0, 71, 6, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 226, 3, 0, 0, 226, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 78, 6, 0, 0, 86, 6, 0, 0, 90, 6, 0, 0, 98, 6, 0, 0, 163, 9, 0, 0, 223, 9, 0, 0, 106, 6, 0, 0, 114, 6, 0, 0, 171, 9, 0, 0, 175, 9, 0, 0, 130, 5, 0, 0, 122, 6, 0, 0, 130, 6, 0, 0, 138, 6, 0, 0, 148, 3, 0, 0, 146, 6, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0,
147, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 237, 9, 0, 0, 152, 6, 0, 0, 148, 3, 0, 0, 158, 6, 0, 0, 165, 6, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 11, 7, 0, 0, 243, 9, 0, 0, 231, 9, 0, 0, 171, 6, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 178, 6, 0, 0, 231, 9, 0, 0,
231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 183, 6, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 251, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 2, 10, 0, 0, 9, 10, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 17, 10, 0, 0, 231, 9, 0, 0, 24, 10, 0, 0, 31, 10, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0,
39, 10, 0, 0, 45, 10, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 191, 6, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 199, 6, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 226, 3, 0, 0, 231, 9, 0, 0, 53, 10, 0, 0, 56, 10, 0, 0, 148, 3, 0, 0,
64, 10, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 71, 10, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 79, 10, 0, 0, 85, 10, 0, 0, 207, 6, 0, 0, 215, 6, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 223, 6, 0, 0, 183, 5, 0, 0, 148, 3, 0, 0, 187, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 231, 9, 0, 0, 198, 6, 0, 0, 201, 3, 0, 0, 148, 3, 0, 0, 231, 6, 0, 0, 239, 6, 0, 0, 148, 3, 0, 0, 247, 6, 0, 0, 255, 6, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 3, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 246, 5, 0, 0, 186, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
231, 9, 0, 0, 231, 9, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 231, 6, 0, 0, 231, 9, 0, 0, 11, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 16, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 21, 7, 0, 0, 29, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 99, 5, 0, 0, 231, 9, 0, 0, 245, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 37, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 45, 7, 0, 0, 52, 7, 0, 0, 148, 3, 0, 0,
59, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 57, 5, 0, 0, 67, 7, 0, 0, 148, 3, 0, 0, 75, 7, 0, 0, 82, 7, 0, 0, 148, 3, 0, 0, 161, 4, 0, 0, 87, 7, 0, 0, 148, 3, 0, 0, 186, 4, 0, 0, 148, 3, 0, 0, 95, 7, 0, 0, 103, 7, 0, 0, 188, 4, 0, 0, 148, 3, 0, 0, 107, 7, 0, 0, 187, 4, 0, 0, 115, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 251, 5, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 122, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 126, 7, 0, 0, 42, 9, 0, 0, 46, 9, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0,
62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 93, 10, 0, 0, 101, 10, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 106, 10, 0, 0, 110, 10, 0, 0, 118, 10, 0, 0, 179, 9, 0, 0, 183, 9, 0, 0, 155, 9, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 246, 10, 0, 0, 115, 9, 0, 0, 134, 7, 0, 0, 142, 7, 0, 0, 150, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
191, 9, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 80, 14, 0, 0, 80, 14, 0, 0, 144, 14, 0, 0, 208, 14, 0, 0, 80, 14, 0, 0, 80, 14, 0, 0, 80, 14, 0, 0, 80, 14, 0, 0, 80, 14, 0, 0, 80, 14, 0, 0, 8, 15, 0, 0, 72, 15, 0, 0, 136, 15, 0, 0, 152, 15, 0, 0, 216, 15, 0, 0, 228, 15, 0, 0, 80, 14, 0, 0,
80, 14, 0, 0, 36, 16, 0, 0, 80, 14, 0, 0, 80, 14, 0, 0, 80, 14, 0, 0, 92, 16, 0, 0, 156, 16, 0, 0, 220, 16, 0, 0, 20, 17, 0, 0, 72, 17, 0, 0, 116, 17, 0, 0, 176, 17, 0, 0, 232, 17, 0, 0, 4, 18, 0, 0, 68, 18, 0, 0, 32, 10, 0, 0, 192, 12, 0, 0, 96, 10, 0, 0, 159, 10, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 223, 10, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 31, 11, 0, 0, 160, 1, 0, 0, 69, 11, 0, 0, 128, 11, 0, 0, 192, 11, 0, 0, 0, 12, 0, 0, 253, 12, 0, 0, 64, 12, 0, 0, 61, 13, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 125, 13, 0, 0, 141, 13, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0,
160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 160, 1, 0, 0, 128, 12, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 158, 7, 0, 0, 148, 3, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 166, 7, 0, 0, 183, 5, 0, 0, 148, 3, 0, 0, 180, 4, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 123, 9, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 174, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 187, 4, 0, 0, 181, 7, 0, 0, 188, 7, 0, 0, 195, 7, 0, 0, 11, 4, 0, 0, 203, 7, 0, 0, 9, 5, 0, 0, 148, 3, 0, 0, 161, 4, 0, 0, 210, 7, 0, 0, 148, 3, 0, 0, 216, 7, 0, 0, 11, 4, 0, 0, 221, 7, 0, 0, 229, 7, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 234, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 199, 6, 0, 0, 242, 7, 0, 0, 11, 4, 0, 0, 59, 5, 0, 0, 30, 5, 0, 0, 249, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 181, 7, 0, 0, 1, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 9, 8, 0, 0, 17, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 21, 8, 0, 0, 29, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 37, 8, 0, 0, 30, 5, 0, 0, 170, 7, 0, 0, 148, 3, 0, 0, 45, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 167, 5, 0, 0, 53, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 58, 8, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 65, 8, 0, 0, 73, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 76, 8, 0, 0, 30, 5, 0, 0, 84, 8, 0, 0, 88, 8, 0, 0, 96, 8, 0, 0, 148, 3, 0, 0, 103, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 110, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 118, 8, 0, 0, 124, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 130, 8, 0, 0, 138, 8, 0, 0, 148, 3, 0, 0, 142, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 61, 5, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 8, 0, 0, 156, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 161, 8, 0, 0, 148, 3, 0, 0, 167, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 217, 7, 0, 0, 148, 3, 0, 0, 173, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 181, 8, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 213, 4, 0, 0, 254, 10, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 226, 3, 0, 0, 35, 11, 0, 0, 189, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 196, 8, 0, 0, 204, 8, 0, 0, 210, 8, 0, 0, 148, 3, 0, 0, 216, 8, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 126, 10, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 240, 9, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 187, 3, 0, 0, 148, 3, 0, 0, 153, 7, 0, 0, 148, 3, 0, 0, 182, 3, 0, 0, 148, 3, 0, 0, 156, 7, 0, 0, 148, 3, 0, 0, 224, 8, 0, 0, 131, 9, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 226, 3, 0, 0, 232, 8, 0, 0, 226, 3, 0, 0, 239, 8, 0, 0, 246, 8, 0, 0, 43, 11, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
51, 11, 0, 0, 59, 11, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 167, 8, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 5, 8, 0, 0, 148, 3, 0, 0, 254, 8, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 231, 9, 0, 0, 142, 10, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 71, 10, 0, 0, 147, 10, 0, 0, 151, 10, 0, 0, 79, 10, 0, 0, 6, 9, 0, 0, 182, 3, 0, 0, 148, 3, 0, 0,
12, 9, 0, 0, 148, 3, 0, 0, 155, 7, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 156, 6, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0,
231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 156, 10, 0, 0, 166, 7, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 71, 10, 0, 0, 231, 9, 0, 0,
231, 9, 0, 0, 164, 10, 0, 0, 172, 10, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 16, 9, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0,
54, 9, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 62, 9, 0, 0, 66, 9, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 74, 9, 0, 0, 41, 4, 0, 0, 76, 9, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0,
41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 62, 4, 0, 0, 215, 9, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 84, 9, 0, 0, 41, 4, 0, 0, 92, 9, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 46, 9, 0, 0,
137, 4, 0, 0, 50, 9, 0, 0, 100, 9, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 104, 9, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 107, 9, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0,
41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 46, 9, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 50, 9, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0,
41, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 62, 4, 0, 0, 134, 10, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 41, 4, 0, 0, 142, 10, 0, 0, 231, 9, 0, 0, 180, 10, 0, 0, 231, 9, 0, 0, 188, 10, 0, 0, 193, 10, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 71, 10, 0, 0, 201, 10, 0, 0, 209, 10, 0, 0, 214, 10, 0, 0, 222, 10, 0, 0, 230, 10, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 231, 9, 0, 0, 238, 10, 0, 0, 231, 9, 0, 0, 243, 9, 0, 0, 139, 9, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0,
148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 148, 3, 0, 0, 16, 9, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 226, 3, 0, 0, 226, 3, 0, 0, 226, 3, 0, 0, 226, 3, 0, 0, 226, 3, 0, 0, 226, 3, 0, 0, 226, 3, 0, 0, 14, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0,
6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0,
6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0,
6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 6, 11, 0, 0, 115, 3, 1, 0, 115, 3, 1, 0, 115, 3, 1, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 84, 0, 0, 0, 12, 0,
0, 0, 84, 0, 0, 0, 88, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 12, 0, 0, 0, 12, 0, 0, 0, 12, 0, 0, 0, 84, 0, 0, 0, 88, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 32, 0,
0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 56, 0, 0, 0, 56, 0, 41, 0, 58, 0, 40, 0, 57, 0, 0, 0, 56, 0, 0, 0, 28, 0, 0, 0, 20, 0, 0, 0, 28, 0, 0, 0, 20, 0, 0, 0, 20, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 20, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, 58, 0, 0, 0, 56, 0, 91, 0, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125, 0, 58, 0, 0, 0, 56, 0, 123, 0, 57, 0, 0, 0, 56, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0,
0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 20, 0, 0, 0, 56, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 16, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 32, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 4, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 4, 0, 0, 0, 20, 0, 0, 0, 4, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 32, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 52, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 8, 0, 0, 0, 56, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0,
0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 52, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 32, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 59, 15, 58, 0, 58, 15, 57, 0, 61, 15, 58, 0, 60, 15, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 156, 22, 58, 0, 155, 22, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 16, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0,
0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 88, 0, 0, 0, 88, 0, 0, 0, 88, 0, 0, 0, 88, 0, 0, 0, 88, 0, 0, 0, 88, 0, 0, 0, 88, 0, 0, 0, 88, 0, 0, 0, 88, 0, 0, 0, 88, 0,
0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0,
0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 44, 0, 0, 0, 76, 0, 0, 0, 36, 0, 0, 0, 64, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 28, 0, 0, 0, 28, 0, 0, 0, 56, 0,
126, 32, 58, 0, 125, 32, 57, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 28, 0, 0, 0, 28, 0, 0, 0, 56, 0, 142, 32, 58, 0, 141, 32, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0,
0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 42, 35, 58, 0, 41, 35, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0,
0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0,
0, 0, 88, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 48, 58, 0, 8, 48, 57, 0, 11, 48, 58, 0, 10, 48, 57, 0, 13, 48, 58, 0, 12, 48, 57, 0, 15, 48, 58, 0, 14, 48, 57, 0, 17, 48, 58, 0, 16, 48, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 21, 48, 58, 0, 20, 48, 57, 0, 23, 48, 58, 0, 22, 48, 57, 0, 25, 48, 58, 0,
24, 48, 57, 0, 27, 48, 58, 0, 26, 48, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 56, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 255, 58, 0, 0, 0, 56, 0, 59, 255, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 255, 58, 0, 0, 0, 56, 0, 91, 255, 57, 0, 0, 0, 56, 0, 96, 255, 58, 0, 95, 255, 57, 0, 0, 0, 56, 0, 99, 255, 58, 0, 98, 255, 57, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0,
0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0,
0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 28, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 56, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0,
0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0,
0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 56, 0, 0, 0, 56, 0, 9, 255, 58, 0, 8, 255, 57, 0, 0, 0, 56, 0, 0, 0, 28, 0, 0, 0, 20, 0, 0, 0, 28, 0, 0, 0, 20, 0, 0, 0, 20, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0,
0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 20, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 52, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0,
0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0,
0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 24, 0,
0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 28, 0, 0, 0, 32, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 28, 0, 0, 0, 28, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 32, 0, 0, 0, 32, 0,
0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 88, 0, 0, 0, 12, 0, 0, 0, 40, 0, 0, 0, 72, 0, 0, 0, 60, 0, 0, 0, 48, 0, 0, 0, 80, 0, 0, 0, 20, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0,
0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 20, 0, 0, 0, 56, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 20, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 90, 254, 58, 0, 89, 254, 57, 0, 92, 254, 58, 0, 91, 254, 57, 0, 94, 254, 58, 0, 93, 254, 57, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 16, 0,
0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 8, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0,
0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 20, 0, 70, 32, 58, 0, 69, 32, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 88, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
9, 35, 58, 0, 8, 35, 57, 0, 11, 35, 58, 0, 10, 35, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 105, 39, 58, 0, 104, 39, 57, 0, 107, 39, 58, 0, 106, 39, 57, 0, 109, 39, 58, 0, 108, 39, 57, 0, 111, 39, 58, 0, 110, 39, 57, 0, 113, 39, 58, 0, 112, 39, 57, 0, 115, 39, 58, 0, 114, 39, 57, 0, 117, 39, 58, 0, 116, 39, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 198, 39, 58, 0, 197, 39, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 231, 39, 58, 0, 230, 39, 57, 0, 233, 39, 58, 0, 232, 39, 57, 0, 235, 39, 58, 0, 234, 39, 57, 0, 237, 39, 58, 0, 236, 39, 57, 0, 239, 39, 58, 0, 238, 39, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 132, 41, 58, 0, 131, 41, 57, 0, 134, 41, 58, 0, 133, 41, 57, 0, 136, 41, 58, 0, 135, 41, 57, 0, 138, 41, 58, 0, 137, 41, 57, 0, 140, 41, 58, 0, 139, 41, 57, 0, 144, 41, 58, 0,
143, 41, 57, 0, 142, 41, 58, 0, 141, 41, 57, 0, 146, 41, 58, 0, 145, 41, 57, 0, 148, 41, 58, 0, 147, 41, 57, 0, 150, 41, 58, 0, 149, 41, 57, 0, 152, 41, 58, 0, 151, 41, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 217, 41, 58, 0, 216, 41, 57, 0, 219, 41, 58, 0, 218, 41, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 253, 41, 58, 0, 252, 41, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 35, 46, 58, 0, 34, 46, 57, 0, 37, 46, 58, 0, 36, 46, 57, 0, 39, 46, 58, 0, 38, 46, 57, 0, 41, 46, 58, 0, 40, 46, 57, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 86, 46, 58, 0, 85, 46, 57, 0, 88, 46, 58, 0, 87, 46, 57, 0, 90, 46, 58, 0, 89, 46, 57, 0, 92, 46, 58, 0, 91, 46, 57, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 56, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 56, 0,
0, 0, 56, 0, 0, 0, 56, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0,
0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0,
0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0,
0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0,
0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
}
}

28
src/Avalonia.Base/Media/TextFormatting/Unicode/BiDiAlgorithm.cs

@ -66,7 +66,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// The forward mapping maps the start index to the end index.
/// The reverse mapping maps the end index to the start index.
/// </remarks>
private readonly Dictionary<int, int> _isolatePairs = new Dictionary<int, int>();
private readonly BidiDictionary<int, int> _isolatePairs = new BidiDictionary<int, int>();
/// <summary>
/// The working BiDi classes
@ -188,12 +188,6 @@ namespace Avalonia.Media.TextFormatting.Unicode
{
}
/// <summary>
/// Gets a per-thread instance that can be re-used as often
/// as necessary.
/// </summary>
public static ThreadLocal<BidiAlgorithm> Instance { get; } = new ThreadLocal<BidiAlgorithm>(() => new BidiAlgorithm());
/// <summary>
/// Gets the resolved levels.
/// </summary>
@ -1414,35 +1408,37 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// Sets the direction of a bracket pair, including setting the direction of
/// NSM's inside the brackets and following.
/// </summary>
/// <param name="bracketPair">The paired brackets</param>
/// <param name="pairedBracket">The paired brackets</param>
/// <param name="direction">The resolved direction for the bracket pair</param>
private void SetPairedBracketDirection(in BracketPair bracketPair, BidiClass direction)
private void SetPairedBracketDirection(in BracketPair pairedBracket, BidiClass direction)
{
// Set the direction of the brackets
_runResolvedClasses[bracketPair.OpeningIndex] = direction;
_runResolvedClasses[bracketPair.ClosingIndex] = direction;
_runResolvedClasses[pairedBracket.OpeningIndex] = direction;
_runResolvedClasses[pairedBracket.ClosingIndex] = direction;
// Set the directionality of NSM's inside the brackets
for (var i = bracketPair.OpeningIndex + 1; i < bracketPair.ClosingIndex; i++)
// BN characters (such as ZWJ or ZWSP) that appear between the base bracket character
// and the nonspacing mark should be ignored.
for (int i = pairedBracket.OpeningIndex + 1; i < pairedBracket.ClosingIndex; i++)
{
if (_runOriginalClasses[i] == BidiClass.NonspacingMark)
{
_runOriginalClasses[i] = direction;
}
else
else if (_runOriginalClasses[i] != BidiClass.BoundaryNeutral)
{
break;
}
}
// Set the directionality of NSM's following the brackets
for (var i = bracketPair.ClosingIndex + 1; i < _runLength; i++)
for (int i = pairedBracket.ClosingIndex + 1; i < _runLength; i++)
{
if (_runOriginalClasses[i] == BidiClass.NonspacingMark)
{
_runResolvedClasses[i] = direction;
_runOriginalClasses[i] = direction;
}
else
else if (_runOriginalClasses[i] != BidiClass.BoundaryNeutral)
{
break;
}

25
src/Avalonia.Base/Media/TextFormatting/Unicode/BiDiData.cs

@ -18,17 +18,12 @@ namespace Avalonia.Media.TextFormatting.Unicode
private ArrayBuilder<BidiClass> _savedClasses;
private ArrayBuilder<BidiPairedBracketType> _savedPairedBracketTypes;
private ArrayBuilder<sbyte> _tempLevelBuffer;
public BidiData(sbyte paragraphEmbeddingLevel = 0)
public BidiData(sbyte paragraphEmbeddingLevel)
{
ParagraphEmbeddingLevel = paragraphEmbeddingLevel;
}
public BidiData(ReadOnlySlice<char> text, sbyte paragraphEmbeddingLevel = 0) : this(paragraphEmbeddingLevel)
{
Append(text);
}
public sbyte ParagraphEmbeddingLevel { get; private set; }
public bool HasBrackets { get; private set; }
@ -64,13 +59,23 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// </remarks>
public ArraySlice<int> PairedBracketValues { get; private set; }
/// <summary>
/// Appends text to the bidi data.
/// </summary>
/// <param name="text">The text to process.</param>
public void Append(ReadOnlySlice<char> text)
{
_classes.Add(text.Length);
_pairedBracketTypes.Add(text.Length);
_pairedBracketValues.Add(text.Length);
var i = Length;
// Resolve the BidiCharacterType, paired bracket type and paired
// bracket values for all code points
HasBrackets = false;
HasEmbeddings = false;
HasIsolates = false;
int i = Length;
var codePointEnumerator = new CodepointEnumerator(text);
@ -115,13 +120,13 @@ namespace Avalonia.Media.TextFormatting.Unicode
// Opening bracket types can never have a null pairing.
codepoint.TryGetPairedBracket(out var paired);
_pairedBracketValues[i] = Codepoint.GetCanonicalType(paired).Value;
_pairedBracketValues[i] = (int)Codepoint.GetCanonicalType(paired).Value;
HasBrackets = true;
}
else if (pbt == BidiPairedBracketType.Close)
{
_pairedBracketValues[i] = Codepoint.GetCanonicalType(codepoint).Value;
_pairedBracketValues[i] = (int)Codepoint.GetCanonicalType(codepoint).Value;
HasBrackets = true;
}

44
src/Avalonia.Base/Media/TextFormatting/Unicode/Codepoint.cs

@ -5,50 +5,52 @@ namespace Avalonia.Media.TextFormatting.Unicode
{
public readonly struct Codepoint
{
private readonly uint _value;
/// <summary>
/// The replacement codepoint that is used for non supported values.
/// </summary>
public static readonly Codepoint ReplacementCodepoint = new Codepoint('\uFFFD');
public Codepoint(int value)
public Codepoint(uint value)
{
Value = value;
_value = value;
}
/// <summary>
/// Get the codepoint's value.
/// </summary>
public int Value { get; }
public uint Value => _value;
/// <summary>
/// Gets the <see cref="Unicode.GeneralCategory"/>.
/// </summary>
public GeneralCategory GeneralCategory => UnicodeData.GetGeneralCategory(Value);
public GeneralCategory GeneralCategory => UnicodeData.GetGeneralCategory(_value);
/// <summary>
/// Gets the <see cref="Unicode.Script"/>.
/// </summary>
public Script Script => UnicodeData.GetScript(Value);
public Script Script => UnicodeData.GetScript(_value);
/// <summary>
/// Gets the <see cref="Unicode.BidiClass"/>.
/// </summary>
public BidiClass BiDiClass => UnicodeData.GetBiDiClass(Value);
public BidiClass BiDiClass => UnicodeData.GetBiDiClass(_value);
/// <summary>
/// Gets the <see cref="Unicode.BidiPairedBracketType"/>.
/// </summary>
public BidiPairedBracketType PairedBracketType => UnicodeData.GetBiDiPairedBracketType(Value);
public BidiPairedBracketType PairedBracketType => UnicodeData.GetBiDiPairedBracketType(_value);
/// <summary>
/// Gets the <see cref="Unicode.LineBreakClass"/>.
/// </summary>
public LineBreakClass LineBreakClass => UnicodeData.GetLineBreakClass(Value);
public LineBreakClass LineBreakClass => UnicodeData.GetLineBreakClass(_value);
/// <summary>
/// Gets the <see cref="GraphemeBreakClass"/>.
/// </summary>
public GraphemeBreakClass GraphemeBreakClass => UnicodeData.GetGraphemeClusterBreak(Value);
public GraphemeBreakClass GraphemeBreakClass => UnicodeData.GetGraphemeClusterBreak(_value);
/// <summary>
/// Determines whether this <see cref="Codepoint"/> is a break char.
@ -60,7 +62,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
{
get
{
switch (Value)
switch (_value)
{
case '\u000A':
case '\u000B':
@ -109,12 +111,12 @@ namespace Avalonia.Media.TextFormatting.Unicode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Codepoint GetCanonicalType(Codepoint codePoint)
{
if (codePoint.Value == 0x3008)
if (codePoint._value == 0x3008)
{
return new Codepoint(0x2329);
}
if (codePoint.Value == 0x3009)
if (codePoint._value == 0x3009)
{
return new Codepoint(0x232A);
}
@ -141,19 +143,19 @@ namespace Avalonia.Media.TextFormatting.Unicode
return false;
}
codepoint = UnicodeData.GetBiDiPairedBracket(Value);
codepoint = UnicodeData.GetBiDiPairedBracket(_value);
return true;
}
public static implicit operator int(Codepoint codepoint)
{
return codepoint.Value;
return (int)codepoint._value;
}
public static implicit operator uint(Codepoint codepoint)
{
return (uint)codepoint.Value;
return codepoint._value;
}
/// <summary>
@ -191,7 +193,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
if (0xDC00 <= low && low <= 0xDFFF)
{
count = 2;
return new Codepoint((hi - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000);
return new Codepoint((uint)((hi - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000));
}
return ReplacementCodepoint;
@ -212,7 +214,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
if (0xD800 <= hi && hi <= 0xDBFF)
{
count = 2;
return new Codepoint((hi - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000);
return new Codepoint((uint)((hi - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000));
}
return ReplacementCodepoint;
@ -220,5 +222,13 @@ namespace Avalonia.Media.TextFormatting.Unicode
return new Codepoint(code);
}
/// <summary>
/// Returns <see langword="true"/> if <paramref name="value"/> is between
/// <paramref name="lowerBound"/> and <paramref name="upperBound"/>, inclusive.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsInRangeInclusive(Codepoint cp, uint lowerBound, uint upperBound)
=> (cp._value - lowerBound) <= (upperBound - lowerBound);
}
}

7
src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeBreak.cs

@ -0,0 +1,7 @@
namespace Avalonia.Media.TextFormatting.Unicode
{
internal static class GraphemeBreak
{
public static byte[] Data => new byte[0];
}
}

422
src/Avalonia.Base/Media/TextFormatting/Unicode/GraphemeBreak.trie.cs

@ -1,31 +1,409 @@
using System;
namespace Avalonia.Media.TextFormatting.Unicode
{
internal static class GraphemeBreakTrie
{
public static ReadOnlySpan<byte> Data => new byte[]
{
0,14,16,0,0,0,0,0,0,0,133,64,0,245,7,10,248,236,157,127,136,29,87,21,199,103,157,111,246,157,100,211,138,180,69,177,5,241,7,88,91,40,182,150,210,12,138,161,88,27,163,96,241,15,75,161,210,18,44,149,10,193,46,24,80,49,254,163,33,16,136,54,127,84,8,34,18,253,199,68,196,42,136,154,82,21,149,6,218,82,43,72,107,161,54,22,196,173,10,110,
16,140,210,82,250,125,190,51,228,228,228,206,204,157,121,119,230,109,182,243,133,15,231,220,115,207,156,123,239,121,111,247,253,216,129,189,33,207,178,130,220,66,118,147,61,228,126,19,43,230,180,171,228,139,100,31,217,31,145,127,128,28,174,153,63,66,142,146,99,228,56,249,49,249,5,249,21,57,101,242,158,36,127,36,207,145,23,201,26,89,39,255,34,103,201,43,4,200,178,47,
147,175,146,131,152,93,91,242,40,217,206,216,55,200,17,114,148,28,35,199,201,9,242,19,114,146,252,134,252,150,60,65,158,54,227,63,145,191,104,254,75,228,140,94,255,63,242,32,89,218,50,91,103,43,237,25,218,55,109,57,87,255,205,244,223,166,227,119,211,190,135,92,110,214,47,152,127,61,99,103,39,51,127,7,253,157,90,175,32,31,162,255,49,29,223,78,123,135,250,119,
211,222,71,246,146,255,154,243,238,227,120,63,57,64,14,155,58,5,185,82,206,241,46,229,26,242,126,165,48,185,69,13,95,143,204,43,18,243,16,207,243,16,121,158,231,125,94,207,252,45,142,191,87,246,7,231,231,95,193,248,247,93,15,30,118,227,194,240,51,157,251,37,237,99,234,239,37,47,235,252,83,140,253,129,60,71,78,147,53,178,174,121,103,213,190,26,168,143,101,62,
255,150,47,140,151,172,146,203,107,230,139,72,62,201,243,223,165,61,184,201,196,247,146,7,106,206,93,140,100,125,247,224,42,247,248,158,12,60,7,138,4,252,213,252,12,188,61,193,115,170,24,201,198,30,100,99,15,242,177,7,99,15,178,177,7,249,216,131,177,7,217,216,131,124,236,193,216,131,108,236,65,62,246,96,236,65,150,188,7,87,47,207,190,75,43,199,159,136,248,254,
226,189,188,230,102,243,153,247,24,191,83,123,133,236,100,108,151,198,111,167,189,131,92,37,179,239,3,239,162,15,250,159,214,249,251,105,87,201,62,29,239,167,253,51,237,129,134,207,210,135,57,127,43,235,124,152,220,70,118,145,143,144,221,228,163,228,214,113,46,27,251,146,141,207,9,25,127,30,198,223,5,89,178,223,5,55,144,29,228,3,164,24,223,139,100,99,15,178,177,7,
249,216,131,62,122,112,164,231,191,167,236,87,138,0,187,3,177,51,198,191,199,253,237,179,88,0,187,46,153,113,144,172,109,111,230,20,243,158,13,228,190,229,210,243,199,187,56,62,72,78,145,236,141,179,216,141,180,159,33,223,33,143,144,117,178,115,37,203,62,71,94,220,202,191,125,109,203,50,89,154,113,167,241,197,113,98,229,194,88,136,47,153,26,63,162,255,15,94,119,45,
247,113,47,57,176,61,174,198,72,54,246,96,105,236,193,216,131,108,236,193,210,230,235,193,58,95,23,50,190,46,60,202,247,9,167,249,122,248,146,222,231,177,198,239,174,222,202,215,231,119,232,107,244,223,201,239,152,179,194,207,44,143,47,207,230,127,79,123,141,121,13,127,54,240,94,227,36,57,189,124,238,62,178,53,250,235,21,239,73,254,195,248,171,102,110,153,223,131,93,170,
247,152,21,1,46,227,220,149,102,254,157,147,115,247,61,77,185,118,114,254,253,95,239,171,169,117,115,205,92,65,174,227,57,111,114,239,87,62,200,107,110,35,31,159,94,11,222,203,164,53,110,113,121,69,4,159,50,235,223,75,255,179,110,63,15,112,188,91,235,126,161,97,175,133,225,43,45,114,139,30,185,175,67,79,138,158,249,46,123,179,99,192,245,246,178,7,39,184,230,195,
129,199,228,231,27,228,113,42,90,178,71,239,3,91,85,246,56,86,107,248,60,46,204,127,189,81,204,193,209,134,207,118,47,187,241,177,13,120,111,221,113,238,233,135,21,251,186,34,209,253,159,63,104,121,238,159,6,242,207,246,220,135,175,233,207,255,161,13,240,123,224,65,238,225,50,190,206,127,211,236,229,219,9,246,181,74,126,61,153,217,83,180,79,145,103,54,192,121,139,72,
94,224,94,255,214,176,223,67,29,207,243,207,139,160,15,135,220,30,255,125,17,236,185,232,192,35,27,96,15,215,231,75,255,39,231,219,243,60,130,55,24,127,41,242,154,60,130,81,139,211,216,255,44,217,243,56,239,200,162,31,55,188,206,73,41,212,176,153,133,139,144,114,223,165,197,212,9,248,155,93,147,10,98,133,22,164,254,221,149,90,232,129,20,123,26,66,168,97,210,144,
227,107,100,53,57,41,53,81,139,148,69,91,10,9,217,204,66,11,46,86,33,130,216,58,214,135,62,215,177,0,36,16,203,52,46,138,31,195,252,108,214,9,117,147,145,18,3,28,226,226,165,38,165,211,81,147,142,215,133,36,166,230,36,148,16,56,87,121,29,166,206,156,130,214,18,199,84,162,216,92,104,12,186,95,49,22,101,226,130,132,10,68,247,8,71,72,147,10,208,1,
49,126,149,80,193,68,237,144,130,33,239,161,126,174,181,183,168,159,39,170,153,87,144,66,121,75,134,88,175,73,112,207,61,184,121,113,115,80,242,6,144,128,124,78,250,18,28,161,24,166,193,134,49,76,124,40,193,80,55,39,126,114,64,65,215,135,142,197,128,6,36,144,47,74,89,27,21,196,10,202,34,4,119,158,161,215,246,123,128,163,148,40,126,140,50,208,32,52,204,251,
92,216,64,207,130,243,225,206,58,148,224,122,43,26,67,69,46,2,99,84,212,76,181,63,4,98,177,18,205,135,99,42,40,50,29,168,21,141,165,22,148,190,132,10,134,22,140,133,233,39,12,165,68,241,99,148,129,10,193,16,43,196,38,38,22,2,231,204,76,76,166,3,55,6,137,17,34,115,196,128,152,194,9,5,183,190,152,56,20,63,198,52,80,35,40,139,16,212,138,250,
18,240,203,60,81,166,18,5,74,157,160,196,8,138,40,139,20,148,210,151,169,19,41,84,196,68,129,193,230,75,13,208,156,121,5,181,162,62,42,136,169,131,26,82,9,145,251,133,201,109,83,27,1,134,18,148,190,215,8,89,43,81,82,158,9,45,145,138,184,173,25,18,90,208,54,31,61,48,175,16,217,55,184,124,113,185,125,74,26,214,66,205,92,91,193,209,69,80,43,234,
35,34,183,171,208,245,194,134,154,80,250,20,20,49,62,2,72,3,112,62,34,137,221,99,95,130,65,28,8,196,189,68,129,241,197,1,67,159,130,34,10,122,90,71,204,58,168,161,220,147,181,165,143,26,164,2,68,82,10,1,164,156,28,72,168,65,140,21,7,140,191,40,33,130,174,53,165,237,133,9,37,129,115,136,139,139,155,79,45,184,53,196,0,55,7,51,215,86,210,0,
26,16,151,55,175,96,240,99,68,34,13,243,94,240,129,138,57,209,49,76,204,11,3,81,181,214,60,130,97,72,65,73,85,7,74,40,134,10,188,208,48,174,138,165,148,40,80,36,144,131,158,214,20,183,246,80,66,34,186,174,93,55,135,26,250,16,90,32,74,234,245,69,129,67,92,92,148,170,58,67,10,21,136,130,138,113,151,117,98,114,164,41,169,71,161,167,122,48,216,57,
148,3,39,40,109,36,230,58,81,234,242,218,74,20,84,248,153,137,45,90,216,228,107,35,64,76,174,29,135,4,71,223,130,33,52,215,70,80,82,74,180,166,164,44,218,81,8,32,21,113,24,250,18,18,215,19,3,34,144,132,107,136,137,137,137,87,9,106,197,128,6,250,16,220,30,196,204,73,197,88,90,212,142,149,40,246,90,84,96,133,0,125,75,12,104,64,2,121,162,182,
79,33,97,29,81,80,129,4,242,36,48,143,68,123,234,42,232,94,68,125,24,74,137,3,138,24,127,72,65,73,37,49,160,1,49,121,162,182,141,96,174,19,227,35,128,168,109,146,40,112,72,32,134,166,98,29,36,6,68,32,198,79,37,49,192,81,10,138,56,80,38,168,68,237,144,66,36,67,236,35,54,15,1,68,129,97,30,137,171,5,199,84,168,64,212,166,18,58,146,153,
189,160,2,169,240,83,9,21,248,156,210,98,234,24,27,35,9,80,214,192,212,49,113,24,155,82,80,68,73,89,19,134,148,66,13,41,106,103,166,31,210,129,58,193,209,69,104,153,47,202,34,5,197,250,152,14,84,168,161,47,193,209,103,253,33,133,30,73,181,86,147,208,148,208,49,183,173,16,160,42,142,72,230,21,106,104,154,71,36,165,80,131,157,207,106,114,82,11,142,212,
245,96,232,83,162,244,85,87,90,176,104,137,50,228,90,178,32,182,110,0,172,182,45,152,149,158,185,196,209,86,219,18,226,181,178,1,240,226,191,181,184,160,103,125,50,244,122,94,175,1,0,0,255,255,0,0,0,255,255,99,102,0,0};
0, 16, 14, 0, 0, 0, 0, 0, 144, 155, 0, 0, 89, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 113, 3, 0, 0, 137, 3, 0, 0, 145, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0,
97, 3, 0, 0, 105, 3, 0, 0, 153, 3, 0, 0, 161, 3, 0, 0, 157, 3, 0, 0, 165, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 173, 3, 0, 0, 181, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 185, 3, 0, 0, 193, 3, 0, 0, 201, 3, 0, 0,
209, 3, 0, 0, 217, 3, 0, 0, 225, 3, 0, 0, 231, 3, 0, 0, 239, 3, 0, 0, 97, 3, 0, 0, 105, 3, 0, 0, 244, 3, 0, 0, 252, 3, 0, 0, 1, 4, 0, 0, 9, 4, 0, 0, 15, 4, 0, 0, 23, 4, 0, 0, 22, 4, 0, 0, 30, 4, 0, 0, 35, 4, 0, 0, 43, 4, 0, 0, 176, 4, 0, 0, 183, 4, 0, 0, 187, 4, 0, 0, 97, 3, 0, 0, 51, 4, 0, 0, 97, 3, 0, 0, 194, 4, 0, 0, 59, 4, 0, 0,
202, 4, 0, 0, 204, 4, 0, 0, 212, 4, 0, 0, 220, 4, 0, 0, 228, 4, 0, 0, 229, 4, 0, 0, 237, 4, 0, 0, 245, 4, 0, 0, 253, 4, 0, 0, 254, 4, 0, 0, 6, 5, 0, 0, 11, 5, 0, 0, 253, 4, 0, 0, 254, 4, 0, 0, 19, 5, 0, 0, 27, 5, 0, 0, 228, 4, 0, 0, 35, 5, 0, 0, 43, 5, 0, 0, 220, 4, 0, 0, 51, 5, 0, 0, 203, 4, 0, 0, 59, 5, 0, 0, 97, 3, 0, 0, 67, 5, 0, 0,
35, 5, 0, 0, 75, 5, 0, 0, 220, 4, 0, 0, 228, 4, 0, 0, 81, 5, 0, 0, 89, 5, 0, 0, 220, 4, 0, 0, 97, 5, 0, 0, 99, 5, 0, 0, 67, 4, 0, 0, 220, 4, 0, 0, 228, 4, 0, 0, 97, 3, 0, 0, 107, 5, 0, 0, 88, 8, 0, 0, 97, 3, 0, 0, 115, 5, 0, 0, 122, 5, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 126, 5, 0, 0, 134, 5, 0, 0, 97, 3, 0, 0, 138, 5, 0, 0, 145, 5, 0, 0,
97, 3, 0, 0, 153, 5, 0, 0, 161, 5, 0, 0, 168, 5, 0, 0, 50, 5, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 176, 5, 0, 0, 184, 5, 0, 0, 192, 5, 0, 0, 200, 5, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 124, 8, 0, 0, 124, 8, 0, 0, 124, 8, 0, 0, 133, 8, 0, 0, 133, 8, 0, 0, 139, 8, 0, 0, 157, 8, 0, 0, 157, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 182, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 208, 5, 0, 0, 214, 5, 0, 0, 23, 5, 0, 0, 23, 5, 0, 0, 97, 3, 0, 0, 220, 5, 0, 0, 228, 5, 0, 0, 97, 3, 0, 0, 127, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 79, 5, 0, 0,
233, 5, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 241, 5, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 248, 5, 0, 0, 97, 3, 0, 0, 255, 5, 0, 0, 7, 6, 0, 0, 97, 3, 0, 0, 149, 3, 0, 0, 14, 4, 0, 0, 97, 3, 0, 0, 15, 6, 0, 0, 18, 6, 0, 0, 26, 6, 0, 0, 32, 6, 0, 0, 40, 6, 0, 0, 48, 6, 0, 0,
97, 3, 0, 0, 55, 6, 0, 0, 97, 3, 0, 0, 62, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 68, 6, 0, 0, 76, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 153, 3, 0, 0, 153, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 133, 4, 0, 0, 139, 4, 0, 0, 94, 6, 0, 0, 93, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 149, 3, 0, 0, 171, 5, 0, 0, 97, 3, 0, 0, 180, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 187, 8, 0, 0, 194, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 197, 8, 0, 0, 204, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 204, 8, 0, 0, 97, 3, 0, 0, 209, 8, 0, 0, 215, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 223, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 229, 8, 0, 0, 237, 8, 0, 0, 239, 8, 0, 0, 247, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 3, 9, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 10, 9, 0, 0, 17, 9, 0, 0, 24, 9, 0, 0, 32, 9, 0, 0, 35, 9, 0, 0, 43, 9, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 51, 9, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 58, 9, 0, 0, 97, 3, 0, 0, 66, 9, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 83, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 226, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 153, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 89, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 72, 9, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 104, 6, 0, 0, 24, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 140, 5, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 112, 6, 0, 0, 120, 6, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 237, 7, 0, 0, 93, 8, 0, 0, 128, 6, 0, 0, 136, 6, 0, 0, 97, 3, 0, 0, 144, 6, 0, 0, 151, 6, 0, 0, 125, 8, 0, 0, 202, 4, 0, 0, 156, 6, 0, 0, 101, 8, 0, 0, 164, 6, 0, 0, 97, 3, 0, 0, 170, 6, 0, 0, 178, 6, 0, 0, 182, 6, 0, 0, 97, 3, 0, 0, 190, 6, 0, 0, 5, 4, 0, 0, 198, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 206, 6, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0,
166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0,
170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0,
167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0,
171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0,
168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0,
172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0,
169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0,
166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0,
170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0,
167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0,
171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0,
168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0,
172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0, 169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 172, 8, 0, 0, 166, 8, 0, 0, 167, 8, 0, 0, 168, 8, 0, 0,
169, 8, 0, 0, 170, 8, 0, 0, 171, 8, 0, 0, 147, 8, 0, 0, 154, 8, 0, 0, 158, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 210, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 165, 3, 0, 0, 165, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 113, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 24, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
147, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 228, 13, 0, 0, 228, 13, 0, 0, 36, 14, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 100, 14, 0, 0, 116, 14, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0,
132, 13, 0, 0, 180, 14, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 132, 13, 0, 0, 228, 14, 0, 0, 36, 15, 0, 0, 100, 15, 0, 0, 156, 15, 0, 0, 132, 13, 0, 0, 208, 15, 0, 0, 4, 16, 0, 0, 60, 16, 0, 0, 88, 16, 0, 0, 140, 16, 0, 0, 64, 11, 0, 0, 112, 11, 0, 0, 226, 9, 0, 0, 33, 10, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 89, 10, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 173, 11, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 123, 10, 0, 0, 149, 1, 0, 0, 237, 11, 0, 0, 176, 10, 0, 0, 40, 12, 0, 0, 104, 12, 0, 0, 162, 12, 0, 0, 226, 12, 0, 0, 34, 13, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0,
149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 149, 1, 0, 0, 240, 10, 0, 0, 0, 11, 0, 0, 6, 7, 0, 0, 7, 4, 0, 0, 16, 4, 0, 0, 10, 7, 0, 0, 40, 6, 0, 0, 73, 4, 0, 0, 81, 4, 0, 0, 97, 3, 0, 0, 17, 4, 0, 0, 16, 7, 0, 0, 108, 8, 0, 0, 22, 7, 0, 0, 40, 6, 0, 0, 27, 7, 0, 0, 89, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
35, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 226, 3, 0, 0, 43, 7, 0, 0, 97, 5, 0, 0, 99, 5, 0, 0, 51, 7, 0, 0, 59, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 65, 7, 0, 0, 73, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 81, 7, 0, 0, 89, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 94, 7, 0, 0, 102, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 110, 7, 0, 0, 34, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 118, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 182, 3, 0, 0, 126, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 131, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 93, 4, 0, 0, 101, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 138, 7, 0, 0, 146, 7, 0, 0, 154, 7, 0, 0, 105, 4, 0, 0, 161, 7, 0, 0, 97, 3, 0, 0, 113, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 168, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 176, 7, 0, 0, 182, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 188, 7, 0, 0, 121, 4, 0, 0, 97, 3, 0, 0, 196, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 202, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 154, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 238, 7, 0, 0, 96, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
161, 4, 0, 0, 254, 7, 0, 0, 252, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 6, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 137, 3, 0, 0, 153, 3, 0, 0, 153, 3, 0, 0, 153, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 153, 3, 0, 0, 153, 3, 0, 0, 153, 3, 0, 0, 153, 3, 0, 0, 153, 3, 0, 0, 153, 3, 0, 0, 153, 3, 0, 0, 168, 4, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0,
137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0,
137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0,
137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 137, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 218, 6, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 34, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 226, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 234, 6, 0, 0, 238, 6, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 79, 5, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 236, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 246, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 30, 4, 0, 0, 97, 3, 0, 0, 254, 6, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 208, 7, 0, 0, 97, 3, 0, 0, 214, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
220, 7, 0, 0, 116, 8, 0, 0, 226, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 233, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 153, 3, 0, 0, 246, 7, 0, 0, 16, 4, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 153, 3, 0, 0, 14, 8, 0, 0, 153, 3, 0, 0, 21, 8, 0, 0, 28, 8, 0, 0, 36, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 44, 8, 0, 0, 52, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 214, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
214, 6, 0, 0, 97, 3, 0, 0, 57, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 214, 7, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 64, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0,
97, 3, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 79, 9, 0, 0, 209, 8, 0, 0, 97, 3, 0, 0, 84, 9, 0, 0, 92, 9, 0, 0, 99, 9, 0, 0, 252, 8, 0, 0, 80, 8, 0, 0, 107, 9, 0, 0, 114, 9, 0, 0, 122, 9, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0,
252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 72, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 253, 8, 0, 0, 130, 9, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0,
252, 8, 0, 0, 134, 9, 0, 0, 97, 3, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 67, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 138, 9, 0, 0, 252, 8, 0, 0, 146, 9, 0, 0, 97, 3, 0, 0, 152, 9, 0, 0, 97, 3, 0, 0, 160, 9, 0, 0, 165, 9, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 69, 8, 0, 0, 169, 9, 0, 0,
176, 9, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 97, 3, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0,
252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0,
252, 8, 0, 0, 252, 8, 0, 0, 252, 8, 0, 0, 253, 8, 0, 0, 88, 3, 1, 0, 88, 3, 1, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0,
3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0,
3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0,
3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
8, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 7, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0,
3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0,
8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0,
8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
8, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0,
4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0,
6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0,
9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0,
10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0,
11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0,
10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0,
11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0,
11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0,
13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 12, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0,
13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0,
14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
}
}

1
src/Avalonia.Base/Media/TextFormatting/Unicode/LineBreakClass.cs

@ -35,7 +35,6 @@ namespace Avalonia.Media.TextFormatting.Unicode
EModifier, //EM
ZWJ, //ZWJ
ContingentBreak, //CB
Unknown, //XX
Ambiguous, //AI
MandatoryBreak, //BK

14
src/Avalonia.Base/Media/TextFormatting/Unicode/LineBreakEnumerator.cs

@ -450,6 +450,20 @@ namespace Avalonia.Media.TextFormatting.Unicode
_lb30a = 0;
}
// Rule LB30b
if (_nextClass == LineBreakClass.EModifier && _lastPosition > 0)
{
// Mahjong Tiles (Unicode block) are extended pictographics but have a class of ID
// Unassigned codepoints with Line_Break=ID in some blocks are also assigned the Extended_Pictographic property.
// Those blocks are intended for future allocation of emoji characters.
var cp = Codepoint.ReadAt(_text, _lastPosition - 1, out int _);
if (Codepoint.IsInRangeInclusive(cp, 0x1F000, 0x1F02F))
{
shouldBreak = false;
}
}
_currentClass = _nextClass;
return shouldBreak;

5
src/Avalonia.Base/Media/TextFormatting/Unicode/Script.cs

@ -30,6 +30,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
Cherokee, //Cher
Chorasmian, //Chrs
Coptic, //Copt
CyproMinoan, //Cpmn
Cypriot, //Cprt
Cyrillic, //Cyrl
Devanagari, //Deva
@ -109,6 +110,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
Oriya, //Orya
Osage, //Osge
Osmanya, //Osma
OldUyghur, //Ougr
Palmyrene, //Palm
PauCinHau, //Pauc
OldPermic, //Perm
@ -151,8 +153,11 @@ namespace Avalonia.Media.TextFormatting.Unicode
Thai, //Thai
Tibetan, //Tibt
Tirhuta, //Tirh
Tangsa, //Tnsa
Toto, //Toto
Ugaritic, //Ugar
Vai, //Vaii
Vithkuqi, //Vith
WarangCiti, //Wara
Wancho, //Wcho
OldPersian, //Xpeo

42
src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeData.cs

@ -36,29 +36,9 @@ namespace Avalonia.Media.TextFormatting.Unicode
static UnicodeData()
{
unsafe
{
var unicodeData = UnicodeDataTrie.Data;
fixed (byte* unicodeDataPtr = unicodeData)
{
s_unicodeDataTrie = new UnicodeTrie(new UnmanagedMemoryStream(unicodeDataPtr, unicodeData.Length));
}
var graphemeData = GraphemeBreakTrie.Data;
fixed (byte* graphemeDataPtr = graphemeData)
{
s_graphemeBreakTrie = new UnicodeTrie(new UnmanagedMemoryStream(graphemeDataPtr, graphemeData.Length));
}
var bidiData = BiDiTrie.Data;
fixed (byte* bidiDataPtr = bidiData)
{
s_biDiTrie = new UnicodeTrie(new UnmanagedMemoryStream(bidiDataPtr, bidiData.Length));
}
}
s_unicodeDataTrie = new UnicodeTrie(UnicodeDataTrie.Data);
s_graphemeBreakTrie = new UnicodeTrie(GraphemeBreakTrie.Data);
s_biDiTrie = new UnicodeTrie(BidiTrie.Data);
}
/// <summary>
@ -67,7 +47,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <param name="codepoint">The codepoint in question.</param>
/// <returns>The code point's general category.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static GeneralCategory GetGeneralCategory(int codepoint)
public static GeneralCategory GetGeneralCategory(uint codepoint)
{
return (GeneralCategory)(s_unicodeDataTrie.Get(codepoint) & CATEGORY_MASK);
}
@ -78,7 +58,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <param name="codepoint">The codepoint in question.</param>
/// <returns>The code point's script.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Script GetScript(int codepoint)
public static Script GetScript(uint codepoint)
{
return (Script)((s_unicodeDataTrie.Get(codepoint) >> SCRIPT_SHIFT) & SCRIPT_MASK);
}
@ -89,7 +69,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <param name="codepoint">The codepoint in question.</param>
/// <returns>The code point's biDi class.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static BidiClass GetBiDiClass(int codepoint)
public static BidiClass GetBiDiClass(uint codepoint)
{
return (BidiClass)((s_biDiTrie.Get(codepoint) >> BIDICLASS_SHIFT) & BIDICLASS_MASK);
}
@ -100,7 +80,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <param name="codepoint">The codepoint in question.</param>
/// <returns>The code point's paired bracket type.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static BidiPairedBracketType GetBiDiPairedBracketType(int codepoint)
public static BidiPairedBracketType GetBiDiPairedBracketType(uint codepoint)
{
return (BidiPairedBracketType)((s_biDiTrie.Get(codepoint) >> BIDIPAIREDBRACKEDTYPE_SHIFT) & BIDIPAIREDBRACKEDTYPE_MASK);
}
@ -111,9 +91,9 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <param name="codepoint">The codepoint in question.</param>
/// <returns>The code point's paired bracket.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Codepoint GetBiDiPairedBracket(int codepoint)
public static Codepoint GetBiDiPairedBracket(uint codepoint)
{
return new Codepoint((int)(s_biDiTrie.Get(codepoint) & BIDIPAIREDBRACKED_MASK));
return new Codepoint((s_biDiTrie.Get(codepoint) & BIDIPAIREDBRACKED_MASK));
}
/// <summary>
@ -122,7 +102,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <param name="codepoint">The codepoint in question.</param>
/// <returns>The code point's line break class.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static LineBreakClass GetLineBreakClass(int codepoint)
public static LineBreakClass GetLineBreakClass(uint codepoint)
{
return (LineBreakClass)((s_unicodeDataTrie.Get(codepoint) >> LINEBREAK_SHIFT) & LINEBREAK_MASK);
}
@ -133,7 +113,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// <param name="codepoint">The codepoint in question.</param>
/// <returns>The code point's grapheme break type.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static GraphemeBreakClass GetGraphemeClusterBreak(int codepoint)
public static GraphemeBreakClass GetGraphemeClusterBreak(uint codepoint)
{
return (GraphemeBreakClass)s_graphemeBreakTrie.Get(codepoint);
}

1192
src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeData.trie.cs

File diff suppressed because it is too large

156
src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrie.cs

@ -15,92 +15,119 @@
// Ported from: https://github.com/foliojs/unicode-trie
// Copied from: https://github.com/toptensoftware/RichTextKit
using System;
using System.IO;
using System.IO.Compression;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
namespace Avalonia.Media.TextFormatting.Unicode
{
internal class UnicodeTrie
{
private readonly int[] _data;
private readonly uint[] _data;
private readonly int _highStart;
private readonly uint _errorValue;
/// <summary>
/// Initializes a new instance of the <see cref="UnicodeTrie"/> class.
/// </summary>
/// <param name="rawData">The uncompressed trie data.</param>
public UnicodeTrie(ReadOnlySpan<byte> rawData)
{
var header = UnicodeTrieHeader.Parse(rawData);
int length = header.DataLength;
uint[] data = new uint[length / sizeof(uint)];
MemoryMarshal.Cast<byte, uint>(rawData.Slice(rawData.Length - length))
.CopyTo(data);
_highStart = header.HighStart;
_errorValue = header.ErrorValue;
_data = data;
}
/// <summary>
/// Initializes a new instance of the <see cref="UnicodeTrie"/> class.
/// </summary>
/// <param name="stream">The stream containing the data.</param>
public UnicodeTrie(Stream stream)
{
int dataLength;
using (var bw = new BinaryReader(stream, Encoding.UTF8, true))
// Read the header info
using (var br = new BinaryReader(stream, Encoding.UTF8, true))
{
_highStart = bw.ReadInt32BE();
_errorValue = bw.ReadUInt32BE();
dataLength = bw.ReadInt32BE() / 4;
_highStart = br.ReadInt32();
_errorValue = br.ReadUInt32();
_data = new uint[br.ReadInt32() / sizeof(uint)];
}
using (var infl1 = new DeflateStream(stream, CompressionMode.Decompress, true))
using (var infl2 = new DeflateStream(infl1, CompressionMode.Decompress, true))
using (var bw = new BinaryReader(infl2, Encoding.UTF8, true))
// Read the data in compressed format.
using (var br = new BinaryReader(stream, Encoding.UTF8, true))
{
_data = new int[dataLength];
for (int i = 0; i < _data.Length; i++)
{
_data[i] = bw.ReadInt32();
_data[i] = br.ReadUInt32();
}
}
}
public UnicodeTrie(byte[] buf) : this(new MemoryStream(buf))
{
}
internal UnicodeTrie(int[] data, int highStart, uint errorValue)
/// <summary>
/// Initializes a new instance of the <see cref="UnicodeTrie"/> class.
/// </summary>
/// <param name="data">The uncompressed trie data.</param>
/// <param name="highStart">The start of the last range which ends at U+10ffff.</param>
/// <param name="errorValue">The value for out-of-range code points and illegal UTF-8.</param>
public UnicodeTrie(uint[] data, int highStart, uint errorValue)
{
_data = data;
_highStart = highStart;
_errorValue = errorValue;
}
/// <summary>
/// Saves the <see cref="UnicodeTrie"/> to the stream in a compressed format.
/// </summary>
/// <param name="stream">The output stream.</param>
internal void Save(Stream stream)
{
// Write the header info
using (var bw = new BinaryWriter(stream, Encoding.UTF8, true))
{
bw.WriteBE(_highStart);
bw.WriteBE(_errorValue);
bw.WriteBE(_data.Length * 4);
bw.Write(_highStart);
bw.Write(_errorValue);
bw.Write(_data.Length * sizeof(uint));
}
// Double compress the data
using (var def1 = new DeflateStream(stream, CompressionLevel.Optimal, true))
using (var def2 = new DeflateStream(def1, CompressionLevel.Optimal, true))
using (var bw = new BinaryWriter(def2, Encoding.UTF8, true))
// Write the data.
using (var bw = new BinaryWriter(stream, Encoding.UTF8, true))
{
foreach (var v in _data)
for (int i = 0; i < _data.Length; i++)
{
bw.Write(v);
bw.Write(_data[i]);
}
bw.Flush();
def2.Flush();
def1.Flush();
}
}
public uint Get(int codePoint)
/// <summary>
/// Get the value for a code point as stored in the trie.
/// </summary>
/// <param name="codePoint">The code point.</param>
/// <returns>The <see cref="uint"/> value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint Get(uint codePoint)
{
int index;
if ((codePoint < 0) || (codePoint > 0x10ffff))
{
return _errorValue;
}
uint index;
ref uint dataBase = ref MemoryMarshal.GetReference(_data.AsSpan());
if ((codePoint < 0xd800) || ((codePoint > 0xdbff) && (codePoint <= 0xffff)))
if (codePoint is < 0x0d800 or (> 0x0dbff and <= 0x0ffff))
{
// Ordinary BMP code point, excluding leading surrogates.
// BMP uses a single level lookup. BMP index starts at offset 0 in the index.
// data is stored in the index array itself.
index = (_data[codePoint >> UnicodeTrieBuilder.SHIFT_2] << UnicodeTrieBuilder.INDEX_SHIFT) + (codePoint & UnicodeTrieBuilder.DATA_MASK);
return (uint)_data[index];
// BMP uses a single level lookup. BMP index starts at offset 0 in the Trie2 index.
// 16 bit data is stored in the index array itself.
index = _data[codePoint >> UnicodeTrieBuilder.SHIFT_2];
index = (index << UnicodeTrieBuilder.INDEX_SHIFT) + (codePoint & UnicodeTrieBuilder.DATA_MASK);
return Unsafe.Add(ref dataBase, (nint)index);
}
if (codePoint <= 0xffff)
@ -109,20 +136,57 @@ namespace Avalonia.Media.TextFormatting.Unicode
// lead surrogate code units and code points.
// The main index has the code unit data.
// For this function, we need the code point data.
index = (_data[UnicodeTrieBuilder.LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> UnicodeTrieBuilder.SHIFT_2)] << UnicodeTrieBuilder.INDEX_SHIFT) + (codePoint & UnicodeTrieBuilder.DATA_MASK);
return (uint)_data[index];
// Note: this expression could be refactored for slightly improved efficiency, but
// surrogate code points will be so rare in practice that it's not worth it.
index = _data[UnicodeTrieBuilder.LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> UnicodeTrieBuilder.SHIFT_2)];
index = (index << UnicodeTrieBuilder.INDEX_SHIFT) + (codePoint & UnicodeTrieBuilder.DATA_MASK);
return Unsafe.Add(ref dataBase, (nint)index);
}
if (codePoint < _highStart)
{
// Supplemental code point, use two-level lookup.
index = _data[(UnicodeTrieBuilder.INDEX_1_OFFSET - UnicodeTrieBuilder.OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> UnicodeTrieBuilder.SHIFT_1)];
index = _data[index + ((codePoint >> UnicodeTrieBuilder.SHIFT_2) & UnicodeTrieBuilder.INDEX_2_MASK)];
index = UnicodeTrieBuilder.INDEX_1_OFFSET - UnicodeTrieBuilder.OMITTED_BMP_INDEX_1_LENGTH + (codePoint >> UnicodeTrieBuilder.SHIFT_1);
index = _data[index];
index += (codePoint >> UnicodeTrieBuilder.SHIFT_2) & UnicodeTrieBuilder.INDEX_2_MASK;
index = _data[index];
index = (index << UnicodeTrieBuilder.INDEX_SHIFT) + (codePoint & UnicodeTrieBuilder.DATA_MASK);
return (uint)_data[index];
return Unsafe.Add(ref dataBase, (nint)index);
}
if (codePoint <= 0x10ffff)
{
return Unsafe.Add(ref dataBase, (nint)(_data.Length - UnicodeTrieBuilder.DATA_GRANULARITY));
}
// Fall through. The code point is outside of the legal range of 0..0x10ffff.
return _errorValue;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct UnicodeTrieHeader
{
public int HighStart
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public uint ErrorValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
public int DataLength
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
return (uint)_data[_data.Length - UnicodeTrieBuilder.DATA_GRANULARITY];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UnicodeTrieHeader Parse(ReadOnlySpan<byte> data)
=> MemoryMarshal.Cast<byte, UnicodeTrieHeader>(data)[0];
}
}
}

14
src/Avalonia.Base/Media/TextFormatting/Unicode/UnicodeTrieBuilder.cs

@ -368,24 +368,24 @@ namespace Avalonia.Media.TextFormatting.Unicode
// calculate the sizes of, and allocate, the index and data arrays
var indexLength = allIndexesLength + _dataLength;
var data = new int[indexLength];
var data = new uint[indexLength];
// write the index-2 array values shifted right by INDEX_SHIFT, after adding dataMove
var destIdx = 0;
for (i = 0; i < INDEX_2_BMP_LENGTH; i++)
{
data[destIdx++] = ((_index2[i] + dataMove) >> INDEX_SHIFT);
data[destIdx++] = (uint)((_index2[i] + dataMove) >> INDEX_SHIFT);
}
// write UTF-8 2-byte index-2 values, not right-shifted
for (i = 0; i < 0xc2 - 0xc0; i++)
{ // C0..C1
data[destIdx++] = (dataMove + BAD_UTF8_DATA_OFFSET);
data[destIdx++] = (uint)(dataMove + BAD_UTF8_DATA_OFFSET);
}
for (; i < 0xe0 - 0xc0; i++)
{ // C2..DF
data[destIdx++] = (dataMove + _index2[i << (6 - SHIFT_2)]);
data[destIdx++] = (uint)(dataMove + _index2[i << (6 - SHIFT_2)]);
}
if (_highStart > 0x10000)
@ -396,21 +396,21 @@ namespace Avalonia.Media.TextFormatting.Unicode
// write 16-bit index-1 values for supplementary code points
for (i = 0; i < index1Length; i++)
{
data[destIdx++] = (INDEX_2_OFFSET + _index1[i + OMITTED_BMP_INDEX_1_LENGTH]);
data[destIdx++] = (uint)(INDEX_2_OFFSET + _index1[i + OMITTED_BMP_INDEX_1_LENGTH]);
}
// write the index-2 array values for supplementary code points,
// shifted right by INDEX_SHIFT, after adding dataMove
for (i = 0; i < _index2Length - index2Offset; i++)
{
data[destIdx++] = ((dataMove + _index2[index2Offset + i]) >> INDEX_SHIFT);
data[destIdx++] = (uint)((dataMove + _index2[index2Offset + i]) >> INDEX_SHIFT);
}
}
// write 16-bit data values
for (i = 0; i < _dataLength; i++)
{
data[destIdx++] = (int)_data[i];
data[destIdx++] = _data[i];
}
return new UnicodeTrie(data, _highStart, _errorValue);

14
src/Avalonia.Base/Point.cs

@ -188,7 +188,7 @@ namespace Avalonia
}
/// <summary>
/// Returns a boolean indicating whether the point is equal to the other given point.
/// Returns a boolean indicating whether the point is equal to the other given point (bitwise).
/// </summary>
/// <param name="other">The other point to test equality against.</param>
/// <returns>True if this point is equal to other; False otherwise.</returns>
@ -200,6 +200,18 @@ namespace Avalonia
// ReSharper enable CompareOfFloatsByEqualityOperator
}
/// <summary>
/// Returns a boolean indicating whether the point is equal to the other given point
/// (numerically).
/// </summary>
/// <param name="other">The other point to test equality against.</param>
/// <returns>True if this point is equal to other; False otherwise.</returns>
public bool NearlyEquals(Point other)
{
return MathUtilities.AreClose(_x, other._x) &&
MathUtilities.AreClose(_y, other._y);
}
/// <summary>
/// Checks for equality between a point and an object.
/// </summary>

1
src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs

@ -158,6 +158,7 @@ namespace Avalonia.Rendering.SceneGraph
if (result != null && result.Parent != parent)
{
Deindex(scene, result);
((VisualNode?)result.Parent)?.RemoveChild(result);
result = null;
}

2
src/Avalonia.Base/Utilities/ArrayBuilder.cs

@ -101,7 +101,7 @@ namespace Avalonia.Utilities
/// </summary>
/// <param name="value">The array slice.</param>
/// <returns>The <see cref="ArraySlice{T}"/>.</returns>
public ArraySlice<T> Add(in ReadOnlySlice<T> value)
public ArraySlice<T> Add(in ArraySlice<T> value)
{
var position = _size;

2
src/Avalonia.Base/Utilities/ArraySlice.cs

@ -116,7 +116,7 @@ namespace Avalonia.Utilities
/// </summary>
public static implicit operator ReadOnlySlice<T>(ArraySlice<T> slice)
{
return new ReadOnlySlice<T>(slice._data).AsSlice(slice.Start, slice.Length);
return new ReadOnlySlice<T>(slice._data, 0, slice.Length, slice.Start);
}
/// <summary>

40
src/Avalonia.Base/Utilities/BidiDictionary.cs

@ -0,0 +1,40 @@
using System.Collections.Generic;
namespace Avalonia.Utilities
{
/// <summary>
/// A simple bi-directional dictionary.
/// </summary>
/// <typeparam name="T1">Key type</typeparam>
/// <typeparam name="T2">Value type</typeparam>
internal sealed class BidiDictionary<T1, T2> where T1 : notnull where T2 : notnull
{
public Dictionary<T1, T2> Forward { get; } = new Dictionary<T1, T2>();
public Dictionary<T2, T1> Reverse { get; } = new Dictionary<T2, T1>();
public void Clear()
{
Forward.Clear();
Reverse.Clear();
}
public void Add(T1 key, T2 value)
{
Forward.Add(key, value);
Reverse.Add(value, key);
}
#pragma warning disable CS8601
public bool TryGetValue(T1 key, out T2 value) => Forward.TryGetValue(key, out value);
#pragma warning restore CS8601
#pragma warning disable CS8601
public bool TryGetKey(T2 value, out T1 key) => Reverse.TryGetValue(value, out key);
#pragma warning restore CS8601
public bool ContainsKey(T1 key) => Forward.ContainsKey(key);
public bool ContainsValue(T2 value) => Reverse.ContainsKey(value);
}
}

6
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -49,9 +49,9 @@ namespace Avalonia.Build.Tasks
string projectDirectory,
string output, bool verifyIl, MessageImportance logImportance, string strongNameKey, bool patchCom, bool skipXamlCompilation, bool debuggerLaunch)
{
var typeSystem = new CecilTypeSystem(references
.Where(r => !r.ToLowerInvariant().EndsWith("avalonia.build.tasks.dll"))
.Concat(new[] { input }), input);
var typeSystem = new CecilTypeSystem(
references.Where(r => !r.ToLowerInvariant().EndsWith("avalonia.build.tasks.dll")),
input);
var asm = typeSystem.TargetAssemblyDefinition;

20
src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs

@ -128,8 +128,8 @@ namespace Avalonia.Controls.Primitives
if (_inputTarget != null)
{
_inputTarget.PointerEnter += InputTarget_PointerEnter;
_inputTarget.PointerLeave += InputTarget_PointerLeave;
_inputTarget.PointerEntered += InputTarget_PointerEntered;
_inputTarget.PointerExited += InputTarget_PointerExited;
_inputTarget.PointerPressed += InputTarget_PointerPressed;
_inputTarget.PointerMoved += InputTarget_PointerMoved;
_inputTarget.PointerReleased += InputTarget_PointerReleased;
@ -194,8 +194,8 @@ namespace Avalonia.Controls.Primitives
if (_inputTarget != null)
{
_inputTarget.PointerEnter -= InputTarget_PointerEnter;
_inputTarget.PointerLeave -= InputTarget_PointerLeave;
_inputTarget.PointerEntered -= InputTarget_PointerEntered;
_inputTarget.PointerExited -= InputTarget_PointerExited;
_inputTarget.PointerPressed -= InputTarget_PointerPressed;
_inputTarget.PointerMoved -= InputTarget_PointerMoved;
_inputTarget.PointerReleased -= InputTarget_PointerReleased;
@ -362,7 +362,7 @@ namespace Avalonia.Controls.Primitives
}
/// <inheritdoc/>
protected override void OnPointerLeave(PointerEventArgs e)
protected override void OnPointerExited(PointerEventArgs e)
{
// We only want to bother with the color name tool tip if we can provide color names.
if (_selectionEllipsePanel != null &&
@ -373,7 +373,7 @@ namespace Avalonia.Controls.Primitives
UpdatePseudoClasses();
base.OnPointerLeave(e);
base.OnPointerExited(e);
}
/// <inheritdoc/>
@ -848,16 +848,16 @@ namespace Avalonia.Controls.Primitives
UpdatePseudoClasses();
}
/// <inheritdoc cref="InputElement.PointerEnter"/>
private void InputTarget_PointerEnter(object? sender, PointerEventArgs args)
/// <inheritdoc cref="InputElement.PointerEntered"/>
private void InputTarget_PointerEntered(object? sender, PointerEventArgs args)
{
_isPointerOver = true;
UpdatePseudoClasses();
args.Handled = true;
}
/// <inheritdoc cref="InputElement.PointerLeave"/>
private void InputTarget_PointerLeave(object? sender, PointerEventArgs args)
/// <inheritdoc cref="InputElement.PointerExited"/>
private void InputTarget_PointerExited(object? sender, PointerEventArgs args)
{
_isPointerOver = false;
UpdatePseudoClasses();

12
src/Avalonia.Controls.DataGrid/DataGridCell.cs

@ -139,18 +139,18 @@ namespace Avalonia.Controls
}
}
protected override void OnPointerEnter(PointerEventArgs e)
protected override void OnPointerEntered(PointerEventArgs e)
{
base.OnPointerEnter(e);
base.OnPointerEntered(e);
if (OwningRow != null)
{
IsMouseOver = true;
}
}
protected override void OnPointerLeave(PointerEventArgs e)
protected override void OnPointerExited(PointerEventArgs e)
{
base.OnPointerLeave(e);
base.OnPointerExited(e);
if (OwningRow != null)
{
@ -178,9 +178,9 @@ namespace Avalonia.Controls
{
var handled = OwningGrid.UpdateStateOnMouseLeftButtonDown(e, ColumnIndex, OwningRow.Slot, !e.Handled);
// Do not handle PointerPressed with touch,
// Do not handle PointerPressed with touch or pen,
// so we can start scroll gesture on the same event.
if (e.Pointer.Type != PointerType.Touch)
if (e.Pointer.Type != PointerType.Touch && e.Pointer.Type != PointerType.Pen)
{
e.Handled = handled;
}

2
src/Avalonia.Controls.DataGrid/DataGridColumn.cs

@ -855,7 +855,7 @@ namespace Avalonia.Controls
if (OwningGrid != null && OwningGrid.UseLayoutRounding)
{
var scale = LayoutHelper.GetLayoutScale(HeaderCell);
var roundSize = LayoutHelper.RoundLayoutSize(new Size(leftEdge + ActualWidth, 1), scale, scale);
var roundSize = LayoutHelper.RoundLayoutSizeUp(new Size(leftEdge + ActualWidth, 1), scale, scale);
LayoutRoundedWidth = roundSize.Width - leftEdge;
}
else

12
src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs

@ -83,9 +83,9 @@ namespace Avalonia.Controls
{
PointerPressed += DataGridColumnHeader_PointerPressed;
PointerReleased += DataGridColumnHeader_PointerReleased;
PointerMoved += DataGridColumnHeader_PointerMove;
PointerEnter += DataGridColumnHeader_PointerEnter;
PointerLeave += DataGridColumnHeader_PointerLeave;
PointerMoved += DataGridColumnHeader_PointerMoved;
PointerEntered += DataGridColumnHeader_PointerEntered;
PointerExited += DataGridColumnHeader_PointerExited;
}
private void OnAreSeparatorsVisibleChanged(AvaloniaPropertyChangedEventArgs e)
@ -452,7 +452,7 @@ namespace Avalonia.Controls
SetDragCursor(mousePosition);
}
private void DataGridColumnHeader_PointerEnter(object sender, PointerEventArgs e)
private void DataGridColumnHeader_PointerEntered(object sender, PointerEventArgs e)
{
if (!IsEnabled)
{
@ -464,7 +464,7 @@ namespace Avalonia.Controls
UpdatePseudoClasses();
}
private void DataGridColumnHeader_PointerLeave(object sender, PointerEventArgs e)
private void DataGridColumnHeader_PointerExited(object sender, PointerEventArgs e)
{
if (!IsEnabled)
{
@ -506,7 +506,7 @@ namespace Avalonia.Controls
UpdatePseudoClasses();
}
private void DataGridColumnHeader_PointerMove(object sender, PointerEventArgs e)
private void DataGridColumnHeader_PointerMoved(object sender, PointerEventArgs e)
{
if (OwningGrid == null || !IsEnabled)
{

8
src/Avalonia.Controls.DataGrid/DataGridRow.cs

@ -607,15 +607,15 @@ namespace Avalonia.Controls
}
}
protected override void OnPointerEnter(PointerEventArgs e)
protected override void OnPointerEntered(PointerEventArgs e)
{
base.OnPointerEnter(e);
base.OnPointerEntered(e);
IsMouseOver = true;
}
protected override void OnPointerLeave(PointerEventArgs e)
protected override void OnPointerExited(PointerEventArgs e)
{
IsMouseOver = false;
base.OnPointerLeave(e);
base.OnPointerExited(e);
}
internal void ApplyCellsState()

8
src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs

@ -375,7 +375,7 @@ namespace Avalonia.Controls
ApplyHeaderStatus();
}
protected override void OnPointerEnter(PointerEventArgs e)
protected override void OnPointerEntered(PointerEventArgs e)
{
if (IsEnabled)
{
@ -383,10 +383,10 @@ namespace Avalonia.Controls
UpdatePseudoClasses();
}
base.OnPointerEnter(e);
base.OnPointerEntered(e);
}
protected override void OnPointerLeave(PointerEventArgs e)
protected override void OnPointerExited(PointerEventArgs e)
{
if (IsEnabled)
{
@ -394,7 +394,7 @@ namespace Avalonia.Controls
UpdatePseudoClasses();
}
base.OnPointerLeave(e);
base.OnPointerExited(e);
}
private void SetIsCheckedNoCallBack(bool value)

8
src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs

@ -158,23 +158,23 @@ namespace Avalonia.Controls.Primitives
}
}
protected override void OnPointerEnter(PointerEventArgs e)
protected override void OnPointerEntered(PointerEventArgs e)
{
if (OwningRow != null)
{
OwningRow.IsMouseOver = true;
}
base.OnPointerEnter(e);
base.OnPointerEntered(e);
}
protected override void OnPointerLeave(PointerEventArgs e)
protected override void OnPointerExited(PointerEventArgs e)
{
if (OwningRow != null)
{
OwningRow.IsMouseOver = false;
}
base.OnPointerLeave(e);
base.OnPointerExited(e);
}
//TODO TabStop

12
src/Avalonia.Controls/Calendar/CalendarItem.cs

@ -189,7 +189,7 @@ namespace Avalonia.Controls.Primitives
EventHandler<PointerPressedEventArgs> cellMouseLeftButtonDown = Cell_MouseLeftButtonDown;
EventHandler<PointerReleasedEventArgs> cellMouseLeftButtonUp = Cell_MouseLeftButtonUp;
EventHandler<PointerEventArgs> cellMouseEnter = Cell_MouseEnter;
EventHandler<PointerEventArgs> cellMouseEntered = Cell_MouseEntered;
EventHandler<RoutedEventArgs> cellClick = Cell_Click;
for (int i = 1; i < Calendar.RowsPerMonth; i++)
@ -206,7 +206,7 @@ namespace Avalonia.Controls.Primitives
cell.SetValue(Grid.ColumnProperty, j);
cell.CalendarDayButtonMouseDown += cellMouseLeftButtonDown;
cell.CalendarDayButtonMouseUp += cellMouseLeftButtonUp;
cell.PointerEnter += cellMouseEnter;
cell.PointerEntered += cellMouseEntered;
cell.Click += cellClick;
children.Add(cell);
}
@ -222,7 +222,7 @@ namespace Avalonia.Controls.Primitives
EventHandler<PointerPressedEventArgs> monthCalendarButtonMouseDown = Month_CalendarButtonMouseDown;
EventHandler<PointerReleasedEventArgs> monthCalendarButtonMouseUp = Month_CalendarButtonMouseUp;
EventHandler<PointerEventArgs> monthMouseEnter = Month_MouseEnter;
EventHandler<PointerEventArgs> monthMouseEntered = Month_MouseEntered;
for (int i = 0; i < Calendar.RowsPerYear; i++)
{
@ -238,7 +238,7 @@ namespace Avalonia.Controls.Primitives
month.SetValue(Grid.ColumnProperty, j);
month.CalendarLeftMouseButtonDown += monthCalendarButtonMouseDown;
month.CalendarLeftMouseButtonUp += monthCalendarButtonMouseUp;
month.PointerEnter += monthMouseEnter;
month.PointerEntered += monthMouseEntered;
children.Add(month);
}
}
@ -876,7 +876,7 @@ namespace Avalonia.Controls.Primitives
}
}
internal void Cell_MouseEnter(object? sender, PointerEventArgs e)
internal void Cell_MouseEntered(object? sender, PointerEventArgs e)
{
if (Owner != null)
{
@ -1162,7 +1162,7 @@ namespace Avalonia.Controls.Primitives
}
}
private void Month_MouseEnter(object? sender, PointerEventArgs e)
private void Month_MouseEntered(object? sender, PointerEventArgs e)
{
if (_isMouseLeftButtonDownYearView)
{

2
src/Avalonia.Controls/Converters/MenuScrollingVisibilityConverter.cs

@ -26,7 +26,7 @@ namespace Avalonia.Controls.Converters
if (visibility == ScrollBarVisibility.Auto)
{
if (extent == viewport)
if (MathUtilities.AreClose(extent, viewport))
{
return false;
}

4
src/Avalonia.Controls/GridSplitter.cs

@ -349,9 +349,9 @@ namespace Avalonia.Controls
}
}
protected override void OnPointerEnter(PointerEventArgs e)
protected override void OnPointerEntered(PointerEventArgs e)
{
base.OnPointerEnter(e);
base.OnPointerEntered(e);
GridResizeDirection direction = GetEffectiveResizeDirection();

52
src/Avalonia.Controls/MenuItem.cs

@ -79,25 +79,33 @@ namespace Avalonia.Controls
/// Defines the <see cref="Click"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> ClickEvent =
RoutedEvent.Register<MenuItem, RoutedEventArgs>(nameof(Click), RoutingStrategies.Bubble);
RoutedEvent.Register<MenuItem, RoutedEventArgs>(
nameof(Click),
RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="PointerEnterItem"/> event.
/// Defines the <see cref="PointerEnteredItem"/> event.
/// </summary>
public static readonly RoutedEvent<PointerEventArgs> PointerEnterItemEvent =
RoutedEvent.Register<MenuItem, PointerEventArgs>(nameof(PointerEnterItem), RoutingStrategies.Bubble);
public static readonly RoutedEvent<PointerEventArgs> PointerEnteredItemEvent =
RoutedEvent.Register<MenuItem, PointerEventArgs>(
nameof(PointerEnteredItem),
RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="PointerLeaveItem"/> event.
/// Defines the <see cref="PointerExitedItem"/> event.
/// </summary>
public static readonly RoutedEvent<PointerEventArgs> PointerLeaveItemEvent =
RoutedEvent.Register<MenuItem, PointerEventArgs>(nameof(PointerLeaveItem), RoutingStrategies.Bubble);
public static readonly RoutedEvent<PointerEventArgs> PointerExitedItemEvent =
RoutedEvent.Register<MenuItem, PointerEventArgs>(
nameof(PointerExitedItem),
RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="SubmenuOpened"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> SubmenuOpenedEvent =
RoutedEvent.Register<MenuItem, RoutedEventArgs>(nameof(SubmenuOpened), RoutingStrategies.Bubble);
RoutedEvent.Register<MenuItem, RoutedEventArgs>(
nameof(SubmenuOpened),
RoutingStrategies.Bubble);
/// <summary>
/// The default value for the <see cref="ItemsControl.ItemsPanel"/> property.
@ -174,24 +182,24 @@ namespace Avalonia.Controls
/// Occurs when the pointer enters a menu item.
/// </summary>
/// <remarks>
/// A bubbling version of the <see cref="InputElement.PointerEnter"/> event for menu items.
/// A bubbling version of the <see cref="InputElement.PointerEntered"/> event for menu items.
/// </remarks>
public event EventHandler<PointerEventArgs>? PointerEnterItem
public event EventHandler<PointerEventArgs>? PointerEnteredItem
{
add { AddHandler(PointerEnterItemEvent, value); }
remove { RemoveHandler(PointerEnterItemEvent, value); }
add { AddHandler(PointerEnteredItemEvent, value); }
remove { RemoveHandler(PointerEnteredItemEvent, value); }
}
/// <summary>
/// Raised when the pointer leaves a menu item.
/// </summary>
/// <remarks>
/// A bubbling version of the <see cref="InputElement.PointerLeave"/> event for menu items.
/// A bubbling version of the <see cref="InputElement.PointerExited"/> event for menu items.
/// </remarks>
public event EventHandler<PointerEventArgs>? PointerLeaveItem
public event EventHandler<PointerEventArgs>? PointerExitedItem
{
add { AddHandler(PointerLeaveItemEvent, value); }
remove { RemoveHandler(PointerLeaveItemEvent, value); }
add { AddHandler(PointerExitedItemEvent, value); }
remove { RemoveHandler(PointerExitedItemEvent, value); }
}
/// <summary>
@ -437,22 +445,22 @@ namespace Avalonia.Controls
}
/// <inheritdoc/>
protected override void OnPointerEnter(PointerEventArgs e)
protected override void OnPointerEntered(PointerEventArgs e)
{
base.OnPointerEnter(e);
base.OnPointerEntered(e);
var point = e.GetCurrentPoint(null);
RaiseEvent(new PointerEventArgs(PointerEnterItemEvent, this, e.Pointer, this.VisualRoot, point.Position,
RaiseEvent(new PointerEventArgs(PointerEnteredItemEvent, this, e.Pointer, this.VisualRoot, point.Position,
e.Timestamp, point.Properties, e.KeyModifiers));
}
/// <inheritdoc/>
protected override void OnPointerLeave(PointerEventArgs e)
protected override void OnPointerExited(PointerEventArgs e)
{
base.OnPointerLeave(e);
base.OnPointerExited(e);
var point = e.GetCurrentPoint(null);
RaiseEvent(new PointerEventArgs(PointerLeaveItemEvent, this, e.Pointer, this.VisualRoot, point.Position,
RaiseEvent(new PointerEventArgs(PointerExitedItemEvent, this, e.Pointer, this.VisualRoot, point.Position,
e.Timestamp, point.Properties, e.KeyModifiers));
}

16
src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs

@ -53,9 +53,9 @@ namespace Avalonia.Controls.Platform
Menu.PointerPressed += PointerPressed;
Menu.PointerReleased += PointerReleased;
Menu.AddHandler(AccessKeyHandler.AccessKeyPressedEvent, AccessKeyPressed);
Menu.AddHandler(Avalonia.Controls.Menu.MenuOpenedEvent, this.MenuOpened);
Menu.AddHandler(MenuItem.PointerEnterItemEvent, PointerEnter);
Menu.AddHandler(MenuItem.PointerLeaveItemEvent, PointerLeave);
Menu.AddHandler(Avalonia.Controls.Menu.MenuOpenedEvent, MenuOpened);
Menu.AddHandler(MenuItem.PointerEnteredItemEvent, PointerEntered);
Menu.AddHandler(MenuItem.PointerExitedItemEvent, PointerExited);
Menu.AddHandler(InputElement.PointerMovedEvent, PointerMoved);
_root = Menu.VisualRoot;
@ -89,9 +89,9 @@ namespace Avalonia.Controls.Platform
Menu.PointerPressed -= PointerPressed;
Menu.PointerReleased -= PointerReleased;
Menu.RemoveHandler(AccessKeyHandler.AccessKeyPressedEvent, AccessKeyPressed);
Menu.RemoveHandler(Avalonia.Controls.Menu.MenuOpenedEvent, this.MenuOpened);
Menu.RemoveHandler(MenuItem.PointerEnterItemEvent, PointerEnter);
Menu.RemoveHandler(MenuItem.PointerLeaveItemEvent, PointerLeave);
Menu.RemoveHandler(Avalonia.Controls.Menu.MenuOpenedEvent, MenuOpened);
Menu.RemoveHandler(MenuItem.PointerEnteredItemEvent, PointerEntered);
Menu.RemoveHandler(MenuItem.PointerExitedItemEvent, PointerExited);
Menu.RemoveHandler(InputElement.PointerMovedEvent, PointerMoved);
if (_root is InputElement inputRoot)
@ -297,7 +297,7 @@ namespace Avalonia.Controls.Platform
e.Handled = true;
}
protected internal virtual void PointerEnter(object? sender, PointerEventArgs e)
protected internal virtual void PointerEntered(object? sender, PointerEventArgs e)
{
var item = GetMenuItem(e.Source as IControl);
@ -358,7 +358,7 @@ namespace Avalonia.Controls.Platform
}
}
protected internal virtual void PointerLeave(object? sender, PointerEventArgs e)
protected internal virtual void PointerExited(object? sender, PointerEventArgs e)
{
var item = GetMenuItem(e.Source as IControl);

4
src/Avalonia.Controls/Presenters/ContentPresenter.cs

@ -635,8 +635,8 @@ namespace Avalonia.Controls.Presenters
if (useLayoutRounding)
{
sizeForChild = LayoutHelper.RoundLayoutSize(sizeForChild, scale, scale);
availableSize = LayoutHelper.RoundLayoutSize(availableSize, scale, scale);
sizeForChild = LayoutHelper.RoundLayoutSizeUp(sizeForChild, scale, scale);
availableSize = LayoutHelper.RoundLayoutSizeUp(availableSize, scale, scale);
}
switch (horizontalContentAlignment)

8
src/Avalonia.Controls/Primitives/ScrollBar.cs

@ -218,9 +218,9 @@ namespace Avalonia.Controls.Primitives
}
}
protected override void OnPointerEnter(PointerEventArgs e)
protected override void OnPointerEntered(PointerEventArgs e)
{
base.OnPointerEnter(e);
base.OnPointerEntered(e);
if (AllowAutoHide)
{
@ -228,9 +228,9 @@ namespace Avalonia.Controls.Primitives
}
}
protected override void OnPointerLeave(PointerEventArgs e)
protected override void OnPointerExited(PointerEventArgs e)
{
base.OnPointerLeave(e);
base.OnPointerExited(e);
if (AllowAutoHide)
{

2
src/Avalonia.Controls/Selection/InternalSelectionModel.cs

@ -168,7 +168,7 @@ namespace Avalonia.Controls.Selection
{
if (_writableSelectedItems is INotifyCollectionChanged incc)
{
incc.CollectionChanged += OnSelectedItemsCollectionChanged;
incc.CollectionChanged -= OnSelectedItemsCollectionChanged;
}
}

12
src/Avalonia.Controls/ToolTipService.cs

@ -26,14 +26,14 @@ namespace Avalonia.Controls
if (e.OldValue != null)
{
control.PointerEnter -= ControlPointerEnter;
control.PointerLeave -= ControlPointerLeave;
control.PointerEntered -= ControlPointerEntered;
control.PointerExited -= ControlPointerExited;
}
if (e.NewValue != null)
{
control.PointerEnter += ControlPointerEnter;
control.PointerLeave += ControlPointerLeave;
control.PointerEntered += ControlPointerEntered;
control.PointerExited += ControlPointerExited;
}
if (ToolTip.GetIsOpen(control) && e.NewValue != e.OldValue && !(e.NewValue is ToolTip))
@ -80,7 +80,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param>
private void ControlPointerEnter(object? sender, PointerEventArgs e)
private void ControlPointerEntered(object? sender, PointerEventArgs e)
{
StopTimer();
@ -101,7 +101,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param>
private void ControlPointerLeave(object? sender, PointerEventArgs e)
private void ControlPointerExited(object? sender, PointerEventArgs e)
{
var control = (Control)sender!;
Close(control);

6
src/Avalonia.Controls/TopLevel.cs

@ -484,7 +484,11 @@ namespace Avalonia.Controls
/// Raises the <see cref="Opened"/> event.
/// </summary>
/// <param name="e">The event args.</param>
protected virtual void OnOpened(EventArgs e) => Opened?.Invoke(this, e);
protected virtual void OnOpened(EventArgs e)
{
FrameSize = PlatformImpl?.FrameSize;
Opened?.Invoke(this, e);
}
/// <summary>
/// Raises the <see cref="Closed"/> event.

52
src/Avalonia.Controls/Window.cs

@ -871,10 +871,10 @@ namespace Avalonia.Controls
var scaling = owner?.DesktopScaling ?? PlatformImpl?.DesktopScaling ?? 1;
// TODO: We really need non-client size here.
var rect = new PixelRect(
PixelPoint.Origin,
PixelSize.FromSize(ClientSize, scaling));
// Use frame size, falling back to client size if the platform can't give it to us.
var rect = FrameSize.HasValue ?
new PixelRect(PixelSize.FromSize(FrameSize.Value, scaling)) :
new PixelRect(PixelSize.FromSize(ClientSize, scaling));
if (startupLocation == WindowStartupLocation.CenterScreen)
{
@ -901,10 +901,10 @@ namespace Avalonia.Controls
{
if (owner != null)
{
// TODO: We really need non-client size here.
var ownerSize = owner.FrameSize ?? owner.ClientSize;
var ownerRect = new PixelRect(
owner.Position,
PixelSize.FromSize(owner.ClientSize, scaling));
PixelSize.FromSize(ownerSize, scaling));
Position = ownerRect.CenterRect(rect).Position;
}
}
@ -991,28 +991,28 @@ namespace Avalonia.Controls
/// <inheritdoc/>
protected sealed override void HandleResized(Size clientSize, PlatformResizeReason reason)
{
if (ClientSize == clientSize)
return;
var sizeToContent = SizeToContent;
// If auto-sizing is enabled, and the resize came from a user resize (or the reason was
// unspecified) then turn off auto-resizing for any window dimension that is not equal
// to the requested size.
if (sizeToContent != SizeToContent.Manual &&
CanResize &&
reason == PlatformResizeReason.Unspecified ||
reason == PlatformResizeReason.User)
if (ClientSize != clientSize || double.IsNaN(Width) || double.IsNaN(Height))
{
if (clientSize.Width != ClientSize.Width)
sizeToContent &= ~SizeToContent.Width;
if (clientSize.Height != ClientSize.Height)
sizeToContent &= ~SizeToContent.Height;
SizeToContent = sizeToContent;
}
var sizeToContent = SizeToContent;
// If auto-sizing is enabled, and the resize came from a user resize (or the reason was
// unspecified) then turn off auto-resizing for any window dimension that is not equal
// to the requested size.
if (sizeToContent != SizeToContent.Manual &&
CanResize &&
reason == PlatformResizeReason.Unspecified ||
reason == PlatformResizeReason.User)
{
if (clientSize.Width != ClientSize.Width)
sizeToContent &= ~SizeToContent.Width;
if (clientSize.Height != ClientSize.Height)
sizeToContent &= ~SizeToContent.Height;
SizeToContent = sizeToContent;
}
Width = clientSize.Width;
Height = clientSize.Height;
Width = clientSize.Width;
Height = clientSize.Height;
}
base.HandleResized(clientSize, reason);
}

10
src/Avalonia.Controls/WindowBase.cs

@ -236,10 +236,14 @@ namespace Avalonia.Controls
/// <param name="reason">The reason for the resize.</param>
protected override void HandleResized(Size clientSize, PlatformResizeReason reason)
{
ClientSize = clientSize;
FrameSize = PlatformImpl?.FrameSize;
LayoutManager.ExecuteLayoutPass();
Renderer?.Resized(clientSize);
if (ClientSize != clientSize)
{
ClientSize = clientSize;
LayoutManager.ExecuteLayoutPass();
Renderer?.Resized(clientSize);
}
}
/// <summary>

28
src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlLayoutViewModel.cs

@ -30,20 +30,28 @@ namespace Avalonia.Diagnostics.ViewModels
if (control is AvaloniaObject ao)
{
MarginThickness = ao.GetValue(Layoutable.MarginProperty);
if (HasPadding)
try
{
PaddingThickness = ao.GetValue(Decorator.PaddingProperty);
}
_updatingFromControl = true;
MarginThickness = ao.GetValue(Layoutable.MarginProperty);
if (HasPadding)
{
PaddingThickness = ao.GetValue(Decorator.PaddingProperty);
}
if (HasBorder)
if (HasBorder)
{
BorderThickness = ao.GetValue(Border.BorderThicknessProperty);
}
HorizontalAlignment = ao.GetValue(Layoutable.HorizontalAlignmentProperty);
VerticalAlignment = ao.GetValue(Layoutable.VerticalAlignmentProperty);
}
finally
{
BorderThickness = ao.GetValue(Border.BorderThicknessProperty);
_updatingFromControl = false;
}
HorizontalAlignment = ao.GetValue(Layoutable.HorizontalAlignmentProperty);
VerticalAlignment = ao.GetValue(Layoutable.VerticalAlignmentProperty);
}
UpdateSize();

4
src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs

@ -121,8 +121,8 @@ namespace Avalonia.Diagnostics.Views
if (header != null)
{
header.PointerEnter += AddAdorner;
header.PointerLeave += RemoveAdorner;
header.PointerEntered += AddAdorner;
header.PointerExited += RemoveAdorner;
}
item.TemplateApplied -= TreeViewItemTemplateApplied;

12
src/Avalonia.Themes.Fluent/Controls/FocusAdorner.xaml

@ -19,16 +19,4 @@
</FocusAdornerTemplate>
</Setter>
</Style>
<!-- DottedLine FocusAdorner -->
<Style Selector="Window.DottedLineFocusAdorner :is(Control)">
<Setter Property="FocusAdorner">
<FocusAdornerTemplate>
<Rectangle Stroke="{StaticResource SystemControlFocusVisualPrimaryBrush}"
StrokeThickness="1"
StrokeDashArray="1,2"
Margin="1" />
</FocusAdornerTemplate>
</Setter>
</Style>
</Styles>

12
src/Shared/RawEventGrouping.cs

@ -2,10 +2,8 @@
using System;
using System.Collections.Generic;
using Avalonia.Collections.Pooled;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Threading;
using JetBrains.Annotations;
namespace Avalonia;
@ -19,7 +17,7 @@ internal class RawEventGrouper : IDisposable
private readonly Action<RawInputEventArgs> _eventCallback;
private readonly Queue<RawInputEventArgs> _inputQueue = new();
private readonly Action _dispatchFromQueue;
readonly Dictionary<long, RawTouchEventArgs> _lastTouchPoints = new();
readonly Dictionary<long, RawPointerEventArgs> _lastTouchPoints = new();
RawInputEventArgs? _lastEvent;
public RawEventGrouper(Action<RawInputEventArgs> eventCallback)
@ -49,7 +47,7 @@ internal class RawEventGrouper : IDisposable
_lastEvent = null;
if (ev is RawTouchEventArgs { Type: RawPointerEventType.TouchUpdate } touchUpdate)
_lastTouchPoints.Remove(touchUpdate.TouchPointId);
_lastTouchPoints.Remove(touchUpdate.RawPointerId);
_eventCallback?.Invoke(ev);
@ -88,11 +86,11 @@ internal class RawEventGrouper : IDisposable
{
if (args is RawTouchEventArgs touchEvent)
{
if (_lastTouchPoints.TryGetValue(touchEvent.TouchPointId, out var lastTouchEvent))
if (_lastTouchPoints.TryGetValue(touchEvent.RawPointerId, out var lastTouchEvent))
MergeEvents(lastTouchEvent, touchEvent);
else
{
_lastTouchPoints[touchEvent.TouchPointId] = touchEvent;
_lastTouchPoints[touchEvent.RawPointerId] = touchEvent;
AddToQueue(touchEvent);
}
}
@ -105,7 +103,7 @@ internal class RawEventGrouper : IDisposable
{
_lastTouchPoints.Clear();
if (args is RawTouchEventArgs { Type: RawPointerEventType.TouchUpdate } touchEvent)
_lastTouchPoints[touchEvent.TouchPointId] = touchEvent;
_lastTouchPoints[touchEvent.RawPointerId] = touchEvent;
}
AddToQueue(args);
}

2
src/Skia/Avalonia.Skia/TextShaperImpl.cs

@ -85,7 +85,7 @@ namespace Avalonia.Skia
var second = glyphInfos[length - 1];
if (!new Codepoint((int)second.Codepoint).IsBreakChar)
if (!new Codepoint(second.Codepoint).IsBreakChar)
{
return;
}

2
src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs

@ -85,7 +85,7 @@ namespace Avalonia.Direct2D1.Media
var second = glyphInfos[length - 1];
if (!new Codepoint((int)second.Codepoint).IsBreakChar)
if (!new Codepoint(second.Codepoint).IsBreakChar)
{
return;
}

217
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -225,20 +225,17 @@ namespace Avalonia.Win32.Interop
[Flags]
public enum ModifierKeys
{
MK_CONTROL = 0x0008,
MK_NONE = 0x0000,
MK_LBUTTON = 0x0001,
MK_MBUTTON = 0x0010,
MK_RBUTTON = 0x0002,
MK_SHIFT = 0x0004,
MK_ALT = 0x0020,
MK_SHIFT = 0x0004,
MK_CONTROL = 0x0008,
MK_MBUTTON = 0x0010,
MK_ALT = 0x0020,
MK_XBUTTON1 = 0x0020,
MK_XBUTTON2 = 0x0040
}
@ -514,6 +511,33 @@ namespace Avalonia.Win32.Interop
CS_DROPSHADOW = 0x00020000
}
[Flags]
public enum PointerDeviceChangeFlags
{
PDC_ARRIVAL = 0x001,
PDC_REMOVAL = 0x002,
PDC_ORIENTATION_0 = 0x004,
PDC_ORIENTATION_90 = 0x008,
PDC_ORIENTATION_180 = 0x010,
PDC_ORIENTATION_270 = 0x020,
PDC_MODE_DEFAULT = 0x040,
PDC_MODE_CENTERED = 0x080,
PDC_MAPPING_CHANGE = 0x100,
PDC_RESOLUTION = 0x200,
PDC_ORIGIN = 0x400,
PDC_MODE_ASPECTRATIOPRESERVED = 0x800
}
public enum PointerInputType
{
PT_NONE = 0x00000000,
PT_POINTER = 0x00000001,
PT_TOUCH = 0x00000002,
PT_PEN = 0x00000003,
PT_MOUSE = 0x00000004,
PT_TOUCHPAD = 0x00000005
}
public enum WindowsMessage : uint
{
WM_NULL = 0x0000,
@ -689,6 +713,25 @@ namespace Avalonia.Win32.Interop
WM_EXITSIZEMOVE = 0x0232,
WM_DROPFILES = 0x0233,
WM_MDIREFRESHMENU = 0x0234,
WM_POINTERDEVICECHANGE = 0x0238,
WM_POINTERDEVICEINRANGE = 0x239,
WM_POINTERDEVICEOUTOFRANGE = 0x23A,
WM_NCPOINTERUPDATE = 0x0241,
WM_NCPOINTERDOWN = 0x0242,
WM_NCPOINTERUP = 0x0243,
WM_POINTERUPDATE = 0x0245,
WM_POINTERDOWN = 0x0246,
WM_POINTERUP = 0x0247,
WM_POINTERENTER = 0x0249,
WM_POINTERLEAVE = 0x024A,
WM_POINTERACTIVATE = 0x024B,
WM_POINTERCAPTURECHANGED = 0x024C,
WM_TOUCHHITTESTING = 0x024D,
WM_POINTERWHEEL = 0x024E,
WM_POINTERHWHEEL = 0x024F,
DM_POINTERHITTEST = 0x0250,
WM_IME_SETCONTEXT = 0x0281,
WM_IME_NOTIFY = 0x0282,
WM_IME_CONTROL = 0x0283,
@ -844,6 +887,134 @@ namespace Avalonia.Win32.Interop
SCF_ISSECURE = 0x00000001,
}
[Flags]
public enum PointerFlags
{
POINTER_FLAG_NONE = 0x00000000,
POINTER_FLAG_NEW = 0x00000001,
POINTER_FLAG_INRANGE = 0x00000002,
POINTER_FLAG_INCONTACT = 0x00000004,
POINTER_FLAG_FIRSTBUTTON = 0x00000010,
POINTER_FLAG_SECONDBUTTON = 0x00000020,
POINTER_FLAG_THIRDBUTTON = 0x00000040,
POINTER_FLAG_FOURTHBUTTON = 0x00000080,
POINTER_FLAG_FIFTHBUTTON = 0x00000100,
POINTER_FLAG_PRIMARY = 0x00002000,
POINTER_FLAG_CONFIDENCE = 0x00000400,
POINTER_FLAG_CANCELED = 0x00000800,
POINTER_FLAG_DOWN = 0x00010000,
POINTER_FLAG_UPDATE = 0x00020000,
POINTER_FLAG_UP = 0x00040000,
POINTER_FLAG_WHEEL = 0x00080000,
POINTER_FLAG_HWHEEL = 0x00100000,
POINTER_FLAG_CAPTURECHANGED = 0x00200000,
POINTER_FLAG_HASTRANSFORM = 0x00400000
}
public enum PointerButtonChangeType : ulong
{
POINTER_CHANGE_NONE,
POINTER_CHANGE_FIRSTBUTTON_DOWN,
POINTER_CHANGE_FIRSTBUTTON_UP,
POINTER_CHANGE_SECONDBUTTON_DOWN,
POINTER_CHANGE_SECONDBUTTON_UP,
POINTER_CHANGE_THIRDBUTTON_DOWN,
POINTER_CHANGE_THIRDBUTTON_UP,
POINTER_CHANGE_FOURTHBUTTON_DOWN,
POINTER_CHANGE_FOURTHBUTTON_UP,
POINTER_CHANGE_FIFTHBUTTON_DOWN,
POINTER_CHANGE_FIFTHBUTTON_UP
}
[Flags]
public enum PenFlags
{
PEN_FLAGS_NONE = 0x00000000,
PEN_FLAGS_BARREL = 0x00000001,
PEN_FLAGS_INVERTED = 0x00000002,
PEN_FLAGS_ERASER = 0x00000004,
}
[Flags]
public enum PenMask
{
PEN_MASK_NONE = 0x00000000,
PEN_MASK_PRESSURE = 0x00000001,
PEN_MASK_ROTATION = 0x00000002,
PEN_MASK_TILT_X = 0x00000004,
PEN_MASK_TILT_Y = 0x00000008
}
[Flags]
public enum TouchFlags
{
TOUCH_FLAG_NONE = 0x00000000
}
[Flags]
public enum TouchMask
{
TOUCH_MASK_NONE = 0x00000000,
TOUCH_MASK_CONTACTAREA = 0x00000001,
TOUCH_MASK_ORIENTATION = 0x00000002,
TOUCH_MASK_PRESSURE = 0x00000004,
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct POINTER_TOUCH_INFO
{
public POINTER_INFO pointerInfo;
public TouchFlags touchFlags;
public TouchMask touchMask;
public int rcContactLeft;
public int rcContactTop;
public int rcContactRight;
public int rcContactBottom;
public int rcContactRawLeft;
public int rcContactRawTop;
public int rcContactRawRight;
public int rcContactRawBottom;
public uint orientation;
public uint pressure;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct POINTER_PEN_INFO
{
public POINTER_INFO pointerInfo;
public PenFlags penFlags;
public PenMask penMask;
public uint pressure;
public uint rotation;
public int tiltX;
public int tiltY;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct POINTER_INFO
{
public PointerInputType pointerType;
public uint pointerId;
public uint frameId;
public PointerFlags pointerFlags;
public IntPtr sourceDevice;
public IntPtr hwndTarget;
public int ptPixelLocationX;
public int ptPixelLocationY;
public int ptHimetricLocationX;
public int ptHimetricLocationY;
public int ptPixelLocationRawX;
public int ptPixelLocationRawY;
public int ptHimetricLocationRawX;
public int ptHimetricLocationRawY;
public uint dwTime;
public uint historyCount;
public int inputData;
public ModifierKeys dwKeyStates;
public ulong PerformanceCount;
public PointerButtonChangeType ButtonChangeType;
}
[StructLayout(LayoutKind.Sequential)]
public struct RGBQUAD
{
@ -911,6 +1082,36 @@ namespace Avalonia.Win32.Interop
public const int SizeOf_BITMAPINFOHEADER = 40;
[DllImport("user32.dll", SetLastError = true)]
public static extern bool IsMouseInPointerEnabled();
[DllImport("user32.dll", SetLastError = true)]
public static extern int EnableMouseInPointer(bool enable);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetPointerCursorId(uint pointerId, out uint cursorId);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetPointerType(uint pointerId, out PointerInputType pointerType);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetPointerInfo(uint pointerId, out POINTER_INFO pointerInfo);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetPointerInfoHistory(uint pointerId, ref int entriesCount, [MarshalAs(UnmanagedType.LPArray), In, Out] POINTER_INFO[] pointerInfos);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetPointerPenInfo(uint pointerId, out POINTER_PEN_INFO penInfo);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetPointerPenInfoHistory(uint pointerId, ref int entriesCount, [MarshalAs(UnmanagedType.LPArray), In, Out] POINTER_PEN_INFO[] penInfos);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetPointerTouchInfo(uint pointerId, out POINTER_TOUCH_INFO touchInfo);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetPointerTouchInfoHistory(uint pointerId, ref int entriesCount, [MarshalAs(UnmanagedType.LPArray), In, Out] POINTER_TOUCH_INFO[] touchInfos);
[DllImport("user32.dll")]
public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip,
MonitorEnumDelegate lpfnEnum, IntPtr dwData);

1
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -68,6 +68,7 @@ namespace Avalonia
/// <remarks>
/// Multitouch allows a surface (a touchpad or touchscreen) to recognize the presence of more than one point of contact with the surface at the same time.
/// </remarks>
[Obsolete("Multitouch is always enabled on supported Windows versions")]
public bool? EnableMultitouch { get; set; } = true;
/// <summary>

429
src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

@ -1,4 +1,6 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;
@ -26,8 +28,8 @@ namespace Avalonia.Win32
uint timestamp = unchecked((uint)GetMessageTime());
RawInputEventArgs e = null;
var shouldTakeFocus = false;
switch ((WindowsMessage)msg)
var message = (WindowsMessage)msg;
switch (message)
{
case WindowsMessage.WM_ACTIVATE:
{
@ -82,7 +84,7 @@ namespace Avalonia.Win32
case WindowsMessage.WM_DESTROY:
{
UiaCoreProviderApi.UiaReturnRawElementProvider(_hwnd, IntPtr.Zero, IntPtr.Zero, null);
// We need to release IMM context and state to avoid leaks.
if (Imm32InputMethod.Current.HWND == _hwnd)
{
@ -108,9 +110,9 @@ namespace Avalonia.Win32
var newDisplayRect = Marshal.PtrToStructure<RECT>(lParam);
_scaling = dpi / 96.0;
ScalingChanged?.Invoke(_scaling);
using (SetResizeReason(PlatformResizeReason.DpiChange))
{
{
SetWindowPos(hWnd,
IntPtr.Zero,
newDisplayRect.left,
@ -178,6 +180,10 @@ namespace Avalonia.Win32
case WindowsMessage.WM_MBUTTONDOWN:
case WindowsMessage.WM_XBUTTONDOWN:
{
if (IsMouseInPointerEnabled)
{
break;
}
shouldTakeFocus = ShouldTakeFocusOnClick;
if (ShouldIgnoreTouchEmulatedMessage())
{
@ -188,7 +194,7 @@ namespace Avalonia.Win32
_mouseDevice,
timestamp,
_owner,
(WindowsMessage)msg switch
message switch
{
WindowsMessage.WM_LBUTTONDOWN => RawPointerEventType.LeftButtonDown,
WindowsMessage.WM_RBUTTONDOWN => RawPointerEventType.RightButtonDown,
@ -207,6 +213,10 @@ namespace Avalonia.Win32
case WindowsMessage.WM_MBUTTONUP:
case WindowsMessage.WM_XBUTTONUP:
{
if (IsMouseInPointerEnabled)
{
break;
}
if (ShouldIgnoreTouchEmulatedMessage())
{
break;
@ -216,7 +226,7 @@ namespace Avalonia.Win32
_mouseDevice,
timestamp,
_owner,
(WindowsMessage)msg switch
message switch
{
WindowsMessage.WM_LBUTTONUP => RawPointerEventType.LeftButtonUp,
WindowsMessage.WM_RBUTTONUP => RawPointerEventType.RightButtonUp,
@ -231,11 +241,19 @@ namespace Avalonia.Win32
}
// Mouse capture is lost
case WindowsMessage.WM_CANCELMODE:
_mouseDevice.Capture(null);
if (!IsMouseInPointerEnabled)
{
_mouseDevice.Capture(null);
}
break;
case WindowsMessage.WM_MOUSEMOVE:
{
if (IsMouseInPointerEnabled)
{
break;
}
if (ShouldIgnoreTouchEmulatedMessage())
{
break;
@ -259,42 +277,58 @@ namespace Avalonia.Win32
timestamp,
_owner,
RawPointerEventType.Move,
DipFromLParam(lParam), GetMouseModifiers(wParam));
DipFromLParam(lParam),
GetMouseModifiers(wParam));
break;
}
case WindowsMessage.WM_MOUSEWHEEL:
{
if (IsMouseInPointerEnabled)
{
break;
}
e = new RawMouseWheelEventArgs(
_mouseDevice,
timestamp,
_owner,
PointToClient(PointFromLParam(lParam)),
new Vector(0, (ToInt32(wParam) >> 16) / wheelDelta), GetMouseModifiers(wParam));
new Vector(0, (ToInt32(wParam) >> 16) / wheelDelta),
GetMouseModifiers(wParam));
break;
}
case WindowsMessage.WM_MOUSEHWHEEL:
{
if (IsMouseInPointerEnabled)
{
break;
}
e = new RawMouseWheelEventArgs(
_mouseDevice,
timestamp,
_owner,
PointToClient(PointFromLParam(lParam)),
new Vector(-(ToInt32(wParam) >> 16) / wheelDelta, 0), GetMouseModifiers(wParam));
new Vector(-(ToInt32(wParam) >> 16) / wheelDelta, 0),
GetMouseModifiers(wParam));
break;
}
case WindowsMessage.WM_MOUSELEAVE:
{
if (IsMouseInPointerEnabled)
{
break;
}
_trackingMouse = false;
e = new RawPointerEventArgs(
_mouseDevice,
timestamp,
_owner,
RawPointerEventType.LeaveWindow,
new Point(-1, -1), WindowsKeyboardDevice.Instance.Modifiers);
new Point(-1, -1),
WindowsKeyboardDevice.Instance.Modifiers);
break;
}
@ -303,11 +337,15 @@ namespace Avalonia.Win32
case WindowsMessage.WM_NCMBUTTONDOWN:
case WindowsMessage.WM_NCXBUTTONDOWN:
{
if (IsMouseInPointerEnabled)
{
break;
}
e = new RawPointerEventArgs(
_mouseDevice,
timestamp,
_owner,
(WindowsMessage)msg switch
message switch
{
WindowsMessage.WM_NCLBUTTONDOWN => RawPointerEventType
.NonClientLeftButtonDown,
@ -323,6 +361,10 @@ namespace Avalonia.Win32
}
case WindowsMessage.WM_TOUCH:
{
if (_wmPointerEnabled)
{
break;
}
var touchInputCount = wParam.ToInt32();
var pTouchInputs = stackalloc TOUCHINPUT[touchInputCount];
@ -348,6 +390,120 @@ namespace Avalonia.Win32
return IntPtr.Zero;
}
break;
}
case WindowsMessage.WM_NCPOINTERDOWN:
case WindowsMessage.WM_NCPOINTERUP:
case WindowsMessage.WM_POINTERDOWN:
case WindowsMessage.WM_POINTERUP:
case WindowsMessage.WM_POINTERUPDATE:
{
if (!_wmPointerEnabled)
{
break;
}
GetDevicePointerInfo(wParam, out var device, out var info, out var point, out var modifiers, ref timestamp);
var eventType = GetEventType(message, info);
var args = CreatePointerArgs(device, timestamp, eventType, point, modifiers, info.pointerId);
args.IntermediatePoints = CreateLazyIntermediatePoints(info);
e = args;
break;
}
case WindowsMessage.WM_POINTERDEVICEOUTOFRANGE:
case WindowsMessage.WM_POINTERLEAVE:
case WindowsMessage.WM_POINTERCAPTURECHANGED:
{
if (!_wmPointerEnabled)
{
break;
}
GetDevicePointerInfo(wParam, out var device, out var info, out var point, out var modifiers, ref timestamp);
var eventType = device is TouchDevice ? RawPointerEventType.TouchCancel : RawPointerEventType.LeaveWindow;
e = CreatePointerArgs(device, timestamp, eventType, point, modifiers, info.pointerId);
break;
}
case WindowsMessage.WM_POINTERWHEEL:
case WindowsMessage.WM_POINTERHWHEEL:
{
if (!_wmPointerEnabled)
{
break;
}
GetDevicePointerInfo(wParam, out var device, out var info, out var point, out var modifiers, ref timestamp);
var val = (ToInt32(wParam) >> 16) / wheelDelta;
var delta = message == WindowsMessage.WM_POINTERWHEEL ? new Vector(0, val) : new Vector(val, 0);
e = new RawMouseWheelEventArgs(device, timestamp, _owner, point.Position, delta, modifiers)
{
RawPointerId = info.pointerId
};
break;
}
case WindowsMessage.WM_POINTERDEVICEINRANGE:
{
if (!_wmPointerEnabled)
{
break;
}
// Do not generate events, but release mouse capture on any other device input.
GetDevicePointerInfo(wParam, out var device, out var info, out var point, out var modifiers, ref timestamp);
if (device != _mouseDevice)
{
_mouseDevice.Capture(null);
return IntPtr.Zero;
}
break;
}
case WindowsMessage.WM_POINTERACTIVATE:
{
//occurs when a pointer activates an inactive window.
//we should handle this and return PA_ACTIVATE or PA_NOACTIVATE
//https://docs.microsoft.com/en-us/previous-versions/windows/desktop/inputmsg/wm-pointeractivate
break;
}
case WindowsMessage.WM_POINTERDEVICECHANGE:
{
//notifies about changes in the settings of a monitor that has a digitizer attached to it.
//https://docs.microsoft.com/en-us/previous-versions/windows/desktop/inputmsg/wm-pointerdevicechange
break;
}
case WindowsMessage.WM_NCPOINTERUPDATE:
{
//NC stands for non-client area - window header and window border
//As I found above in an old message handling - we dont need to handle NC pointer move/updates.
//All we need is pointer down and up. So this is skipped for now.
break;
}
case WindowsMessage.WM_POINTERENTER:
{
//this is not handled by WM_MOUSEENTER so I think there is no need to handle this too.
//but we can detect a new pointer by this message and calling IS_POINTER_NEW_WPARAM
//note: by using a pen there can be a pointer leave or enter inside a window coords
//when you are just lift up the pen above the display
break;
}
case WindowsMessage.DM_POINTERHITTEST:
{
//DM stands for direct manipulation.
//https://docs.microsoft.com/en-us/previous-versions/windows/desktop/directmanipulation/direct-manipulation-portal
break;
}
case WindowsMessage.WM_TOUCHHITTESTING:
{
//This is to determine the most probable touch target.
//provides an input bounding box and receives hit proximity
//https://docs.microsoft.com/en-us/previous-versions/windows/desktop/inputmsg/wm-touchhittesting
//https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-touch_hit_testing_input
break;
}
case WindowsMessage.WM_PARENTNOTIFY:
{
//This message is sent in a dialog scenarios. Contains mouse position.
//Old message, but listed in the wm_pointer reference
//https://docs.microsoft.com/en-us/previous-versions/windows/desktop/inputmsg/wm-parentnotify
break;
}
case WindowsMessage.WM_NCPAINT:
@ -446,7 +602,7 @@ namespace Avalonia.Win32
case WindowsMessage.WM_GETMINMAXINFO:
{
MINMAXINFO mmi = Marshal.PtrToStructure<MINMAXINFO>(lParam);
_maxTrackSize = mmi.ptMaxTrackSize;
if (_minSize.Width > 0)
@ -530,7 +686,7 @@ namespace Avalonia.Win32
if (_managedDrag.PreprocessInputEvent(ref e))
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
#endif
if(shouldTakeFocus)
{
SetFocus(_hwnd);
@ -540,7 +696,7 @@ namespace Avalonia.Win32
{
Input(e);
if ((WindowsMessage)msg == WindowsMessage.WM_KEYDOWN)
if (message == WindowsMessage.WM_KEYDOWN)
{
// Handling a WM_KEYDOWN message should cause the subsequent WM_CHAR message to
// be ignored. This should be safe to do as WM_CHAR should only be produced in
@ -549,6 +705,11 @@ namespace Avalonia.Win32
_ignoreWmChar = e.Handled;
}
if (s_intermediatePointsPooledList.Count > 0)
{
s_intermediatePointsPooledList.Dispose();
}
if (e.Handled)
{
return IntPtr.Zero;
@ -561,6 +722,196 @@ namespace Avalonia.Win32
}
}
private unsafe Lazy<IReadOnlyList<RawPointerPoint>> CreateLazyIntermediatePoints(POINTER_INFO info)
{
var historyCount = Math.Min((int)info.historyCount, MaxPointerHistorySize);
if (historyCount > 1)
{
return new Lazy<IReadOnlyList<RawPointerPoint>>(() =>
{
s_intermediatePointsPooledList.Clear();
s_intermediatePointsPooledList.Capacity = historyCount;
// Pointers in history are ordered from newest to oldest, so we need to reverse iteration.
// Also we skip the newest pointer, because original event arguments already contains it.
if (info.pointerType == PointerInputType.PT_TOUCH)
{
if (GetPointerTouchInfoHistory(info.pointerId, ref historyCount, s_historyTouchInfos))
{
for (int i = historyCount - 1; i >= 1; i--)
{
var historyTouchInfo = s_historyTouchInfos[i];
s_intermediatePointsPooledList.Add(CreateRawPointerPoint(historyTouchInfo));
}
}
}
else if (info.pointerType == PointerInputType.PT_PEN)
{
if (GetPointerPenInfoHistory(info.pointerId, ref historyCount, s_historyPenInfos))
{
for (int i = historyCount - 1; i >= 1; i--)
{
var historyPenInfo = s_historyPenInfos[i];
s_intermediatePointsPooledList.Add(CreateRawPointerPoint(historyPenInfo));
}
}
}
else
{
// Currently Windows does not return history info for mouse input, but we handle it just for case.
if (GetPointerInfoHistory(info.pointerId, ref historyCount, s_historyInfos))
{
for (int i = historyCount - 1; i >= 1; i--)
{
var historyInfo = s_historyInfos[i];
s_intermediatePointsPooledList.Add(CreateRawPointerPoint(historyInfo));
}
}
}
return s_intermediatePointsPooledList;
});
}
return null;
}
private RawPointerEventArgs CreatePointerArgs(IInputDevice device, ulong timestamp, RawPointerEventType eventType, RawPointerPoint point, RawInputModifiers modifiers, uint rawPointerId)
{
return device is TouchDevice
? new RawTouchEventArgs(device, timestamp, _owner, eventType, point, modifiers, rawPointerId)
: new RawPointerEventArgs(device, timestamp, _owner, eventType, point, modifiers)
{
RawPointerId = rawPointerId
};
}
private void GetDevicePointerInfo(IntPtr wParam,
out IPointerDevice device, out POINTER_INFO info, out RawPointerPoint point,
out RawInputModifiers modifiers, ref uint timestamp)
{
var pointerId = (uint)(ToInt32(wParam) & 0xFFFF);
GetPointerType(pointerId, out var type);
modifiers = default;
switch (type)
{
case PointerInputType.PT_PEN:
device = _penDevice;
GetPointerPenInfo(pointerId, out var penInfo);
info = penInfo.pointerInfo;
point = CreateRawPointerPoint(penInfo);
if (penInfo.penFlags.HasFlag(PenFlags.PEN_FLAGS_BARREL))
{
modifiers |= RawInputModifiers.PenBarrelButton;
}
if (penInfo.penFlags.HasFlag(PenFlags.PEN_FLAGS_ERASER))
{
modifiers |= RawInputModifiers.PenEraser;
}
if (penInfo.penFlags.HasFlag(PenFlags.PEN_FLAGS_INVERTED))
{
modifiers |= RawInputModifiers.PenInverted;
}
break;
case PointerInputType.PT_TOUCH:
device = _touchDevice;
GetPointerTouchInfo(pointerId, out var touchInfo);
info = touchInfo.pointerInfo;
point = CreateRawPointerPoint(touchInfo);
break;
default:
device = _mouseDevice;
GetPointerInfo(pointerId, out info);
point = CreateRawPointerPoint(info);
break;
}
if (info.dwTime != 0)
{
timestamp = info.dwTime;
}
modifiers |= GetInputModifiers(info.pointerFlags);
}
private RawPointerPoint CreateRawPointerPoint(POINTER_INFO pointerInfo)
{
var point = PointToClient(new PixelPoint(pointerInfo.ptPixelLocationX, pointerInfo.ptPixelLocationY));
return new RawPointerPoint
{
Position = point
};
}
private RawPointerPoint CreateRawPointerPoint(POINTER_TOUCH_INFO info)
{
var pointerInfo = info.pointerInfo;
var point = PointToClient(new PixelPoint(pointerInfo.ptPixelLocationX, pointerInfo.ptPixelLocationY));
return new RawPointerPoint
{
Position = point,
// POINTER_PEN_INFO.pressure is normalized to a range between 0 and 1024, with 512 as a default.
// But in our API we use range from 0.0 to 1.0.
Pressure = info.pressure / 1024f
};
}
private RawPointerPoint CreateRawPointerPoint(POINTER_PEN_INFO info)
{
var pointerInfo = info.pointerInfo;
var point = PointToClient(new PixelPoint(pointerInfo.ptPixelLocationX, pointerInfo.ptPixelLocationY));
return new RawPointerPoint
{
Position = point,
// POINTER_PEN_INFO.pressure is normalized to a range between 0 and 1024, with 512 as a default.
// But in our API we use range from 0.0 to 1.0.
Pressure = info.pressure / 1024f,
Twist = info.rotation,
XTilt = info.tiltX,
YTilt = info.tiltY
};
}
private static RawPointerEventType GetEventType(WindowsMessage message, POINTER_INFO info)
{
var isTouch = info.pointerType == PointerInputType.PT_TOUCH;
if (info.pointerFlags.HasFlag(PointerFlags.POINTER_FLAG_CANCELED))
{
return isTouch ? RawPointerEventType.TouchCancel : RawPointerEventType.LeaveWindow;
}
var eventType = ToEventType(info.ButtonChangeType, isTouch);
if (eventType == RawPointerEventType.LeftButtonDown &&
message == WindowsMessage.WM_NCPOINTERDOWN)
{
eventType = RawPointerEventType.NonClientLeftButtonDown;
}
return eventType;
}
private static RawPointerEventType ToEventType(PointerButtonChangeType type, bool isTouch)
{
return type switch
{
PointerButtonChangeType.POINTER_CHANGE_FIRSTBUTTON_DOWN when isTouch => RawPointerEventType.TouchBegin,
PointerButtonChangeType.POINTER_CHANGE_FIRSTBUTTON_DOWN when !isTouch => RawPointerEventType.LeftButtonDown,
PointerButtonChangeType.POINTER_CHANGE_SECONDBUTTON_DOWN => RawPointerEventType.RightButtonDown,
PointerButtonChangeType.POINTER_CHANGE_THIRDBUTTON_DOWN => RawPointerEventType.MiddleButtonDown,
PointerButtonChangeType.POINTER_CHANGE_FOURTHBUTTON_DOWN => RawPointerEventType.XButton1Down,
PointerButtonChangeType.POINTER_CHANGE_FIFTHBUTTON_DOWN => RawPointerEventType.XButton2Down,
PointerButtonChangeType.POINTER_CHANGE_FIRSTBUTTON_UP when isTouch => RawPointerEventType.TouchEnd,
PointerButtonChangeType.POINTER_CHANGE_FIRSTBUTTON_UP when !isTouch => RawPointerEventType.LeftButtonUp,
PointerButtonChangeType.POINTER_CHANGE_SECONDBUTTON_UP => RawPointerEventType.RightButtonUp,
PointerButtonChangeType.POINTER_CHANGE_THIRDBUTTON_UP => RawPointerEventType.MiddleButtonUp,
PointerButtonChangeType.POINTER_CHANGE_FOURTHBUTTON_UP => RawPointerEventType.XButton1Up,
PointerButtonChangeType.POINTER_CHANGE_FIFTHBUTTON_UP => RawPointerEventType.XButton2Up,
_ when isTouch => RawPointerEventType.TouchUpdate,
_ => RawPointerEventType.Move
};
}
private void UpdateInputMethod(IntPtr hkl)
{
// note: for non-ime language, also create it so that emoji panel tracks cursor
@ -568,11 +919,11 @@ namespace Avalonia.Win32
if (langid == _langid && Imm32InputMethod.Current.HWND == Hwnd)
{
return;
}
}
_langid = langid;
Imm32InputMethod.Current.SetLanguageAndWindow(this, Hwnd, hkl);
}
private static int ToInt32(IntPtr ptr)
@ -597,10 +948,7 @@ namespace Avalonia.Win32
private bool ShouldIgnoreTouchEmulatedMessage()
{
if (!_multitouch)
{
return false;
}
// Note: GetMessageExtraInfo doesn't work with WM_POINTER events.
// MI_WP_SIGNATURE
// https://docs.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages
@ -613,6 +961,11 @@ namespace Avalonia.Win32
private static RawInputModifiers GetMouseModifiers(IntPtr wParam)
{
var keys = (ModifierKeys)ToInt32(wParam);
return GetInputModifiers(keys);
}
private static RawInputModifiers GetInputModifiers(ModifierKeys keys)
{
var modifiers = WindowsKeyboardDevice.Instance.Modifiers;
if (keys.HasAllFlags(ModifierKeys.MK_LBUTTON))
@ -642,5 +995,37 @@ namespace Avalonia.Win32
return modifiers;
}
private static RawInputModifiers GetInputModifiers(PointerFlags flags)
{
var modifiers = WindowsKeyboardDevice.Instance.Modifiers;
if (flags.HasAllFlags(PointerFlags.POINTER_FLAG_FIRSTBUTTON))
{
modifiers |= RawInputModifiers.LeftMouseButton;
}
if (flags.HasAllFlags(PointerFlags.POINTER_FLAG_SECONDBUTTON))
{
modifiers |= RawInputModifiers.RightMouseButton;
}
if (flags.HasAllFlags(PointerFlags.POINTER_FLAG_THIRDBUTTON))
{
modifiers |= RawInputModifiers.MiddleMouseButton;
}
if (flags.HasAllFlags(PointerFlags.POINTER_FLAG_FOURTHBUTTON))
{
modifiers |= RawInputModifiers.XButton1MouseButton;
}
if (flags.HasAllFlags(PointerFlags.POINTER_FLAG_FIFTHBUTTON))
{
modifiers |= RawInputModifiers.XButton2MouseButton;
}
return modifiers;
}
}
}

53
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using Avalonia.Controls;
using Avalonia.Automation.Peers;
@ -21,6 +22,7 @@ using Avalonia.Win32.OpenGl;
using Avalonia.Win32.WinRT;
using Avalonia.Win32.WinRT.Composition;
using static Avalonia.Win32.Interop.UnmanagedMethods;
using Avalonia.Collections.Pooled;
using Avalonia.Metadata;
namespace Avalonia.Win32
@ -68,18 +70,19 @@ namespace Avalonia.Win32
private const WindowStyles WindowStateMask = (WindowStyles.WS_MAXIMIZE | WindowStyles.WS_MINIMIZE);
private readonly TouchDevice _touchDevice;
private readonly MouseDevice _mouseDevice;
private readonly PenDevice _penDevice;
private readonly ManagedDeferredRendererLock _rendererLock;
private readonly FramebufferManager _framebuffer;
private readonly IGlPlatformSurface _gl;
private readonly bool _wmPointerEnabled;
private Win32NativeControlHost _nativeControlHost;
private WndProc _wndProcDelegate;
private string _className;
private IntPtr _hwnd;
private bool _multitouch;
private IInputRoot _owner;
private WindowProperties _windowProperties;
private bool _trackingMouse;
private bool _trackingMouse;//ToDo - there is something missed. Needs investigation @Steven Kirk
private bool _topmost;
private double _scaling = 1;
private WindowState _showWindowState;
@ -96,10 +99,17 @@ namespace Avalonia.Win32
private uint _langid;
private bool _ignoreWmChar;
private const int MaxPointerHistorySize = 512;
private static readonly PooledList<RawPointerPoint> s_intermediatePointsPooledList = new();
private static readonly POINTER_TOUCH_INFO[] s_historyTouchInfos = new POINTER_TOUCH_INFO[MaxPointerHistorySize];
private static readonly POINTER_PEN_INFO[] s_historyPenInfos = new POINTER_PEN_INFO[MaxPointerHistorySize];
private static readonly POINTER_INFO[] s_historyInfos = new POINTER_INFO[MaxPointerHistorySize];
public WindowImpl()
{
_touchDevice = new TouchDevice();
_mouseDevice = new WindowsMouseDevice();
_penDevice = new PenDevice();
#if USE_MANAGED_DRAG
_managedDrag = new ManagedWindowResizeDragHelper(this, capture =>
@ -128,6 +138,8 @@ namespace Avalonia.Win32
egl.Display is AngleWin32EglDisplay angleDisplay &&
angleDisplay.PlatformApi == AngleOptions.PlatformApi.DirectX11;
_wmPointerEnabled = Win32Platform.WindowsVersion >= PlatformConstants.Windows8;
CreateWindow();
_framebuffer = new FramebufferManager(_hwnd);
UpdateInputMethod(GetKeyboardLayout(0));
@ -208,6 +220,8 @@ namespace Avalonia.Win32
}
}
private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.Primary)?.PixelDensity ?? 1;
public double RenderScaling => _scaling;
public double DesktopScaling => RenderScaling;
@ -280,6 +294,8 @@ namespace Avalonia.Win32
protected IntPtr Hwnd => _hwnd;
private bool IsMouseInPointerEnabled => _wmPointerEnabled && IsMouseInPointerEnabled();
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
{
TransparencyLevel = EnableBlur(transparencyLevel);
@ -469,10 +485,14 @@ namespace Avalonia.Win32
{
GetWindowRect(_hwnd, out var rc);
return new PixelPoint(rc.left, rc.top);
var border = HiddenBorderSize;
return new PixelPoint(rc.left + border.Width, rc.top + border.Height);
}
set
{
var border = HiddenBorderSize;
value = new PixelPoint(value.X - border.Width, value.Y - border.Height);
SetWindowPos(
Handle.Handle,
IntPtr.Zero,
@ -486,6 +506,24 @@ namespace Avalonia.Win32
private bool HasFullDecorations => _windowProperties.Decorations == SystemDecorations.Full;
private PixelSize HiddenBorderSize
{
get
{
// Windows 10 and 11 add a 7 pixel invisible border on the left/right/bottom of windows for resizing
if (Win32Platform.WindowsVersion.Major < 10 || !HasFullDecorations)
{
return PixelSize.Empty;
}
DwmGetWindowAttribute(_hwnd, (int)DwmWindowAttribute.DWMWA_EXTENDED_FRAME_BOUNDS, out var clientRect, Marshal.SizeOf(typeof(RECT)));
GetWindowRect(_hwnd, out var frameRect);
var borderWidth = GetSystemMetrics(SystemMetric.SM_CXBORDER);
return new PixelSize(clientRect.left - frameRect.left - borderWidth, 0);
}
}
public void Move(PixelPoint point) => Position = point;
public void SetMinMaxSize(Size minSize, Size maxSize)
@ -790,12 +828,7 @@ namespace Avalonia.Win32
Handle = new WindowImplPlatformHandle(this);
_multitouch = Win32Platform.Options.EnableMultitouch ?? true;
if (_multitouch)
{
RegisterTouchWindow(_hwnd, 0);
}
RegisterTouchWindow(_hwnd, 0);
if (ShCoreAvailable && Win32Platform.WindowsVersion > PlatformConstants.Windows8)
{
@ -922,7 +955,7 @@ namespace Avalonia.Win32
if (WindowState == WindowState.Maximized)
{
_extendedMargins = new Thickness(0, (borderCaptionThickness.top - borderThickness.top) / RenderScaling, 0, 0);
_offScreenMargin = new Thickness(borderThickness.left / RenderScaling, borderThickness.top / RenderScaling, borderThickness.right / RenderScaling, borderThickness.bottom / RenderScaling);
_offScreenMargin = new Thickness(borderThickness.left / PrimaryScreenRenderScaling, borderThickness.top / PrimaryScreenRenderScaling, borderThickness.right / PrimaryScreenRenderScaling, borderThickness.bottom / PrimaryScreenRenderScaling);
}
else
{

52
tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs

@ -189,7 +189,7 @@ namespace Avalonia.Base.UnitTests.Input
// Ensure that e.Handled is reset between controls.
root.PointerMoved += (s, e) => e.Handled = true;
decorator.PointerEnter += (s, e) => e.Handled = true;
decorator.PointerEntered += (s, e) => e.Handled = true;
SetHit(renderer, decorator);
impl.Object.Input!(CreateRawPointerMovedArgs(device, root));
@ -231,7 +231,7 @@ namespace Avalonia.Base.UnitTests.Input
}
});
AddEnterLeaveHandlers(HandleEvent, canvas, decorator);
AddEnteredExitedHandlers(HandleEvent, canvas, decorator);
// Enter decorator
SetHit(renderer, decorator);
@ -246,17 +246,17 @@ namespace Avalonia.Base.UnitTests.Input
Assert.Equal(
new[]
{
((object?)decorator, "PointerEnter"),
(decorator, "PointerMoved"),
(decorator, "PointerLeave"),
(canvas, "PointerEnter"),
(canvas, "PointerMoved")
((object?)decorator, nameof(InputElement.PointerEntered)),
(decorator, nameof(InputElement.PointerMoved)),
(decorator, nameof(InputElement.PointerExited)),
(canvas, nameof(InputElement.PointerEntered)),
(canvas, nameof(InputElement.PointerMoved))
},
result);
}
[Fact]
public void PointerEnter_Leave_Should_Be_Raised_In_Correct_Order()
public void PointerEntered_Exited_Should_Be_Raised_In_Correct_Order()
{
using var app = UnitTestApplication.Start(new TestServices(inputManager: new InputManager()));
@ -289,7 +289,7 @@ namespace Avalonia.Base.UnitTests.Input
SetHit(renderer, canvas);
impl.Object.Input!(CreateRawPointerMovedArgs(deviceMock.Object, root));
AddEnterLeaveHandlers(HandleEvent, root, canvas, border, decorator);
AddEnteredExitedHandlers(HandleEvent, root, canvas, border, decorator);
SetHit(renderer, decorator);
impl.Object.Input!(CreateRawPointerMovedArgs(deviceMock.Object, root));
@ -297,16 +297,16 @@ namespace Avalonia.Base.UnitTests.Input
Assert.Equal(
new[]
{
((object?)canvas, "PointerLeave"),
(decorator, "PointerEnter"),
(border, "PointerEnter"),
((object?)canvas, nameof(InputElement.PointerExited)),
(decorator, nameof(InputElement.PointerEntered)),
(border, nameof(InputElement.PointerEntered)),
},
result);
}
// https://github.com/AvaloniaUI/Avalonia/issues/7896
[Fact]
public void PointerEnter_Leave_Should_Set_Correct_Position()
public void PointerEntered_Exited_Should_Set_Correct_Position()
{
using var app = UnitTestApplication.Start(new TestServices(inputManager: new InputManager()));
@ -331,7 +331,7 @@ namespace Avalonia.Base.UnitTests.Input
}
});
AddEnterLeaveHandlers(HandleEvent, root, canvas);
AddEnteredExitedHandlers(HandleEvent, root, canvas);
SetHit(renderer, canvas);
impl.Object.Input!(CreateRawPointerMovedArgs(deviceMock.Object, root, expectedPosition));
@ -342,10 +342,10 @@ namespace Avalonia.Base.UnitTests.Input
Assert.Equal(
new[]
{
((object?)canvas, "PointerEnter", expectedPosition),
(root, "PointerEnter", expectedPosition),
(canvas, "PointerLeave", expectedPosition),
(root, "PointerLeave", expectedPosition)
((object?)canvas, nameof(InputElement.PointerEntered), expectedPosition),
(root, nameof(InputElement.PointerEntered), expectedPosition),
(canvas, nameof(InputElement.PointerExited), expectedPosition),
(root, nameof(InputElement.PointerExited), expectedPosition)
},
result);
}
@ -415,7 +415,7 @@ namespace Avalonia.Base.UnitTests.Input
}
});
AddEnterLeaveHandlers(HandleEvent, root, canvas);
AddEnteredExitedHandlers(HandleEvent, root, canvas);
// Init pointer over.
SetHit(renderer, canvas);
@ -429,22 +429,22 @@ namespace Avalonia.Base.UnitTests.Input
Assert.Equal(
new[]
{
((object?)canvas, "PointerEnter", lastClientPosition),
(root, "PointerEnter", lastClientPosition),
(canvas, "PointerLeave", lastClientPosition),
(root, "PointerLeave", lastClientPosition),
((object?)canvas, nameof(InputElement.PointerEntered), lastClientPosition),
(root, nameof(InputElement.PointerEntered), lastClientPosition),
(canvas, nameof(InputElement.PointerExited), lastClientPosition),
(root, nameof(InputElement.PointerExited), lastClientPosition),
},
result);
}
private static void AddEnterLeaveHandlers(
private static void AddEnteredExitedHandlers(
EventHandler<PointerEventArgs> handler,
params IInputElement[] controls)
{
foreach (var c in controls)
{
c.PointerEnter += handler;
c.PointerLeave += handler;
c.PointerEntered += handler;
c.PointerExited += handler;
c.PointerMoved += handler;
}
}

24
tests/Avalonia.Base.UnitTests/Input/TouchDeviceTests.cs

@ -219,30 +219,36 @@ namespace Avalonia.Input.UnitTests
{
for (int i = 0; i < touchPointIds.Length; i++)
{
inputManager.ProcessInput(new RawTouchEventArgs(device, 0,
inputManager.ProcessInput(new RawPointerEventArgs(device, 0,
root,
type,
new Point(0, 0),
RawInputModifiers.None,
touchPointIds[i]));
RawInputModifiers.None)
{
RawPointerId = touchPointIds[i]
});
}
}
private static void TapOnce(IInputManager inputManager, TouchDevice device, IInputRoot root, ulong timestamp = 0, long touchPointId = 0)
{
inputManager.ProcessInput(new RawTouchEventArgs(device, timestamp,
inputManager.ProcessInput(new RawPointerEventArgs(device, timestamp,
root,
RawPointerEventType.TouchBegin,
new Point(0, 0),
RawInputModifiers.None,
touchPointId));
inputManager.ProcessInput(new RawTouchEventArgs(device, timestamp,
RawInputModifiers.None)
{
RawPointerId = touchPointId
});
inputManager.ProcessInput(new RawPointerEventArgs(device, timestamp,
root,
RawPointerEventType.TouchEnd,
new Point(0, 0),
RawInputModifiers.None,
touchPointId));
RawInputModifiers.None)
{
RawPointerId = touchPointId
});
}
}
}

31
tests/Avalonia.Base.UnitTests/Layout/LayoutableTests.cs

@ -173,37 +173,6 @@ namespace Avalonia.Base.UnitTests.Layout
target.Verify(x => x.InvalidateMeasure(root), Times.Once());
}
[Theory]
[InlineData(16, 6, 5.333333333333333)]
[InlineData(18, 10, 4)]
public void UseLayoutRounding_Arranges_Center_Alignment_Correctly_With_Fractional_Scaling(
double containerWidth,
double childWidth,
double expectedX)
{
Border target;
var root = new TestRoot
{
LayoutScaling = 1.5,
UseLayoutRounding = true,
Child = new Decorator
{
Width = containerWidth,
Height = 100,
Child = target = new Border
{
Width = childWidth,
HorizontalAlignment = HorizontalAlignment.Center,
}
}
};
root.Measure(new Size(100, 100));
root.Arrange(new Rect(target.DesiredSize));
Assert.Equal(new Rect(expectedX, 0, childWidth, 100), target.Bounds);
}
[Fact]
public void LayoutUpdated_Is_Called_At_End_Of_Layout_Pass()
{

140
tests/Avalonia.Base.UnitTests/Layout/LayoutableTests_LayoutRounding.cs

@ -0,0 +1,140 @@
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.UnitTests;
using Xunit;
using Xunit.Sdk;
namespace Avalonia.Base.UnitTests.Layout
{
public class LayoutableTests_LayoutRounding
{
[Theory]
[InlineData(100, 100)]
[InlineData(101, 101.33333333333333)]
[InlineData(103, 103.33333333333333)]
public void Measure_Adjusts_DesiredSize_Upwards_When_Constraint_Allows(double desiredSize, double expectedSize)
{
var target = new TestLayoutable(new Size(desiredSize, desiredSize));
var root = CreateRoot(1.5, target);
root.LayoutManager.ExecuteInitialLayoutPass();
Assert.Equal(new Size(expectedSize, expectedSize), target.DesiredSize);
}
[Fact]
public void Measure_Constrains_Adjusted_DesiredSize_To_Constraint()
{
var target = new TestLayoutable(new Size(101, 101));
var root = CreateRoot(1.5, target, constraint: new Size(101, 101));
root.LayoutManager.ExecuteInitialLayoutPass();
// Desired width/height with layout rounding is 101.3333 but constraint is 101,101 so
// layout rounding should be ignored.
Assert.Equal(new Size(101, 101), target.DesiredSize);
}
[Fact]
public void Measure_Adjusts_DesiredSize_Upwards_When_Margin_Present()
{
var target = new TestLayoutable(new Size(101, 101), margin: 1);
var root = CreateRoot(1.5, target);
root.LayoutManager.ExecuteInitialLayoutPass();
// - 1 pixel margin is rounded up to 1.3333; for both sides it is 2.6666
// - Size of 101 gets rounded up to 101.3333
// - Final size = 101.3333 + 2.6666 = 104
AssertEqual(new Size(104, 104), target.DesiredSize);
}
[Fact]
public void Arrange_Adjusts_Bounds_Upwards_With_Margin()
{
var target = new TestLayoutable(new Size(101, 101), margin: 1);
var root = CreateRoot(1.5, target);
root.LayoutManager.ExecuteInitialLayoutPass();
// - 1 pixel margin is rounded up to 1.3333
// - Size of 101 gets rounded up to 101.3333
AssertEqual(new Point(1.3333333333333333, 1.3333333333333333), target.Bounds.Position);
AssertEqual(new Size(101.33333333333333, 101.33333333333333), target.Bounds.Size);
}
[Theory]
[InlineData(16, 6, 5.333333333333333)]
[InlineData(18, 10, 4)]
public void Arranges_Center_Alignment_Correctly_With_Fractional_Scaling(
double containerWidth,
double childWidth,
double expectedX)
{
Border target;
var root = new TestRoot
{
LayoutScaling = 1.5,
UseLayoutRounding = true,
Child = new Decorator
{
Width = containerWidth,
Height = 100,
Child = target = new Border
{
Width = childWidth,
HorizontalAlignment = HorizontalAlignment.Center,
}
}
};
root.Measure(new Size(100, 100));
root.Arrange(new Rect(target.DesiredSize));
Assert.Equal(new Rect(expectedX, 0, childWidth, 100), target.Bounds);
}
private static TestRoot CreateRoot(
double scaling,
Control child,
Size? constraint = null)
{
return new TestRoot
{
LayoutScaling = scaling,
UseLayoutRounding = true,
Child = child,
ClientSize = constraint ?? new Size(1000, 1000),
};
}
private static void AssertEqual(Point expected, Point actual)
{
if (!expected.NearlyEquals(actual))
{
throw new EqualException(expected, actual);
}
}
private static void AssertEqual(Size expected, Size actual)
{
if (!expected.NearlyEquals(actual))
{
throw new EqualException(expected, actual);
}
}
private class TestLayoutable : Control
{
private Size _desiredSize;
public TestLayoutable(Size desiredSize, double margin = 0)
{
_desiredSize = desiredSize;
Margin = new Thickness(margin);
}
protected override Size MeasureOverride(Size availableSize) => _desiredSize;
}
}
}

2
tests/Avalonia.Base.UnitTests/Media/TextFormatting/BiDiAlgorithmTests.cs

@ -27,7 +27,7 @@ namespace Avalonia.Visuals.UnitTests.Media.TextFormatting
private bool Run(BiDiTestData testData)
{
var bidi = BidiAlgorithm.Instance.Value;
var bidi = new BidiAlgorithm();
// Run the algorithm...
ArraySlice<sbyte> resultLevels;

9
tests/Avalonia.Base.UnitTests/Media/TextFormatting/BiDiClassTests.cs

@ -30,7 +30,7 @@ namespace Avalonia.Visuals.UnitTests.Media.TextFormatting
private bool Run(BiDiClassData t)
{
var bidi = BidiAlgorithm.Instance.Value;
var bidi = new BidiAlgorithm();
var bidiData = new BidiData(t.ParagraphLevel);
var text = Encoding.UTF32.GetString(MemoryMarshal.Cast<int, byte>(t.CodePoints).ToArray());
@ -39,9 +39,12 @@ namespace Avalonia.Visuals.UnitTests.Media.TextFormatting
bidiData.Append(text.AsMemory());
// Act
bidi.Process(bidiData);
for (int i = 0; i < 10; i++)
{
bidi.Process(bidiData);
}
var resultLevels = bidi.ResolvedLevels;
var resultLevels = bidi.ResolvedLevels;
var resultParagraphLevel = bidi.ResolvedParagraphEmbeddingLevel;
// Assert

2
tests/Avalonia.Base.UnitTests/Media/TextFormatting/BiDiTestDataGenerator.cs

@ -129,6 +129,8 @@ namespace Avalonia.Visuals.UnitTests.Media.TextFormatting
ParagraphEmbeddingLevel = paragraphEmbeddingLevel,
Levels = levels
});
break;
}
}
}

9
tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakClassTrieGenerator.cs

@ -19,11 +19,6 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
var trie = GenerateBreakTypeTrie();
UnicodeDataGenerator.GenerateTrieClass("GraphemeBreak", trie);
using (var stream = File.Create("Generated\\GraphemeBreak.trie"))
{
trie.Save(stream);
}
}
private static UnicodeTrie GenerateBreakTypeTrie()
@ -38,9 +33,9 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
{
foreach (var (start, end, graphemeBreakType) in breakData)
{
if (!Enum.TryParse<GraphemeBreakClass>(graphemeBreakType, out var value))
if (!Enum.TryParse<GraphemeBreakClass>(graphemeBreakType.Replace("_", ""), out var value))
{
continue;
continue;
}
if (start == end)

84
tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakClassTrieGeneratorTests.cs

@ -1,6 +1,10 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using Avalonia.Media.TextFormatting.Unicode;
using Avalonia.Visuals.UnitTests.Media.TextFormatting;
using Xunit;
using Xunit.Abstractions;
namespace Avalonia.Base.UnitTests.Media.TextFormatting
{
@ -10,20 +14,74 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
/// </summary>
public class GraphemeBreakClassTrieGeneratorTests
{
[Theory(Skip = "Only run when we update the trie.")]
[ClassData(typeof(GraphemeBreakTestDataGenerator))]
public void Should_Enumerate(string text, int expectedLength)
private readonly ITestOutputHelper _outputHelper;
public GraphemeBreakClassTrieGeneratorTests(ITestOutputHelper outputHelper)
{
var textMemory = text.AsMemory();
_outputHelper = outputHelper;
}
var enumerator = new GraphemeEnumerator(textMemory);
[Fact(/*Skip = "Only run when we update the trie."*/)]
public void Should_Enumerate()
{
var generator = new GraphemeBreakTestDataGenerator();
Assert.True(enumerator.MoveNext());
foreach (var testData in generator)
{
Assert.True(Run(testData));
}
}
Assert.Equal(expectedLength, enumerator.Current.Text.Length);
private bool Run(GraphemeBreakData t)
{
var text = Encoding.UTF32.GetString(MemoryMarshal.Cast<int, byte>(t.Codepoints).ToArray());
var grapheme = Encoding.UTF32.GetString(MemoryMarshal.Cast<int, byte>(t.Grapheme).ToArray()).AsSpan();
var enumerator = new GraphemeEnumerator(text.AsMemory());
enumerator.MoveNext();
var actual = enumerator.Current.Text.Span;
var pass = true;
if(actual.Length != grapheme.Length)
{
pass = false;
}
if (pass)
{
for (int i = 0; i < grapheme.Length; i++)
{
var a = grapheme[i];
var b = actual[i];
if (a != b)
{
pass = false;
break;
}
}
}
if (!pass)
{
_outputHelper.WriteLine($"Failed line {t.LineNumber}");
_outputHelper.WriteLine($" Text: {text}");
_outputHelper.WriteLine($" Codepoints: {string.Join(" ", t.Codepoints)}");
_outputHelper.WriteLine($" Grapheme: {string.Join(" ", t.Grapheme)}");
_outputHelper.WriteLine($" Line: {t.Line}");
return false;
}
return true;
}
[Fact(Skip = "Only run when we update the trie.")]
[Fact(/*Skip = "Only run when we update the trie."*/)]
public void Should_Enumerate_Other()
{
const string text = "ABCDEFGHIJ";
@ -44,18 +102,10 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
Assert.Equal(10, count);
}
[Fact(Skip = "Only run when we update the trie.")]
[Fact(/*Skip = "Only run when we update the trie."*/)]
public void Should_Generate_Trie()
{
GraphemeBreakClassTrieGenerator.Execute();
}
private class GraphemeBreakTestDataGenerator : TestDataGenerator
{
public GraphemeBreakTestDataGenerator()
: base("auxiliary/GraphemeBreakTest.txt")
{
}
}
}
}

108
tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakTestDataGenerator.cs

@ -0,0 +1,108 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using Avalonia.Base.UnitTests.Media.TextFormatting;
namespace Avalonia.Visuals.UnitTests.Media.TextFormatting
{
internal class GraphemeBreakTestDataGenerator : IEnumerable<GraphemeBreakData>
{
private readonly List<GraphemeBreakData> _testData;
public GraphemeBreakTestDataGenerator()
{
_testData = ReadData();
}
public IEnumerator<GraphemeBreakData> GetEnumerator()
{
return _testData.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private static List<GraphemeBreakData> ReadData()
{
var testData = new List<GraphemeBreakData>();
var url = Path.Combine(UnicodeDataGenerator.Ucd, "auxiliary/GraphemeBreakTest.txt");
using (var client = new HttpClient())
using (var result = client.GetAsync(url).GetAwaiter().GetResult())
{
if (!result.IsSuccessStatusCode)
{
return testData;
}
using (var stream = result.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
using (var reader = new StreamReader(stream))
{
var lineNumber = 0;
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
lineNumber++;
if (line == null)
{
break;
}
if (line.StartsWith("#") || string.IsNullOrEmpty(line))
{
continue;
}
var elements = line.Split('#');
elements = elements[0].Replace("÷\t", "÷").Trim('÷').Split('÷');
var graphemeChars = elements[0].Replace(" × ", " ").Split(' ');
var codepoints = graphemeChars.Where(x => x != "" && x != "×")
.Select(x => Convert.ToInt32(x, 16)).ToList();
var grapheme = codepoints.ToArray();
if(elements.Length > 1)
{
var remainingChars = elements[1].Replace(" × ", " ").Split(' ');
var remaining = remainingChars.Where(x => x != "" && x != "×").Select(x => Convert.ToInt32(x, 16)).ToArray();
codepoints.AddRange(remaining);
}
var data = new GraphemeBreakData
{
Line = line,
LineNumber = lineNumber,
Grapheme = grapheme,
Codepoints = codepoints.ToArray()
};
testData.Add(data);
}
}
}
return testData;
}
}
internal struct GraphemeBreakData
{
public string Line { get; set; }
public int LineNumber { get; set; }
public int[] Grapheme { get; set; }
public int[] Codepoints{ get; set; }
}
}

2
tests/Avalonia.Base.UnitTests/Media/TextFormatting/LineBreakEnumuratorTests.cs

@ -134,7 +134,7 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
_outputHelper.WriteLine($"Expected Breaks: {string.Join(" ", breakPoints)}");
_outputHelper.WriteLine($" Actual Breaks: {string.Join(" ", foundBreaks)}");
_outputHelper.WriteLine($" Text: {text}");
_outputHelper.WriteLine($" Char Props: {string.Join(" ", codePoints.Select(x => new Codepoint(x).LineBreakClass))}");
_outputHelper.WriteLine($" Char Props: {string.Join(" ", codePoints.Select(x => new Codepoint((uint)x).LineBreakClass))}");
_outputHelper.WriteLine("");
}

85
tests/Avalonia.Base.UnitTests/Media/TextFormatting/TestDataGenerator.cs

@ -1,85 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
namespace Avalonia.Base.UnitTests.Media.TextFormatting
{
public abstract class TestDataGenerator : IEnumerable<object[]>
{
private readonly string _fileName;
private readonly List<object[]> _testData;
protected TestDataGenerator(string fileName)
{
_fileName = fileName;
_testData = ReadTestData();
}
public IEnumerator<object[]> GetEnumerator()
{
return _testData.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private List<object[]> ReadTestData()
{
var testData = new List<object[]>();
using (var client = new HttpClient())
{
var url = Path.Combine(UnicodeDataGenerator.Ucd, _fileName);
using (var result = client.GetAsync(url).GetAwaiter().GetResult())
{
if (!result.IsSuccessStatusCode)
return testData;
using (var stream = result.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
using (var reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (line == null)
{
break;
}
if (line.StartsWith("#") || string.IsNullOrEmpty(line))
{
continue;
}
var elements = line.Split('#');
elements = elements[0].Replace("÷\t", "÷").Trim('÷').Split('÷');
var chars = elements[0].Replace(" × ", " ").Split(' ');
var codepoints = chars.Where(x => x != "" && x != "×")
.Select(x => Convert.ToInt32(x, 16)).ToArray();
var text = string.Join(null, codepoints.Select(char.ConvertFromUtf32));
var length = codepoints.Select(x => x > ushort.MaxValue ? 2 : 1).Sum();
var data = new object[] { text, length };
testData.Add(data);
}
}
}
}
return testData;
}
}
}

58
tests/Avalonia.Base.UnitTests/Media/TextFormatting/UnicodeDataGenerator.cs

@ -10,22 +10,22 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
{
internal static class UnicodeDataGenerator
{
public const string Ucd = "https://www.unicode.org/Public/13.0.0/ucd/";
public const string Ucd = "https://www.unicode.org/Public/14.0.0/ucd/";
public static UnicodeTrie GenerateBiDiTrie(out BiDiDataEntries biDiDataEntries,out Dictionary<int, BiDiDataItem> biDiData)
public static UnicodeTrie GenerateBiDiTrie(out BiDiDataEntries biDiDataEntries, out Dictionary<int, BiDiDataItem> biDiData)
{
biDiData = new Dictionary<int, BiDiDataItem>();
var biDiClassEntries =
UnicodeEnumsGenerator.CreateBiDiClassEnum();
var bidiClassEntries =
UnicodeEnumsGenerator.CreateBidiClassEnum();
var biDiClassMappings = CreateTagToIndexMappings(biDiClassEntries);
var bidiClassMappings = CreateTagToIndexMappings(bidiClassEntries);
var biDiClassData = ReadBiDiData();
var bidiClassData = ReadBiDiData();
foreach (var (range, name) in biDiClassData)
foreach (var (range, name) in bidiClassData)
{
var biDiClass = biDiClassMappings[name];
var biDiClass = bidiClassMappings[name];
AddBiDiClassRange(biDiData, range, biDiClass);
}
@ -56,19 +56,14 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
biDiDataEntries = new BiDiDataEntries()
{
PairedBracketTypes = biDiPairedBracketTypeEntries, BiDiClasses = biDiClassEntries
PairedBracketTypes = biDiPairedBracketTypeEntries, BiDiClasses = bidiClassEntries
};
var trie = biDiTrieBuilder.Freeze();
GenerateTrieClass("BiDi", trie);
using (var stream = File.Create("Generated\\BiDi.trie"))
{
trie.Save(stream);
GenerateTrieClass("Bidi", trie);
return trie;
}
return trie;
}
public static void GenerateTrieClass(string name, UnicodeTrie trie)
@ -92,6 +87,8 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
writer.Write(" ");
long length = stream.Length;
while (true)
{
var b = stream.ReadByte();
@ -100,18 +97,22 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
{
break;
}
writer.Write(b.ToString());
writer.Write(',');
writer.Write(b.ToString());
if (stream.Position % 100 == 0)
if (stream.Position % 100 > 0 && stream.Position != length)
{
writer.Write(", ");
}
else
{
writer.Write(',');
writer.Write(Environment.NewLine);
writer.Write(" ");
continue;
if (stream.Position != length)
{
writer.Write(" ");
}
}
}
@ -161,12 +162,7 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
GenerateTrieClass("UnicodeData", trie);
using (var stream = File.Create("Generated\\UnicodeData.trie"))
{
trie.Save(stream);
return trie;
}
return trie;
}
private static Dictionary<int, UnicodeDataItem> GetUnicodeData(IReadOnlyDictionary<string, int> generalCategoryMappings,
@ -461,9 +457,7 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
public int BracketType { get; set; }
public int BiDiClass { get; set; }
}
}
}
internal class UnicodeDataEntries

4
tests/Avalonia.Base.UnitTests/Media/TextFormatting/UnicodeDataGeneratorTests.cs

@ -22,7 +22,7 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
foreach (var value in unicodeData.Values)
{
var data = unicodeDataTrie.Get(value.Codepoint);
var data = unicodeDataTrie.Get((uint)value.Codepoint);
Assert.Equal(value.GeneralCategory, GetValue(data, 0, UnicodeData.CATEGORY_MASK));
@ -35,7 +35,7 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
foreach (var value in biDiData.Values)
{
var data = biDiTrie.Get(value.Codepoint);
var data = biDiTrie.Get((uint)value.Codepoint);
Assert.Equal(value.Bracket, GetValue(data, 0, UnicodeData.BIDIPAIREDBRACKED_MASK));

10
tests/Avalonia.Base.UnitTests/Media/TextFormatting/UnicodeEnumsGenerator.cs

@ -244,18 +244,18 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
return orderedLineBreakEntries.Values.ToList();
}
public static List<DataEntry> CreateBiDiClassEnum()
public static List<DataEntry> CreateBidiClassEnum()
{
var entries = new List<DataEntry> { new DataEntry("Left_To_Right", "L", string.Empty) };
ParseDataEntries("# Bidi_Class (bc)", entries);
using (var stream = File.Create("Generated\\BiDiClass.cs"))
using (var stream = File.Create("Generated\\BidiClass.cs"))
using (var writer = new StreamWriter(stream))
{
writer.WriteLine("namespace Avalonia.Media.TextFormatting.Unicode");
writer.WriteLine("{");
writer.WriteLine(" public enum BiDiClass");
writer.WriteLine(" public enum BidiClass");
writer.WriteLine(" {");
foreach (var entry in entries)
@ -277,12 +277,12 @@ namespace Avalonia.Base.UnitTests.Media.TextFormatting
ParseDataEntries("# Bidi_Paired_Bracket_Type (bpt)", entries);
using (var stream = File.Create("Generated\\BiDiPairedBracketType.cs"))
using (var stream = File.Create("Generated\\BidiPairedBracketType.cs"))
using (var writer = new StreamWriter(stream))
{
writer.WriteLine("namespace Avalonia.Media.TextFormatting.Unicode");
writer.WriteLine("{");
writer.WriteLine(" public enum BiDiPairedBracketType");
writer.WriteLine(" public enum BidiPairedBracketType");
writer.WriteLine(" {");
foreach (var entry in entries)

64
tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs

@ -594,6 +594,69 @@ namespace Avalonia.Base.UnitTests.Rendering.SceneGraph
}
}
[Fact]
public void Should_Update_When_Control_Moved_Causing_Layout_Change()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
{
Decorator moveFrom;
Decorator moveTo;
Canvas moveMe;
var tree = new TestRoot
{
Width = 100,
Height = 100,
Child = new DockPanel
{
Children =
{
(moveFrom = new Decorator
{
Child = moveMe = new Canvas
{
Width = 100,
Height = 100,
},
}),
(moveTo = new Decorator()),
}
}
};
tree.Measure(Size.Infinity);
tree.Arrange(new Rect(tree.DesiredSize));
var scene = new Scene(tree);
var sceneBuilder = new SceneBuilder();
sceneBuilder.UpdateAll(scene);
var moveFromNode = (VisualNode)scene.FindNode(moveFrom);
var moveToNode = (VisualNode)scene.FindNode(moveTo);
Assert.Equal(1, moveFromNode.Children.Count);
Assert.Same(moveMe, moveFromNode.Children[0].Visual);
Assert.Empty(moveToNode.Children);
moveFrom.Child = null;
moveTo.Child = moveMe;
tree.LayoutManager.ExecuteLayoutPass();
scene = scene.CloneScene();
moveFromNode = (VisualNode)scene.FindNode(moveFrom);
moveToNode = (VisualNode)scene.FindNode(moveTo);
moveFromNode.SortChildren(scene);
moveToNode.SortChildren(scene);
sceneBuilder.Update(scene, moveFrom);
sceneBuilder.Update(scene, moveTo);
sceneBuilder.Update(scene, moveMe);
Assert.Empty(moveFromNode.Children);
Assert.Equal(1, moveToNode.Children.Count);
Assert.Same(moveMe, moveToNode.Children[0].Visual);
}
}
[Fact]
public void Should_Update_When_Control_Made_Invisible()
{
@ -838,6 +901,7 @@ namespace Avalonia.Base.UnitTests.Rendering.SceneGraph
Canvas canvas;
var tree = new TestRoot
{
ClientSize = new Size(100, 100),
Child = decorator = new Decorator
{
Margin = new Thickness(0, 10, 0, 0),

65
tests/Avalonia.Controls.UnitTests/BorderTests.cs

@ -1,6 +1,8 @@
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Rendering;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Moq;
using Xunit;
@ -60,5 +62,68 @@ namespace Avalonia.Controls.UnitTests
renderer.Verify(x => x.AddDirty(target), Times.Once);
}
public class UseLayoutRounding
{
[Fact]
public void Measure_Rounds_Padding()
{
var target = new Border
{
Padding = new Thickness(1),
Child = new Canvas
{
Width = 101,
Height = 101,
}
};
var root = CreatedRoot(1.5, target);
root.LayoutManager.ExecuteInitialLayoutPass();
// - 1 pixel padding is rounded up to 1.3333; for both sides it is 2.6666
// - Size of 101 gets rounded up to 101.3333
// - Desired size = 101.3333 + 2.6666 = 104
Assert.Equal(new Size(104, 104), target.DesiredSize);
}
[Fact]
public void Measure_Rounds_BorderThickness()
{
var target = new Border
{
BorderThickness = new Thickness(1),
Child = new Canvas
{
Width = 101,
Height = 101,
}
};
var root = CreatedRoot(1.5, target);
root.LayoutManager.ExecuteInitialLayoutPass();
// - 1 pixel border thickness is rounded up to 1.3333; for both sides it is 2.6666
// - Size of 101 gets rounded up to 101.3333
// - Desired size = 101.3333 + 2.6666 = 104
Assert.Equal(new Size(104, 104), target.DesiredSize);
}
private static TestRoot CreatedRoot(
double scaling,
Control child,
Size? constraint = null)
{
return new TestRoot
{
LayoutScaling = scaling,
UseLayoutRounding = true,
Child = child,
ClientSize = constraint ?? new Size(1000, 1000),
};
}
}
}
}

12
tests/Avalonia.Controls.UnitTests/ButtonTests.cs

@ -150,7 +150,7 @@ namespace Avalonia.Controls.UnitTests
target.Click += (s, e) => clicked = true;
RaisePointerEnter(target);
RaisePointerEntered(target);
RaisePointerMove(target, pt);
RaisePointerPressed(target, 1, MouseButton.Left, pt);
@ -182,10 +182,10 @@ namespace Avalonia.Controls.UnitTests
target.Click += (s, e) => clicked = true;
RaisePointerEnter(target);
RaisePointerEntered(target);
RaisePointerMove(target, new Point(50,50));
RaisePointerPressed(target, 1, MouseButton.Left, new Point(50, 50));
RaisePointerLeave(target);
RaisePointerExited(target);
Assert.Equal(_helper.Captured, target);
@ -224,7 +224,7 @@ namespace Avalonia.Controls.UnitTests
target.Click += (s, e) => clicked = true;
RaisePointerEnter(target);
RaisePointerEntered(target);
RaisePointerMove(target, pt);
RaisePointerPressed(target, 1, MouseButton.Left, pt);
@ -422,12 +422,12 @@ namespace Avalonia.Controls.UnitTests
_helper.Up(button, mouseButton, pt);
}
private void RaisePointerEnter(Button button)
private void RaisePointerEntered(Button button)
{
_helper.Enter(button);
}
private void RaisePointerLeave(Button button)
private void RaisePointerExited(Button button)
{
_helper.Leave(button);
}

41
tests/Avalonia.Controls.UnitTests/DecoratorTests.cs

@ -1,6 +1,7 @@
using System.Collections.Specialized;
using System.Linq;
using Avalonia.LogicalTree;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Controls.UnitTests
@ -116,5 +117,45 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new Size(16, 16), target.DesiredSize);
}
public class UseLayoutRounding
{
[Fact]
public void Measure_Rounds_Padding()
{
var target = new Decorator
{
Padding = new Thickness(1),
Child = new Canvas
{
Width = 101,
Height = 101,
}
};
var root = CreatedRoot(1.5, target);
root.LayoutManager.ExecuteInitialLayoutPass();
// - 1 pixel padding is rounded up to 1.3333; for both sides it is 2.6666
// - Size of 101 gets rounded up to 101.3333
// - Desired size = 101.3333 + 2.6666 = 104
Assert.Equal(new Size(104, 104), target.DesiredSize);
}
private static TestRoot CreatedRoot(
double scaling,
Control child,
Size? constraint = null)
{
return new TestRoot
{
LayoutScaling = scaling,
UseLayoutRounding = true,
Child = child,
ClientSize = constraint ?? new Size(1000, 1000),
};
}
}
}
}

64
tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs

@ -174,7 +174,7 @@ namespace Avalonia.Controls.UnitTests.Platform
}
[Fact]
public void PointerEnter_Opens_Item_When_Old_Item_Is_Open()
public void PointerEntered_Opens_Item_When_Old_Item_Is_Open()
{
var target = new DefaultMenuInteractionHandler(false);
var menu = new Mock<IMenu>();
@ -187,11 +187,11 @@ namespace Avalonia.Controls.UnitTests.Platform
x.IsTopLevel == true &&
x.HasSubMenu == true &&
x.Parent == menu.Object);
var e = CreateArgs(MenuItem.PointerEnterItemEvent, nextItem);
var e = CreateArgs(MenuItem.PointerEnteredItemEvent, nextItem);
menu.SetupGet(x => x.SelectedItem).Returns(item);
target.PointerEnter(nextItem, e);
target.PointerEntered(nextItem, e);
Mock.Get(item).Verify(x => x.Close());
menu.VerifySet(x => x.SelectedItem = nextItem);
@ -202,31 +202,31 @@ namespace Avalonia.Controls.UnitTests.Platform
}
[Fact]
public void PointerLeave_Deselects_Item_When_Menu_Not_Open()
public void PointerExited_Deselects_Item_When_Menu_Not_Open()
{
var target = new DefaultMenuInteractionHandler(false);
var menu = new Mock<IMenu>();
var item = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.Parent == menu.Object);
var e = CreateArgs(MenuItem.PointerLeaveItemEvent, item);
var e = CreateArgs(MenuItem.PointerExitedItemEvent, item);
menu.SetupGet(x => x.SelectedItem).Returns(item);
target.PointerLeave(item, e);
target.PointerExited(item, e);
menu.VerifySet(x => x.SelectedItem = null);
Assert.False(e.Handled);
}
[Fact]
public void PointerLeave_Doesnt_Deselect_Item_When_Menu_Open()
public void PointerExited_Doesnt_Deselect_Item_When_Menu_Open()
{
var target = new DefaultMenuInteractionHandler(false);
var menu = new Mock<IMenu>();
var item = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.Parent == menu.Object);
var e = CreateArgs(MenuItem.PointerLeaveItemEvent, item);
var e = CreateArgs(MenuItem.PointerExitedItemEvent, item);
menu.SetupGet(x => x.IsOpen).Returns(true);
menu.SetupGet(x => x.SelectedItem).Returns(item);
target.PointerLeave(item, e);
target.PointerExited(item, e);
menu.VerifySet(x => x.SelectedItem = null, Times.Never);
Assert.False(e.Handled);
@ -382,31 +382,31 @@ namespace Avalonia.Controls.UnitTests.Platform
}
[Fact]
public void PointerEnter_Selects_Item()
public void PointerEntered_Selects_Item()
{
var target = new DefaultMenuInteractionHandler(false);
var menu = Mock.Of<IMenu>();
var parentItem = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.HasSubMenu == true && x.Parent == menu);
var item = Mock.Of<IMenuItem>(x => x.Parent == parentItem);
var e = CreateArgs(MenuItem.PointerEnterItemEvent, item);
var e = CreateArgs(MenuItem.PointerEnteredItemEvent, item);
target.PointerEnter(item, e);
target.PointerEntered(item, e);
Mock.Get(parentItem).VerifySet(x => x.SelectedItem = item);
Assert.False(e.Handled);
}
[Fact]
public void PointerEnter_Opens_Submenu_After_Delay()
public void PointerEntered_Opens_Submenu_After_Delay()
{
var timer = new TestTimer();
var target = new DefaultMenuInteractionHandler(false, null, timer.RunOnce);
var menu = Mock.Of<IMenu>();
var parentItem = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.HasSubMenu == true && x.Parent == menu);
var item = Mock.Of<IMenuItem>(x => x.Parent == parentItem && x.HasSubMenu == true);
var e = CreateArgs(MenuItem.PointerEnterItemEvent, item);
var e = CreateArgs(MenuItem.PointerEnteredItemEvent, item);
target.PointerEnter(item, e);
target.PointerEntered(item, e);
Mock.Get(item).Verify(x => x.Open(), Times.Never);
timer.Pulse();
@ -416,7 +416,7 @@ namespace Avalonia.Controls.UnitTests.Platform
}
[Fact]
public void PointerEnter_Closes_Sibling_Submenu_After_Delay()
public void PointerEntered_Closes_Sibling_Submenu_After_Delay()
{
var timer = new TestTimer();
var target = new DefaultMenuInteractionHandler(false, null, timer.RunOnce);
@ -424,11 +424,11 @@ namespace Avalonia.Controls.UnitTests.Platform
var parentItem = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.HasSubMenu == true && x.Parent == menu);
var item = Mock.Of<IMenuItem>(x => x.Parent == parentItem);
var sibling = Mock.Of<IMenuItem>(x => x.Parent == parentItem && x.HasSubMenu == true && x.IsSubMenuOpen == true);
var e = CreateArgs(MenuItem.PointerEnterItemEvent, item);
var e = CreateArgs(MenuItem.PointerEnteredItemEvent, item);
Mock.Get(parentItem).SetupGet(x => x.SubItems).Returns(new[] { item, sibling });
target.PointerEnter(item, e);
target.PointerEntered(item, e);
Mock.Get(sibling).Verify(x => x.Close(), Times.Never);
timer.Pulse();
@ -438,48 +438,48 @@ namespace Avalonia.Controls.UnitTests.Platform
}
[Fact]
public void PointerLeave_Deselects_Item()
public void PointerExited_Deselects_Item()
{
var target = new DefaultMenuInteractionHandler(false);
var menu = Mock.Of<IMenu>();
var parentItem = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.HasSubMenu == true && x.Parent == menu);
var item = Mock.Of<IMenuItem>(x => x.Parent == parentItem);
var e = CreateArgs(MenuItem.PointerLeaveItemEvent, item);
var e = CreateArgs(MenuItem.PointerExitedItemEvent, item);
Mock.Get(parentItem).SetupGet(x => x.SelectedItem).Returns(item);
target.PointerLeave(item, e);
target.PointerExited(item, e);
Mock.Get(parentItem).VerifySet(x => x.SelectedItem = null);
Assert.False(e.Handled);
}
[Fact]
public void PointerLeave_Doesnt_Deselect_Sibling()
public void PointerExited_Doesnt_Deselect_Sibling()
{
var target = new DefaultMenuInteractionHandler(false);
var menu = Mock.Of<IMenu>();
var parentItem = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.HasSubMenu == true && x.Parent == menu);
var item = Mock.Of<IMenuItem>(x => x.Parent == parentItem);
var sibling = Mock.Of<IMenuItem>(x => x.Parent == parentItem);
var e = CreateArgs(MenuItem.PointerLeaveItemEvent, item);
var e = CreateArgs(MenuItem.PointerExitedItemEvent, item);
Mock.Get(parentItem).SetupGet(x => x.SelectedItem).Returns(sibling);
target.PointerLeave(item, e);
target.PointerExited(item, e);
Mock.Get(parentItem).VerifySet(x => x.SelectedItem = null, Times.Never);
Assert.False(e.Handled);
}
[Fact]
public void PointerLeave_Doesnt_Deselect_Item_If_Pointer_Over_Submenu()
public void PointerExited_Doesnt_Deselect_Item_If_Pointer_Over_Submenu()
{
var target = new DefaultMenuInteractionHandler(false);
var menu = Mock.Of<IMenu>();
var parentItem = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.HasSubMenu == true && x.Parent == menu);
var item = Mock.Of<IMenuItem>(x => x.Parent == parentItem && x.HasSubMenu == true && x.IsPointerOverSubMenu == true);
var e = CreateArgs(MenuItem.PointerLeaveItemEvent, item);
var e = CreateArgs(MenuItem.PointerExitedItemEvent, item);
target.PointerLeave(item, e);
target.PointerExited(item, e);
Mock.Get(parentItem).VerifySet(x => x.SelectedItem = null, Times.Never);
Assert.False(e.Handled);
@ -510,11 +510,11 @@ namespace Avalonia.Controls.UnitTests.Platform
var parentItem = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.HasSubMenu == true && x.Parent == menu);
var item = Mock.Of<IMenuItem>(x => x.Parent == parentItem && x.HasSubMenu == true);
var childItem = Mock.Of<IMenuItem>(x => x.Parent == item);
var enter = CreateArgs(MenuItem.PointerEnterItemEvent, item);
var leave = CreateArgs(MenuItem.PointerLeaveItemEvent, item);
var enter = CreateArgs(MenuItem.PointerEnteredItemEvent, item);
var leave = CreateArgs(MenuItem.PointerExitedItemEvent, item);
// Pointer enters item; item is selected.
target.PointerEnter(item, enter);
target.PointerEntered(item, enter);
Assert.True(timer.ActionIsQueued);
Mock.Get(parentItem).VerifySet(x => x.SelectedItem = item);
Mock.Get(parentItem).Invocations.Clear();
@ -526,13 +526,13 @@ namespace Avalonia.Controls.UnitTests.Platform
Mock.Get(item).Invocations.Clear();
// Pointer briefly exits item, but submenu remains open.
target.PointerLeave(item, leave);
target.PointerExited(item, leave);
Mock.Get(item).Verify(x => x.Close(), Times.Never);
Mock.Get(item).Invocations.Clear();
// Pointer enters child item; is selected.
enter.Source = childItem;
target.PointerEnter(childItem, enter);
target.PointerEntered(childItem, enter);
Mock.Get(item).VerifySet(x => x.SelectedItem = childItem);
Mock.Get(parentItem).VerifySet(x => x.SelectedItem = item);
Mock.Get(item).Invocations.Clear();

66
tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Layout.cs

@ -1,5 +1,6 @@
using Avalonia.Controls.Presenters;
using Avalonia.Layout;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Controls.UnitTests.Presenters
@ -232,5 +233,68 @@ namespace Avalonia.Controls.UnitTests.Presenters
Assert.Equal(new Rect(32, 32, 0, 0), content.Bounds);
}
public class UseLayoutRounding
{
[Fact]
public void Measure_Rounds_Padding()
{
var target = new ContentPresenter
{
Padding = new Thickness(1),
Content = new Canvas
{
Width = 101,
Height = 101,
}
};
var root = CreatedRoot(1.5, target);
root.LayoutManager.ExecuteInitialLayoutPass();
// - 1 pixel padding is rounded up to 1.3333; for both sides it is 2.6666
// - Size of 101 gets rounded up to 101.3333
// - Desired size = 101.3333 + 2.6666 = 104
Assert.Equal(new Size(104, 104), target.DesiredSize);
}
[Fact]
public void Measure_Rounds_BorderThickness()
{
var target = new ContentPresenter
{
BorderThickness = new Thickness(1),
Content = new Canvas
{
Width = 101,
Height = 101,
}
};
var root = CreatedRoot(1.5, target);
root.LayoutManager.ExecuteInitialLayoutPass();
// - 1 pixel border thickness is rounded up to 1.3333; for both sides it is 2.6666
// - Size of 101 gets rounded up to 101.3333
// - Desired size = 101.3333 + 2.6666 = 104
Assert.Equal(new Size(104, 104), target.DesiredSize);
}
private static TestRoot CreatedRoot(
double scaling,
Control child,
Size? constraint = null)
{
return new TestRoot
{
LayoutScaling = scaling,
UseLayoutRounding = true,
Child = child,
ClientSize = constraint ?? new Size(1000, 1000),
};
}
}
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save