How to define a public function in a CXP application
-
- Posts: 167
- Joined: Thu Nov 05, 2020 10:51 am
- Location: DOMINICAN REPUBLIC
How to define a public function in a CXP application
Hello!
I am very excited about CXP. It's an incredible technology, quite robust, agile, safe, it's a shame I didn't start before, due to my fears about configuring the hardware. That, after all, was also easy. Fearing things causes the mind to block, unnecessarily.
For my new Web application, I already have my main menu ready, and I have started to develop some options, such as customer registration. The only drawback I have is not being able to have global functions. In other words, a function defined in the main CXP can be called from the other CXPs. In a CXP there is a Global section. However, functions defined in the Global section can only be used in the CXP where the function resides. I can write DLL helpers, but I would be more comfortable avoiding helpers.
Do any of you have experience defining global functions within the main CXP, and that these same functions can be called from other CXPs?
Best regards.
I am very excited about CXP. It's an incredible technology, quite robust, agile, safe, it's a shame I didn't start before, due to my fears about configuring the hardware. That, after all, was also easy. Fearing things causes the mind to block, unnecessarily.
For my new Web application, I already have my main menu ready, and I have started to develop some options, such as customer registration. The only drawback I have is not being able to have global functions. In other words, a function defined in the main CXP can be called from the other CXPs. In a CXP there is a Global section. However, functions defined in the Global section can only be used in the CXP where the function resides. I can write DLL helpers, but I would be more comfortable avoiding helpers.
Do any of you have experience defining global functions within the main CXP, and that these same functions can be called from other CXPs?
Best regards.
Re: How to define a public function in a CXP application
I don't work with CXP, but if you create several DLLs containing different functionalities, functions from those DLLs are published to other DLLs by including their LIB files. So, if you have a DLL containing your customer registration called "CUST.DLL", publishing functions from this DLL to others is done by
#pragma library("CUST.LIB")
in the PRG files. A PRG having the #pragma can call any (not STATIC) functions from CUST.DLL.
#pragma library("CUST.LIB")
in the PRG files. A PRG having the #pragma can call any (not STATIC) functions from CUST.DLL.
Best regards,
Tom
"Did I offend you?"
"No."
"Okay, give me a second chance."
Tom
"Did I offend you?"
"No."
"Okay, give me a second chance."
-
- Posts: 167
- Joined: Thu Nov 05, 2020 10:51 am
- Location: DOMINICAN REPUBLIC
Re: How to define a public function in a CXP application
you're right Tom.
Excellent idea. I wanted to eliminate the use of DLL, but the matter is not so traumatic, if I include the library that has the function through #pragma.
Thank you.
Also, Tom, I take this opportunity to thank you for your opinion on the library I bought, to work on my new web application. You realized that your views, or presentations in the browser were obsolete. I was able to reconsider in time, thanks to your recommendations, and currently I use Bootstrap, and Metro UI, with great efficiency and modernity.
In fact, Alaska Fotware has used Metro UI, and has made some interfaces with it, handled through the XppWebUI library. I have come late to modernity, but I am making the most of it, and I am very happy with what I have achieved.
I thank you again.
Excellent idea. I wanted to eliminate the use of DLL, but the matter is not so traumatic, if I include the library that has the function through #pragma.
Thank you.
Also, Tom, I take this opportunity to thank you for your opinion on the library I bought, to work on my new web application. You realized that your views, or presentations in the browser were obsolete. I was able to reconsider in time, thanks to your recommendations, and currently I use Bootstrap, and Metro UI, with great efficiency and modernity.
In fact, Alaska Fotware has used Metro UI, and has made some interfaces with it, handled through the XppWebUI library. I have come late to modernity, but I am making the most of it, and I am very happy with what I have achieved.
I thank you again.
Re: How to define a public function in a CXP application
Hi. Diego.
Great to hear it works for you! Maybe you can show a little of what you achieved?
Great to hear it works for you! Maybe you can show a little of what you achieved?
Best regards,
Tom
"Did I offend you?"
"No."
"Okay, give me a second chance."
Tom
"Did I offend you?"
"No."
"Okay, give me a second chance."
-
- Posts: 167
- Joined: Thu Nov 05, 2020 10:51 am
- Location: DOMINICAN REPUBLIC
Re: How to define a public function in a CXP application
Hello Tom.
Yes, of course, as long as I have something more robust, I can show it. At the moment, I only have the main menu, and the customer registry. First I wanted to concentrate on the logistics of the matter. In fact, the only thing that changes is what is displayed in the browser, which must be HTML. Your Xbase++ code is not lost, since you can create a DLL, with all your source programs, and include it in the XML where the hepelrs are defined. I even included the Express library in the hepelrs. Before, the project was an EXE, now it is a DLL. What must be replaced, as I said before, is the view that will appear in the browser. Before it was a dialog, and now an HTML.
In Alaska Xbase's WebSamples folder, there are two very interesting projects: one called event management, developed with Metro UI, and another called order reservation, developed with Bootstrap. Both projects have a very modern aesthetic. My new project, based on those examples from Alaska, is practically a copy. I wasted a lot of time trying to avoid learning HTML, and trying to avoid configuring IIS. It was a serious mistake.
The important thing is that I have reconsidered. That's where I've invested more time, learning HTML, and a bit of javascript. For the rest, the logic of Alaska Xbase++ is still intact, very functional, and almost totally to the Web, through the HttpEndpoint() server, and libraries that facilitate the handling of HTML such as XppWebUI.
It's really fabulous.
Yes, of course, as long as I have something more robust, I can show it. At the moment, I only have the main menu, and the customer registry. First I wanted to concentrate on the logistics of the matter. In fact, the only thing that changes is what is displayed in the browser, which must be HTML. Your Xbase++ code is not lost, since you can create a DLL, with all your source programs, and include it in the XML where the hepelrs are defined. I even included the Express library in the hepelrs. Before, the project was an EXE, now it is a DLL. What must be replaced, as I said before, is the view that will appear in the browser. Before it was a dialog, and now an HTML.
In Alaska Xbase's WebSamples folder, there are two very interesting projects: one called event management, developed with Metro UI, and another called order reservation, developed with Bootstrap. Both projects have a very modern aesthetic. My new project, based on those examples from Alaska, is practically a copy. I wasted a lot of time trying to avoid learning HTML, and trying to avoid configuring IIS. It was a serious mistake.
The important thing is that I have reconsidered. That's where I've invested more time, learning HTML, and a bit of javascript. For the rest, the logic of Alaska Xbase++ is still intact, very functional, and almost totally to the Web, through the HttpEndpoint() server, and libraries that facilitate the handling of HTML such as XppWebUI.
It's really fabulous.
Re: How to define a public function in a CXP application
Hi Diego,
When you are developing a web app using a web technology you should use web solutions.
CXP allows to execute one CXP page from other CXP page(s), and that is a proper solution. The CXP page to be called is standalone and it can be called anytime from any CXP page. You should read CXP documentation how to do that.
DLL solution is a desktop, not a web solution. You should create all you web functionalities with web solutions.
When you are developing a web app using a web technology you should use web solutions.
CXP allows to execute one CXP page from other CXP page(s), and that is a proper solution. The CXP page to be called is standalone and it can be called anytime from any CXP page. You should read CXP documentation how to do that.
DLL solution is a desktop, not a web solution. You should create all you web functionalities with web solutions.
Best regards,
Slavoljub Damnjanovic
SD-SoftDesign, Alaska Software Technology Partner
https://www.sd-softdesign.com
https://www.sd-softdesign.rs
Slavoljub Damnjanovic
SD-SoftDesign, Alaska Software Technology Partner
https://www.sd-softdesign.com
https://www.sd-softdesign.rs
-
- Posts: 167
- Joined: Thu Nov 05, 2020 10:51 am
- Location: DOMINICAN REPUBLIC
Re: How to define a public function in a CXP application
Hello SlavkoDam,
I differ with you. My opinion is different from yours. The only thing that fits in a Web project is the views, or screen displays, since these are executed in the browser. All alaska functions work the same, and you can include them in a CXP, or in a DLL. The commands that don't "work" are those from the graphical desktop GUI. I put it in quotes, because these cannot go out to the browser, but when they are executed, they do not give an error, since they are listened to by the HTTPCXPENDPOINT server that is in the backend.
I bought Alaska Xbase++ 2.0 a year ago. I spent a year studying the Web samples that come with the Alaska package, and some of them use DLLs. There are very complete examples, which look like applications, for developers to take as an example. I started very late with my project. The important thing is that I already understand the logic of the matter.
Best regards.
I differ with you. My opinion is different from yours. The only thing that fits in a Web project is the views, or screen displays, since these are executed in the browser. All alaska functions work the same, and you can include them in a CXP, or in a DLL. The commands that don't "work" are those from the graphical desktop GUI. I put it in quotes, because these cannot go out to the browser, but when they are executed, they do not give an error, since they are listened to by the HTTPCXPENDPOINT server that is in the backend.
I bought Alaska Xbase++ 2.0 a year ago. I spent a year studying the Web samples that come with the Alaska package, and some of them use DLLs. There are very complete examples, which look like applications, for developers to take as an example. I started very late with my project. The important thing is that I already understand the logic of the matter.
Best regards.
Last edited by Diego Euri Almanzar on Sat Jul 09, 2022 4:40 pm, edited 2 times in total.
-
- Posts: 167
- Joined: Thu Nov 05, 2020 10:51 am
- Location: DOMINICAN REPUBLIC
Re: How to define a public function in a CXP application
Code: Select all
<"<!--
/// <code id="ccfe068a-ffa3-4a06-8e23-6920cdd70804" version="1.0.0"/>
/// <summary>
/// Dynamically create an image
/// </summary>
/// <objective>
/// The dynamic content returned by CXP pages is not limited to
/// simple HTML. Instead, arbitrary content can be generated.
/// In this sample, a GIF image is created in CXP code and
/// is then returned to the browser. No HTML markup is used here.
/// Instead, the member variable :ContentType and the method
/// :WriteBinary() of the HTTP response object are used to send
/// the image data back to the browser.
/// </objective>
/// <load>load_grafik.html</load>
/// <author name="Alaska Software Inc." year="2011"></author>
/// <order id="100"/>
/// <category order="100" tags="advanced"/>
///
-->
<%#code locality="page-global"%>
<%
/// Calculates the differences of two colors in means
/// of readable contrast.
FUNCTION LuminosityDiff(aRGB1,aRGB2)
LOCAL L1,L2
L1 := 0.2126 * (aRGB1[1]/255 ^ 2.2) + 0.7152 * (aRGB1[2]/255 ^ 2.2) + 0.0722 * (aRGB1[3]/255 ^ 2.2)
L2 := 0.2126 * (aRGB2[1]/255 ^ 2.2) + 0.7152 * (aRGB2[2]/255 ^ 2.2) + 0.0722 * (aRGB2[3]/255 ^ 2.2)
IF(L1 > L2)
RETURN(L1+0.05) / (L2+0.05)
ENDIF
RETURN (L2+0.05) / (L1+0.05)
/// Returns a RGB color pair randomly selected with an
/// readble/acceptable contrast
FUNCTION ChooseRandomColor()
LOCAL aRGB1,aRGB2,nDiff
// Random Select color pairs, calculate contrast and select
// only those which are readable
aRGB1 := { RandomInt(50,200) , RandomInt(50,200), RandomInt(50,200) }
DO WHILE .T.
aRGB2 := { RandomInt(0,255) , RandomInt(0,255), RandomInt(0,255) }
nDiff := LuminosityDiff(aRGB1,aRGB2)
IF(nDiff>1.0100)
RETURN( { aRGB1, aRGB2 } )
ENDIF
ENDDO
RETURN(NIL)
%>
<%#code locality="page-render"%>
<%
#include "gra.ch"
#include "xbp.ch"
// The image created in this sample can easily be embedded in
// other HTML or CXP pages using an ordinary HTML markup.
// Example: <img src="./grafik.cxp" >.
// See load_grafik.html for an example
xs := 250
ys := 150
// Choose random colors
aColors := ChooseRandomColor()
// Create a bitmap and associate it with a
// canvas object we can use for drawing
oBmp:= XbpBitmap():New():Create()
oPS := XbpPresSpace():new():create()
oBmp:presSpace( oPS )
oBmp:make( xs , ys )
// Set up a font for text output
oFont := XbpFont():new()
oFont:familyName := "Segoe UI"
oFont:height := 16
oFont:width := 12
oFont:Create()
oPS:SetFont(oFont)
// Erase the bitmap with color yellow,
// then draw some text
oPS:SetColor( GraMakeRGBColor(aColors[1]), 0)
GraBox(oPS,{0,0},{xs,ys},1,0,0)
// Randomly rotate the text a bit
aMatrix := GraInitMatrix()
GraRotate( oPS , aMatrix, RandomInt(-15,15), {125,75}, GRA_TRANSFORM_ADD )
oPS:setGraTransform( aMatrix, GRA_TRANSFORM_REPLACE )
oPS:SetColor( GraMakeRGBColor(aColors[2]), 0)
GraStringAt(oPS,{10,80},"Image by Xbase++")
GraStringAt(oPS,{10,60},"Create Time " + Time())
// Get the binary image data of the bitmap
// in GIF format and send it back to the
// browser as our page result. To do this,
// we need to first specify the content/mime
// type of the binary data we send via the
// HTTP response object
::HttpResponse:ContentType := "image/gif"
::HttpResponse:WriteBinary( oBmp:SetBuffer(, XBPBMP_FORMAT_GIF) )
oBmp:Destroy()
%>" />
But, the Alaska developers have defied "gravity", and have made the browser what they wanted, they are geniuses.
For example, I attach a source where they bring their graphic mode to the browser.
I'm very grateful to you, SlavkoDam, but when it comes to what to send to the browser, I'm already an expert. If you really want to help me, it will be by telling me or helping me send a PDF to the browser, through your library POWERWEB, or through any other library like PDFJS.
I am already using PRINT ON, and other functions of the EXPRESS library within my CXPs, because I refuse to leave behind my reports, and the design of invoice tickets, and receipts. It is strange that a library to develop WEB APP does not have a PDF converter, or at least a PDF viewer, because everything is incomplete when the documents cannot be printed. Roger went to great lengths to help his users report, and he gives us examples like customers.cxp
But, if it is a WEB library like POWERWEB, it is essential that it has a PDF viewer. Because, as I said before, an APP without printing an invoice or reports is not an APP.
At least now I was able to convert my reports through the Express library. I just need CXP, or a WEB library to allow me to send them to the browser.
Thank you very much.
<!--
/// <code id="ccfe068a-ffa3-4a06-8e23-6920cdd70804" version="1.0.0"/>
/// <summary>
/// Dynamically create an image
/// </summary>
/// <objective>
/// The dynamic content returned by CXP pages is not limited to
/// simple HTML. Instead, arbitrary content can be generated.
/// In this sample, a GIF image is created in CXP code and
/// is then returned to the browser. No HTML markup is used here.
/// Instead, the member variable :ContentType and the method
/// :WriteBinary() of the HTTP response object are used to send
/// the image data back to the browser.
/// </objective>
/// <load>load_grafik.html</load>
/// <author name="Alaska Software Inc." year="2011"></author>
/// <order id="100"/>
/// <category order="100" tags="advanced"/>
///
-->
<%#code locality="page-global"%>
<%
/// Calculates the differences of two colors in means
/// of readable contrast.
FUNCTION LuminosityDiff(aRGB1,aRGB2)
LOCAL L1,L2
L1 := 0.2126 * (aRGB1[1]/255 ^ 2.2) + 0.7152 * (aRGB1[2]/255 ^ 2.2) + 0.0722 * (aRGB1[3]/255 ^ 2.2)
L2 := 0.2126 * (aRGB2[1]/255 ^ 2.2) + 0.7152 * (aRGB2[2]/255 ^ 2.2) + 0.0722 * (aRGB2[3]/255 ^ 2.2)
IF(L1 > L2)
RETURN(L1+0.05) / (L2+0.05)
ENDIF
RETURN (L2+0.05) / (L1+0.05)
/// Returns a RGB color pair randomly selected with an
/// readble/acceptable contrast
FUNCTION ChooseRandomColor()
LOCAL aRGB1,aRGB2,nDiff
// Random Select color pairs, calculate contrast and select
// only those which are readable
aRGB1 := { RandomInt(50,200) , RandomInt(50,200), RandomInt(50,200) }
DO WHILE .T.
aRGB2 := { RandomInt(0,255) , RandomInt(0,255), RandomInt(0,255) }
nDiff := LuminosityDiff(aRGB1,aRGB2)
IF(nDiff>1.0100)
RETURN( { aRGB1, aRGB2 } )
ENDIF
ENDDO
RETURN(NIL)
%>
<%#code locality="page-render"%>
<%
#include "gra.ch"
#include "xbp.ch"
// The image created in this sample can easily be embedded in
// other HTML or CXP pages using an ordinary HTML markup.
// Example: <img src="./grafik.cxp" >.
// See load_grafik.html for an example
xs := 250
ys := 150
// Choose random colors
aColors := ChooseRandomColor()
// Create a bitmap and associate it with a
// canvas object we can use for drawing
oBmp:= XbpBitmap():New():Create()
oPS := XbpPresSpace():new():create()
oBmp:presSpace( oPS )
oBmp:make( xs , ys )
// Set up a font for text output
oFont := XbpFont():new()
oFont:familyName := "Segoe UI"
oFont:height := 16
oFont:width := 12
oFont:Create()
oPS:SetFont(oFont)
// Erase the bitmap with color yellow,
// then draw some text
oPS:SetColor( GraMakeRGBColor(aColors[1]), 0)
GraBox(oPS,{0,0},{xs,ys},1,0,0)
// Randomly rotate the text a bit
aMatrix := GraInitMatrix()
GraRotate( oPS , aMatrix, RandomInt(-15,15), {125,75}, GRA_TRANSFORM_ADD )
oPS:setGraTransform( aMatrix, GRA_TRANSFORM_REPLACE )
oPS:SetColor( GraMakeRGBColor(aColors[2]), 0)
GraStringAt(oPS,{10,80},"Image by Xbase++")
GraStringAt(oPS,{10,60},"Create Time " + Time())
// Get the binary image data of the bitmap
// in GIF format and send it back to the
// browser as our page result. To do this,
// we need to first specify the content/mime
// type of the binary data we send via the
// HTTP response object
::HttpResponse:ContentType := "image/gif"
::HttpResponse:WriteBinary( oBmp:SetBuffer(, XBPBMP_FORMAT_GIF) )
oBmp:Destroy()
%>
- Attachments
-
- GRAXBASE.jpg (66.31 KiB) Viewed 4831 times
Last edited by Diego Euri Almanzar on Sun Jul 10, 2022 7:39 pm, edited 2 times in total.
-
- Posts: 167
- Joined: Thu Nov 05, 2020 10:51 am
- Location: DOMINICAN REPUBLIC
Re: How to define a public function in a CXP application
Continuing with my comment, about the DLLs in a CXP project,
I attach an XPJ document of the applications developed by Alaska, and that come as an example in version 2.0
They recommend including all desktop application prg sources in DLL files, which they call helpers. I have been guided by those examples, and I have done the same. Obviously, instead of having screen views in Xbase graphics, I have replaced them with render calls to CXP files, so that they can be seen in the browser.
Best regards.
[PROJECT]
VERSION = 2.1
project.xpj
[project.xpj]
event-management.web
helpers\ical-helper.dll
helpers\event-helper.dll
[event-management.web]
COMPILE = xpp
COMPILE_FLAGS = /q /w
DEBUG = yes
GUI = no
LINKER = alink
LINK_FLAGS =
RC_COMPILE = arc
RC_FLAGS =
HOSTPROCESS = index.cxp
// $START-AUTODEPEND
// $STOP-AUTODEPEND
application.config
site.layout
add-event.cxp
delete-event.cxp
edit-event.cxp
export-events.cxp
index.cxp
list-events.cxp
save-event.cxp
show-event.cxp
show-events.cxp
toggle-event.cxp
[helpers\ical-helper.dll]
COMPILE = xpp
COMPILE_FLAGS = /dll:dynamic /ga
DEBUG = yes
GUI = no
LINKER = alink
LINK_FLAGS = /dll
RC_COMPILE = arc
RC_FLAGS =
// $START-AUTODEPEND
ical-helper.obj
// $STOP-AUTODEPEND
ical-helper.prg
[helpers\event-helper.dll]
COMPILE = xpp
COMPILE_FLAGS = /dll:dynamic /ga
DEBUG = yes
GUI = no
LINKER = alink
LINK_FLAGS = /dll
RC_COMPILE = arc
RC_FLAGS =
// $START-AUTODEPEND
event-helper.obj
// $STOP-AUTODEPEND
event-helper.prg
I attach an XPJ document of the applications developed by Alaska, and that come as an example in version 2.0
They recommend including all desktop application prg sources in DLL files, which they call helpers. I have been guided by those examples, and I have done the same. Obviously, instead of having screen views in Xbase graphics, I have replaced them with render calls to CXP files, so that they can be seen in the browser.
Best regards.
[PROJECT]
VERSION = 2.1
project.xpj
[project.xpj]
event-management.web
helpers\ical-helper.dll
helpers\event-helper.dll
[event-management.web]
COMPILE = xpp
COMPILE_FLAGS = /q /w
DEBUG = yes
GUI = no
LINKER = alink
LINK_FLAGS =
RC_COMPILE = arc
RC_FLAGS =
HOSTPROCESS = index.cxp
// $START-AUTODEPEND
// $STOP-AUTODEPEND
application.config
site.layout
add-event.cxp
delete-event.cxp
edit-event.cxp
export-events.cxp
index.cxp
list-events.cxp
save-event.cxp
show-event.cxp
show-events.cxp
toggle-event.cxp
[helpers\ical-helper.dll]
COMPILE = xpp
COMPILE_FLAGS = /dll:dynamic /ga
DEBUG = yes
GUI = no
LINKER = alink
LINK_FLAGS = /dll
RC_COMPILE = arc
RC_FLAGS =
// $START-AUTODEPEND
ical-helper.obj
// $STOP-AUTODEPEND
ical-helper.prg
[helpers\event-helper.dll]
COMPILE = xpp
COMPILE_FLAGS = /dll:dynamic /ga
DEBUG = yes
GUI = no
LINKER = alink
LINK_FLAGS = /dll
RC_COMPILE = arc
RC_FLAGS =
// $START-AUTODEPEND
event-helper.obj
// $STOP-AUTODEPEND
event-helper.prg
Re: How to define a public function in a CXP application
Hi Diego,
You are talking about two different matters, printing a report and displaying a PDF. They are not the same. Yes, you can convert printing report to PDF and display it in that format, but way to do that when you can display and print it directly.
With PowerWeb library you can create a report and print it on a printer in Xbase++ style and in web style, I have already sent you examples how to do that. Yes, there is no function to convert a report to PDF, but its not the prime goal of creating a report. The main thing is that with PowerWeb library you can display a report in a browser and print it on a printer. It is your way to convert all your reports automatically to PDF and present them in that format. I don't think that all programmers in any languages, desktop or web, follow only that way. Converting a report to PDF, or any other format (why just PDF?), can be only an option and not a must. That is the usual way in programming.
The purpose of PowerWeb library is to create a functional web UI in Xbase++ style, without knowledge of web programming and without using any other external tools, and it fulfills that. PowerWeb library is pure Xbase++ code and its unique in that. It don't have any format converters, since it is not mandatory in any application. Yes, its useful and convenient, but not mandatory. There is no mention of format converting in PowerWeb documentation. If you want more when using PowerWeb library, you can freely add-on some other tools with functionalities you need.
Good luck with PDF.
You are talking about two different matters, printing a report and displaying a PDF. They are not the same. Yes, you can convert printing report to PDF and display it in that format, but way to do that when you can display and print it directly.
With PowerWeb library you can create a report and print it on a printer in Xbase++ style and in web style, I have already sent you examples how to do that. Yes, there is no function to convert a report to PDF, but its not the prime goal of creating a report. The main thing is that with PowerWeb library you can display a report in a browser and print it on a printer. It is your way to convert all your reports automatically to PDF and present them in that format. I don't think that all programmers in any languages, desktop or web, follow only that way. Converting a report to PDF, or any other format (why just PDF?), can be only an option and not a must. That is the usual way in programming.
The purpose of PowerWeb library is to create a functional web UI in Xbase++ style, without knowledge of web programming and without using any other external tools, and it fulfills that. PowerWeb library is pure Xbase++ code and its unique in that. It don't have any format converters, since it is not mandatory in any application. Yes, its useful and convenient, but not mandatory. There is no mention of format converting in PowerWeb documentation. If you want more when using PowerWeb library, you can freely add-on some other tools with functionalities you need.
Good luck with PDF.
Best regards,
Slavoljub Damnjanovic
SD-SoftDesign, Alaska Software Technology Partner
https://www.sd-softdesign.com
https://www.sd-softdesign.rs
Slavoljub Damnjanovic
SD-SoftDesign, Alaska Software Technology Partner
https://www.sd-softdesign.com
https://www.sd-softdesign.rs