go to post Timothy Leavitt · Nov 4, 2016 Here's one lazy option: USER>w $System.SQL.CEILING(.1) 1 USER>w $System.SQL.CEILING(1.2) 2 USER>w $System.SQL.CEILING(1.7) 2 If you look at the implementation of that method in %SYSTEM.SQL, you'll see: $s('$isvalidnum(val):"",+val[".":+$p(val,".")+(val>0),1:+val) So that's another option (although messier).
go to post Timothy Leavitt · Nov 2, 2016 Stepping back a bit: What endpoint are you using? From Terminal, I see different certificates for googleapis.com and www.googleapis.com: USER>set old = $io set dev = "|TCP|443" open dev:("googleapis.com":443:/TLS="Demo") use dev w 123,! use dev s cer = $System.Security.Users.SSLGetPeerCertificate() use old w $System.Encryption.X509GetField(cer,"Subject"),!,$System.Encryption.X509GetField(cer,"Extension:subjectAltName") CN=www.google.com,O=Google Inc,L=Mountain View,ST=California,C=US DNS:www.google.com USER>close dev set old = $io set dev = "|TCP|443" open dev:("www.googleapis.com":443:/TLS="Demo") use dev w 123,! use dev s cer = $System.Security.Users.SSLGetPeerCertificate() use old w $System.Encryption.X509GetField(cer,"Subject"),!,$System.Encryption.X509GetField(cer,"Extension:subjectAltName") CN=*.googleapis.com,O=Google Inc,L=Mountain View,ST=California,C=US DNS:*.googleapis.com, DNS:*.clients6.google.com, DNS:*.cloudendpointsapis.com, DNS:cloudendpointsapis.com, DNS:googleapis.com However, in my browser, if I navigate to https://googleapis.com, I see the googleapis.com certificate (and a 404 error). This difference in behavior might have something to do with Caché's lack of support for Server Name Indication (SNI). Regardless, what happens if you change the endpoint to www.googleapis.com rather than googleapis.com?
go to post Timothy Leavitt · Nov 2, 2016 LOGIN^%ZSTART could do the trick. See the documentation. For example, put this in %ZSTART.mac: Quit LOGIN Do ^%CD Quit Then, when you log in to terminal, you'll get: Username: tleavitt Password: *** Namespace: ? '?' for help. '@' (at-sign) to edit the default, the last namespace name attempted. Edit the line just as if it were a line of code. <RETURN> will leave you in the current namespace. Here are the defined namespaces: %SYS ... Namespace: USER You're in namespace USER Default directory is c:\intersystems\ensemble2\mgr\user\ USER> If you wanted to make this a per-user setting, it'd take a bit more work, but would certainly be possible.
go to post Timothy Leavitt · Oct 26, 2016 Assuming you're doing this using the Studio extension framework, the class reference for %Studio.Extension.Base has really helpful documentation.I think the pattern you want is:In UserAction, return Action = 7 for your menu item(s):7 - Display a dialog with a textbox and Yes/No/Cancel buttons. The text for this dialog is provided by the 'Target' return argument. The initial text for the textbox is provided by the 'Msg' return argumentThe user can enter a password in this dialog. Then, in AfterUserAction, you can handle the user's response.
go to post Timothy Leavitt · Oct 20, 2016 The best tool I've seen for tracking unit test coverage in Caché ObjectScript is https://github.com/litesolutions/cache-utcov - maybe you'd already found that from some old Developer Community posts. However, it's gone stale, it's not really mature/complete, and it doesn't have a solution for the problem you've described. There are further complications because %Monitor.System.LineByLine looks at the generated (.int) code, which contains code that isn't in the class definition (because it's generated) and may not contain code that is in the class (for example, a classmethod that returns a constant). It also looks at code line-by-line, and there may be multiple statements on a line; tracing with ZBREAK instead could be a solution for this.It's worth noting that #; comments don't appear in .int code - so, if only this type of comment is used, you could accurately measure the percentage of code coverage for a method/classmethod as the percentage of code coverage of the generated .int code corresponding to the method/classmethod. Otherwise, you're stuck parsing the code (which, if you're just trying to detect comments, wouldn't be too bad) to detect lines that contain comments and omit them from consideration when determining code coverage percentage.
go to post Timothy Leavitt · Oct 18, 2016 Here's one option: <column header="Total Phones" colName="TotalPhones" colExpression="(select count(*) from ZenTutorial.PhoneNumber where Contact=ZenTutorial.Contact.ID)" width="9%" /> The colExpression property allows you to specify a more complex expression to get the value for the column.
go to post Timothy Leavitt · Sep 20, 2016 System default settings are likely the right tool for the job. Settings can be controlled separately from the production definition.
go to post Timothy Leavitt · Sep 20, 2016 I've observed the same issue (garbage output) on a few occasions when there is output (i.e., write statements) before HTTP headers are written. The garbage output might be a CSP Gateway issue, but it is wrong to write prior to headers anyway. Other than redesigning the class entirely, one thing to try might be outputting headers at the beginning of OnHTTPHeader: Set tStatus = %response.WriteHTTPHeader(.OutputBody) It looks like this doesn't happen automatically if OnHTTPHeader is overridden. Note that %response.WriteHTTPHeader(.OutputBody) will indicate "don't call OnPage" (OutputBody = 0) if there's a redirect or server-side redirect. It's worth considering how your custom OnHTTPHeader behavior should interact with redirects.
go to post Timothy Leavitt · Aug 24, 2016 Here's one option: ##class(%SYS.System).InstanceGUID() See the class reference.
go to post Timothy Leavitt · Aug 22, 2016 You can pass a stream to $fromJSON instead of a string: USER>set tStream = ##class(%Stream.TmpCharacter).%New() USER>d tStream.Write("{""a"":2}") USER>s obj = {}.$fromJSON(tStream) USER>w obj.a 2 In your case: Set RequestObj = ##class(%Object).$fromJSON(%request.Content) This is much easier than reading the stream into a string first, and avoids <MAXLENTH> issues.
go to post Timothy Leavitt · Aug 16, 2016 If you're talking about storing dynamic data along with the session, see the documentation on %session.Data. This is just a multidimensional property - so you can do something like: Set %session.Data("hello","world")=15 And then reference that data in a request later in the same session. For a more advanced approach - for example, if there's a large amount of data related to the session - you could use one or more tables instead, and clear data when appropriate by implementing OnEndSession in a subclass of %CSP.SessionEvents and configuring that class as the session events class for your web application (in the web application's security settings).
go to post Timothy Leavitt · Aug 11, 2016 As written, the code in your post should work fine.If the parameter '1' is actually a COS variable name, then the "undefined" would be expected (since the variable with that name is not defined in JavaScript), and you could use something like:&js<zenPage.doReturn(#(..QuoteJS(myVariableName))#);>
go to post Timothy Leavitt · Jul 21, 2016 Here's the documentation on about configuring/implementing source control in Studio: http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...
go to post Timothy Leavitt · Jul 21, 2016 Here's some documentation that might be helpful (if you're looking for a better solution): Packaging DeepSee Elements into Classes It's also possible to export .DFI files directly with $System.OBJ.Export and reload with $System.OBJ.Load, same as with classes/routines. Back to your actual question - what do you mean by "source code of a dashboard in udl format"? If you mean a file containing the same XML you see in Studio - e.g.: <?xml version="1.0"?> <pivot xmlns="http://www.intersystems.com/deepsee/library" name="test2" folderName="" title="" description="" keywords="" owner="" shared="true" public="false" locked="false" resource="" timeCreated="2016-07-21T12:43:26.593Z" createdBy="tleavitt" category="" bookCover="" mdx="" cellWidth="120" columnHeaderStyle="" rowHeaderStyle="" cellStyle="" rowLabelSpan="true" columnLabelSpan="true" cellHeight="22" showEmptyRows="false" showEmptyColumns="false" cubeName="" caption="" listing="" listingRows="" showStatus="true" pageSize="100" colorScale="" rowTotals="false" columnTotals="false" rowTotalAgg="sum" columnTotalAgg="sum" rowTotalSource="page" showZebra="false" showRowCaption="true" printTitle="" printSubtitle="" printSubtitleOn="" showUser="" printPageSize="" printOrientation="" printMarginTop="" printMarginLeft="" printMarginRight="" printMarginBottom="" printLabelWidth="" printCellWidth="" autoExecute="true" manualMode="false" userMDX="" chartMarginTop="" chartMarginLeft="" chartMarginRight="" chartMarginBottom="" maxRows="" borderLeftCell="" borderRightCell="" borderTopCell="" borderBottomCell="" borderLeftCol="" borderRightCol="" borderTopCol="" borderBottomCol="" borderLeftRow="" borderRightRow="" borderTopRow="" borderBottomRow="" fontFamilyCell="" fontSizeCell="" fontFamilyCol="" fontSizeCol="" fontFamilyRow="" fontSizeRow="" showFilters="" showListingFilters="" showDate="" listingFontSize="" showZebraStripes="" filterTableStyle="" filterTableCaptionStyle="" filterTableItemStyle="" nowDisplayFormat="" measureLocation="" hideMeasures="" backgroundImage="" backgroundOpacity=".12"> <rowAxisOptions spec="" key="" value="" text="" headEnabled="true" headCount="" filterEnabled="true" filterExpression="" orderEnabled="false" orderExpression="" orderDirection="BDESC" aggEnabled="false" aggFunction="" aggFunctionParm="" levelCaption="" levelFormat="" levelSummary="" levelType="" drillLevel="0" advanced="false" levelStyle="" levelHeaderStyle="" suppress8020="false" drilldownSpec="" enabled="true"> </rowAxisOptions> <columnAxisOptions spec="" key="" value="" text="" headEnabled="true" headCount="" filterEnabled="true" filterExpression="" orderEnabled="false" orderExpression="" orderDirection="BDESC" aggEnabled="false" aggFunction="" aggFunctionParm="" levelCaption="" levelFormat="" levelSummary="" levelType="" drillLevel="0" advanced="false" levelStyle="" levelHeaderStyle="" suppress8020="false" drilldownSpec="" enabled="true"> </columnAxisOptions> </pivot> You could import it using %DeepSee.UI.FolderItemDocument: Class User.DFIImport { /// Example use: /// Do ##class(User.DFIImport).ImportDFIXML("foldername-itemname.pivot.DFI","C:\Temp\somefile.xml") ClassMethod ImportDFIXML(pName As %String, pFilename As %String) As %Status { Set tSC = $$$OK Try { set tStream = ##class(%Stream.FileCharacter).%New() set tSC = tStream.LinkToFile(pFilename) If $$$ISERR(tSC) { Quit } set tDoc = ##class(%DeepSee.UI.FolderItemDocument).%New(pName) set tSC = tDoc.ImportFromXML(tStream) If $$$ISERR(tSC) { Quit } set tSC = tDoc.Save() If $$$ISERR(tSC) { Quit } } Catch e { Set tSC = e.AsStatus() } Quit tSC } } Note that the name specified for the %DeepSee.UI.FolderItemDocument will overwrite the "name" and "folderName" in the XML.
go to post Timothy Leavitt · Jul 20, 2016 If you're running on Caché 2016.1, the new JSON/Dynamic Object capabilities might help - see: https://community.intersystems.com/post/introducing-new-json-capabilitie...
go to post Timothy Leavitt · Jul 14, 2016 Another option might be "View Other":If ClassA generates ClassB and sets GeneratedBy = ClassA.CLS, then ClassB will show up under "View Other" for ClassA. (Studio works the same way.)
go to post Timothy Leavitt · Jul 10, 2016 This is a good use case for HAVING. Using Sample.Person as an example, the following queries are equivalent: SELECT a.Age,A.Name FROM Sample.Person a LEFT JOIN Sample.Person b on a.home_state = b.home_state and a.DOB < b.DOB WHERE b.ID is null Implemented with HAVING: SELECT Age,Name FROM Sample.Person GROUP BY Home_State HAVING Age = MIN(Age) The second is much more intuitive, and runs significantly faster too. I suspect your query would be expressed as: SELECT * FROM client_address GROUP BY client_id HAVING date_updated = MIN(date_updated)
go to post Timothy Leavitt · Jun 17, 2016 The business operation's "Archive I/O" setting might do what you want, depending on what messages you're passing around. This will add some extra things to the message trace showing what the input to services or the output from operations is.You can enable I/O archiving in the business operation's settings on the production configuration page, at the end of the "Development and Debugging" section.
go to post Timothy Leavitt · Jun 16, 2016 Your last example is really close - probably just the typo in the component ID that's the problem. Class DC.ZenRadioOnLoad Extends %ZEN.Component.page { /// This XML block defines the contents of this page. XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ] { <page xmlns="http://www.intersystems.com/zen" title=""> <radioSet id="appRadio" name="appRadio" displayList="App One,App Two,App Three" valueList="One,Two,Three" /> </page> } /// This callback is called after the server-side page /// object and all of its children are created.<br/> /// Subclasses can override this to add, remove, or modify /// items within the page object model, or to provide values /// for controls. Method %OnAfterCreatePage() As %Status { Set ..%GetComponentById("appRadio").value = "Three" Quit $$$OK } }