Jump to content

David Schwartz

Members
  • Content Count

    1190
  • Joined

  • Last visited

  • Days Won

    24

Everything posted by David Schwartz

  1. David Schwartz

    VCL - DevExpress

    LOL! When I first heard about TMS WEB Core, I thought, hmmm ... maybe Tim finally caught somebody's attention. But alas, TMS was working with another team entirely.
  2. David Schwartz

    restricting floating point range

    There's always the InRange function https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.Math.InRange function InRange(const AValue, AMin, AMax: Integer): Boolean; function InRange(const AValue, AMin, AMax: Int64): Boolean; function InRange(const AValue, AMin, AMax: UInt64): Boolean; function InRange(const AValue, AMin, AMax: Single): Boolean; function InRange(const AValue, AMin, AMax: Double): Boolean; function InRange(const AValue, AMin, AMax: Extended): Boolean;
  3. David Schwartz

    VCL - DevExpress

    I learned long ago that Irony and sarcasm don't come across in a written media like this. So don't blame me cause I don't know you well enough to tell the difference. Heck, I have a hard enough time when some of my friends are being sarcastic! 🙂
  4. I gave it a class and asked it to generate code needed to move data to and from a JSON message and it did a bang-up job. But it stopped at one point in the toJSON function. I just asked: can you just show the ToJSON function and ... it did! So that's one way to get past this limitation. if it gives you a list of methods and stops at some point, just ask for them individually.
  5. I asked ChatGPT for a sample class in Delphi. Then asked it to extend the class to show how to move the data to and from a JSON message. This is what it produced. type TPerson = class private FFirstName: string; FLastName: string; FAge: Integer; public property FirstName: string read FFirstName write FFirstName; property LastName: string read FLastName write FLastName; property Age: Integer read FAge write FAge; function ToJSON: string; class function FromJSON(const AJSON: string): TPerson; end; function TPerson.ToJSON: string; var JSONObj: TJSONObject; begin JSONObj := TJSONObject.Create; try JSONObj.AddPair('FirstName', FirstName); JSONObj.AddPair('LastName', LastName); JSONObj.AddPair('Age', TJSONNumber.Create(Age)); Result := JSONObj.ToString; finally JSONObj.Free; end; end; class function TPerson.FromJSON(const AJSON: string): TPerson; var JSONObj: TJSONObject; begin JSONObj := TJSONObject.ParseJSONValue(AJSON) as TJSONObject; try Result := TPerson.Create; Result.FirstName := JSONObj.GetValue('FirstName').Value; Result.LastName := JSONObj.GetValue('LastName').Value; Result.Age := JSONObj.GetValue('Age').Value.ToInteger; finally JSONObj.Free; end; end; This could be a HUGE TIME-SAVER for stuff like this! It's like having a team of interns on staff who write at the speed of light. This took less than two minutes. I asked it to add the uses clause and it generated an entire unit: unit Person; interface uses System.SysUtils, System.JSON; type TPerson = class private FFirstName: string; FLastName: string; FAge: Integer; public property FirstName: string read FFirstName write FFirstName; property LastName: string read FLastName write FLastName; property Age: Integer read FAge write FAge; function ToJSON: string; class function FromJSON(const AJSON: string): TPerson; end; implementation { TPerson } function TPerson.ToJSON: string; var JSONObj: TJSONObject; begin JSONObj := TJSONObject.Create; try JSONObj.AddPair('FirstName', FirstName); JSONObj.AddPair('LastName', LastName); JSONObj.AddPair('Age', TJSONNumber.Create(Age)); Result := JSONObj.ToString; finally JSONObj.Free; end; end; class function TPerson.FromJSON(const AJSON: string): TPerson; var JSONObj: TJSONObject; begin JSONObj := TJSONObject.ParseJSONValue(AJSON) as TJSONObject; try Result := TPerson.Create; Result.FirstName := JSONObj.GetValue('FirstName').Value; Result.LastName := JSONObj.GetValue('LastName').Value; Result.Age := JSONObj.GetValue('Age').Value.ToInteger; finally JSONObj.Free; end; end; end. It also added this: The uses clause includes the System.SysUtils unit for the TJSONNumber.ToInteger method, as well as the System.JSON unit for the TJSONObject and TJSONValue classes and related functions.
  6. David Schwartz

    VCL - DevExpress

    What do you mean "Naaaaaah." That's exactly what I said! I refused to buy it! Raize charged a small upgrade fee ($69 or so) every time they updated the library, which was every few years, and they provided free upgrades each time Delphi required an update. Embt bought it, tried selling it with ANNUAL FEES (several hundred dollars) that simply got you an update every time Dephi was updated -- something Raise had always offered for FREE. That didn't work out well, did it? After 18 months and one upgrade with no new features in it, they dumped it into GetIt where they DO now provide it for free along with free updates each time Delphi is updated as well. And they even make small tweaks to it here and there. I still prefer it over the basic components. I played with FMX a bit, thinking it might be a good replacement for VCL, and it's not that. It's tolerable if you want to use their cross-platform tools for UI stuff. People constantly bitched and complained that while it provided a more-or-less consistent UI experience for the same app on different platforms, it was slow and buggy and inconsistent with the "native" controls on other platforms that most people were used to. So OTHER VENDORS came out with components that let you build cross-platform apps using "native" controls. I don't know if Embt ever saw the light, as I don't even pay attention to FMX any more. I'm glad you seem to like it, I think it's worthless. Anyway, I get the impression that YOU basically have abandoned VCL. That's all I've ever worked with. Every project I've worked on used VCL and many used DevEx. NOBODY used Dephi for anything but Windows development. You seem to be blind to the fact that the vast majority of Embt's customers are large corporations with huge apps built in the early 2000's that are still alive and kicking and making them tens if not hundreds of millions of dollars a year. Cross-platform stuff seemed to be a "hail Mary" approach at something desperately needed to revive interest in something that was on its dying legs outside of Corporate America. It still is here in America, but seems to be doing much better in several foreign countries. One thing we probably DO agree on is that the world seems to have moved on to Web-based apps. There's no evidence that Embt even has anything on the horizon in that respect. TMS is YEARS ahead of them with WEB Core! There's a company that got there 10 years ago, Elevate Software, that's still poking along, but it seems to be a one-man shop. Maybe Embt could buy them up and try competing with TMS? Working with WEB Core takes a little getting used to, but it's quite refreshing and I **LOVE** being able to build an app in Delphi and seeing it run inside of a web browser!!!
  7. David Schwartz

    VCL - DevExpress

    Ever since Borland released Delphi, there has been one overriding dictate: The stuff in the box needs to be "useful", not "the best". Unlike Microsoft, who has a history of buying up great tools and dumping them into their products, Borland wanted to draw a line and say to vendors, "Feel free to build better stuff than this, we won't interfere." And that attitude continues today. (I can't speak for C++ Builder as it has been more of a distant step-child of Dephi's forever. They've been working hard at making it more of an "equal", but the language has become so verbose and the libraries so complex that I find Delphi to be much simpler and easier to work with. Not to mention that Delphi's "generics" and C++'s "templates" are not the same. C++ and Delphi have about 95% overlap in their semantics, but there's some nice stuff I used regularly when I worked with C++ that Delphi simply doesn't support syntactically, and probably never will.) Here's a bit of a history lesson that may be more than you want to know, but it answers your question quite thoroughly: A lot of component libs were created for Dephi that barely added much to the existing stuff; they sold well because they were fairly cheap and saved more time than they cost. Over time, most of them have either disappeared or been turned into FOSS libs. Even some fairly big ones. But if you look closely, for example, at Raize Components, my thinking is, "this is what the base components in Delphi should be!" I'm guessing that Raize got to the point where they sold so few licenses that they just sold the rights to EMBT and washed their hands of the product. But here you can see that original attitude perfectly: EMBT initially started trying to sell this wonderful library for WAY more than Raize charged, and it utterly failed -- I'm guessing because people didn't like the idea of shelling out several hundred dollars for something that looks like the next evolution of what you get in the box. So they made it free and added it to the GetIt library, and it lives on there. I've used Raize Components on every project I can rather than the built-in components because they're so much easier to work with. However, I've noticed that Embt regularly adds more updates to the base components than to the Raize Components, and they'll never replace the base components with Raize Components even though most of the latter are literally derived from the former. (That is, TMemo and TrzMemo are both derived from TCustomMemo, and TMemo adds nothing in terms of logic to TCustomMemo, which is how the library is designed.) So you can see that even when the company has had a great reason and opportunity to upgrade the basic components in a meaningful way, they STILL refused! If we were to say that Raize is a relatively small improvement on the built-in components, like traveling across town, then DevEx is more like going to the Moon in comparison! DevEx started out as Delphi-only, but as Delphi sales shrunk, they expanded to cover C# and other platforms (eg, C++) as appropriate. Several big libraries did this, just as a way to survive, thankfully. Because if they hadn't, they wouldn't still be around today. Another vendor that has been VERY ACTIVELY building stuff that enhances Delphi's base components is TMS Software. I believe they have the widest selection of "Made-for-Delphi" components on the market today. And they're constantly releasing improvements across the board. Personally, I'm a HUGE fan of their Biz library, WEB Core tools, and FNC components, and I've used their VCL components in projects here and there many times over the years. I think that WEB Core is taking Delphi in a direction (web apps) that fits where the market is clearly heading, and there's no sign that EMBT has any interest in going in that direction -- so don't expect anything out-of-the-box to get you there today, or probably ever. Long story short, whatever comes "in the box" with Delphi is a "starting point". Very few projects I've worked on find it adequate to build a well-embellished application that has a lot of user-friendly features included -- at least, not without a lot of manual customization of existing components if not fully customized extensions. (I worked on a project once where Management thought TMS charged WAY too much for their ALL-ACCESS Pass when it was only around $1200 USD, and instead had three devs each working for nearly 6 montus building custom components that duplicated what some stuff in the TMS VCL Pack does. Those Devs cost them around $50k each to build components they could have gotten by paying $1200 per seat -- plus dozens more! Never mind that the annual renewal cost for ALL-ACCESS is only 30% of the new license cost, and those fees allow THEM to deal with all of the maintenance and updates.)
  8. David Schwartz

    Curious TRESTRequest behavior

    I've got a datamodule with these components on it: TOAuth2Authenticator TRESTClient TRESTRequest TRESTResponse I'm using them to make a request of a service, and it works fine. Here's what the code looks like: RESTClient.BaseURL := BASE_URL+'list'; // second endpoint is 'api' RESTRequest.Params.Clear; RESTRequest.AddParameter( 'language', aLanguage ); RESTRequest.Execute; Result := RESTResponse.Content; Then I change the endpoint and clear params and make another request, and it blows up. Here's a bit of test code: RESTClient.BaseURL := BASE_URL+'api'; try RESTRequest.AddParameter( 'abcdef', 'kljahsldfkjashdf' ); except on e:Exception do Logger.Debug('--> *** blew up assigning Parameter: '+e.Message); end; Here's the response in the Logger: *** blew up assigning Parameter: Access violation at address 00DED977 in module 'MyWebService.exe'. Read of address FF000240 I have tried everything I can think of, but it just isn't working. (I also tried RESTRequest.Params.AddItem(...) but it does the same thing.) I can call the first API as many times as I want, and it works perfectly. I can go back and forth -- the first one always works, the second one always fails at the same point. It looks to me like there may be a data overrun, but ... why? Any ideas or suggestions?
  9. David Schwartz

    Curious TRESTRequest behavior

    BTW, I very much appreciate all of the suggestions and ideas.
  10. David Schwartz

    Curious TRESTRequest behavior

    O K ... mystery solved ... It looked like a data overrun problem because ... it was. I failed to create an instance of the DataModule I was using, and somehow the first part worked, but the later part looked like it had been overwritten ... which it had. In my experience, when objects haven't been created, they blow up right away. I'll have to remember this -- strange memory overwrite symptoms can be because the object wasn't created!
  11. David Schwartz

    Curious TRESTRequest behavior

    I don't know. These are standard Delphi components, and the Params is a TCollection. I just call Clear to rest them and then add new ones that are arguments for the POST request. As I said, I can go back and forth, and the first API works -- once, twice, five times, however many in a row you want, using different arguments -- and then go to the second API and it fails at the same place every time -- once, twice, ... every time. Back to the first API and it works fine. It blows up simply CLEARING the Params -- I cannot SET any of them. Even if I comment out the Params.Clear it blows up on the first AddParameter / Params.AddItem call it encounters. It's a real head-scratcher. It's ONLY happening inside of the service. But I have no way to debug it ... do I? Can delphi debug it running locally? I was also thinking there could be some threading involved and this could be due to a race condition, but it would all be implicit as I don't do any explicit threading.
  12. David Schwartz

    Curious TRESTRequest behavior

    It CAN'T be destroyed! As I said, I can flip between each API request -- the first one always works, the second one always blows up on any attempt to modify Params. These four objects are on the DataManager "form". It's the SAME OBJECT in BOTH cases! And it did the same thing if I duplicated all of the REST objects and ran them each separately, one set for each API. There's very little logic going on outside of what I showed. A button click goes to each of the methods and that's pretty much all that's done -- Set the API endpoint, clear Params, add new Params, call Execute and wait for the result. Both are POST requests, both are using the same auth details, ... there just aren't that many variables to test. I guess I'll create three of these four REST objects dynamically (using the auth object as it is) and see what happens. If that doesn't work, I'll make another unit and put the second call there and see if that makes any difference.
  13. David Schwartz

    Curious TRESTRequest behavior

    Right now I'm simply asking if this looks familiar to anybody. I've been messing with it for a week now and this is as much clarity as I can get. I *AM* clearing the params in the first endpoint, but in the second one is where it blows up. ANY attempt to alter Params in the second case blows up. It's running in the service so it's hard to track down specifics. The exact same code unit is compiled into another project that all runs locally and it works fine -- I can call both APIs and they work perfectly. Go figure. I'll change the BaseURL setting as you suggest. I forgot about that... been too focused on this main issue.
  14. David Schwartz

    Is there a Delphi equivalent of WriteStr ?

    I use Format for that.
  15. David Schwartz

    FastMM5. Can't get a log file

    semi-OT: I'm doing some debugging and getting some memory leaks. I've used FastMM4 a lot over the years, and it would always drop a log file that was in a specific format. I built a small viewer that parses the file and gives me a more useful look at the data. But on my current project, it only drops the log file if there's an exception thrown or some kind of actual error. Otherwise it shows the log in a popup window upon exit, and if I save it, I can't parse it the same as the regular log file (it's very different). I haven't changed any of the options in forever. When I go through the options in the IDE for the project, I tell it to ALWAYS save a debug file. But I don't see a flag that says "only on errors". Any thoughts on what the problem could be?
  16. Actually, it seems to work in Chrome and Opera, just not Safari for some reason. It's very cool. 🙂
  17. Nothing shows up on the page. It's completely blank.
  18. David Schwartz

    swagger help needed

    I'm trying to build a small test bed in Delphi for accessing an internal company API and there's a swagger link published for it. What I want to do is suck in the Swagger definition and use it to build something that lets me query the API in Delphi. I'm not sure what all that requires. I guess most of the time people use some kind of javascript framework for this; I want to use Delphi. I searched around on Google and found this project: https://github.com/marcelojaloto/SwagDoc There's a demo in it named 'GenerateUnitFileForMVCFramework' that lets me put in the Swagger URL and it generates a Delphi unit. It works fine, but there may be a bug in this code in that it duplicates every class and interface definition. I was able to fix that without much trouble in the code generator, but there may be a problem in the part that's parsing the Swagger. (Right now I don't care.) I guess the MVC Framework comes from here: https://github.com/danieleteti/delphimvcframework I'm not exactly sure what to do from here. I need a way to connect to the service with OAuth2, and then make some queries and display the results in a form, like in a TListview. I'm looking for suggestions on how to proceed. Thanks! FWIW, someone here wrote a similar thing that generates C# code from a Swagger URL, and that code looks very similar to the Delphi code that's generated by this SwagDoc tool.
  19. David Schwartz

    swagger help needed

    hehe, yeah, 3 years later! 🙂 I noticed that when it was released and thought ... where were you back when I need this? 🙂
  20. What exactly are you intending to do with this data? All you've said was this: It's really not very inforamtive. I mean, if these are records or classes, you could make a TList of each one and then export each list as a CSV file, which can be imported in practically anything. Is that all you need?
  21. The thing is, the Fortune algorithm's code is partly in service to a UI that I think in your case is irrelevant. If I'm understanding you correctly, you just need the polygon vertices when the whole process is complete so you can colorize each of them, right? Meaning, I think you can go with a simpler algorithm. The logic behind those hand-made art pieces is about as simple as it gets. There is no UI component at all. You just start with a random set of points and go through the math to find the bisections between pairs of points and points where they intersect. Those intersection points for a given center-point form the coordinates of your polygons. The bisection lines themselves are infinitely long until they're cut off by intersecting with another bisection line. Each of those points is going to be a member of typically three other polygons, and more if there happens to be a highly "perfect" relationship between the "random" points (very unlikely). One of the unique things about the Dr. Dobb's article is that the authors change the coordinate system from (x,y) like (lat, lon) to a pair made up of an (arccos, radius) as measured from the centroid, allowing all the math to be done using 16-bit integers; even 8-bit integers are sufficient for even smaller sized v-cells. At the time it was published (1992), this resulted in a HUGE savings in floating-point computational overhead, but today it's not as significant. It still makes the problem a lot simpler. But, you may object, how does this work for tracking locations on an ellpisoidal sphere like the Earth's surface? Well, the centroids are specified using a 3D coordinate system where (x,y,z) represents the point on the Earth's surface (lat, lon, radius). However, the distance between them is small enough that the voronoi cells can be treated as a 2D surface because the error due to curvature is minimal compared to the error due to localized variations in the Earth's surface over that same area. So the only floating point calculations need to be done on the centroids and everything in between is simple integer-based 2D Euclidian calculations
  22. I'm not sure what Fortune's algorithm has to do with anything except it's not giving you the data you want. Here's a nice theoretical discussion from a University course: https://cs.brown.edu/courses/cs252/misc/resources/lectures/pdf/notes09.pdf Here's your question on SO with a proposed solution: https://stackoverflow.com/questions/68850889/convert-voronoi-edges-into-polygons This might seem silly, but I suspect that modeling a manual method may be the simplest: https://www.instructables.com/Hand-Drawn-Voronoi-Diagrams/ Overall, it doesn't seem that complicated. You just keep bisecting lines between points and the enclosed regions represent your polygons. You pick a point, then trace a bisection line until you hit an intersecting line, then keep going in the direction that gets you closer to the point you're enclosing. (It's pretty much always a Y and the other direction will take you further away.) Those intersection points are the points that form your polygonal surfaces. Here's a C++ implmentation of Fortune's algorithm: https://github.com/dkotsur/FortuneAlgo This is where I was first introduced to Voronoi Diagrams: http://www.lukatela.com/hrvoje/papers/dobbs92.html Here's the DDJ code that goes with that article. At one point I translated most of it into Delphi, but never quite finished. http://www.lukatela.com/hrvoje/papers/dobbs92.zip
  23. David Schwartz

    Delete substring from a string

    assuming you have a string that's just a comma-separated list of numbers like: var nums := '100, 101, 110, 1000, 1010, 1100, 200, 210'; just do something like this: var slist := TStringlist.Create; slist.CommaText := nums; if slist.IndexOf( '101' ) > 0 then // it's there else // it's not
  24. David Schwartz

    Delete substring from a string

    You never stated whether there are always three digits in the list. What if you look to delete '100' from a list of (100, 110, 1001, 1009, 1100) ? Context can be important! You just gave a few samples without telling the whole story about everything that can possibly be in the list.
×