Jump to content

David Schwartz

  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by David Schwartz

  1. 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.
  2. David Schwartz

    swagger help needed

    Just FYI, I'm not "still on" any particular version of swagger. The project I _was_ on had swagger info published that's generated from Microsoft tools that are in widespread use, and that code itself reports that it was V2.0. I have sampled a bunch of swagger specs I've found around the internet, and I've found very few that are V3.0. I don't know who produces these or how, but if most are being generated by MS tools, then consider it's MS themselves that's responsible for this disparity. Certainly nothing I'm connected to. (I'm not on that project any more, and anyway they had told me not to even use Delphi. So at this point it's just a curiosity.) If MS isn't supporting V3.0, then I'm not sure who's going to use it if it's really that hard to parse.
  3. You might want to look at TMS WebCore running on VSC.
  4. David Schwartz

    swagger help needed

    The API I was originally working with is internal, but I've tried reading a number of ones I've found around the internet. There are tons of them. I'm not understanding why java is needed to build something to consume JSON text, build some internal tables, then spit out Delphi classes. From playing with the earlier referenced code, the trickiest part lies in two areas: 1) recognizing isomorphic structures (ie, classes with the exact same data members) and combining them into a single definition; and 2) if you allow selecting only certain APIs or groups, then optionally being able to emit only dependent variable and class definitions and skip everything else. The first step is needed to avoid having a bunch of identical classes defined just because the Swagger code defined them and didn't name them, but the parser gave them all unique default names; or they were named in the Swagger text and all were given different unique names for no particular reason. (I saw a situation recently where a common error return structure generated over 50 identical classes where each one had been given a different name. It's completely unnecessary, and simply requires that the structure of these be recognized as identical and a common base class generated that's used for all references. Worst-case, it would be used as the base class for child classes derived from it. I'd lean towards leaving them all referring to the common base class, then maybe add derived classes to distinguise different error returns, or whatever makes sense in the context. A flag to give you a choice might be a nice option.) There's also the matter of how the emitted classes are ordered. The original code sorted them alphabetically, which might not work for Delphi. If you remove the sorting, then they are emitted in the order they're encountered in the Swagger spec, which may not translate into proper ordering for Delphi either. So internally, it needs to have a way of flagging dependencies and using that to emit code in "layers", or at least in an order where dependent types, vars and classes get defined before they're referenced.
  5. David Schwartz

    swagger help needed

    I don't even use Java, so this isn't much help for me. This thing from my original post: https://github.com/marcelojaloto/SwagDoc and related updates already gets us into the ballpark. The main problem is that it assumes the use of the MVC framework here: https://github.com/danieleteti/delphimvcframework Instead of calling the mvc framework, it needs callbacks or another way to handle data as its parsed. I guess JSON can be a little ambiguous in some cases, which makes it hard to parse?
  6. David Schwartz

    Download Images from a URL

    The FNC components are intended to save you the most EXPENSIVE time -- YOUR PROGRAMMING TIME. If you don't value your time, then don't bother using them. You could also look at the source code and see what they're calling "under the hood" to investigate if there may be a more efficient approach on one platform or another. There may well be. But so what? In order to get a set of components that work and act the same on all platforms, they've needed to implement certain abstractions that are necessarily going to have a cost. That said, the time of the data transfers in this instance will, in most cases, swamp out the abstraction logic, unless they're doing unnecessary data copies. The truth is, most people do not bother to optimize their images in the first place. So you're looking in the wrong place for large speed improvements! Do you have any idea how much bandwidth is wasted by people who take 16 MPixel images then send them to their friends to look at in a 1" x 1" box on their cell phone? A 16 MP image is like a full HD screen in resolution; the 1" x 1" box on the cell phone is under 10kb for an image that most people couldn't see any difference between the two. You need to optimize the images BEFORE they're downloaded to get the most sigificant improvement in DL speeds! Because there's nothing you can do to move an 8MB image as if it's only 10KB in size.
  7. David Schwartz

    Event Listeners Delphi <-> Web

    This problem reminds me of a system I had to analyze in college for an Information Analysis course that involved a new meal ticketing system being set up in the cafeterias around campus. They wanted people to be able to buy a meal ticket at any of the cafeterias, right there in line. So Joe would buy a ticket, get it scanned, and go in to have lunch; but his buddy Bob would come by just as he was entering and say "Hey, Joe!" and they'd shake hands and the ticket would invisibly move from Joe to Bob. Then Bob would go to another cafeteria and use it again. They knew there was a problem, and some said it was a bug in the software. But that wasn't it. Joe got what he paid for, but Bob got a free meal. This is a very old and common problem involving a state machine that has nothing to do with Delphi, web apps, firing events, QR codes, or how many gaming centers a company may or may not have. And it's not so much a matter of programming as it is recognizing the nature of the problem and the best approach to a solution. First, I suggest you rewrite the description, leaving out all of the implementation details. They may be causing you confusion. Express it as a list of "current_state -> event -> next_state" rules. Second, refresh your knowledge of protocols and state machines, and review "protocol sequence diagrams" and maybe "state transition diagrams". (There are certainly tools that let you do this, but a pencil and paper are probably much quicker.) Third, go read some of the RFCs for email handling on the internet from back in the 70s and 80s. The internet was literally designed to survive a nuclear attack that took out random data centers, and the data packets (eg, email messages) would still find their way to their destination in a reasonable time-frame. (Results may depend on one's definition of "reasonable".) What you're trying to model here isn't much different than how basic email delivery is managed. Data moving at 150 baud on a dial-up line is pretty damn slow by today's standards; but sending out a 64 byte packet (probably overkill for this) will still make it 10 miles across town way faster than any human can move. Which leads us to the forth and final thing to do: write up the Terms and Conditions that apply to all kinds of tickets and how they can be used in this network. Starting with the misnomer that "customer buys a ticket" equals "days of free [access]". That's like saying if you buy a bus pass for a week then you get a week of "free rides". No! If you don't have that pass with you and you're caught, it's going to be even MORE expensive than what you already paid, right? (This was the source of the problems with the meal ticketing system I analyzed. They were selling tickets at the door, but the data was entered manually some hours later, but before the next meal. So the tickets could be used any number of times between when they were purchased and when they got entered into the system. They had to change the rules about when tickets could be purchased, and ensure the data was entered into the system before they could be used.) Terminology is important when it comes to design. In this case, the system might actually support "free passes". And if a center is stuffed to the gills with customers who PAID for tickets, you might want to BLOCK those with "free passes" from coming in, or just during certain times. See the distinction?
  8. David Schwartz

    caFree & ,Free??

    Marco is enumerating a few ways of approaching a common situation. Which you choose is up to you, based in large part on surrounding contextual stuff you might know about in that situation that someone else would not. You're asking something like, "What is the best way to introduce a person to another person in terms of what you say?" Are they two friends of yours? Are they strangers to you? Is one a dignitary? Is one the opposite sex and you have to follow certain rules? Are they possibly antagonistic towards each other (eg, a drug dealer vs. a police officer)? Is one a family member or someone you are concerned about for some reason? Do you have an agenda in introducing them? You seem to be asking for something to say that will work in 100% of situations. It's not possible without sometimes sounding like an idiot. You need to adapt your interactions to the situation at hand, just like you would employ different water management policies in a rain forest as opposed to a desert, although you'd use the same tools in both cases.
  9. David Schwartz

    Learning Delphi

    I just made a list of some stuff off the top of my head. These are all things I run into pretty regularly, so they're not very mysterious. It would be instructive to make a list of all of the different ways the following three common idioms are expressed by different programmers in different projects, and how many variations can be found within the same large project: * Logic that would use a Case with a string discriminant if the language supported it * Ways of mapping Enums or regular consts (both numbers and strings) at run-time to some kind of display string that's more readable, including how they're initialized * Form interactions (we could be talking 2-3 DOZEN here!). Variations would include these idioms for both getting and setting values in the form: -- auto-create vs. on-the-fly creation and destruction -- constructor injection -- requires overloading Create that hides default ctor -- property injection -- method injection -- direct access of members (UGH!) -- forms that manage Add / Edit in the same form vs. one for each -- embedded selection popups on fields: read-only vs. ability to add something new (requires another form) -- field validation (before vs. after exiting the form) -- Hiding / Closing / Freeing the form Actually, I bet a whole book could be written on "Form Interactions in Delphi". It's hard to argue there's a "right way" or even a "best way" to do it, but there certainly are a LOT of ways!
  10. David Schwartz

    caFree & ,Free??

    This is a REALLY BAD APPROACH. I don't care if you use with or not. But you don't create an object then say "with <object> do" and then refer to the object in a Finally to free it AFTER you ALREADY FREED the object inside of the Try block! But you don't know at this point because you already (and invisibly) delegated the form's lifetime to the form itself. BAAAAAAADDDDDD! Here's what you could use instead: // Do NOT override the Create to inject parameters into the form unless they're actually required. with TMyForm.Create(self_or_NIL); try // Forms rarely if ever need Constructor injection. The most common misuse is passing DB-related details into // forms that are designed to only work with one table or one specific query or stored proc. It's hardwired. // It just needs a key to do a lookup. And don't rely on the "current record" in another form! // Instead, use PROPERTY INJECTION to initialize properties in TMyForm here, eg., by passing in a key. // And yes, TMyForm is an OBJECT and you should access things inside of it using PROPERTIES! // The setter for this property could trigger a DB lookup that initializes other fields on the form. UserName := 'Fred Flintstone'; . . . // now show the form, and do NOT delegate lifetime to the form if (ShowModal = mrOK) then // requires setting the Action param to caClose NOT caFree!!! begin // now retrieve values from properties in the form, if needed. // note that you can't do this if you use caFree since it's DESTROYED at this point! // which is why it's a Bad Idea to delegate lifetime to the form. // You're using a with statement here, so you can't set it to nil. And even if you weren't, // there's no way to know that the form killed itself. // Unfortunately, it will work often enough that you'll think the occasional exception is for other reasons. Result := PhoneNum; . . . end; finally // NOW Free the form instance Free; end; This is a nice, solid pattern that will serve you well in ALL form interactions. The only excuse not to use it (and not use PROPERTIES inside of the form) is if you're being LAZY. The use of with can be debated until the cows come home and it boils down to a religious debate; but at the end of the day it's really a personal preference as far as I'm concerned. But the way you've done it is obviously error-prone and not something you'd want to do everywhere (for consistency). See my CodeRage 9 talk for more on this topic: https://www.youtube.com/watch?v=JgOhg2GbydQ
  11. David Schwartz

    Learning Delphi

    Right out of school ... it will depend what they were exposed to in school. They probably understand OOP and OOD, but may not have much experience with strongly-typed languages like C/C++ and Pascal/Delphi. To me, after 40 years, most imperative languages all look the same, except for added things for stuff like vectors, parallelism, and more esoteric stuff that all tend to be language-specific. The latest feature that most languages are adopting is the use of "attributes" on classes and class members. I don't know how Delphi's stack up against any others, but it may be worth discussing. Other than that, what I'd call the "dynamics" are going to be a big part of what can hang them up. For instance, Delphi has added some interesting features to the language like for...in that make using various kinds of containers a lot easier. But there are things missing from Delphi that make it impossible to use some of these newer features at times. For...in is great unless you need to refer to the index or position of the selected item in the list, for example. The lack of a trinary operator means there are lots of if...then...else statements that could be collapsed into a much simpler trinary expression. There's the IfThen method, but it evaluates both arguments before choosing one, which makes it useless when trying to avoid referencing null pointers. Most contemporary languages accomodate both of these things today, so it might seem confusing in that respect. (Delphi may support it in an upcoming release as part of NULL expressions, but a trinary operator could have been introduced in the languge way back that simplified it forever.) The RTL has been extended using class helpers to mirror a lot of stuff commonly found in C# today. Class helpers seem like a hack to me, but they do let you introduce new methods into a class without having to either modify the class itself or subclass it. Unfortunately, they're not inheritable, which seems really strange to me (and probalby newcomers as well). Most contemporary languages also support case statements that take strings as discriminant variables, but not Delphi. This gives rise to maybe a dozen different ways people work-around this missing language feature that's only missing for little more than "religious" reasons. Initialization of arrays, lists, and objects in Delphi is something that isn't often consistently applied within and across projects, so make some clear recommendations. (Good Idea for a Coding Style document.) In particular, if you have a list of Enums, there's a common practice of prefixing them with a couple of letters so you know what class they belong to. This prevents simple use of RTTI to get a string representation of their name to display at run-time. So you need a second array of names and a lookup function for that purpose, although I've seen slightly more elegant ways of doing it that escape my mind at the moment. (To me this sort of variable-name-to-string-name mapping should be a fundamental language feature of every programming language ever written. In practice, few if any offer anything at all.) This stuff can be really confusing to people familiar with what other contemporary languages offer in their place. So I'd say give them a lot of "bread-and-butter" type code to write and do a lot of code reviews to suggest alternate ways of expressing things to expand their understanding of the language and RTL. If you're having them build UI-based apps, try to instill some good coding practices, like avoiding putting logic into Event handler methods. It's so easy to do, right? For example, the presence of an Add and Edit button on a form might lead to two almost identical methods, one of which might initialize stuff from one set of vars while the other will initialize with constants. And to allow a "Cancel" button, you probably need to track whether you're in Add or Edit mode. (Forms that use DB-aware controls can handle this directly.) One thing that I personally find quite ridiculous is the fact that most Delphi programmers don't treat interfacing with forms the same way as other objects. For reasons going back to Delphi 1, Delphi allows the programmer to reach directly into forms and fiddle with local variables and even fields from methods inside of the client forms (which are bona fide objects!) using with them, where nobody in their right mind would do the same thing with normal objects. I see very few Delphi apps that do this consistently and what I'd say is "correctly". Again, I think this gets into more of a "religious" debate, but if there's not a lot of consistency in how it's done in your projects, a new programmer is going to naturally ask "WHY?" and be rightfully confused over something that really has no excuse other than the programmers were lazy. Finally, keep on the lookout for use / abuse of global variables. As far as learning the language itself goes, I'd say any old Delphi book from D4 onwards can be used as a guide for most things, except the screenshots of the IDE. Newer versions have more methods in older (ie, "classic") objects than are found in older books, but what's there is pretty much all still 100% valid. I'd also be tempted to give them some exercises to learn all they can about TStringList. It has always been one of the objects in the RTL that I've used the most over time, and they seem to keep adding new functions to it with every Delphi release. This is what comes to mind in a few minutes. There's probably a lot more.
  12. David Schwartz

    Learning Delphi

    Of course, there's also Marco's latest book. And even stuff like old Delphi 3 and 4 books would work for covering the basics (just don't look at the screen-shots!). Are they new to programming? Or just new to Delphi?
  13. David Schwartz

    Copy a form in a project?

    I'm taking an approach where I'm building something piece by piece where I do some work with a form until I get where I want to be, then I want to clone it and modify it for the next step. So each step is a separate form. This is simply for development purposes, and I don't want separate projects. I'm curious if there's an easy way to "smart copy" a form? Right now it seems you have to "Save As..." a new form name, then rename the form and its class, then add the previous form back into the project. Are there any wizards that might add a "Copy form..." or "Clone form..." option to the Project Manager's right-click on a form name?
  14. David Schwartz

    How to gracefully get rid of the use of dictionaries?

    I saw where it ended up, although I didn't look all that closely at the details. Just chiming in with my thoughts about the use of TDictionary in the first place, AND the use of code to explain code.
  15. David Schwartz

    How to gracefully get rid of the use of dictionaries?

    Code is supposed to reflect your design goals. I get nervous whenever someone tries explaining their design with code. I still don't know what you're trying to accomplish here other than change your code somehow. Are you familiar with Einstein's famous quote: "You cannot solve a problem at the same level of logic used to create it"? You showed us some code, assert there's a problem, then ask how to rewrite the code to solve this supposed problem without explaining a larger context. Several people made guesses based on assumptions they all had to make, but none of us really know for sure what the problem really is. I mean ... I do not understand why the dictionaries are there in the first place either.
  16. You are conflating "Is-A" and "Has-A" attributes. You're not talking about different kinds of humans. (Is-A) You're talking about Employees that all "Have-A" different Role. And each Role "Has-A" set of properties, like Responsibilities, Authorities, Permissions, etc. Each management level "Has-A" set of people who report to them. Also, just because you can look at something like an Org Chart that's hierarchical does not imply there's an "Is-A" relationship anywhere. Job roles are not inherited from the top-down! Nor even from the bottom-up. Each layer "Has-A" different set of properties, some of which may be delegated from time to time and for different durations, but they're certainly not all inherited for ever and ever. "Has-A" is called "composition" "Is-A" is called "inheritance". Since the larger context here is a "business", the base class identified as "human" is more of a distraction than anything else. Sure, everybody working in a business is a "human", but so what? Virtually every one of those people will, in reality, tell you that nobody at the company gives a crap about their life outside of the context of the business, which therefore excludes the vast majority of what their "human" attributes would include. If you dont have a much larger context in which all of those other attributes are being used, then it's "too abstract". No, the common attribute everybody at a company shares is better described as an "Employee". That might be a subclass of "human" but the vast majority of the human parts are irrelevant as far as the company is concerned. Just ask anybody who's not being paid a living wage or decent benefits! The company asks, "Why are these MY problem?" Technically, they're not. At least, not until you look at a much larger context of the role the company has in society, for example -- which is a question far too many people here in America prefer to ignore because they have been brainwashed into thinking that's "socialism" or even "communism". But that's what happens when your base class brings along too much baggage. It also leads to confusion. Try starting with "Employee" as your base class and see what happens. At that point, pretty much everything else can be expressed as collections of properties -- that is, "Has-A" attribute collections. Maybe there are some things where inheritance applies, but mostly you're talking about lots of mutually exclusive collections of rights, permissions, and authorities.
  17. David Schwartz

    Delphi LAMP- or WAMP-based Web Application

    Perhaps check out TMS WebCore ...
  18. David Schwartz

    Developer Express gave up on FMX

    I've never much cared for FMX as most of my work is Windows-based. I guess if you're working in mobile platforms, then FMX would make sense. But DevEx grids are so massive and there are so many tiny features that they just don't seem like something that would fit on a tiny screen unless you have tiny fingers and very sharp eyesight.
  19. David Schwartz

    50 Years of Pascal

    Libs, not DCUs. I don't know what they were called, or even when they were introduced since I never used TP. I jumped on-board when Turbo C++ was released.
  20. David Schwartz

    50 Years of Pascal

    a "timesharing calculator"! LOL!
  21. WebCore is really cool. I'm wanting to build an audio-based app using the Web Audio API. The pas2js guys processed the API with their magical tool and provided it as one of the free interface libs included with WebCore, but there's not a single bit of documentation and no examples. I've been trying to reproduce some of the many examples published for the API in JS, but either I'm not clear about how things are supposed to work (which is quite likely) or there's something about this library that's not working as intended (also very likely). Anyway, it would be great to find some other folks who are also interested in this API to help figure things out. I've asked them to adapt some existing JS examples, but Bruno says the guys are just too busy. Is anybody else here interested in audio?
  22. David Schwartz

    Refactor menu grayed out for Rename...

    I've noticed this quite a bit. Also, for some projects, the <ctrl>-Space does nothing, even though the project compiles and runs fine. Restarting the IDE doesn't help.
  23. At work, all of our computers and networks and everything need to be compliant with PCI, HIPPA, and a half-dozen other security protocols. So when we install software in Windows, we need to elevate to Admin. Most software has shows something that asks if we want to install for "this user" or "All Users". Delphi doesn't ask that, and seems to default to "this user" -- which if you're forced to install as Admin, means a lot of stuff is not accessible if you're NOT running as Admin. We are forbidden from running any sort of normal stuff as Admin! So I'm unable to install updates or new software in my laptop. Maybe there's a flag that lets you set this somewhere? I know a lot of Delphi is used in healthcare environments that are subject to HIPPA and other provisions, so I can't be the only person having to deal with this. (Note: I don't have this problem on my own machine; it's only an issue with my work computer.)
  24. David Schwartz

    50 Years of Pascal

    Originally, Intel built a custom chip for a calculator company who decided not to use it. So Intel made some small modifications and released it as the 4004. It got a lot of interest, but it only had a 4-bit data path. So not long after that, they released the 8008 with 8-bit data paths and registers. I was in 8th grade, I think, and saw something in Popular Electronics about this and wrote the company asking for more info. I got a reply from a guy in their Marketing Dept named William H. "Bill" Davidow. He sent me a rather large package of stuff, including a printout of the source code for their "monitor" software, the thing that evolved into the "boot ROM" code. When you get into most routers today, the UI is still nearly the same. 🙂 (People have asked me why I don't get "Cisco certified" as if it would open up lots of job opportunities for me. I ask, "Why? I spent many years writing and adapting that same ugly software for lots of different equipment! Those routers look exactly the same as what I worked with in the early 1980s.") Intel then released the 8080 and learned a very important lesson: The 8080 instruction set was different from the 8008, and so they naturally put out an assembler that was different. They charged an arm and a leg for their dev systems, and when people discovered they'd have to start all over rewriting their 8008 software to run on the 8080, including more dev systemss, they balked. So someone quickly rewrote the 8008 assembler to generate code for the 8080, and with minimal changes it could then be used to generate code for either one. This put the 8080 on the map. A guy named Charlie Bass left Intel and founded a company named Zilog, who then came out with the Z80 chip. It was the 8080 with a dozen or so additional instructions. But they had their own assembler with a different syntax, and nobody wanted to rewrite their code. Intel actually had the 8085 in the pipeline with almost the same bunch of additional instructions as the Z80, and they watched as the market refused to adopt the Z80's extended instructions. Shortly before its release, the afor-mentioned Bill Davidow -- who was now Intel's VP of Marketing -- decided the Z80 was not a threat, and when they released the 8085 it was only touted as being faster than the 8080 while consuming less power. And it had one additional instruction. However, the entire first generation of 8085 chips were all endowed with a full complement of extended instructions that were never officially documented. The next release did away with most of them. When the 8086 came out, they had learned their lesson, and the assembler would accept all of the source code written for the 8008, 8080, and 8085 chips, with additional features added for the new 8086 instructions. Intel realized that to ensure you got your existing customers to adopt your newer technology, you had to make it as frictionless as possible to "upgrade". That ultimately extended to hardware as well. When they introduced the 80386, they published "reference designs" of the motherboards. But so many companies didn't want to go to the hassle of building their own that Intel eventually started outsourcing their reference designs to HW manufacturers. When the 80486 went into general release, they had a list of sources with motherboards IN-STOCK that their customers could buy to start working with right away. I suspect it has a lot to do with why the latest Delphi compiler will STILL compile Delphi 1 code (and even TurboPascal code with minimal changes). Sad to say, there are still companies that haven't figured this out!