Noutați

Free (Reverse)Geocoding with OpenStreetMap Nominatim in TMS FNC Maps

TMS FNC Maps v2.2 now includes a new free geocoding service in addition to the existing supported geocoding services from Azure, Bing, Google, Here and MapBox. OpenStreetMap Nominatim The OpenStreetMap Nominatim API service provides geocoding and reverse geocoding free of charge and does not require an API key. This service can be used in combination with all supported mapping services in TMS FNC Maps. Specifically in combination with the OpenLayers mapping service this is a worthwhile free alternative to comparable paying services. Geocoding A geocoding request converts a text address to a latitude & longitude coordinate. The coordinate can then be used to display a location on the map. With the following code we are going to look up the location of “Baker Street, London” and display it on the center of the map with a marker and a title that contains the address.Note that this example uses the asynchronous method with a callback. procedure TForm1.Button1Click(Sender: TObject); var Item: TTMSFNCGeocodingItem; begin TMSFNCGeocoding1.Service := gsOpenStreetMap; TMSFNCGeocoding1.GetGeocoding(‘Baker Street, London’, procedure(const ARequest: TTMSFNCGeocodingRequest; const ARequestResult: TTMSFNCCloudBaseRequestResult) begin if (ARequestResult.Success) and (ARequest.Items.Count > 0) then begin Item := ARequest.Items[0]; TMSFNCMaps1.BeginUpdate; TMSFNCMaps1.SetCenterCoordinate(Item.Coordinate.ToRec); TMSFNCMaps1.AddMarker(Item.Coordinate.ToRec, Item.Address); TMSFNCMaps1.EndUpdate; end; end ); end; Reverse Geocoding A reverse geocoding request converts a latitude & longitude coordinate to a text address. The text address can then be used to display an address associated with a location on the map. With the following code we are going to track a click on the map, retrieve the address for that location and display it on the map with a marker and a title that contains the address Note that this example uses the synchronous method that provides an immediate result without a callback. procedure TForm1.TMSFNCMaps1MapClick(Sender: TObject; AEventData: TTMSFNCMapsEventData); var Address: string; begin TMSFNCGeocoding1.Service := gsOpenStreetMap; Address := TMSFNCGeocoding1.GetReverseGeocodingSync(AEventData.Coordinate.ToRec); TMSFNCMaps1.BeginUpdate; TMSFNCMaps1.SetCenterCoordinate(AEventData.Coordinate.ToRec); TMSFNCMaps1.AddMarker(AEventData.Coordinate.ToRec, Address); TMSFNCMaps1.EndUpdate; end; Available Now The TMS FNC Maps v2.2 update is available now for Delphi & Visual Studio Code (with TMS WEB Core). You can download the latest version and start using the new features right away!

Read More

The Inexorable Rise Of The Supercharged Developer

Over time, software development has experienced a major drift not just in implementation, but in terms of the mindset as well. Back in the day, the engineering teams had clear, specific, and defined roles. The individuals in the team were expected to perform their part of the duty with minimalistic involvement and participation in other fields. Now that we are living in an agile world, the engineering mindset has been revamped and every individual is regarded as a full-stack package and should have the knowledge and expertise to execute the end-to-end cycle of software development. In this article, we’ll look at some of the key points of focus for software developers as an all-in-one package, especially when it comes to desktop and native application development. How can I make a full-fledged application using third-party APIs? Nowadays, when we talk of disruption and breakthrough technologies, it is highly dependent on time investment. Disruption in technology comes with effective use and management of time. Therefore, it is useless to recreate the wheel and engineer things from scratch that are already available in the form of open-source projects, SDKs, toolkits, packages, and libraries. When it comes to desktop or native ecosystems, we know that desktop apps are powerful execution tools that can natively run on your local machine to provide holistic application navigation and utilization experiences. With the advancement of modern web technologies, the desktop application development paradigm also experienced a major drift in terms of implementation. Technologies such as JavaScript and Python have inspired the hybrid implementation of desktop apps. Delphi is by far one of the most popular choices for native desktop application development. To develop a full-fledged application, you can easily integrate third-party APIs in your Delphi code and create exciting desktop applications as an all-in-one developer. For instance, you need to create an application that involves some modules related to maps. For this problem statement, you already have Google Maps APIs readily available. You can simply utilize these ready-to-use Google Maps APIs and map them according to your use case. Similarly, there are tons of other APIs, libraries, and SDKs for different use cases that you can use and integrate without starting the development process of these modules from scratch. Leveraging APIs such as those from API Layer among others is the smart way to use other people’s hard work to inject that kind of capable broad-strength modernity into your apps. Supercharged developers employ smart techniques to reach their targets – and there’s nothing smarter than standing on the shoulders of giants who have already done the hard work for you. What is an easy way to develop an end-to-end artificial intelligence-based application? Undoubtedly, artificial intelligence is at a boom right now and there’s every sign that this is a trend which is very much here to stay. There are tons of applications and use cases where AI has proved beneficial. From the technology and development perspective as well, researchers and engineers are actively working on producing dynamic and scalable frameworks that facilitate the development of AI applications. As the AI offerings improve and new techniques are refined many of the things we previously only thought possible in science fiction or would require vast computing resources are becoming available to regular developers at extremely affordable pricing plans and with easy […]

