Fabian Haupt · Mar 15, 2017 go to post

Note that this needs to be allowed on the mail server you are using. To prevent spam and spoofing of email addresses (which is what this does), many configurations only allow to set the from address to the account logging into the mailserver. -Fab

Fabian Haupt · Feb 6, 2017 go to post

Does that hold true for in-memory arrays as well? Or only for globals on disk?

Fabian Haupt · Jan 31, 2017 go to post

Hi Ken,

your suspicion is correct. You'll need to map everything in your /webservices path to the csp module. Since your paths for the REST requests don't end with .cls or .csp, IIS won't pass them along to the csp modules.

Best, Fab

Fabian Haupt · Jan 24, 2017 go to post

Hi Marc,

different languages have feature like the annotation you are describing. Most of these have one thing in common: they are quite young. Especially compared to M/COS. That being said, some of the functionality you are envisioning is there already. Well, kinda, sorta ;)

You can use ZBREAK to add hooks to your existing code (even already compiled ones). This is more comparable to introspection than annotation as it happens at runtime. However, with the ZBREAK execute_code parameter it is easy to do anything from any point in your code.

To actually implement annotations the way you are thinking of here, you'd need to implement a wrapping solution around the compiler. You might be able to hook into the source control utilities to do that: extending studio, however, modifying the sourcecode before passing it to the compiler would be difficult.

Using the wrapper approach, you could programmatically create shadow classes of your actual code and insert your annotation's code. This will come with the drawback that you'd have to invoke your shadow classes instead of the direct code. On the other hand it would allow you to have the annotations optional, so you're not slowing down your application once you're done developing.

You could possibly also use generator methods to move the wrapping into the class and generate new methods based on the code you put in and the annotations you added.

HTH, Fab

Fabian Haupt · Jan 23, 2017 go to post

Hi Mack,

there isn't an easy answer for this. The amount of storage heavily depends on how your data and your global structure can be compressed. In storing your globals there are a number of mechanisms that optimize the storage used. It might be useful to have a look at some of the internal mechanisms for that: https://community.intersystems.com/post/internal-structure-cach%C3%A9-database-blocks-part-1.

As you can see from this article (which is still pretty high level), it won't be easy to create an accurate prediction mechanism.

As such, the best way to try this out, would be to just use a small amount of your source data and store it in Caché. This will give you a baseline of how much overhead you can expect. Depending on your data structures there might also be additional indices being created.

So if you try and store 10MB,100MB,1GB,1TB of your source data on a test system, you'll be able to get a pretty good prediction curve out of it with a low error rate. Any other approach either is going to be too much guesswork, or going to need a lot more detailed work, so it would probably not be worth the time.

I tried to include an actual path forward for you, so I hope this helps!

HTH, Fab

Fabian Haupt · Jan 22, 2017 go to post

In that case, we are missing at least the following: visualization, tools, python

Fabian Haupt · Jan 18, 2017 go to post

Not enough information: What else is involved here? Mirroring? Shadowing? How is your namespace setup? Do you have routine mappings? Is it all the queries? Only some? Since when are you seeing the issue? What changed?

You could look at the journal files to see what/if the methods are being changed from another service.  

You might want to consider opening up a WRC issue to get help tracking this down!

-Fab

Fabian Haupt · Jan 16, 2017 go to post

Just a little addition: 

2.5) Your cached query is messed up. 

This comes up from time to time (and imho much more often than 3-7) ;)  

Typical symptoms: slightly different (new) queries DO return data; depending of which incarnation of 'messed up' you are encountering, you might actually get an error instead of actual data. 

Cheers,

Fab

Fabian Haupt · Jan 16, 2017 go to post

As Dmitry already pointed out, it seems you should cover your basics first. 

A CSP page is first and foremost a static page which is being rendered on the server. The data model of webpages has traditionally been dominated by a request-response approach. This comes down to the basic stateless design of http: a client sends requests to GET some information from the server (very simplified). 

This means it is quite difficult to "push" updates from the server to the client. One solution, or rather, workaround to this problem, is to implement a timer on the client side which periodically asks the server if there is new data. This can easily be solved with a javascript timeout. 

Nowadays we have moved on a little bit from this rather clumsy approach. Dmitry already mentioned a possibility for this: websockets. Websockets give you a two way communication channel between your client and your server (see RFC6455). 

This introduced the exciting possibility to actually push events from the server to the client without the need for periodic pulling of information.  

Have a look at this basic example how to do that in Caché technology: asynchronous-websockets-quick-tutorial (shameless plug;) )

There have been quite a few advances and developments in this area, building on the basic websocket connection and building frameworks for the efficient handling and caching of even bigger datasets. React/Flux are just some frameworks you could look at as you make your way through the jungle of web technology. Good Luck!

-Fab

Fabian Haupt · Jan 2, 2017 go to post

Which part is slow?

Resolving of the host? Establishing of the connection? The latency once the connection is established? The transfer of data/characters within a session?

