The internal hackathon is over but I'd love to still hear more thoughts here. :)
- Log in to post comments
The internal hackathon is over but I'd love to still hear more thoughts here. :)
Agreed - this feels like the biggest gamechanger among Virtual Summit announcements since we've called it Virtual (or Global) Summit.
I'm guessing Yuri meant IaC - Infrastructure as Code.
One note here, $$Quote^%qcr will represent control characters with $c(decimalAsciiCode) syntax - like the newlines in this case. I think there's some more official classmethod that's equivalent, but I don't recall where it is off the top of my head.
Hi Erica,
$$$Text generates content into the message globals at compile time. Here's one way to solve the problem:
Class Erica.DemoLocalizedXData
{
Parameter DOMAIN = "Demo";
XData LocalizedEmail [ MimeType = text/html ]
{
<body>
<p>
Text to be translated into another language
</p>
</body>
}
ClassMethod GetLocalizedContent(xDataName As %String) As %String [ CodeMode = objectgenerator ]
{
do %code.WriteLine(" Quit $Case(xDataName,")
set key = ""
for {
set xdata = %class.XDatas.GetNext(.key)
quit:key=""
set data = xdata.Data.Read() // Assumptions about length here...
do %code.WriteLine(" "_$$$QUOTE(xdata.Name)_":$$$Text("_$$Quote^%qcr(data)_"),")
}
do %code.WriteLine(" :"""")")
}
}After compilation you'll have:
^IRIS.Msg("Demo")="en"
^IRIS.Msg("Demo","en",3630108798)="<body>"_$c(13,10)_"<p>"_$c(13,10)_"Text to be translated into another language"_$c(13,10)_"</p>"_$c(13,10)_"</body>"_$c(13,10)If you want to localize individual strings in the XData block independent of the HTML markup that gets a little more complicated. I'd think it's simpler/possibly better to localize the entire block at once though.
Neat trick for the expression for r! (Which I hope to never see again outside of the context of contests like this. :))
Gaming the system and using the code provided to check the result length, 3:
ClassMethod AddWater(p As %String, t = {$e(p)}, r = {$case(p,"":"",:..AddWater($e(p,2,*)))}, f = {$Select(t:$tr($j(t,t)," ",t)_r,1:r)}) As %String [ CodeMode = expression ]
{
f
}Edit: down from 73 to 67 to 58 (but still looking for better...)
Missing an important test case:
Do $$$AssertEquals(##class(CodeGolf.MagicTowel).AddWater("00020"), "22")
Theory: bad export is caused by slashes in InternalName when working from the workspace context menu in Studio. (https://github.com/MakarovS96/cache-tort-git/issues/4#issuecomment-9171…)
@Ben Spead yes - haven't had a chance to verify if that actually works yet, but I do intend to...
PBKDF2 is not a method of encryption, it's a method of hashing - e.g., it's one-way.
Depending on what you're looking to accomplish (e.g., validating users against some external system), delegated authentication (https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cl…) with a ZAUTHETNICATE routine (see https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cl…) might help.
@Craig Regester I'd be really interested to see what you're doing with the server hooks. (Maybe @Raj Singh would be interested too?) It sounds like you're rolling your own; what are you integrating with? Git, Perforce, SVN, etc.?
A few tidbits that may or may not be relevant for your use cases:
%Studio.Extension.Base:UserAction (see https://docs.intersystems.com/irislatest/csp/documatic/%25CSP.Documatic…) with Action=3 will also launch an external browser given a full URL provided in Target (not necessarily CSP, but could be). This isn't truly a "modal" window but would give you a little bit more control perhaps.
For the sake of VSCode specifically there's a different API (not really documented) for closing a page opened with Action = 2 - specifically, sending a message to the parent frame (a VSCode web view) with data {"result":"done"}. This looks something like (in %CSP.Page:OnPage):
If (%request.Get("EndTemplate") = 1) {
If (%request.UserAgent [ " Code/") {
// For VSCode only:
Set %response.ContentType="text/html",%response.CharSet="UTF-8"
Write "<html>",!
Write "<script type=""text/javascript"">",!
&js<if (window.parent) {
window.parent.postMessage({"result":"done"},'*')
}>
Write "</script>",!
Write "</html>",!
} Else {
Set %response.ContentType="text/xml",%response.CharSet="UTF-8"
Set delim = ##class(%CSP.StudioTemplateError).#DELIM
Write "<?xml version=""1.0""?>",!
Write "<template><![CDATA[BODY",delim
Write delim,"]]]]><![CDATA[></template>",!
}
Quit $$$OK
}@Evgeny Shvarov, the power of generators and projections is more in the creation of frameworks/tools that speed up building solutions. This includes many parts of IRIS itself, but moves into the user space for larger/more complicated applications (e.g., what we've done with AppS.REST both for REST-enabling older ObjectScript-based applications and for quickly building out new applications using IRIS and modern web technologies).
If only da Vinci had provided explicit documentation (preferably written above the painting, in Latin) about how to maintain it going forward...
@Evgeny Shvarov anything with CodeMode=objectgenerator, typical uses of projections, anything that works with %Dictionary.(.*Definition|Compiled.*), anything that works directly with %Library.Routine / %Library.RoutineMgr... there are examples all over the place, including throughout both of my Open Exchange projects.
https://openexchange.intersystems.com/package/Test-Coverage-Tool
https://openexchange.intersystems.com/package/apps-rest
These don't go to the level of dynamically modifying/instrumenting code, but another of my projects (a mock framework for ObjectScript, still internal to InterSystems) does.
I've found writing applications INSIDE the DB environment to be the single coolest thing about InterSystems' technology. The code itself being stored in the database and accessible through both object and relational modes (just like the actual data) makes metaprogramming a really natural part of the language.
Thank you!
The right way to describe a list of a particular type of object is:
ClassMethod myMethod() As %ListOfObjects(ELEMENTTYPE="MyPackage.MyClass")
This is most relevant from the perspective of XML projections - e.g., web services. You can also define a subclass of %ListOfObjects with the ELEMENTTYPE parameter overridden for reuse. See https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=G…
Internally, we've developed a mock framework for ObjectScript based on Mockito that can do exactly this (and many other things). If we're able to get it out on the Open Exchange at some point I'll let you know.
One note - many use cases that call for a composite primary key in a typical boring database would be good use cases for a parent-child relationship in IRIS. This provides nicer features from an object/SQL perspective (e.g., using arrow syntax / implicit joins instead of explicit joins on the composite key fields). See: https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View…
@Yuri Marx there's actually a separate "API Security Top 10" which is particularly relevant for REST APIs and modern web applications: https://owasp.org/www-project-api-security/
API4, API9, and API10 are all good IAM use cases; for the others, I'd recommend looking at https://github.com/intersystems/apps-rest for a security-first generic REST API implementation.
Weird! Try the developer tools in IE to see if you can spot the issue there.
I'd recommend using browser developer tools to inspect the CSS and see what's causing it - I wouldn't expect the rows to be particularly tall, but there could be stray CSS from somewhere else that is making them so. See docs on using Chrome's developer tools (for example - but they're all similar these days) here: https://developer.chrome.com/docs/devtools/css/
I'd expect that to work provided the id (not name) of the combobox/dataCombo is 'MyCombo'. e.g., this works fine:
Class DC.Demo.FindElement Extends %ZEN.Component.page
{
XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]
{
<page xmlns="http://www.intersystems.com/zen">
<form>
<tabGroup showTabBar="true">
<tab caption="Tab One">
<combobox id="MyCombo" editable="true" />
</tab>
<tab caption="Tab Two">
</tab>
</tabGroup>
</form>
<button onclick="zenPage.alertComboValue()" />
</page>
}
ClientMethod alertComboValue() [ Language = javascript ]
{
alert(zen('MyCombo').findElement('input').value);
}
}I'd typically use:
$$$comMemberDefined("%SYS.NLS.Locale",$$$cCLASSproperty,"test")
Just to add - I'm successfully using both source control and non-source control extensions (all using the %Studio.Extension framework) from VSCode. If there are specific issues you see, I'd be curious to hear about them.
@Utsavi Gajjar in case you end up reaching out to InterSystems Support about this (which I'd recommend if you're blocked on the issue), the internal Jira reference for the wrong level of %DynamicObject being passed to %JSONNew is DP-406169
This is a little messy and I'm going to report part of the answer as a bug internally. But regardless, here's one way to make it work - in short, have all of the things that could be listed as a recipient extend a common parent class, and in that class override %JSONNew to detect which type it is.
Class DC.Demo.Container Extends (%RegisteredObject, %JSON.Adaptor)
{
Property recipient As DC.Demo.Recipient;
ClassMethod Demo()
{
for json = {"recipient":{"dob":"2021-06-10"}}, {"recipient":{"reference":"foo"}} {
set inst = ..%New()
do inst.%JSONImport(json)
write !,json.%ToJSON(),!,$classname(inst.recipient),!
}
}
}
Class DC.Demo.Recipient Extends (%RegisteredObject, %JSON.Adaptor)
{
/// Get an instance of an JSON enabled class.<br><br>
///
/// You may override this method to do custom processing (such as initializing
/// the object instance) before returning an instance of this class.
/// However, this method should not be called directly from user code.<br>
/// Arguments:<br>
/// dynamicObject is the dynamic object with thee values to be assigned to the new object.<br>
/// containerOref is the containing object instance when called from JSONImport.
ClassMethod %JSONNew(dynamicObject As %DynamicObject, containerOref As %RegisteredObject = "") As %RegisteredObject
{
// This is weird: shouldn't need to reference .recipient here
if dynamicObject.recipient.%IsDefined("dob") {
quit ##class(DC.Demo.Patient).%New()
} elseif dynamicObject.recipient.%IsDefined("reference") {
quit ##class(DC.Demo.Reference).%New()
} else {
quit ..%New()
}
}
}
Class DC.Demo.Reference Extends DC.Demo.Recipient
{
Property reference As %String;
}
Class DC.Demo.Patient Extends DC.Demo.Recipient
{
Property dob As %Date;
}Output is:
d ##class(DC.Demo.Container).Demo() {"recipient":{"dob":"2021-06-10"}} DC.Demo.Patient {"recipient":{"reference":"foo"}} DC.Demo.Reference
Only problem is, %JSONNew (as advertised in class reference documentation) should get the %DynamicObject representing the object itself, not the parent %DynamicObject. This would only really work if each type is used in exactly one context like this, which seems unlikely.
First off, it's generally best to avoid xecute. ;)
In the first case, routine is private (it isn't visible in the xecute stack frame). In the second, it's public, so it is visible there.
You could get the best of both worlds with:
ClassMethod Run()
{
set routine="variable"
set call="(routine) write routine,!"
xecute (call, routine)
quit
}For more info see https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KE…
I recently wrote up an example here: https://community.intersystems.com/post/making-most-query