Read More

Introducing the new TMS Aurelius Dictionary

TMS Aurelius 5.6 has been released, and the major feature is a brand new, full-feature dictionary. Aurelius dictionary is intended to be used in Aurelius queries. The idea is that instead of using strings to reference entity properties, you use the dictionary properties directly. For example, a usual Aurelius query is like this: Results := Manager.Find   .Where(Linq[‘Name’].Like(‘M%’))   .List; But the above approach is error prone, the ‘Name’ string can be wrong, it can be wrongly typed, or the name might be modified. You will only find the errors at runtime. With the dictionary, you can write the query like this: Results := Manager.Find   .Where(Dic.Customer.Name.Like(‘M%’))   .List; You can also reference associated objects, for example, querying all invoices where the country of the customer of the invoice is from Brazil:   Manager.Find     .Select(Dic.Invoice.Total.Sum)     .Where(Dic.Invoice.Customer.Country.Name = ‘Brazil’) It’s a simple thing that makes a huge difference when you are using it daily. You have code completion, you have compile-time check, you minimize the errors at runtime. In summary, it increases your productivity a lot. TDictionaryGenerator.GenerateFile(‘C:SomeFolderMyDictionary.pas’); Or from command-line using the AureliusDictionaryGenerator.exe tool, which generates it from a BPL package: AureliusDictionaryGenerator.exe -i:Default -p:”C:MyProjectBplEntities” “C:MyProjectMyDictionary.pas” Last but not least, the dictionary can be validated at runtime! This way, if somehow the dictionary and the real classes do not match (for example, you might modify your classes and forget to generate the dictionary again), the dictionary will tell you the differences: TDictionaryValidator.Check(Dic); It’s as simple as that. This way you make sure you don’t have surprises at runtime and your dictionary is correct! This is an awesome new feature that brings a night-and-day difference when writing Aurelius queries. If you want to have more detailed information, of course please refer to the documentation where all the above features are explained in details. Wagner R. Landgraf

Read More

Do You Know The German Word For “Sauerkraut”?

You know, the hardest part about learning a new language is remembering some of the more esoteric words and phrases. Does that error message say “syntax error” or “successful compilation”? Does that button really say “end” in Danish or has there been some kind of horrible misunderstanding? How do I exit VIM? Just kidding – nobody knows that. But seriously, it’s not just the rote learning of words which are direct equivalents of your own first language, it’s also about noting down phrases which mean something entirely different in the one you are trying to master. My own favorite is the French phrase “il s’offre des fleurs“, literally, “he gives himself flowers” but it actually is used to mean that a particularly vain man thinks a little too highly of himself. Audio notebook to the rescue! This offline Audio Notebook helps you learn a new foreign language. According to the developer, “The own individual vocabulary (words, phrases, idioms) for learning a foreign language is entered from you in your native language (left) and in the foreign language (right). In addition, an audio note (for example, the debate in the foreign language) be included. Thus you can specifically customize the learning to your own needs the new language. Listen to the audio recording on the bus or on the train and thus strengthening your sense of language and your vocabulary. The lyrics and the audio example: you can at any time and thus adapt easily. The detained words, phrases or expressions can be corrected and completed. You can also add or remove new superfluous. For learning a language you put just a new language (language folder) and you add your own lessons. The foreign-language expression can be shown or hidden. This facilitates learning. If you are looking for something, then use the full-text search, so you can browse through all lessons and display the desired text and then edit them as necessary.” Oh, and Sauerkraut? It’s a Chinese invention…. but the word is totally German. Google Play Sprachen Lernen-AudioNotizbuch Screenshot Gallery RAD Studio Delphi can help you turn your great ideas into reality. Why not download a free trial copy today and see what it can do for you?