The terminal application on the server itself uses a completely different mechanism to connect to the local instance. So again, what do you mean by slow?

Fabian Haupt · Dec 27, 2016 go to post

Hi Jonathan,

unfortunately there is no easy way to do this from within Caché. The PDF format is a rather complex binary format and Caché doesn't have a library to access it.  There are a couple of tools that allow the annotation of PDF documents, but none of them would allow you to easily integrate with the engine. 

PDF is in itself a rather complex format, so to directly edit it, say via opening it as %BinaryStream, would require you to implement your own PDF rendering engine. (Have a look at [this post](https://blog.idrsolutions.com/2013/01/understanding-the-pdf-file-format…) to get a glimpse of the problems you'd be facing)

The solution to use a PDF as background for the rendering of a new report via FOP might be a way out. But you'd need to know the layout of the incoming PDF and be sure it doesn't change. Only then you could get the ZEN report to print into specific fields. 

-Fab

Fabian Haupt · Dec 27, 2016 go to post

Here is a simple example to upload and store a file via a csp page:

<html>
<head></head>
<body>
 
<form enctype="multipart/form-data" method="post" action="upload.csp">
    Enter a file to upload here: <input type=file size=30 name=FileStream>
    <hr />
    <ul><input type="submit" value="Upload file"></ul>
</form>
 
<csp:if condition='($data(%request.MimeData("FileStream",1)))'>
    <h2>Saving file...</h2>
    <script language="Cache" runat="server">
        Set data=%request.MimeData("FileStream",1)
                 
        Set stream=##class(%FileBinaryStream).%New()
        Do stream.LinkToFile("C:\"_%request.MimeData("FileStream",1).FileName)
 
        While (data.AtEnd'=1) {
           Set x=data.Read()
           Do stream.Write(x)
        }
 
        Set Status = stream.SaveStream()
        If (Status = 1) {
            Write "<h2>Uploaded!</h2>"
        }
        Else {
            Write "<h2>Saving failed!</h2>"
        }
    </script>
</csp:if>
</body>
</html>
Fabian Haupt · Dec 22, 2016 go to post

also, if anything, you should have made it a gif to capture the animation :)

Fabian Haupt · Dec 22, 2016 go to post

@Ben, please remove the screenshot. We want people to run the code themselves! :) No spoilers!

Fabian Haupt · Dec 15, 2016 go to post

Hi, 

is your instance on the same machine? Anything executed with $ZF calls from within your sourcecontrol class is being executed on the instance, not on the machine your studio is running on. 

Also, check out Atelier, with it you get already working version control for not only subversion, but many more.

-Fab

Fabian Haupt · Dec 14, 2016 go to post

Hi Sebastian,

so if I understand you correctly, you want to use your csp application to authenticate users for another application? 

In that case, I would recommend having a look at the oauth article over here and here. Using this SSO approach, you get rid of the problem of transmitting usernames and passwords in cleartext altogether. And it allows your two different applications to use the same credentials. 

Hope this is helps! 

-Fab

Fabian Haupt · Dec 8, 2016 go to post

Hi Scott,

while it is generally possible to search through a stream object for certain strings, it would really depend on the pdf you're putting in here. 

PDF documents are notoriously weird ;) Sometimes the containing text is actually contained as text (similar to postscript), but more regularly pdfs are containing vectorized graphics. In that case you'd have to run  OCR on the document first to get textual information out of it. 

A good test would be to run strings on the document and see if you can spot the information you need. Or you can open the pdf document in a text editor and take a look manually. 

Caché doesn't have a pdf rendering engine itself, so from its perspective it would just be a binary stream of data and you need to interpret it in your code. 

Cheers,

Fab

Fabian Haupt · Nov 18, 2016 go to post

You can use %Net.HttpRequest to do that.

Something along these lines will work (of course you should checks for errors etc...):

USER>s request=##class(%Net.HttpRequest).%New()

USER>d request.Get("http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")

USER>s file=##class(%FileBinaryStream).%New()

USER>d file.LinkToFile("/Users/kazamatzuri/temp/test.pdf")

USER>d file.CopyFrom(request.HttpResponse.Data)

USER>w file.%Close()
1
USER>
Fabian Haupt · Nov 18, 2016 go to post

John,

this has been added under the covers but hasn't made it into the UI or any further. At this point they aren't really in wide-spread use. 

Best,

Fabian

Fabian Haupt · Nov 18, 2016 go to post

Hi Bapu,

without having tested the actual performance difference of these different approaches yet. Usually in a webservice context, the serialisation itself is taking less time than the logic around it.  The requests have to go through the webserver/csp gateway and you have your connections latency and bandwidth to consider as well. 

That being said, why are you trying to use %XML.DataSet? Is your SelectDoses a %ResultSet? See  http://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?APP=1&LIBRARY=%25SYS&CLASSNAME=%25XML.DataSet