Jump to content

Gustav Schubert

Members
  • Content Count

    114
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by Gustav Schubert

  1. Gustav Schubert

    About MedGray and WindowWhite

    I think the VCL version of MedGray contains a typo: // Search for MedGray in unit System.UITypes: MedGray = TColor($A4A0A0); MedGray = Alpha or TAlphaColor($A0A0A0); See (also) the following docwiki topics: RADStudio/Sydney/en/Colors_in_the_VCL RADStudio/Sydney/en/Colors_in_FireMonkey Already known: Gray is darker than DarkGray, this is ok ( I learned it from Stackoverflow). Use Dimgray if you want a darker gray than Gray. The default background color of a Window is not a named color in TAlphaColorRec. Duplicate color values in TAlphaColorRec are by design. There is an open RSP (29269) which complains about duplicated color values in System.UITypes.TAlphaColorRec. Questions: Are color values other then web colors allowed to have a name in TAlphaColorRec? If so, what color names would you like to be included, for convenience? QuickSilver = Alpha or TAlphaColor($A0A0A0); // Mediumgrey or Mediumgray or MedGray? WindowWhite = Alpha or TAlphaColor($F0F0F0); // ButtonFace or BtnFace or Buttonface or Windowgray? I never used MedGray, but I need a WindowWhite in FMX. I intend to specify a reduced set of named colors for use in my application. I need those colors to have a good name. I will have VCL, FMX, and LCL versions of my very own TRggColors, which will be available under the same name to client code in VCL and FMX. Gray would be ok. ( Not sure about DarkGray. ) Mediumgray will look nice next to Lightgray. Not sure about WindowWhite. ( This topic is about accessing color values by name for drawing to the canvas of the platform, without creating noise in the diff, and without stopping at surprises. )
  2. Gustav Schubert

    About MedGray and WindowWhite

    Update: There are now 141 web colors (139 unique). The relatively new web color is Rebeccapurple, not (yet) included in TAlphaColorRec. In my temporary capacity as an expert on LegacySkyBlue I have reported to Quality: RSP-32781. And I have uploaded FrmColor.pas (the main form in RG69.dpr) as a test for my TRggWebColorListBox runtime component. ( The component can show colors in a sort order that is NOT alphabetically, and filter by group of web colors. )
  3. Gustav Schubert

    About MedGray and WindowWhite

    Actually, there are 138 unique color values in the 140 web colors, because of Aqua = Cyan and Fuchsia = Magenta. AlphaColors array in System.UIConsts has a 'unique constraint' on the Name but not on the Value. Definitions of Cream and LegacySkyBlue are wrong in FMX. // Colors do not match - verified with pipette in MS Paint. Rectangle1.Fill.Color := TAlphaColors.Cream; // FMX Shape1.Brush.Color := TColors.Cream; // VCL Reason: TAlphaColorRec Red = Alpha or TAlphaColor($FF0000); // correct MoneyGreen = TAlphaColor($FFC0DCC0); // symmetry LegacySkyBlue = Alpha or TAlphaColor($F0CAA6); // wrong Cream = Alpha or TAlphaColor($F0FBFF); // wrong {$IFDEF BIGENDIAN} (A, R, G, B: System.Byte); {$ELSE} (B, G, R, A: System.Byte); {$ENDIF} TColorRec Red = TColor($0000FF); // correct MoneyGreen = TColor($C0DCC0); // the original LegacySkyBlue = TColor($F0CAA6); // the original Cream = TColor($F0FBFF); // the original {$IFDEF BIGENDIAN} (A, B, G, R: System.Byte); {$ELSE} (R, G, B, A: System.Byte); {$ENDIF} Test program: program CreamTest; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.UIConsts, System.UITypes; var c: TAlphaColor; cr: TColorRec; acr: TAlphaColorRec; i: Integer; begin try cr.Color := TColors.Red; acr.Color := TAlphaColors.Red; Assert(cr.R = acr.R); Assert(cr.G = acr.G); Assert(cr.B = acr.B); WriteLn('Red test ok.'); // Green and Blue are ok as well WriteLn; cr.Color := TColors.Cream; acr.Color := TAlphaColors.Cream; Assert(cr.R = acr.B); Assert(cr.G = acr.G); Assert(cr.B = acr.R); WriteLn('Verified: R and B are swapped for Cream!'); cr.Color := TColors.LegacySkyBlue; acr.Color := TAlphaColors.LegacySkyBlue; Assert(cr.R = acr.B); Assert(cr.G = acr.G); Assert(cr.B = acr.R); WriteLn('Verified: R and B are swapped for LegacySkyBlue!'); WriteLn; WriteLn('Cream Test begins'); cr.Color := TColors.Cream; acr.Color := TAlphaColors.Cream; i := 0; if cr.R <> acr.R then begin WriteLn('R is wrong.'); Inc(i); end; if cr.B <> acr.B then begin WriteLn('B is wrong.'); Inc(i); end; if i = 0 then WriteLn('Test ok.') else WriteLn('Cream test failed.'); WriteLn; WriteLn('AlphaColorToString Tests:'); WriteLn('Aqua', '=', AlphaColorToString(TAlphaColors.Aqua)); WriteLn('Cyan', '=', AlphaColorToString(TAlphaColors.Cyan)); WriteLn('Fuchsia', '=', AlphaColorToString(TAlphaColors.Fuchsia)); WriteLn('Magenta', '=', AlphaColorToString(TAlphaColors.Magenta)); WriteLn('MoneyGreen', '=', AlphaColorToString(TAlphaColors.MoneyGreen)); WriteLn('LegacySkyBlue', '=', AlphaColorToString(TAlphaColors.LegacySkyBlue)); WriteLn('Cream', '=', AlphaColorToString(TAlphaColors.Cream)); WriteLn; WriteLn('ColorToString Tests:'); WriteLn('Aqua', '=', ColorToString(TColors.Aqua)); WriteLn('Cyan', '=', ColorToString(TColors.Cyan)); WriteLn('Fuchsia', '=', ColorToString(TColors.Fuchsia)); WriteLn('Magenta', '=', ColorToString(TColors.Magenta)); WriteLn('MoneyGreen', '=', ColorToString(TColors.MoneyGreen)); WriteLn('LegacySkyBlue', '=', ColorToString(TColors.LegacySkyBlue)); WriteLn('Cream', '=', ColorToString(TColors.Cream)); ReadLn; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. Output: Red test ok. Verified: R and B are swapped for Cream! Verified: R and B are swapped for LegacySkyBlue! Cream Test begins R is wrong. B is wrong. Cream test failed. AlphaColorToString Tests: Aqua=Aqua Cyan=Aqua Fuchsia=Fuchsia Magenta=Fuchsia MoneyGreen=#FFC0DCC0 LegacySkyBlue=#FFF0CAA6 Cream=#FFF0FBFF ColorToString Tests: Aqua=clAqua Cyan=clAqua Fuchsia=clFuchsia Magenta=clFuchsia MoneyGreen=clMoneyGreen LegacySkyBlue=clSkyBlue Cream=clCream I am playing with colors, but not yet used in any feature of the app: ( https://github.com/federgraph/RiggVar-RG38/blob/master/FB/RiggVar.FB.Color.pas )
  4. Gustav Schubert

    About MedGray and WindowWhite

    Analysis of the day: 140 web colors + 1 Alpha + 1 Null + 7 Grey duplicats + 6 (LtGray, MedGray, DkGray, MoneyGreen, LegacySkyBlue, Cream) ----- 155 named colors in TAlphaColorRec in System.UITypes ===== 140 web color // see https://www.w3schools.com/cssref/css_colors.asp + 1 Null (claNull) + 7 Grey duplicates // claDarkgrey, claDarkslategrey, claDimgrey, claGrey, claLightgrey, claLightslategrey, claSlategrey ----- 148 global cla Constants in System.UIConsts ===== The 148 named color constants can be iterated over using AlphaColors array, which is private in System.UIConsts. You are supposed to do it with the help of procedure GetAlphaColorValues(Proc: TGetStrProc); See constructor of FMX.Colors.TRTLColors for an example of how to use it. The problem with GetAlphaColorValues is described in RSP-30408. A TWebColors type similar to TAlphaColors but with only 140 entries would be nice. FFF0F0F0 is still a candidate for inclusion in TAlphaColorRec (to be dropped later). I no longer want E0E0E0 (only used as default color for TRectangle.Fill).
  5. Gustav Schubert

    About MedGray and WindowWhite

    BtnFace-F0F0F0 is the most important color in the Delphi universe. A great opportunity still exists for Embarcadero to give this unnamed color a proper place in the encyclopedia of color names. All that is needed is to include it in TAlphaColorRec, and return the name from the AlphaColorToString function. Since there are duplicate names already (defined for some of the gray values), it does not matter much to add one more, and another one for E0E0E0, and an alternative name for DarkGray. Maybe they are reading this and will act. Then I could just clone the TAlphaColorRec and delete everything I do not want. All the standard functions like AlphaColorToString would work for me out of the box. I don't know if that idea was the reason why I posted here. Sometimes it is a bit fuzzy. But thank you for giving me the opportunity to explain my point! mfg
  6. Gustav Schubert

    About MedGray and WindowWhite

    This is from my application: A0B0 := TRggLine.Create('A0B0'); L := A0B0; //L.StrokeColor := TAlphaColors.Gray; // FMX only L.StrokeColor := TRggColors.Gray; // VCL and FMX and LCL L.Point1 := A0; L.Point2 := B0; Add(L); I am designing a color palette (from well known color names) and I am thinking about color names to be included. The user (myself, to begin with) is expected to specify names that can be remembered. I took TAlphaColorRec as a starting point, and I am free to fix any potential problems. For example: F0F0F0 (BtnFace) is not a named color, not in the realm of Delphi FMX. Should Embarcadero give a name to that color, and which? How about MedGray and DarkGray. What to do with the duplicated colors, keep them? Want is your opinion, of the palette of named colors in Delphi?
  7. Gustav Schubert

    About MedGray and WindowWhite

    I only want to use colors that are defined in TAlphaColorRec, and which return the name from AlphaColorToString. This is what I want to figure out.
  8. Gustav Schubert

    About MedGray and WindowWhite

    I am dealing with two missing colors, one ambiguous color (MedGray), one misleading color (DarkGray), and duplicated color values (gray vs. grey). Joke: I suggest that the wiki pages add two buttons, "sort by gray" and "sort by grey". In my test program I show 10 overlapping rectangles (FMX) or shapes (VCL) to verify my understanding of the color values. The second 'color name' in the following output is returned from AlphaColorToString(color) or ColorToString(color). #FFF0F0F0 - default color for a Window background in FMX. #FFE0E0E0 - default value of Rectangle1.Fill.Color in FMX. // FormatString := '%d: [%20s]: %12s = %x = (%d, %d, %d)'; Testprogram output for FMX: 0: [ Whitesmoke F5 245]: Whitesmoke = FFF5F5F5 = (245, 245, 245) 1: [ WindowWhite F0 240]: #FFF0F0F0 = FFF0F0F0 = (240, 240, 240) 2: [ ChinaWhite E0 224]: #FFE0E0E0 = FFE0E0E0 = (224, 224, 224) 3: [ Gainsboro DC 220]: Gainsboro = FFDCDCDC = (220, 220, 220) 4: [ Lightgray D3 211]: Lightgray = FFD3D3D3 = (211, 211, 211) 5: [ Silver C0 192]: Silver = FFC0C0C0 = (192, 192, 192) 6: [ Darkgray A9 169]: Darkgray = FFA9A9A9 = (169, 169, 169) 7: [ MedGray A0 160]: #FFA0A0A0 = FFA0A0A0 = (160, 160, 160) 8: [ Gray 80 128]: Gray = FF808080 = (128, 128, 128) 9: [ Dimgray 69 105]: Dimgray = FF696969 = (105, 105, 105) Testprogram output for VCL colors: 0: [ Whitesmoke F5 245]: $00F5F5F5 = F5F5F5 = (245, 245, 245) 1: [ WindowWhite F0 240]: $00F0F0F0 = F0F0F0 = (240, 240, 240) 2: [ ChinaWhite E0 224]: $00E0E0E0 = E0E0E0 = (224, 224, 224) 3: [ Gainsboro DC 220]: $00DCDCDC = DCDCDC = (220, 220, 220) 4: [ Lightgray D3 211]: $00D3D3D3 = D3D3D3 = (211, 211, 211) 5: [ Silver C0 192]: clSilver = C0C0C0 = (192, 192, 192) 6: [ Darkgray A9 169]: $00A9A9A9 = A9A9A9 = (169, 169, 169) 7: [ MedGray A0 160]: clMedGray = A4A0A0 = (160, 160, 164) 8: [ Gray 80 128]: clGray = 808080 = (128, 128, 128) 9: [ Dimgray 69 105]: $00696969 = 696969 = (105, 105, 105) Color names according to chir.ag: F5 245 Wild Sand approx. (Whitesmoke) F0 240 Gallery approx. (clBtnFace, "WindowWhite") E0 224 Alto approx. () DC 220 Alto approx.(Gainsboro) D3 211 Alto approx. (Lightgray) C0 192 Silver solid (Silver) A9 169 Silver Chalice approx. (Darkgray) A0 160 Silver Chalice approx. (MedGray FMX) 80 128 Gray solid (Gray) 69 105 Dove Gray approx. (DimGray) A0A0A4 Santas Gray approx. (MedGray VCL) clBtnFace is not a named color: https://encycolorpedia.com/named https://colorate.azurewebsites.net/Color/F0F0F0
  9. Gustav Schubert

    About MedGray and WindowWhite

    My problem is that I cannot find the FMX version of clBtnFace in TAlphaColorRec. (WindowWhite) Btw, by now I have decided that grey has lost! I know this is a little unfair, but only a little, and I am not really sorry, mainly because the chance was there, with FMX, in the beginning. As far as the DarkGray problem is concerned, any suggestion for a more appropiate name? I would consider a French name too, for my internal cross platform TRggColors helper.
  10. Quick fix: keep both. TForm22 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private FBaseFrameClass: TBaseFrameClass; { hold on to both } FBaseFrame: TBaseFrame; // object reference FBaseFrameInterface: IInterface; // interface reference end; procedure TForm22.FormCreate(Sender: TObject); begin ReportMemoryLeaksOnShutdown := True; { Happy mixing is possible! } fBaseFrameClass := TMyFrame; FBaseFrame := FBaseFrameClass.Create; FBaseFrameInterface := FBaseFrame; end; procedure TForm22.FormDestroy(Sender: TObject); begin // fBaseFrame.Free; end;
  11. Gustav Schubert

    Documentation drawings

    I created a Wiki to explain how documentation drawings could be done so that they are live (interactive). The example code is in Delphi. https://github.com/federgraph/documentation-drawings
  12. Gustav Schubert

    Text 3D is horrible

    Possible starting point for playing: unit FrmMain; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, System.Math.Vectors, FMX.Controls3D, FMX.Objects3D, FMX.Viewport3D, FMX.MaterialSources; type TFormMain = class(TForm) Viewport: TViewport3D; procedure FormCreate(Sender: TObject); private Text: TText3D; Camera: TCamera; MS: TColorMaterialSource; end; var FormMain: TFormMain; implementation {$R *.fmx} procedure TFormMain.FormCreate(Sender: TObject); begin ReportMemoryLeaksOnShutdown := True; Width := 800; Height := 600; Viewport.Position.X := 10; Viewport.Position.Y := 10; Viewport.Width := 640; Viewport.Height := 480; Camera := TCamera.Create(Self); Camera.Parent := Viewport; Camera.Position.Z := -100; Viewport.Camera := Camera; Viewport.UsingDesignCamera := False; MS := TColorMaterialSource.Create(Self); MS.Parent := nil; MS.Color := TAlphaColors.Dodgerblue; Text := TText3D.Create(Self); Text.Parent := Viewport; Text.WordWrap := False; Text.Stretch := False; Text.Depth := 3; Text.Height := 10; Text.Width := 100; Text.Scale.X := 1; Text.Scale.Y := 1; Text.Text := 'Sample Text'; Text.RotationAngle.X := 20; Text.MaterialShaftSource := MS; end; end.
  13. Sometimes you need to resort to git on the commandline to rename a file, with git mv -f See How do I commit case-sensitive only filename changes in Git?
  14. Gustav Schubert

    ClientHeight in FormResize screen scaling issue

    FMX Rio: ClientHeight is not up to date in FormResize when the form is moved back from a second monitor which has a higher value screen scale. Can this be reproduced in 10.4? If so I would report it, and update this post. Minimal sample with problem in 10.3.3: New app with one TRectangle on main form. Add OnResize handler as given below. Run on Windows. Test with two monitors of different scaling. Main monitor = 1.0 and second monitor to the right = 1.25. Drag Form1 from one monitor to other and then back to see problem. Drag the right border of form to resize again and correct the problem. Problem shows after dragging back from right to main monitor. There is a gap between Rectangle.Bottom and Form.Bottom. It seems to be the diff in actual and perceived ClientHeight, 8 pixel in my setup. Problem will be corrected if form is resized, because then ClientHeight will be good in FormResize. procedure TForm1.FormResize(Sender: TObject); begin { Rectangle1: TRectangle } // Rectangle1.Width := ClientWidth - Rectangle1.Position.X; Rectangle1.Height := ClientHeight - Rectangle1.Position.Y; Caption := Format('%d - %d - %.2f', [Height, ClientHeight, Rectangle1.Scene.GetSceneScale]); end;
  15. Gustav Schubert

    ClientHeight in FormResize screen scaling issue

    The cost of using OnResizeEnd is rather high, as of now.
  16. Gustav Schubert

    Text 3D is horrible

    I wonder how that would look using an orthographic projection.
  17. Gustav Schubert

    git - do you 'pull' before/after switching branches?

    In theory, yes. But I have difficulty to compare branches with only one folder. My merge tool which is my diff tool needs two folders. And, I have more branches at home than I have at github.
  18. Gustav Schubert

    git - do you 'pull' before/after switching branches?

    1) Because for me there is no better was to see what has changed. 2) When learning how to use git. I don't want to do that live at github. 3) I also have different settings for .gitignore 4) My local only one has a longer history, I want to keep that
  19. Gustav Schubert

    git - do you 'pull' before/after switching branches?

    Sometimes I opt to have two local repositories, one which is connected to a remote, and another one which is not - which is the one I will use for development. I know which is which by folder name. When I open the one with connection to remote in Visual Studio Code (folder), it tells me that there is new stuff that I can pull down, and I will, immediately. When I want to publish some work I will use my merge tool to copy the new stuff over to the hot repo and then commit with a button click. ( It is via my merge tool that I keep in control, it works with directories on disc. ) You could have two repos connected to the remote, pull one often - as advised, and the other one only when you want (after a successfull push, from other repo). ( If the repo is large you can care about subfolders only and ignore the rest, only merge the subfolder you are working on. )
  20. This is about the result of testing my FMX app on a high resolution screen, Windows platform. ( A TImage component is the central component on my form, I am drawing onto its bitmap, it has a known fixed size. ) Using ImageWrapMode = TImageWrapMode.Original. Using project options - application- manifest - dpi support = PerMonitorV2. Using 10.3.3. Test is done on a 4K Monitor with Scaling of 2.0. The TImage (which I will draw on) will appear half the size. All components are scaled automatically, except TImage. I tried to work around the issue. Depending on Handle.Scale I can make the Image and Bitmap bigger, and then draw with a scaling transform, it works. But then I also need to adapt custom layout code because I am using Width and Height of components to stack them horizontally or vertically. And this is not nice if one component uses different 'units' for Width and Height. I have reverted back to using Dpi-Support of None, since in this mode the scaling of TImage is done automatically. So, all is well now, except that I could spam some site with 125 lines of minimal test form code!
  21. Gustav Schubert

    ImageWrapMode.Original and Dpi-Support PerMonitorV2

    Progress: Now I have sharp text for the controls AND a sharp drawing on a high resolution screen. I need to scale the drawing - when I do the drawing, and I need to provide a Bitmap which is big enough to show everything. Width and Height of the Image need to be set to the unscaled values: private FScale: single; BitmapWidth: Integer; BitmapHeight: Integer; Image: TImage; procedure TForm1.FormCreate(Sender: TObject); var Bitmap: TBitmap; begin FScale := Handle.Scale; { nominal bitmap size, fixed at time of creation } BitmapWidth := 800; BitmapHeight := 800; Bitmap := TBitmap.Create(Round(BitmapWidth * FScale), Round(BitmapHeight * FScale)); Bitmap.Clear(claWhite); Assert(FScale = Image.Scene.GetSceneScale); { Image Width and Height can change later with alignment or anchoring } Image.Width := BitmapWidth; // unscaled (nominal) value Image.Height := BitmapHeight; Image.Bitmap := Bitmap; Bitmap.Free; // image has copy via assign Image.WrapMode := TImageWrapMode.Original; end; { g = Image.Bitmap.Canvas } procedure TForm1.DrawToCanvas(g: TCanvas); begin g.Offset := TH.Offset; // transform helper if g.BeginScene then try g.SetMatrix(TMatrix.CreateScaling(FScale, FScale)); g.Clear(claWhite); // ... finally g.EndScene; end; end; The TImage is good as is. No bug report and no feature request from me. But I have built myself a significantly more lightweight TOriginalImage control (less than 200 lines), which features a read only Bitmap property. I will no longer provide the Bitmap - only the NominalSize. Whenever I access Image.Bitmap.Canvas to draw on it: the Bitmap will have the correct size for the current monitor I still need to do the scaling via matrix I need to call Image.Repaint after drawing. Moving the form from one monitor to another with different scaling should work, because my new component has a ScaleChangedHandler, as does TImage. The TImage from FMX.Objects works ok, it is just difficult to understand, too much MultiResBitmap stuff which I do not need - when I just want to draw on it.
  22. Gustav Schubert

    ImageWrapMode.Original and Dpi-Support PerMonitorV2

    I'm off because I had an odd dream about TImage.UpdateCurrentBitmap; and now I need to read more about MultiResImages. overridden procedure TImage.Paint; begin NewUpdateCurrentBitmap; if FCurrentBitmap <> nil then MyDrawBitmap(Canvas, LocalRect, FCurrentBitmap, AbsoluteOpacity); end; //private procedure TImage.UpdateCurrentBitmap; strictly; ignore; public procedure TImage.NewUpdateCurrentBitmap; possible; abstract; public MyDrawBitmap(Canvas, LocalRect, FCurrentBitmap, AbsoluteOpacity); virtually; easy; unchanged procedure TImage.SetBitmap(const Value: TBitmap); var LBitmap: TBitmap; begin LBitmap := GetBitmap; if LBitmap <> nil then LBitmap.Assign(Value); end; function TImage.GetBitmap: TBitmap; var Item: TCustomBitmapItem; begin Result := nil; // Return the most appropriate non-empty picture // ? end;
  23. Gustav Schubert

    ImageWrapMode.Original and Dpi-Support PerMonitorV2

    Observation 1: If I use PerMonitorV2 then the text of controls like ListView will be sharper. This is why I want to keep using it. Observation 2: I have been able to produce sharp drawings which take advantage of the many pixels of the 4K screen, in PerMonitorV2 mode. Unfortunately the effort is high, in terms of extra code that I need to write for correct layout and manual scaling. At first I thought that the DrawImage method of TImage might have a bug. But by now I have tested out a change - with only partial success. I can make the drawing scale as I want, but it will appear slightly blurred, because it gets upscaled, as with Dpi-Support None. Status: In order to get a sharp drawing I need to leave EMBA code as is and do the additional work. Problem is of course that I cannot and want not do that in in my bigger application for some existing drawings, not now, and maybe never. For now I will go with sharp text and slightly blurred drawings.
  24. Gustav Schubert

    ImageWrapMode.Original and Dpi-Support PerMonitorV2

    From docwiki: Original - displays the image with its original dimensions. Fit - provides the best fit, keeping image proportions (the ratio between the width and height) for the TImage rectangle. If needed, the image is scaled down or stretched to best fit the rectangle area. This is the default option. In mode original the image should be clipped - ok - but should it not still be scaled according to the sceen scaling factor? Or is the intention really that it appears smaller on a high resolution screen, relative to other controls?
  25. Gustav Schubert

    Converting simple VCL form to FMX

    For me the first step is to empty the form. I will create all components in code - I do this manually - but for this I think there should be a tool! Next I will refactor - a lot, the layout of components and the repetitive settings of basic component properties. So, I am not using any tools, but I can reuse code for laying out components and setting standard properties, much better than before.
×