Read More

Everything You Need To Modernize With RAD Server

In the modern age isn’t it true to say we are completely surrounded and immersed in technology of diverse forms? Much of it now is entirely cloud-based but there’s still a substantial proportion which employs a mix of both cloud and more physical hardware computing resources. However, the common thread amongst all of these technologies, even the most recent ones, is the certainty of them becoming obsolete. After all, even though all technologies evolve rapidly, they are eventually replaced by something which is either an evolutionary step thanks to advances in technological offerings or because new and more potent ways of providing a service or solving a problem emerge. To save a technology or application from fading into oblivion, its makers consistently upgrade it with new features and prepare it in anticipation of future trends and ways of doing things. As simple as this may seem, such a task can become arduous, especially if the application is complex and has a wider codebase. Additionally, many of the libraries and frameworks on which the application is built can go out of service or are superseded and need updates. To tackle the challenge of upgrading and modernizing an application, robust development studio solutions like RAD Server have powerful methods that streamline the process. Such methods help you gain a sense of the kind of changes you will have to implement. Additionally, they also guide you through the modernization tasks themselves. This article dives into what the modernization journey with RAD Server looks like and why can be essential for applications in the first place. Why Would You Need To Modernize Your Applications? The field of software development has a radically different landscape today to that of even five years ago. Applications now use their hardware resources much more efficiently thanks to advances in operating system abstraction and support. The wide range of programming languages enables you to create applications which perform complex tasks better than before and with optimizations in the code creation process thanks to a maturing of the development industry’s tooling providers and the supporting component eco-system. If your application is to survive in such a landscape, it will have to modernize and offer more than before. When it comes to web applications, advancements in what we have come to expect from a web browser and the rendering scaffolding which supports that have come by making them much more dynamic and robust. Developers can now create web applications at remarkable development velocity and, when done right, the same codebase can work on all kinds of devices thanks to the invention of techniques like adaptive rendering of user interfaces and virtualization of hardware differences to provide a generic API or set of properties and methods which address the lowest common denominator of hardware sensors and functionality . Modularity has also been achieved through microservices, and operations have become as serverless as feasible. The question of security and scalability has also become an integral part of the conversation around application development. With a rise in cybersecurity concerns, applications need to be secure throughout and use the best practices. Additionally, the applications also need to be scalable to accommodate a wider user base and deployment when necessary. Without these abilities, your application can lose its competitive edge and be eventually forgotten. What Is […]

Read More

Static code analysis for Delphi with TMS FixInsight v2021.10

We are pleased to announce the immediate availability of the new TMS FixInsight version v2021.10! Highlights of this new release are: Delphi 11 support Better type resolving Improved & more robust code parser 5 New code analysis rules added The first three highlights are quite obvious, but let’s have a deeper look at the 5 new code analysis rules that have been added and that will enable you to detect possible code issues faster. W537 Format parameter type mismatch The Delphi compiler is not able to check data types used in Format() function. The example below will compile, but will never work properly. FixInsight is able to catch that.  var  StringTypeParameter: string; begin   Result := Format(‘String type parameter value = %d’, [StringTypeParameter]); end; W539  Interface method call passing the same interface reference as out parameter In the example below access violation will be raised because Delphi compiler cleans up Node variable before the actual Node.GetParent() function call.  type    INode = interface   [‘{39EE5CA9-C4C1-46E1-B326-BAA2D004A5CD}’]    function GetParent(out Parent: INode): Boolean; end;  TNode = class(TInterfacedObject, INode) strict private   // INode.    function GetParent(out Parent: INode): Boolean; end; { TNode } function TNode.GetParent(out Parent: INode): Boolean; begin   Parent := TNode.Create;   Result := True; end; procedure InterfaceErrorSample; var   Node: INode; begin   Node := TNode.Create;   // Before calling Node GetParent, the compiler generates code that clears the Node variable   // because the GetParent parameter is declared with the out parameters.   // Thus calling Node.GetParent will result in AV.   while Node.GetParent(Node) do     // Getting root node.   ;   // Do somthing with root node. end; W540 String variable used twice in a call both as an output and an input parameter In the example below Str parameter in IsStringSliceNotEmpty() function will always be an empty string if you pass the same variable twice. Because the variable will be cleaned up by Delphi compiler. function IsStringSliceNotEmpty(const Str: string; out Slice: string; Index, Count: Integer): Boolean; begin   Slice := Copy(Str, Index, Count);   Result := Slice ”; end; procedure StringErrorSample; var   Str: string; begin   Str := ‘qwerty’;   if IsStringSliceNotEmpty(Str, Str, 1, Length(Str)) and (Str[Length(Str)] = ‘y’) then     ShowMessage(Str); // ShowMessage never run because Str was cleared before the SliceString call. end;  W541 Type-casting from Pointer to Integer type (or vice versa) Type casting from Pointer to Integer and Integer to Pointer is often used in legacy code. But it is not safe on some platforms, because types size are differ. For instance, Pointer is 8 byte on x64, and the code below will lead to data loss. procedure TypecastSample(A: Pointer); var   B: Integer; begin   B := Integer(A);   //… end; W542 Direct floating-point comparison There are several not obvious problems with comparing floating-point numbers. They are perfectly explained in DocWiki https://docwiki.embarcadero.com/RADStudio/Sydney/en/Floating-Point_Comparison_Routines In short, you should never use equal sign to compare two floating-point numbers, but rather use special comparison routines. var    X:Single;    Y:Double; begin   X:=0.1;   Y:=0.1;   if X=Y then    Writeln(‘Equal’)   else    Writeln(‘Not equal’);   ReadLn; end. The program outputs: Not equal Get the update & increase the quality of your code! If you have an active license for TMS FixInsight, the update is available for you free. Users with an expired license […]

Read More

Discover the Abstract IP Geolocation API with FNC

Intro You would be amazed to find out how much detailed and accurate information you can retrieve from an IP address. Collecting data based on the IP address can be key to various parts of your business. Want to know where your customers are located during an online meeting? Want to include this technology in your application to gather statistical data and don’t know exactly how to get started? The TTMSFNCCloudIPLocalization component (part of the TMS FNC Cloud Pack) is designed to retrieve detailed and accurate information from an IP address and is capable of doing this via the IP Geolocation API from Abstract. The TTMSFNCCloudIPLocalization component is able to retrieve the following information from an IP address. Country name, code & flag image Region name & code Virtual Private Network (VPN) detection Internet Service Provider (ISP) information Latitude & Longitude Timezone information Getting Started The code snippets below are based on the IP Geolocation API from Abstract to retrieve the information we want to visualize. To get started, you will need to create a free account. After logging in, go to dashboard, select IP Geolocation. The process only takes a couple of seconds, afterwards you can copy the API key which is required to work with the TTMSFNCIPLocalization component. Below you can see the page you get after setting up your account. The above steps is all we need to do get started with the TTMSFNCIPLocalization component. Drop an instance of TTMSFNCIPLocalization on the form. Set the API key and set the service property. (Replace ‘MyAPIKey’ with a valid API key). TMSFNCCloudIPLocalization1.APIKey := ‘MyAPIKey’; TMSFNCCloudIPLocalization1.Service := ipsAbstractAPI; TMSFNCCloudIPLocalization1.OnGetIP := DoGetIP; After assigning the OnGetIP event, add a button with the following code to retrieve your own IP address. TMSFNCCloudIPLocalization1.GetIP; Alternatively, you can also add a custom IP address. This can be done with the following code. (Replace ‘x.x.x.x’ with a valid IP address) TMSFNCCloudIPLocalization1.GetIP(‘x.x.x.x’); After clicking the button, calling the GetIP procedure, the OnGetIP event will be triggered. In this event, we have immediate access to the information retreive from the IP address. Backtracing which IP address was requested can be done via AIP.IPAddress procedure TGetIPDataForm.DoGetIP(Sender: TObject; AIP: TTMSFNCCloudIPLocalizationIP; AError: Boolean; const ARequestResult: TTMSFNCCloudBaseRequestResult); begin //retrieve IP address information via the AIP parameter end; Below is an overview of the properties that are available when using the AIP parameter after the request has finished executing. Demo Included in the distribution is a demo, which shows the capabilities of the TTMSFNCCloudIPLocalization component. Below is a screenshot of the demo in action. Note that the IP address and coordinates have been blurred for privacy reasons. Additional Services The blog post focuses on the IP Geolocation API from Abstract, but the TTMSFNCCloudIPLocalization component is also capable of connecting to the following additional services. The account creation and API retrieval process is different for each service, but the way the component operates remains identical. To select one of the other services, set the Service property to either ipsIPData or ipsIPStack and set the API key for that specific service. IPData IPStack Available Today! The TTMSFNCCloudIPLocalization component is available in the latest update, available today. So go ahead and download the latest version of the TMS FNC Cloud Pack. The TMS FNC Cloud Pack is part of the FNC family, so as a reminder, below is an overview […]

Read More

What Is It Like To Be A Developer Brian Barr?

Hello. This article is part of a series where we speak with professional software developers, ask them what it’s like to write code for a living, and perhaps gain a few insights into the software development industry along the way. Talking to us today we have fellow British Delphi fan Brian Barr. Brian is based in Norfolk, England nestled by the English East Coast which brought back many nostalgic memories to me of driving through the wonderful local countryside since my own late father used to live in that area. Brian has a fascinating background coding Delphi programs for use in the TV and radio industry even before the launch of Delphi 1. His Barrcode application reaches an astounding 50 million listeners and viewers products every week. Thank you for taking part in the interviews Brian! Thanks for the homework! 😂 What would be your brief evening news summary of who you are and what you do? Written Delphi programs for the TV and radio industry before Delphi 1 came out. Started writing in BBC Basic for the BBC Model B. Wrote digital playout systems for the biggest commercial radio stations in the UK. Now writes software for the major TV channels in the UK. How and/or why did you become a developer? I was a radio station engineer working with electronics, I needed to learn programming to write some automation systems to support diversely skilled staff. Do you think you will ever stop being a developer? If so, what would be next? Never Brian is not actually from Florida What made you start using Delphi/C++ Builder? As I recall, I saw Delphi 1 in a magazine. I needed to program on the Windows PC platform and Delphi showed much promise. If you could give some advice to a student who is considering a career as a software developer, what would it be? Research the subject thoroughly. Principles of programming are pretty universal – all languages have an IF statement and various loops. Get used to structuring your code so that when you are old, you can still work out what it does. Tabs… or spaces? Spaces – silly!! Don’t get me started on where the “begin” should be. What’s the best day you ever had as a developer? Too many – getting a major contract for Capital Radio in London – led to many more stations. What’s the worst thing about being a developer? When things go wrong – you feel responsible for the chaos. What’s the coolest development tip you know? When things don’t work – it’s always YOUR fault! Work from home, work from an office, work in an open plan / shared space? What do you prefer and why? Do you get to choose? Work from home. My time is my own, also the freedom to leave the keyboard when my brain aches. Tell us something interesting you think we might not know. Darth Vader IS Luke’s father!! Have you been to Silicon Valley? If so, how was it? If not, have you ever wanted to? Who wouldn’t want to program in the sunshine? Have you ever met any famous/well known tech figures? Who was it? How did it go? Because I was in a radio station, I met many “famous” people. Once was shown round […]

Read More

How To Create A Super-Fast Pusher Notification App

What is Pusher ? Pusher is a set of bidirectional APIs targeted on real time communication. The main use case of those APIs are : Real time charts (cryptocurrency values) Network games (synchronization of players) In app chat (application support) Real time results (basketball, soccer, baseball) Instant geolocation (products to home delivery) What are the main specifications of Pusher ? Pusher is a publish-subscribe messaging system that allows to exchange messages reliably and effectively. Pusher solves by design the problems of : Scale of number of messages and users The real time constraint of messages delivery. Pusher supports the concept of channels. A channel of communication can have 4 different type : Public Private Encrypted Presence What is a Public Channel in Pusher? Public channels should be used for publicly accessible data as they do not require any form of authorisation in order to be subscribed to. What is a Private Channel in Pusher? Private channels should be used when access to the channel needs to be restricted in some way. In order for a user to subscribe to a private channel permission must be authorized. The authentication occurs via a HTTP Request to a configurable authentication url when the subscribe method is called with a private- channel name. What is an Encrypted Channel in Pusher? An encrypted channel is similar to a private channel. However the content of the message is end-to-end encrypted  This encryption follows the specifications of the Secretbox encryption standard defined in NaCl and the message is encrypted before it leaves the server. Only authorized subscribers have access to the channel specific decryption key. This means that nobody except authorized subscribers can read the payload data, not even Pusher. End-to-end encrypted channels also provide end-to-end authenticity; that is your messages are protected from forgery, and that they are guaranteed to come from someone who holds the encryption master key. What is a Pusher Presence Channel? Presence channels build on the security of Private channels and expose the additional feature of an awareness of who is subscribed to that channel. This makes it extremely easy to build chat room and “who’s online” type functionality to your application. How can I integrate Pusher into my Delphi app? The first step is to create an “application” on Pusher.com First of all users need to subscribe to the Pusher network and create an application. Pusher will generate several ids and keys needed to use the Pusher system as follows: With all this data, the developer will be able to interact with the Pusher system. How do I connect to the Pusher network with the TsgcWSAPI_Pusher component of ESEGECE? The low-level communication with Pusher is based on web socket. As a result you can find a Pusher component in the websocket component suite of ESEGECE. You can download the component suite from here. The component installation is done by the compilation the bpl for the Delphi version. There are full instructions and it’s quite easy to do, even for novices. Now, in RAD Studio Delphi, create a new application and drop on the main form the web socket component TsgcWebSocketClient and the Pusher component TsgcWSAPI_Pusher. In the property of the pusher component we will need to set : sgcPusher.Pusher.Cluster := ‘eu’; sgcPusher.Pusher.AppId := myAppid; sgcPusher.Pusher.Key := myKey; sgcPusher.Pusher.Secret := mySecret; sgcPusher.Pusher.TLS := True; […]

Read More

Stay on top of what’s happening in the Delphi world with new webinars in October

The Delphi train is unstoppable. Not only did Embarcadero bring a brand new Delphi 11 with tons of valuable new features, our team also worked around the clock to keep bringing useful add-ons to get even more out of Delphi. Here is your chance to stay on top of this with three webinars we have scheduled in October so far: The Aurelius dictionary : Oct 7, 2021 4h00PM UTC / 18h00 CET Learn more about the brand new TMS Aurelius dictionary feature, and how it will bring even more capabilities to your favorite ORM framework for Delphi. Get compile-time errors, check for dictionary validation and make your database queries even easier to build.In short, a webinar that is not to miss for anyone pondering about adding ORM technology to existing applications or get even more out of Aurelius based applications! Your host is Wagner Landgraf, the architect and product manager for TMS Aurelius. Register here now! The new WX pack, new territories open for your Delphi apps : Oct 12, 2021 3h00PM UTC / 17h00 CET WX Pack controls bring a brand new approach to leverage existing non-trivial and complex components and libraries for Delphi VCL Windows applications, cross-platform FireMonkey applications or web client apps. Among the first such components in WX Pack will be: PDF viewer, QR code generator, barcode generator, text to speech, OCR, JSON viewer, …  Learn about the architecture of the new WX controls and see how these are universal and work in VCL, FMX, LCL or WEB Core apps. See the first WX controls in action. We will show also new WX controls in development, what further WX controls we have on our radar and we listen to your questions and inputs, suggestions for more WX controls. Your host is Bruno Fierens, CTO of tmssoftware.com.  Register here now! Miletus brings creating Raspberry Pi apps from your Delphi IDE : Oct 19, 2021 3h00PM UTC / 17h00 CET Miletus technology now also enables you to create applications running directly on the Raspberry Pi SBC. And this all directly from the Delphi IDE. And of course, from the Miletus application, you can control various hardware accessories via the i²c, SPI or UART on the Raspberry Pi. Discover how Miletus will empower you to bring Raspberry Pi apps from the Delphi IDE in this webinar!  Your host is Bruno Fierens, CTO of tmssoftware.com.  Register here now! TMS WEB Academy All webinars will be brought to you via the TMS WEB Academy. Our TMS WEB Academy is our platform, fully created with TMS WEB Core to host webinars for you. During the webinars, interaction is encouraged, you can ask questions via messages or directly spoken and when extra resources are coupled with the webinar content, these will also be live shared during the webinar.

Read More