tag:blogger.com,1999:blog-58694262024-03-07T19:03:47.667+00:00Drools & jBPMAll things Artificial Intelligence related: Rules, Processes, Events, Agents, Planning, Ontologies and more :)Mark Proctorhttp://www.blogger.com/profile/03304277188725220501noreply@blogger.comBlogger995125tag:blogger.com,1999:blog-5869426.post-76400297467385085052020-04-23T08:45:00.001+01:002020-04-23T08:45:35.724+01:00Kogito: A Modular Codegen Design Proposal<div class="markdown-here-wrapper" data-md-url="https://www.blogger.com/blogger.g?blogID=5869426#editor/target=post;postID=7640029746738508505" markdown-here-wrapper-content-modified="true">
<span style="color: #666666;"><i>Originally posted <a href="https://evacchi.github.io/compilers/kogito/2020/04/23/kogito-codegen-design.html">here</a></i></span><br />
<br />
<br /></div>
<div class="markdown-here-wrapper" data-md-url="https://www.blogger.com/blogger.g?blogID=5869426#editor/target=post;postID=7640029746738508505" markdown-here-wrapper-content-modified="true">
</div>
<div class="markdown-here-wrapper" data-md-url="https://www.blogger.com/blogger.g?blogID=5869426#editor/target=post;postID=7640029746738508505" markdown-here-wrapper-content-modified="true">
My favorite topic of discussion last year was <i>moving computations to compile-time</i>.
<br />
<div style="float: right;">
<br />
<img src="https://i.imgur.com/cHmSoB8.png" title="Reflection" /></div>
<div style="margin: 0px 0px 1.2em !important;">
In fact, I went to <a href="https://youtu.be/TWfigR9wGsA">a few</a> <a href="https://www.youtube.com/watch?v=BUrY6On1SxM">conferences</a> explaining how <b>moving processing out of your run-time and into build-time</b>, is a <b>conceptually simple</b> but <b>extremely effective way</b> to make your applications lighter. This was sometimes received with <b>little enthusiasm</b>: the idea itself is in fact far from new. Yet, it is key to a lot of the most interesting recent innovations in the Java ecosystem.</div>
<div style="margin: 0px 0px 1.2em !important;">
For better or worst, <b>run-time reflection</b> is a peculiarity of the Java ecosystem. However, today <b>a lot of modern Java frameworks are embracing code generation</b>; which is ironic, because, as far as I know, run-time reflection was often embraced as a reaction to slow code generation procedures. </div>
<div style="margin: 0px 0px 1.2em !important;">
In <b><a href="https://kogito.kie.org/">Kogito</a></b>, we are using code generation to <b>pre-process</b> and <b>compile</b> so-called “business assets” into <b>executable code</b>. In the following we will explore the history and the motivations for embracing code generation instead of run-time reflection, and how we plan to bring our approach to codegen forward, by <b>taking hints from compiler design</b>.</div>
<h2 id="run-time-vs-build-time-meta-programming" style="border-bottom: 1px solid rgb(238, 238, 238); font-size: 1.4em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Run-Time vs. Build-Time Meta-Programming</h2>
<div style="margin: 0px 0px 1.2em !important;">
I believe there are many reasons why often we reach for run-time reflection, but I will name two; </div>
<ol style="margin: 1.2em 0px; padding-left: 2em;">
<li style="margin: 0.5em 0px;"><div style="margin: 0.5em 0px !important; margin: 0px 0px 1.2em !important;">
the reflection API is “standard”: it is bundled with the JDK and it is relatively easy to use; it allows developers to implement some meta-programming logic with the tools they already know. </div>
</li>
<li style="margin: 0.5em 0px;"><div style="margin: 0.5em 0px !important; margin: 0px 0px 1.2em !important;">
run-time reflection keeps <b>build time low</b> and it allows for <b>more degrees of freedom at run-time</b>. </div>
</li>
</ol>
<div style="margin: 0px 0px 1.2em !important;">
But the JDK <i>does</i> support compile-time manipulation: although there is no “proper” macro support, there <i>are</i> compile-time meta-programming facilities in the <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.compiler/javax/annotation/processing/package-summary.html"><b>annotation processing framework</b></a>. But then, although the annotation processor framework provides way to hook into the Java compiler and <i>process</i> code, is does not provide a standardized set of tools to <i>generate</i> code. Some people use <a href="https://asm.ow2.io/">ASM</a> for bytecode generation; other generate source code using <a href="https://github.com/square/javapoet">JavaPoet</a>, <a href="https://javaparser.org/">JavaParser</a> or other similar libraries. </div>
<div style="margin: 0px 0px 1.2em !important;">
And I believe, this is another reason, why people choose reflection: you don’t need to <i>generate</i> code at all.</div>
<h3 id="the-price-of-run-time-reflection" style="font-size: 1.3em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
The Price of Run-Time Reflection</h3>
<div style="margin: 0px 0px 1.2em !important;">
For this and other reasons code-generation has become a lesser citizen of the Java ecosystem. However, <b>run-time reflection comes at a price</b>. From the top of my head: </div>
<ul style="margin: 1.2em 0px; padding-left: 2em;">
<li style="margin: 0.5em 0px;"><b>your reflection logic <i>must</i> be rock-solid</b>: otherwise many compile-time errors will turn into run-time errors; i.e. errors into your reflective logic</li>
<li style="margin: 0.5em 0px;"><b>moving meta-programming logic in the run-time</b> of your application <a href="https://www.optaplanner.org/blog/2018/01/09/JavaReflectionButMuchFaster.html"><b>impacts performance</b></a>: not only are reflective invocations usually slower than direct invocations, but also meta-programming logic will run as part of your main program logic, inevitably adding overhead to execution. </li>
</ul>
<div style="margin: 0px 0px 1.2em !important;">
Traditionally, this was not regarded as a huge burden: in fact, Java programs used to be long-running and often server-side; the overhead of run-time reflection, being usually paid at application configuration and startup time, was considered irrelevant, because it was tiny, compared to the time they would run. </div>
<h3 id="rediscovering-code-generation" style="font-size: 1.3em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Rediscovering Code Generation</h3>
<div style="float: right; padding-left: 2em;">
<br />
<img src="https://i.imgur.com/mgInxYI.png" title="The Dragon Book" /></div>
<div style="margin: 0px 0px 1.2em !important;">
Today <b><a href="https://micronaut.io/">a lot</a> of <a href="https://quarkus.io/">frameworks</a></b> are actually going back to build-time code generation: <b>Kogito</b> is one of those.</div>
<div style="margin: 0px 0px 1.2em !important;">
In the last few years, <b>the programming landscape <a href="http://www.cdi-spec.org/news/2020/03/09/CDI_for_the_future/">has changed</a></b>; for instance, constrained platforms such as Android used to have more limited support for runtime reflection different performance requirements: applications should be small and quick to start. People started to develop <b>microservices</b> and <b>serverless applications</b>: these services need to start very quickly, to elastically scale with the number of incoming requests. <b>GraalVM’s native image compiler</b> is another run-time platform with additional constraints: it allows to compile a Java program into a native executable, but originally, it posed a few limitations on run-time reflection. Moreover, whereas in the past fat, long-running application servers hosted several, possibly mutable applications in a single process space, today we deploy <b>separate, stand-alone, immutable, containerized applications</b> on Kubernetes. For all these, and other reasons, in the last few years <b>the Java ecosystem is rediscovering code-generation</b>. </div>
<div style="margin: 0px 0px 1.2em !important;">
The Kogito code-generation procedure elaborates all the “knowledge assets” in a codebase and produces equivalent Java code that plugs into our core engines on one side, and into the Quarkus or Spring APIs to expose automatically generated REST service endpoints on the other. </div>
<div style="margin: 0px 0px 1.2em !important;">
Let’s see more in detail how this procedure works.</div>
<h2 id="staged-compilation-in-kogito" style="border-bottom: 1px solid rgb(238, 238, 238); font-size: 1.4em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Staged Compilation in Kogito</h2>
<div style="margin: 0px 0px 1.2em !important;">
In Kogito, the code-generation procedure is designed in <b>stages</b>.<br />
<br />
<div style="margin: auto; text-align: center;">
<img alt="Stages" src="https://i.imgur.com/YvzSkJT.png" width="70%" />
</div>
<br />
First, <b>processes</b> (BPMN files) are analyzed, then <b>rules</b> (DRLs), then <b>decisions</b> (DMNs). Each stage, as a result, generates Java source code; compilation is delegated to the Java compiler. In modern parlance, this would be called a <i>“transpiler”</i>; a term that I despise, because it makes it sound like compilers do not just generate code but do some kind of magic mumbo-jumbo. But that’s another story. Whatever you want to call it, our current architecture of this procedure is rigid, and does not allow for extension</div>
<div style="margin: 0px 0px 1.2em !important;">
In fact, albeit we are processing each type of asset in a <i>separate stage</i>, each stage is effectively a <b>single-pass compiler</b>, because each it always terminates with the generation of the compilation target. This is the reason why it is generally better to <b>break down compilation into more passes</b>. Each compilation pass usually produces what is called an <b>intermediate representation</b>; the input to one stage is the output of the previous, and so on up to the final stage, where target code is actually produced.</div>
<h3 id="compilers-and-compilation-phases" style="font-size: 1.3em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Compilers and Compilation Phases</h3>
<div style="margin: 0px 0px 1.2em !important;">
In a traditional compiler, usually, one of the first stages is <b>parsing</b> the input source code and transforming it into an internal tree representation (the <i>Abstract Syntax Tree</i>); then usually is the <b>name resolution</b> phase, where the names of the values and symbols that are used throughout the program are resolved; then the <b>type-checking phase</b> verifies and validates the correctness of the program; finally <b>code</b> is actually <b>generated</b>.</div>
<div style="margin: 0px 0px 1.2em !important;">
In Kogito, we <b>parse</b> knowledge assets, then we associate <b>names</b> to each assets, and we resolve their internal structure, which may <b>cross-reference</b> other existing assets. <b>Type-checking our assets means validating</b> the models according to specifications and verifying these cross-references. For instance, a BPMN file may reference a Rule Unit definition and a service implementation written in Java. </div>
<h3 id="compilers-and-mini-phases" style="font-size: 1.3em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Compilers and Mini-Phases</h3>
<div style="margin: 0px 0px 1.2em !important;">
So far, our code-generation procedure has been pretty simplistic: we generated code regardless of potential errors, delegating compilation errors to the downstream Java compiler; worse, sometimes they would be caught later at run-time! This in general works, but it either produces pretty obscure compilation errors, or it moves validation too late in the pipeline: which is something that we wanted to avoid in the first place. We want to <b>catch errors early</b> and only <b>generate valid code</b>.</div>
<div style="margin: 0px 0px 1.2em !important;">
By refactoring our compilation phases to a staged, modular compilation architecture we will be able to catch resolution and validation errors early and present them to users in a meaningful way: only when the validation phase will be completed successfully, then we will actually generate code. But we also want our stages to be smaller, so that it is easier to <b>add more compilation stages</b> at different points in the pipeline.</div>
<div style="margin: auto;">
<img alt="Processes, Rules, Decisions" src="https://i.imgur.com/2ffP9Sl.jpg" width="100%" />
</div>
<div style="margin: 0px 0px 1.2em !important;">
For instance, suppose you want to synthesize some elements (e.g. data models) that are inferred from the structure of a process. In our current architecture, the only way to produce additional assets would be to patch the existing code. By de-composing the phases as shown above, you would be able to <b>plug your additional <a href="https://nanopass.org/">mini-phase</a></b> right after “Model Validation”, so that you can be sure that all the names have been resolved, and that only valid models will be processed: you will produce an intermediate representation for the data model that you want to synthesize, and make it available during the “Cross-Referencing” phase.</div>
<h2 id="pre-processing-assets-vs-code-scaffolding-" style="border-bottom: 1px solid rgb(238, 238, 238); font-size: 1.4em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Pre-Processing Assets vs. Code Scaffolding.</h2>
<div style="margin: 0px 0px 1.2em !important;">
As briefly mentioned in the introduction, in our current architecture we are also conflating code-generation for two very different purposes.</div>
<div style="margin: 0px 0px 1.2em !important;">
The <b>first</b> is to <b>pre-process</b> assets to generate their <b>stand-alone run-time representation</b>: the goal is both to reduce run-time processing and support native compilation. The output of this code-generation procedure are objects that interface directly with the internal programmatic APIs of our engines. This programmatic API, in Kogito, is currently considered an implementation detail, not supposed to be consumed by end-users. The reason is that this API is still unstable: we want to make sure to get it right, before making it public. Now, for the sake of explanation, consider a BPMN process definition: this is compiled into a class that implement the <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">Process<T></code> interface of the programmatic API. By instantiating this class, you get an exact 1:1 representation of the process definition, minus parsing and preliminary analysis.</div>
<div style="margin: 0px 0px 1.2em !important;">
The <b>second</b> purpose of code-generation is implemented as a <b>layer</b> on top of these run-time representations; here we exposes calls into the programmatic API as <b>REST endpoints</b>. For example, consider a process called <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">MyProcess</code>; the REST endpoints we generate expose REST APIs to start, execute and terminate an instance of that process. You can imagine that code to look a but like this:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-java" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"><span class="hljs-annotation">@Path</span>(<span class="hljs-string" style="color: #dd1144;">"/MyProcess"</span>)
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">public</span> <span class="hljs-class"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">class</span> <span class="hljs-title" style="color: #990000; font-weight: bold;">MyProcessResource</span> </span>{
<span class="hljs-annotation">@Inject</span>
Process<MyProcess> p;
<span class="hljs-annotation">@POST</span>
<span class="hljs-function"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">public</span> MyProcess <span class="hljs-title" style="color: #990000; font-weight: bold;">start</span><span class="hljs-params">(MyProcess data)</span> </span>{
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">return</span> p.create(data).start();
}
<span class="hljs-annotation">@DELETE</span>(<span class="hljs-string" style="color: #dd1144;">"/{id}"</span>)
<span class="hljs-function"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">public</span> MyProcess <span class="hljs-title" style="color: #990000; font-weight: bold;">abort</span><span class="hljs-params">(String id)</span> </span>{
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">return</span> = p.delete(id);
}
<span class="hljs-annotation">@GET</span>(<span class="hljs-string" style="color: #dd1144;">"/{id}"</span>)
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">public</span> Collection<ProcessInstance<MyProcess>> abort(String id) {
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">return</span> p.instances(id);
}
...
}
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
Today, both the code that is generated for run-time representations and the code that implements REST endpoints is all treated as an <i>implementation detail</i>. It is only visible in the compilation target directory of your project. And you are <i>not</i> supposed to rely on the structure of that code in your own codebase.</div>
<div style="margin: 0px 0px 1.2em !important;">
However, we always meant this procedure to become customizable at some point, promoting it to be <b>scaffolding</b>. </div>
<div style="margin: 0px 0px 1.2em !important;">
In the case of scaffolding, code should not be generated in your compilation target directory, but instead, it should be promoted to your <i>source code</i> directory. We are currently working on a general solution to allow you to opt-out from code generation for specific assets, and instead, “claim” it for ownership. For instance, suppose that you want to customize <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">MyProcess</code>. You will be able to tell the code-generation procedure that you want customize that asset: the code-generation procedure will run once, and then you will be able to edit the generated code as regular source code.</div>
<h2 id="conclusions" style="border-bottom: 1px solid rgb(238, 238, 238); font-size: 1.4em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Conclusions</h2>
<div style="margin: 0px 0px 1.2em !important;">
You should now have a better understanding of the rationale for code generation in Kogito: in the future we are going to improve our code generation procedure to allow extensibility by plugging into the code-generation process, and customization by allowing end-users to promote code generation to scaffolding.</div>
<div style="margin: 0px 0px 1.2em !important;">
In the future we will further document how we plan to refactor our codebase to support these novel use cases. </div>
<div style="font-size: 0em; height: 0; margin: 0; max-height: 0; max-width: 0; overflow: hidden; padding: 0; width: 0;" title="MDH:PGRpdiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7YmFja2dyb3VuZC1jb2xvcjogI2ZmZmZmZjtmb250
LWZhbWlseTogJydGaXJhIENvZGUnLCAnRHJvaWQgU2FucyBNb25vJywgJ21vbm9zcGFjZScsIG1v
bm9zcGFjZSwgJ0Ryb2lkIFNhbnMgRmFsbGJhY2snJywgJ0Ryb2lkIFNhbnMgTW9ubycsICdtb25v
c3BhY2UnLCBtb25vc3BhY2UsICdEcm9pZCBTYW5zIEZhbGxiYWNrJztmb250LXdlaWdodDogbm9y
bWFsO2ZvbnQtc2l6ZTogMTRweDtsaW5lLWhlaWdodDogMTlweDt3aGl0ZS1zcGFjZTogcHJlOyI+
PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4tLS08L3NwYW4+PC9kaXY+PGRpdj48
c3BhbiBzdHlsZT0iY29sb3I6ICM4MDAwMDA7Ij50aXRsZTwvc3Bhbj48c3BhbiBzdHlsZT0iY29s
b3I6ICMwMDAwMDA7Ij46ICA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMGZmOyI+J0tv
Z2l0bzogQSBNb2R1bGFyIENvZGVnZW4gRGVzaWduIFByb3Bvc2FsJzwvc3Bhbj48L2Rpdj48ZGl2
PjxzcGFuIHN0eWxlPSJjb2xvcjogIzgwMDAwMDsiPmNhdGVnb3JpZXM8L3NwYW4+PHNwYW4gc3R5
bGU9ImNvbG9yOiAjMDAwMDAwOyI+OiBbPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDBm
ZjsiPkNvbXBpbGVyczwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4sIDwvc3Bh
bj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwZmY7Ij5Lb2dpdG88L3NwYW4+PHNwYW4gc3R5bGU9
ImNvbG9yOiAjMDAwMDAwOyI+XTwvc3Bhbj48L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjog
IzgwMDAwMDsiPmRhdGU8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+OiAgIDIw
MjAtMDQtMjI8L3NwYW4+PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4t
LS08L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+TXkg
ZmF2b3JpdGUgdG9waWMgb2YgZGlzY3Vzc2lvbiBsYXN0IHllYXIgd2FzIDwvc3Bhbj48c3BhbiBz
dHlsZT0iY29sb3I6ICMwMDAwMDA7Zm9udC1zdHlsZTogaXRhbGljOyI+X21vdmluZyBjb21wdXRh
dGlvbnMgdG8gY29tcGlsZS10aW1lXzwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7
Ij4uIDwvc3Bhbj48L2Rpdj48YnI+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICM4MDAwMDA7Ij4m
bHQ7ZGl2PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiA8L3NwYW4+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjZmYwMDAwOyI+c3R5bGU8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
MDAwMDAwOyI+PTwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwZmY7Ij4iPC9zcGFuPjxz
cGFuIHN0eWxlPSJjb2xvcjogIzAwMDBmZjsiPmZsb2F0OnJpZ2h0PC9zcGFuPjxzcGFuIHN0eWxl
PSJjb2xvcjogIzAwMDBmZjsiPiI8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjODAwMDAwOyI+
Jmd0Ozwvc3Bhbj48L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzgwMDAwMDsiPiZsdDtp
bWc8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IDwvc3Bhbj48c3BhbiBzdHls
ZT0iY29sb3I6ICNmZjAwMDA7Ij5zcmM8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAw
OyI+PTwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwZmY7Ij4iaHR0cHM6Ly9pLmltZ3Vy
LmNvbS9jSG1Tb0I4LnBuZyI8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IDwv
c3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICNmZjAwMDA7Ij50aXRsZTwvc3Bhbj48c3BhbiBzdHls
ZT0iY29sb3I6ICMwMDAwMDA7Ij49PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDBmZjsi
PiJSZWZsZWN0aW9uIjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFu
PjxzcGFuIHN0eWxlPSJjb2xvcjogIzgwMDAwMDsiPi8mZ3Q7PC9zcGFuPjwvZGl2PjxkaXY+PHNw
YW4gc3R5bGU9ImNvbG9yOiAjODAwMDAwOyI+Jmx0Oy9kaXYmZ3Q7PC9zcGFuPjwvZGl2Pjxicj48
ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPkluIGZhY3QsIEkgd2VudCB0byA8L3Nw
YW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+Wzwvc3Bhbj48c3BhbiBzdHlsZT0iY29s
b3I6ICNhMzE1MTU7Ij5hIGZldzwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5d
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPlt2ZG0xOV0gPC9zcGFuPjxzcGFu
IHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPls8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjYTMx
NTE1OyI+Y29uZmVyZW5jZXM8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+XTwv
c3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5bcWNvbnNwMTldIGV4cGxhaW5pbmcg
aG93IDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7
Ij4qKm1vdmluZyBwcm9jZXNzaW5nIG91dCBvZiB5b3VyIHJ1bi10aW1lIGFuZCBpbnRvIGJ1aWxk
LXRpbWUqKjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4sIGlzIGEgPC9zcGFu
PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPioqY29uY2Vw
dHVhbGx5IHNpbXBsZSoqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiBidXQg
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPioq
ZXh0cmVtZWx5IGVmZmVjdGl2ZSB3YXkqKjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAw
MDA7Ij4gdG8gbWFrZSB5b3VyIGFwcGxpY2F0aW9ucyBsaWdodGVyLiBUaGlzIHdhcyBzb21ldGlt
ZXMgcmVjZWl2ZWQgd2l0aCA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQt
d2VpZ2h0OiBib2xkOyI+KipsaXR0bGUgZW50aHVzaWFzbSoqPC9zcGFuPjxzcGFuIHN0eWxlPSJj
b2xvcjogIzAwMDAwMDsiPjogdGhlIGlkZWEgaXRzZWxmIGlzIGluIGZhY3QgZmFyIGZyb20gbmV3
LiBZZXQsIGl0IGlzIGtleSB0byBhIGxvdCBvZiB0aGUgbW9zdCBpbnRlcmVzdGluZyByZWNlbnQg
aW5ub3ZhdGlvbnMgaW4gdGhlIEphdmEgZWNvc3lzdGVtLjwvc3Bhbj48L2Rpdj48YnI+PGRpdj48
c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5Gb3IgYmV0dGVyIG9yIHdvcnN0LCA8L3NwYW4+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+KipydW4tdGlt
ZSByZWZsZWN0aW9uKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IGlzIGEg
cGVjdWxpYXJpdHkgb2YgdGhlIEphdmEgZWNvc3lzdGVtLiBIb3dldmVyLCB0b2RheSA8L3NwYW4+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+KiphIGxvdCBv
ZiBtb2Rlcm4gSmF2YSBmcmFtZXdvcmtzIGFyZSBlbWJyYWNpbmcgY29kZSBnZW5lcmF0aW9uKio8
L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+OyB3aGljaCBpcyBpcm9uaWMsIGJl
Y2F1c2UsIGFzIGZhciBhcyBJIGtub3csIHJ1bi10aW1lIHJlZmxlY3Rpb24gd2FzIG9mdGVuIGVt
YnJhY2VkIGFzIGEgcmVhY3Rpb24gdG8gc2xvdyBjb2RlIGdlbmVyYXRpb24gcHJvY2VkdXJlcy4g
PC9zcGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPkluIDwv
c3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4qKjwv
c3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij5bPC9z
cGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogI2EzMTUxNTtmb250LXdlaWdodDogYm9sZDsiPktvZ2l0
bzwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij5d
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPltr
b2dpdG9dKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+LCB3ZSBhcmUgdXNp
bmcgY29kZSBnZW5lcmF0aW9uIHRvIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7
Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4qKnByZS1wcm9jZXNzKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNv
bG9yOiAjMDAwMDAwOyI+IGFuZCA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2Zv
bnQtd2VpZ2h0OiBib2xkOyI+Kipjb21waWxlKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
MDAwMDAwOyI+IHNvLWNhbGxlZCAiYnVzaW5lc3MgYXNzZXRzIiBpbnRvIDwvc3Bhbj48c3BhbiBz
dHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4qKmV4ZWN1dGFibGUgY29k
ZSoqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPi4gSW4gdGhlIGZvbGxvd2lu
ZyB3ZSB3aWxsIGV4cGxvcmUgdGhlIGhpc3RvcnkgYW5kIHRoZSBtb3RpdmF0aW9ucyBmb3IgZW1i
cmFjaW5nIGNvZGUgZ2VuZXJhdGlvbiBpbnN0ZWFkIG9mIHJ1bi10aW1lIHJlZmxlY3Rpb24sIGFu
ZCBob3cgd2UgcGxhbiB0byBicmluZyBvdXIgYXBwcm9hY2ggdG8gY29kZWdlbiBmb3J3YXJkLCBi
eSA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+
Kip0YWtpbmcgaGludHMgZnJvbSBjb21waWxlciBkZXNpZ24qKjwvc3Bhbj48c3BhbiBzdHlsZT0i
Y29sb3I6ICMwMDAwMDA7Ij4uPC9zcGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xv
cjogIzgwMDAwMDtmb250LXdlaWdodDogYm9sZDsiPiMjIFJ1bi1UaW1lIHZzLiBCdWlsZC1UaW1l
IE1ldGEtUHJvZ3JhbW1pbmcgPC9zcGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xv
cjogIzAwMDAwMDsiPkkgYmVsaWV2ZSB0aGVyZSBhcmUgbWFueSByZWFzb25zIHdoeSBvZnRlbiB3
ZSByZWFjaCBmb3IgcnVuLXRpbWUgcmVmbGVjdGlvbiwgYnV0IEkgd2lsbCBuYW1lIHR3bzsgPC9z
cGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzA0NTFhNTsiPjEuPC9zcGFu
PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiB0aGUgcmVmbGVjdGlvbiBBUEkgaXMgInN0
YW5kYXJkIjogaXQgaXMgYnVuZGxlZCB3aXRoIHRoZSBKREsgYW5kIGl0IGlzIHJlbGF0aXZlbHkg
ZWFzeSB0byB1c2U7IGl0IGFsbG93cyBkZXZlbG9wZXJzIHRvIGltcGxlbWVudCBzb21lIG1ldGEt
cHJvZ3JhbW1pbmcgbG9naWMgd2l0aCB0aGUgdG9vbHMgdGhleSBhbHJlYWR5IGtub3cuIDwvc3Bh
bj48L2Rpdj48YnI+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwNDUxYTU7Ij4yLjwvc3Bhbj48
c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gcnVuLXRpbWUgcmVmbGVjdGlvbiBrZWVwcyA8
L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+Kipi
dWlsZCB0aW1lIGxvdyoqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiBhbmQg
aXQgYWxsb3dzIGZvciA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2Vp
Z2h0OiBib2xkOyI+Kiptb3JlIGRlZ3JlZXMgb2YgZnJlZWRvbSBhdCBydW4tdGltZSoqPC9zcGFu
PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPi4gPC9zcGFuPjwvZGl2Pjxicj48ZGl2Pjxz
cGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPkJ1dCB0aGUgSkRLIDwvc3Bhbj48c3BhbiBzdHls
ZT0iY29sb3I6ICMwMDAwMDA7Zm9udC1zdHlsZTogaXRhbGljOyI+X2RvZXNfPC9zcGFuPjxzcGFu
IHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiBzdXBwb3J0IGNvbXBpbGUtdGltZSBtYW5pcHVsYXRp
b246IGFsdGhvdWdoIHRoZXJlIGlzIG5vICJwcm9wZXIiIG1hY3JvIHN1cHBvcnQsIHRoZXJlIDwv
c3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Zm9udC1zdHlsZTogaXRhbGljOyI+X2Fy
ZV88L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IGNvbXBpbGUtdGltZSBtZXRh
LXByb2dyYW1taW5nIGZhY2lsaXRpZXMgaW4gdGhlIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6
ICMwMDAwMDA7Ij5bPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogI2EzMTUxNTsiPioqYW5ub3Rh
dGlvbiBwcm9jZXNzaW5nIGZyYW1ld29yayoqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAw
MDAwMDsiPl08L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+W2Fubm90YXRpb25z
XS4gQnV0IHRoZW4sIGFsdGhvdWdoIHRoZSBhbm5vdGF0aW9uIHByb2Nlc3NvciBmcmFtZXdvcmsg
cHJvdmlkZXMgd2F5IHRvIGhvb2sgaW50byB0aGUgSmF2YSBjb21waWxlciBhbmQgPC9zcGFuPjxz
cGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDtmb250LXN0eWxlOiBpdGFsaWM7Ij5fcHJvY2Vzc188
L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IGNvZGUsICBpcyBkb2VzIG5vdCBw
cm92aWRlIGEgc3RhbmRhcmRpemVkIHNldCBvZiB0b29scyB0byA8L3NwYW4+PHNwYW4gc3R5bGU9
ImNvbG9yOiAjMDAwMDAwO2ZvbnQtc3R5bGU6IGl0YWxpYzsiPl9nZW5lcmF0ZV88L3NwYW4+PHNw
YW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IGNvZGUuIFNvbWUgcGVvcGxlIHVzZSA8L3NwYW4+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+Wzwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6
ICNhMzE1MTU7Ij5BU008L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+XTwvc3Bh
bj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5bYXNtXSBmb3IgYnl0ZWNvZGUgZ2VuZXJh
dGlvbjsgb3RoZXIgZ2VuZXJhdGUgc291cmNlIGNvZGUgdXNpbmcgPC9zcGFuPjxzcGFuIHN0eWxl
PSJjb2xvcjogIzAwMDAwMDsiPls8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjYTMxNTE1OyI+
SmF2YVBvZXQ8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+XTwvc3Bhbj48c3Bh
biBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5bamF2YXBvZXRdLCA8L3NwYW4+PHNwYW4gc3R5bGU9
ImNvbG9yOiAjMDAwMDAwOyI+Wzwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICNhMzE1MTU7Ij5K
YXZhUGFyc2VyPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPl08L3NwYW4+PHNw
YW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+W2phdmFwYXJzZXJdIG9yIG90aGVyIHNpbWlsYXIg
bGlicmFyaWVzLiA8L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAw
MDAwOyI+QW5kIEkgYmVsaWV2ZSwgdGhpcyBpcyBhbm90aGVyIHJlYXNvbiwgd2h5IHBlb3BsZSBj
aG9vc2UgcmVmbGVjdGlvbjogeW91IGRvbid0IG5lZWQgdG8gPC9zcGFuPjxzcGFuIHN0eWxlPSJj
b2xvcjogIzAwMDAwMDtmb250LXN0eWxlOiBpdGFsaWM7Ij5fZ2VuZXJhdGVfPC9zcGFuPjxzcGFu
IHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiBjb2RlIGF0IGFsbC48L3NwYW4+PC9kaXY+PGJyPjxk
aXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjODAwMDAwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+IyMjIFRo
ZSBQcmljZSBvZiBSdW4tVGltZSBSZWZsZWN0aW9uPC9zcGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFu
IHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPkZvciB0aGlzIGFuZCBvdGhlciByZWFzb25zIGNvZGUt
Z2VuZXJhdGlvbiBoYXMgYmVjb21lIGEgbGVzc2VyIGNpdGl6ZW4gb2YgdGhlIEphdmEgZWNvc3lz
dGVtLiBIb3dldmVyLCA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2Vp
Z2h0OiBib2xkOyI+KipydW4tdGltZSByZWZsZWN0aW9uIGNvbWVzIGF0IGEgcHJpY2UqKjwvc3Bh
bj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4uIEZyb20gdGhlIHRvcCBvZiBteSBoZWFk
OiA8L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDQ1MWE1OyI+LTwv
c3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPjxzcGFuIHN0eWxlPSJj
b2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPioqeW91ciByZWZsZWN0aW9uIGxvZ2lj
IDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC1zdHlsZTogaXRhbGljOyI+
X211c3RfPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9s
ZDsiPiBiZSByb2NrLXNvbGlkKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+
OiBvdGhlcndpc2UgbWFueSBjb21waWxlLXRpbWUgZXJyb3JzIHdpbGwgdHVybiBpbnRvIHJ1bi10
aW1lIGVycm9yczsgaS5lLiBlcnJvcnMgaW50byB5b3VyIHJlZmxlY3RpdmUgbG9naWM8L3NwYW4+
PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwNDUxYTU7Ij4tPC9zcGFuPjxzcGFuIHN0
eWxlPSJjb2xvcjogIzAwMDAwMDsiPiA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgw
O2ZvbnQtd2VpZ2h0OiBib2xkOyI+Kiptb3ZpbmcgbWV0YS1wcm9ncmFtbWluZyBsb2dpYyBpbiB0
aGUgcnVuLXRpbWUqKjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gb2YgeW91
ciBhcHBsaWNhdGlvbiA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+Wzwvc3Bh
bj48c3BhbiBzdHlsZT0iY29sb3I6ICNhMzE1MTU7Ij4qKmltcGFjdHMgcGVyZm9ybWFuY2UqKjwv
c3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5dPC9zcGFuPjxzcGFuIHN0eWxlPSJj
b2xvcjogIzAwMDAwMDsiPltyZWZsZWN0aW9uXTogbm90IG9ubHkgYXJlIHJlZmxlY3RpdmUgaW52
b2NhdGlvbnMgdXN1YWxseSBzbG93ZXIgdGhhbiBkaXJlY3QgaW52b2NhdGlvbnMsIGJ1dCBhbHNv
IG1ldGEtcHJvZ3JhbW1pbmcgbG9naWMgd2lsbCBydW4gYXMgcGFydCBvZiB5b3VyIG1haW4gcHJv
Z3JhbSBsb2dpYywgaW5ldml0YWJseSBhZGRpbmcgb3ZlcmhlYWQgdG8gZXhlY3V0aW9uLiA8L3Nw
YW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+VHJhZGl0aW9u
YWxseSwgdGhpcyB3YXMgbm90IHJlZ2FyZGVkIGFzIGEgaHVnZSBidXJkZW46IGluIGZhY3QsIEph
dmEgcHJvZ3JhbXMgdXNlZCB0byBiZSBsb25nLXJ1bm5pbmcgYW5kIG9mdGVuIHNlcnZlci1zaWRl
OyB0aGUgb3ZlcmhlYWQgb2YgcnVuLXRpbWUgcmVmbGVjdGlvbiwgYmVpbmcgdXN1YWxseSBwYWlk
IGF0IGFwcGxpY2F0aW9uIGNvbmZpZ3VyYXRpb24gYW5kIHN0YXJ0dXAgdGltZSwgd2FzIGNvbnNp
ZGVyZWQgaXJyZWxldmFudCwgYmVjYXVzZSBpdCB3YXMgdGlueSwgY29tcGFyZWQgdG8gdGhlIHRp
bWUgdGhleSB3b3VsZCBydW4uIDwvc3Bhbj48L2Rpdj48YnI+PGRpdj48c3BhbiBzdHlsZT0iY29s
b3I6ICM4MDAwMDA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4jIyMgUmVkaXNjb3ZlcmluZyBDb2RlIEdl
bmVyYXRpb248L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjODAwMDAw
OyI+Jmx0O2Rpdjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPjxz
cGFuIHN0eWxlPSJjb2xvcjogI2ZmMDAwMDsiPnN0eWxlPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xv
cjogIzAwMDAwMDsiPj08L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMGZmOyI+Ijwvc3Bh
bj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwZmY7Ij5mbG9hdDpyaWdodDsgcGFkZGluZy1sZWZ0
OiAyZW08L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMGZmOyI+Ijwvc3Bhbj48c3BhbiBz
dHlsZT0iY29sb3I6ICM4MDAwMDA7Ij4mZ3Q7PC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9
ImNvbG9yOiAjODAwMDAwOyI+Jmx0O2ltZzwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAw
MDA7Ij4gPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogI2ZmMDAwMDsiPnNyYzwvc3Bhbj48c3Bh
biBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij49PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAw
MDBmZjsiPiJodHRwczovL2kuaW1ndXIuY29tL21nSW54WUkucG5nIjwvc3Bhbj48c3BhbiBzdHls
ZT0iY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogI2ZmMDAwMDsi
PnRpdGxlPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPj08L3NwYW4+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjMDAwMGZmOyI+IlRoZSBEcmFnb24gQm9vayI8L3NwYW4+PHNwYW4gc3R5
bGU9ImNvbG9yOiAjODAwMDAwOyI+LyZndDs8L3NwYW4+PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0i
Y29sb3I6ICM4MDAwMDA7Ij4mbHQ7L2RpdiZndDs8L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+VG9kYXkgPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjog
IzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPioqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjog
IzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPls8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
YTMxNTE1O2ZvbnQtd2VpZ2h0OiBib2xkOyI+YSBsb3Q8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9y
OiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+XTwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6
ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij5bbWljcm9uYXV0XSBvZiA8L3NwYW4+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+Wzwvc3Bhbj48c3BhbiBz
dHlsZT0iY29sb3I6ICNhMzE1MTU7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij5mcmFtZXdvcmtzPC9zcGFu
PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPl08L3NwYW4+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+W3F1YXJrdXNd
Kio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IGFyZSBhY3R1YWxseSBnb2lu
ZyBiYWNrIHRvIGJ1aWxkLXRpbWUgY29kZSBnZW5lcmF0aW9uOiA8L3NwYW4+PHNwYW4gc3R5bGU9
ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+KipLb2dpdG8qKjwvc3Bhbj48c3Bh
biBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gaXMgb25lIG9mIHRob3NlLjwvc3Bhbj48L2Rpdj48
YnI+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5JbiB0aGUgbGFzdCBmZXcgeWVh
cnMsIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7
Ij4qKnRoZSBwcm9ncmFtbWluZyBsYW5kc2NhcGUgPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjog
IzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPls8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
YTMxNTE1O2ZvbnQtd2VpZ2h0OiBib2xkOyI+aGFzIGNoYW5nZWQ8L3NwYW4+PHNwYW4gc3R5bGU9
ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+XTwvc3Bhbj48c3BhbiBzdHlsZT0i
Y29sb3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij5bY2RpbGl0ZV0qKjwvc3Bhbj48c3Bh
biBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij47IGZvciBpbnN0YW5jZSwgY29uc3RyYWluZWQgcGxh
dGZvcm1zIHN1Y2ggYXMgQW5kcm9pZCB1c2VkIHRvIGhhdmUgbW9yZSBsaW1pdGVkIHN1cHBvcnQg
Zm9yIHJ1bnRpbWUgcmVmbGVjdGlvbiBkaWZmZXJlbnQgcGVyZm9ybWFuY2UgcmVxdWlyZW1lbnRz
OiBhcHBsaWNhdGlvbnMgc2hvdWxkIGJlIHNtYWxsIGFuZCBxdWljayB0byBzdGFydC4gUGVvcGxl
IHN0YXJ0ZWQgdG8gZGV2ZWxvcCA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2Zv
bnQtd2VpZ2h0OiBib2xkOyI+KiptaWNyb3NlcnZpY2VzKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNv
bG9yOiAjMDAwMDAwOyI+IGFuZCA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2Zv
bnQtd2VpZ2h0OiBib2xkOyI+KipzZXJ2ZXJsZXNzIGFwcGxpY2F0aW9ucyoqPC9zcGFuPjxzcGFu
IHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPjogdGhlc2Ugc2VydmljZXMgbmVlZCB0byBzdGFydCB2
ZXJ5IHF1aWNrbHksIHRvIGVsYXN0aWNhbGx5IHNjYWxlIHdpdGggdGhlIG51bWJlciBvZiBpbmNv
bWluZyByZXF1ZXN0cy4gPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdl
aWdodDogYm9sZDsiPioqR3JhYWxWTSdzIG5hdGl2ZSBpbWFnZSBjb21waWxlcioqPC9zcGFuPjxz
cGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiBpcyBhbm90aGVyIHJ1bi10aW1lIHBsYXRmb3Jt
IHdpdGggYWRkaXRpb25hbCBjb25zdHJhaW50czogaXQgYWxsb3dzIHRvIGNvbXBpbGUgYSBKYXZh
IHByb2dyYW0gaW50byBhIG5hdGl2ZSBleGVjdXRhYmxlLCBidXQgb3JpZ2luYWxseSwgaXQgcG9z
ZWQgYSBmZXcgbGltaXRhdGlvbnMgb24gcnVuLXRpbWUgcmVmbGVjdGlvbi4gTW9yZW92ZXIsIHdo
ZXJlYXMgaW4gdGhlIHBhc3QgZmF0LCBsb25nLXJ1bm5pbmcgYXBwbGljYXRpb24gc2VydmVycyBo
b3N0ZWQgc2V2ZXJhbCwgcG9zc2libHkgbXV0YWJsZSBhcHBsaWNhdGlvbnMgaW4gYSBzaW5nbGUg
cHJvY2VzcyBzcGFjZSwgdG9kYXkgd2UgZGVwbG95IDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6
ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4qKnNlcGFyYXRlLCBzdGFuZC1hbG9uZSwgaW1t
dXRhYmxlLCBjb250YWluZXJpemVkIGFwcGxpY2F0aW9ucyoqPC9zcGFuPjxzcGFuIHN0eWxlPSJj
b2xvcjogIzAwMDAwMDsiPiBvbiBLdWJlcm5ldGVzLiBGb3IgYWxsIHRoZXNlLCBhbmQgb3RoZXIg
cmVhc29ucywgaW4gdGhlIGxhc3QgZmV3IHllYXJzIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6
ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4qKnRoZSBKYXZhIGVjb3N5c3RlbSBpcyByZWRp
c2NvdmVyaW5nIGNvZGUtZ2VuZXJhdGlvbioqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAw
MDAwMDsiPi4gPC9zcGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAw
MDsiPlRoZSBLb2dpdG8gY29kZS1nZW5lcmF0aW9uIHByb2NlZHVyZSBlbGFib3JhdGVzIGFsbCB0
aGUgImtub3dsZWRnZSBhc3NldHMiIGluIGEgY29kZWJhc2UgYW5kIHByb2R1Y2VzIGVxdWl2YWxl
bnQgSmF2YSBjb2RlIHRoYXQgcGx1Z3MgaW50byBvdXIgY29yZSBlbmdpbmVzIG9uIG9uZSBzaWRl
LCBhbmQgaW50byB0aGUgUXVhcmt1cyBvciBTcHJpbmcgQVBJcyB0byBleHBvc2UgYXV0b21hdGlj
YWxseSBnZW5lcmF0ZWQgUkVTVCBzZXJ2aWNlIGVuZHBvaW50cyBvbiB0aGUgb3RoZXIuIDwvc3Bh
bj48L2Rpdj48YnI+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5MZXQncyBzZWUg
bW9yZSBpbiBkZXRhaWwgaG93IHRoaXMgcHJvY2VkdXJlIHdvcmtzLjwvc3Bhbj48L2Rpdj48YnI+
PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICM4MDAwMDA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4jIyBT
dGFnZWQgQ29tcGlsYXRpb24gaW4gS29naXRvPC9zcGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFuIHN0
eWxlPSJjb2xvcjogIzAwMDAwMDsiPkluIEtvZ2l0bywgdGhlIGNvZGUtZ2VuZXJhdGlvbiBwcm9j
ZWR1cmUgaXMgZGVzaWduZWQgaW4gPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtm
b250LXdlaWdodDogYm9sZDsiPioqc3RhZ2VzKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
MDAwMDAwOyI+LiA8L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAw
MDAwOyI+ICAgICAgKy0tLS0tLS0tLS0tKyAgICAgICstLS0tLS0tLS0tLSsgICAgICArLS0tLS0t
LS0tLS0rPC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICAg
ICAgfCAgICAgICAgICAgfCAgICAgIHwgICAgICAgICAgIHwgICAgICB8ICAgICAgICAgICB8PC9z
cGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICAgICAgfCBQcm9j
ZXNzZXMgKy0tLS0tJmd0OysgICBSdWxlcyAgICstLS0tLSZndDsrIERlY2lzaW9ucyB8PC9zcGFu
PjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICAgICAgfCAgICAgICAg
ICAgfCAgICAgIHwgICAgICAgICAgIHwgICAgICB8ICAgICAgICAgICB8PC9zcGFuPjwvZGl2Pjxk
aXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICAgICAgKy0tLS0tKy0tLS0tKyAgICAg
ICstLS0tLSstLS0tLSsgICAgICArLS0tLS0rLS0tLS0rPC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgIHwg
ICAgICAgICAgICAgICAgICB8PC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
MDAwMDAwOyI+ICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAg
ICB8PC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICAgICAg
ICstLS0tdi0tLS0rICAgICAgICArLS0tLXYtLS0tKyAgICAgICAgKy0tLS12LS0tLSs8L3NwYW4+
PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gICAgICAgfCAgICAgICAg
IHwgICAgICAgIHwgICAgICAgICB8ICAgICAgICB8ICAgICAgICAgfDwvc3Bhbj48L2Rpdj48ZGl2
PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiAgICAgICB8IENvZGVnZW4gfCAgICAgICAg
fCBDb2RlZ2VuIHwgICAgICAgIHwgQ29kZWdlbiB8PC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5
bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICAgICAgIHwgICAgICAgICB8ICAgICAgICB8ICAgICAgICAg
fCAgICAgICAgfCAgICAgICAgIHw8L3NwYW4+PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6
ICMwMDAwMDA7Ij4gICAgICAgKy0tLS0tLS0tLSsgICAgICAgICstLS0tLS0tLS0rICAgICAgICAr
LS0tLS0tLS0tKzwvc3Bhbj48L2Rpdj48YnI+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
MDAwMDAwOyI+Rmlyc3QsIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13
ZWlnaHQ6IGJvbGQ7Ij4qKnByb2Nlc3NlcyoqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAw
MDAwMDsiPiAoQlBNTiBmaWxlcykgYXJlIGFuYWx5emVkLCB0aGVuIDwvc3Bhbj48c3BhbiBzdHls
ZT0iY29sb3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4qKnJ1bGVzKio8L3NwYW4+PHNw
YW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IChEUkxzKSwgdGhlbiA8L3NwYW4+PHNwYW4gc3R5
bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+KipkZWNpc2lvbnMqKjwvc3Bh
bj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gKERNTnMpLiBFYWNoIHN0YWdlLCBhcyBh
IHJlc3VsdCwgZ2VuZXJhdGVzIEphdmEgc291cmNlIGNvZGU7IGNvbXBpbGF0aW9uIGlzIGRlbGVn
YXRlZCB0byB0aGUgSmF2YSBjb21waWxlci4gSW4gbW9kZXJuIHBhcmxhbmNlLCB0aGlzIHdvdWxk
IGJlIGNhbGxlZCBhIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Zm9udC1zdHls
ZTogaXRhbGljOyI+XyJ0cmFuc3BpbGVyIl88L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAw
MDAwOyI+OyBhIHRlcm0gdGhhdCBJIGRlc3Bpc2UsIGJlY2F1c2UgaXQgbWFrZXMgaXQgc291bmQg
bGlrZSBjb21waWxlcnMgZG8gbm90IGp1c3QgZ2VuZXJhdGUgY29kZSBidXQgZG8gc29tZSBraW5k
IG9mIG1hZ2ljIG11bWJvLWp1bWJvLiBCdXQgdGhhdCdzIGFub3RoZXIgc3RvcnkuIFdoYXRldmVy
IHlvdSB3YW50IHRvIGNhbGwgaXQsIG91ciBjdXJyZW50IGFyY2hpdGVjdHVyZSBvZiB0aGlzIHBy
b2NlZHVyZSBpcyByaWdpZCwgYW5kIGRvZXMgbm90IGFsbG93IGZvciBleHRlbnNpb248L3NwYW4+
PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+SW4gZmFjdCwgYWxi
ZWl0IHdlIGFyZSBwcm9jZXNzaW5nIGVhY2ggdHlwZSBvZiBhc3NldCBpbiBhIDwvc3Bhbj48c3Bh
biBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Zm9udC1zdHlsZTogaXRhbGljOyI+X3NlcGFyYXRlIHN0
YWdlXzwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4sIGVhY2ggc3RhZ2UgaXMg
ZWZmZWN0aXZlbHkgYSA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2Vp
Z2h0OiBib2xkOyI+KipzaW5nbGUtcGFzcyBjb21waWxlcioqPC9zcGFuPjxzcGFuIHN0eWxlPSJj
b2xvcjogIzAwMDAwMDsiPiwgYmVjYXVzZSBlYWNoIGl0IGFsd2F5cyB0ZXJtaW5hdGVzIHdpdGgg
dGhlIGdlbmVyYXRpb24gb2YgdGhlIGNvbXBpbGF0aW9uIHRhcmdldC4gVGhpcyBpcyB0aGUgcmVh
c29uIHdoeSBpdCBpcyBnZW5lcmFsbHkgYmV0dGVyIHRvIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29s
b3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4qKmJyZWFrIGRvd24gY29tcGlsYXRpb24g
aW50byBtb3JlIHBhc3NlcyoqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPi4g
RWFjaCBjb21waWxhdGlvbiBwYXNzIHVzdWFsbHkgcHJvZHVjZXMgd2hhdCBpcyBjYWxsZWQgYW4g
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPioq
aW50ZXJtZWRpYXRlIHJlcHJlc2VudGF0aW9uKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
MDAwMDAwOyI+OyB0aGUgaW5wdXQgdG8gb25lIHN0YWdlIGlzIHRoZSBvdXRwdXQgb2YgdGhlIHBy
ZXZpb3VzLCBhbmQgc28gb24gdXAgdG8gdGhlIGZpbmFsIHN0YWdlLCB3aGVyZSB0YXJnZXQgY29k
ZSBpcyBhY3R1YWxseSBwcm9kdWNlZC48L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9
ImNvbG9yOiAjODAwMDAwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+IyMjIENvbXBpbGVycyBhbmQgQ29t
cGlsYXRpb24gUGhhc2VzPC9zcGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjog
IzAwMDAwMDsiPkluIGEgdHJhZGl0aW9uYWwgY29tcGlsZXIsIHVzdWFsbHksIG9uZSBvZiB0aGUg
Zmlyc3Qgc3RhZ2VzIGlzIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13
ZWlnaHQ6IGJvbGQ7Ij4qKnBhcnNpbmcqKjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAw
MDA7Ij4gdGhlIGlucHV0IHNvdXJjZSBjb2RlIGFuZCB0cmFuc2Zvcm1pbmcgaXQgaW50byBhbiBp
bnRlcm5hbCB0cmVlIHJlcHJlc2VudGF0aW9uICh0aGUgPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xv
cjogIzAwMDAwMDtmb250LXN0eWxlOiBpdGFsaWM7Ij4qQWJzdHJhY3QgU3ludGF4IFRyZWUqPC9z
cGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPik7IHRoZW4gdXN1YWxseSBpcyB0aGUg
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPioq
bmFtZSByZXNvbHV0aW9uKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IHBo
YXNlLCB3aGVyZSB0aGUgbmFtZXMgb2YgdGhlIHZhbHVlcyBhbmQgc3ltYm9scyB0aGF0IGFyZSB1
c2VkIHRocm91Z2hvdXQgdGhlIHByb2dyYW0gYXJlIHJlc29sdmVkOyB0aGVuIHRoZSA8L3NwYW4+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+Kip0eXBlLWNo
ZWNraW5nIHBoYXNlKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IHZlcmlm
aWVzIGFuZCB2YWxpZGF0ZXMgdGhlIGNvcnJlY3RuZXNzIG9mIHRoZSBwcm9ncmFtOyBmaW5hbGx5
IDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4q
KmNvZGUqKjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gaXMgYWN0dWFsbHkg
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPioq
Z2VuZXJhdGVkKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+Ljwvc3Bhbj48
L2Rpdj48YnI+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5JbiBLb2dpdG8sIHdl
IDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4q
KnBhcnNlKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IGtub3dsZWRnZSBh
c3NldHMsIHRoZW4gd2UgYXNzb2NpYXRlIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAw
ODA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4qKm5hbWVzKio8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9y
OiAjMDAwMDAwOyI+IHRvIGVhY2ggYXNzZXRzLCBhbmQgd2UgcmVzb2x2ZSB0aGVpciBpbnRlcm5h
bCBzdHJ1Y3R1cmUsIHdoaWNoIG1heSA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgw
O2ZvbnQtd2VpZ2h0OiBib2xkOyI+Kipjcm9zcy1yZWZlcmVuY2UqKjwvc3Bhbj48c3BhbiBzdHls
ZT0iY29sb3I6ICMwMDAwMDA7Ij4gb3RoZXIgZXhpc3RpbmcgYXNzZXRzLiA8L3NwYW4+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+KipUeXBlLWNoZWNraW5n
IG91ciBhc3NldHMgbWVhbnMgdmFsaWRhdGluZyoqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjog
IzAwMDAwMDsiPiB0aGUgbW9kZWxzIGFjY29yZGluZyB0byBzcGVjaWZpY2F0aW9ucyBhbmQgdmVy
aWZ5aW5nIHRoZXNlIGNyb3NzLXJlZmVyZW5jZXMuIEZvciBpbnN0YW5jZSwgYSBCUE1OIGZpbGUg
bWF5IHJlZmVyZW5jZSBhIFJ1bGUgVW5pdCBkZWZpbml0aW9uIGFuZCBhIHNlcnZpY2UgaW1wbGVt
ZW50YXRpb24gd3JpdHRlbiBpbiBKYXZhLiA8L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5
bGU9ImNvbG9yOiAjODAwMDAwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+IyMjIENvbXBpbGVycyBhbmQg
TWluaS1QaGFzZXM8L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAw
MDAwOyI+U28gZmFyLCBvdXIgY29kZS1nZW5lcmF0aW9uIHByb2NlZHVyZSBoYXMgYmVlbiBwcmV0
dHkgc2ltcGxpc3RpYzogd2UgZ2VuZXJhdGVkIGNvZGUgcmVnYXJkbGVzcyBvZiBwb3RlbnRpYWwg
ZXJyb3JzLCBkZWxlZ2F0aW5nIGNvbXBpbGF0aW9uIGVycm9ycyB0byB0aGUgZG93bnN0cmVhbSBK
YXZhIGNvbXBpbGVyOyB3b3JzZSwgc29tZXRpbWVzIHRoZXkgd291bGQgYmUgY2F1Z2h0IGxhdGVy
IGF0IHJ1bi10aW1lISBUaGlzIGluIGdlbmVyYWwgd29ya3MsIGJ1dCBpdCBlaXRoZXIgcHJvZHVj
ZXMgcHJldHR5IG9ic2N1cmUgY29tcGlsYXRpb24gZXJyb3JzLCBvciBpdCBtb3ZlcyB2YWxpZGF0
aW9uIHRvbyBsYXRlIGluIHRoZSBwaXBlbGluZTogd2hpY2ggaXMgc29tZXRoaW5nIHRoYXQgd2Ug
d2FudGVkIHRvIGF2b2lkIGluIHRoZSBmaXJzdCBwbGFjZS4gV2Ugd2FudCB0byA8L3NwYW4+PHNw
YW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+KipjYXRjaCBlcnJv
cnMgZWFybHkqKjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gYW5kIG9ubHkg
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPioq
Z2VuZXJhdGUgdmFsaWQgY29kZSoqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsi
Pi48L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+Qnkg
cmVmYWN0b3Jpbmcgb3VyIGNvbXBpbGF0aW9uIHBoYXNlcyB0byBhIHN0YWdlZCwgbW9kdWxhciBj
b21waWxhdGlvbiBhcmNoaXRlY3R1cmUgd2Ugd2lsbCBiZSBhYmxlIHRvIGNhdGNoIHJlc29sdXRp
b24gYW5kIHZhbGlkYXRpb24gZXJyb3JzIGVhcmx5IGFuZCBwcmVzZW50IHRoZW0gdG8gdXNlcnMg
aW4gYSBtZWFuaW5nZnVsIHdheTogb25seSB3aGVuIHRoZSB2YWxpZGF0aW9uIHBoYXNlIHdpbGwg
YmUgY29tcGxldGVkIHN1Y2Nlc3NmdWxseSwgdGhlbiB3ZSB3aWxsIGFjdHVhbGx5IGdlbmVyYXRl
IGNvZGUuIEJ1dCB3ZSBhbHNvIHdhbnQgb3VyIHN0YWdlcyB0byBiZSBzbWFsbGVyLCBzbyB0aGF0
IGl0IGlzIGVhc2llciB0byA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQt
d2VpZ2h0OiBib2xkOyI+KiphZGQgbW9yZSBjb21waWxhdGlvbiBzdGFnZXMqKjwvc3Bhbj48c3Bh
biBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gYXQgZGlmZmVyZW50IHBvaW50cyBpbiB0aGUgcGlw
ZWxpbmUuPC9zcGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsi
PiAgICBQcm9jZXNzZXMsIFJ1bGVzLCBEZWNpc2lvbnM6PC9zcGFuPjwvZGl2Pjxicj48ZGl2Pjxz
cGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiAgICArLS0tLS0tLS0tLS0tLS0tLS0rICAgICAg
Ky0tLS0tLS0tLS0tLS0tLS0tLSsgICAgICArLS0tLS0tLS0tLS0tLS0tLS0tLSsgICAgICArLS0t
LS0tLS0tLS0tLS0tLS0rPC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAw
MDAwOyI+ICAgIHwgICAgICAgICAgICAgICAgIHwgICAgICB8ICAgICAgICAgICAgICAgICAgfCAg
ICAgIHwgICAgICAgICAgICAgICAgICAgfCAgICAgIHwgICAgICAgICAgICAgICAgIHw8L3NwYW4+
PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gICAgfCBOYW1lIFJlc29s
dXRpb24gKy0tLS0tJmd0OysgTW9kZWwgVmFsaWRhdGlvbiArLS0tLS0mZ3Q7KyBDcm9zcy1SZWZl
cmVuY2luZyArLS0tLS0mZ3Q7KyBDb2RlLUdlbmVyYXRpb24gfDwvc3Bhbj48L2Rpdj48ZGl2Pjxz
cGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiAgICB8ICAgICAgICAgICAgICAgICB8ICAgICAg
fCAgICAgICAgICAgICAgICAgIHwgICAgICB8ICAgICAgICAgICAgICAgICAgIHwgICAgICB8ICAg
ICAgICAgICAgICAgICB8PC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAw
MDAwOyI+ICAgICstLS0tLS0tLS0tLS0tLS0tLSsgICAgICArLS0tLS0tLS0tLS0tLS0tLS0tKyAg
ICAgICstLS0tLS0tLS0tLS0tLS0tLS0tKyAgICAgICstLS0tLS0tLS0tLS0tLS0tLSs8L3NwYW4+
PC9kaXY+PGJyPjxicj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPkZvciBpbnN0
YW5jZSwgc3VwcG9zZSB5b3Ugd2FudCB0byBzeW50aGVzaXplIHNvbWUgZWxlbWVudHMgKGUuZy4g
ZGF0YSBtb2RlbHMpIHRoYXQgYXJlIGluZmVycmVkIGZyb20gdGhlIHN0cnVjdHVyZSBvZiBhIHBy
b2Nlc3MuIEluIG91ciBjdXJyZW50IGFyY2hpdGVjdHVyZSwgdGhlIG9ubHkgd2F5IHRvIHByb2R1
Y2UgYWRkaXRpb25hbCBhc3NldHMgd291bGQgYmUgdG8gcGF0Y2ggdGhlIGV4aXN0aW5nIGNvZGUu
IEJ5IGRlLWNvbXBvc2luZyB0aGUgcGhhc2VzIGFzIHNob3duIGFib3ZlLCB5b3Ugd291bGQgYmUg
YWJsZSB0byA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBi
b2xkOyI+KipwbHVnIHlvdXIgYWRkaXRpb25hbCA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
MDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+Wzwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICNh
MzE1MTU7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij5taW5pLXBoYXNlPC9zcGFuPjxzcGFuIHN0eWxlPSJj
b2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPl08L3NwYW4+PHNwYW4gc3R5bGU9ImNv
bG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+W25hbm9wYXNzXSoqPC9zcGFuPjxzcGFu
IHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiByaWdodCBhZnRlciAiTW9kZWwgVmFsaWRhdGlvbiIs
IHNvIHRoYXQgeW91IGNhbiBiZSBzdXJlIHRoYXQgYWxsIHRoZSBuYW1lcyBoYXZlIGJlZW4gcmVz
b2x2ZWQsIGFuZCB0aGF0IG9ubHkgdmFsaWQgbW9kZWxzIHdpbGwgYmUgcHJvY2Vzc2VkOiB5b3Ug
d2lsbCBwcm9kdWNlIGFuIGludGVybWVkaWF0ZSByZXByZXNlbnRhdGlvbiBmb3IgdGhlIGRhdGEg
bW9kZWwgdGhhdCB5b3Ugd2FudCB0byBzeW50aGVzaXplLCBhbmQgbWFrZSBpdCBhdmFpbGFibGUg
ZHVyaW5nIHRoZSAiQ3Jvc3MtUmVmZXJlbmNpbmciIHBoYXNlLjwvc3Bhbj48L2Rpdj48YnI+PGRp
dj48c3BhbiBzdHlsZT0iY29sb3I6ICM4MDAwMDA7Zm9udC13ZWlnaHQ6IGJvbGQ7Ij4jIyBQcmUt
UHJvY2Vzc2luZyBBc3NldHMgdnMuIENvZGUgU2NhZmZvbGRpbmcuPC9zcGFuPjwvZGl2Pjxicj48
ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPkFzIGJyaWVmbHkgbWVudGlvbmVkIGlu
IHRoZSBpbnRyb2R1Y3Rpb24sIGluIG91ciBjdXJyZW50IGFyY2hpdGVjdHVyZSB3ZSBhcmUgYWxz
byBjb25mbGF0aW5nIGNvZGUtZ2VuZXJhdGlvbiBmb3IgdHdvIHZlcnkgZGlmZmVyZW50IHB1cnBv
c2VzLjwvc3Bhbj48L2Rpdj48YnI+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5U
aGUgPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsi
PioqZmlyc3QqKjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gaXMgdG8gPC9z
cGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPioqcHJl
LXByb2Nlc3MqKjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gYXNzZXRzIHRv
IGdlbmVyYXRlIHRoZWlyIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwODA7Zm9udC13
ZWlnaHQ6IGJvbGQ7Ij4qKnN0YW5kLWFsb25lIHJ1bi10aW1lIHJlcHJlc2VudGF0aW9uKio8L3Nw
YW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+OiB0aGUgZ29hbCBpcyBib3RoIHRvIHJl
ZHVjZSBydW4tdGltZSBwcm9jZXNzaW5nIGFuZCBzdXBwb3J0IG5hdGl2ZSBjb21waWxhdGlvbi4g
VGhlIG91dHB1dCBvZiB0aGlzIGNvZGUtZ2VuZXJhdGlvbiBwcm9jZWR1cmUgYXJlIG9iamVjdHMg
dGhhdCBpbnRlcmZhY2UgZGlyZWN0bHkgd2l0aCB0aGUgaW50ZXJuYWwgcHJvZ3JhbW1hdGljIEFQ
SXMgb2Ygb3VyIGVuZ2luZXMuIFRoaXMgcHJvZ3JhbW1hdGljIEFQSSwgaW4gS29naXRvLCBpcyBj
dXJyZW50bHkgY29uc2lkZXJlZCBhbiBpbXBsZW1lbnRhdGlvbiBkZXRhaWwsIG5vdCBzdXBwb3Nl
ZCB0byBiZSBjb25zdW1lZCBieSBlbmQtdXNlcnMuIFRoZSByZWFzb24gaXMgdGhhdCB0aGlzIEFQ
SSBpcyBzdGlsbCB1bnN0YWJsZTogd2Ugd2FudCB0byBtYWtlIHN1cmUgdG8gZ2V0IGl0IHJpZ2h0
LCBiZWZvcmUgbWFraW5nIGl0IHB1YmxpYy4gTm93LCBmb3IgdGhlIHNha2Ugb2YgZXhwbGFuYXRp
b24sIGNvbnNpZGVyIGEgQlBNTiBwcm9jZXNzIGRlZmluaXRpb246IHRoaXMgaXMgY29tcGlsZWQg
aW50byBhIGNsYXNzIHRoYXQgaW1wbGVtZW50IHRoZSA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9y
OiAjODAwMDAwOyI+YFByb2Nlc3MmbHQ7VCZndDtgPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjog
IzAwMDAwMDsiPiBpbnRlcmZhY2Ugb2YgdGhlIHByb2dyYW1tYXRpYyBBUEkuIEJ5IGluc3RhbnRp
YXRpbmcgdGhpcyBjbGFzcywgeW91IGdldCBhbiBleGFjdCAxOjEgcmVwcmVzZW50YXRpb24gb2Yg
dGhlIHByb2Nlc3MgZGVmaW5pdGlvbiwgbWludXMgcGFyc2luZyBhbmQgcHJlbGltaW5hcnkgYW5h
bHlzaXMuPC9zcGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsi
PlRoZSA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xk
OyI+KipzZWNvbmQqKjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gcHVycG9z
ZSBvZiBjb2RlLWdlbmVyYXRpb24gaXMgaW1wbGVtZW50ZWQgYXMgYSA8L3NwYW4+PHNwYW4gc3R5
bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBib2xkOyI+KipsYXllcioqPC9zcGFuPjxz
cGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiBvbiB0b3Agb2YgdGhlc2UgcnVuLXRpbWUgcmVw
cmVzZW50YXRpb25zOyBoZXJlIHdlIGV4cG9zZXMgY2FsbHMgaW50byB0aGUgcHJvZ3JhbW1hdGlj
IEFQSSBhcyA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDgwO2ZvbnQtd2VpZ2h0OiBi
b2xkOyI+KipSRVNUIGVuZHBvaW50cyoqPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAw
MDsiPi4gRm9yIGV4YW1wbGUsIGNvbnNpZGVyIGEgcHJvY2VzcyBjYWxsZWQgPC9zcGFuPjxzcGFu
IHN0eWxlPSJjb2xvcjogIzgwMDAwMDsiPmBNeVByb2Nlc3NgPC9zcGFuPjxzcGFuIHN0eWxlPSJj
b2xvcjogIzAwMDAwMDsiPjsgdGhlIFJFU1QgZW5kcG9pbnRzIHdlIGdlbmVyYXRlIGV4cG9zZSBS
RVNUIEFQSXMgdG8gc3RhcnQsIGV4ZWN1dGUgYW5kIHRlcm1pbmF0ZSBhbiBpbnN0YW5jZSBvZiB0
aGF0IHByb2Nlc3MuIFlvdSBjYW4gaW1hZ2luZSB0aGF0IGNvZGUgdG8gbG9vayBhIGJ1dCBsaWtl
IHRoaXM6PC9zcGFuPjwvZGl2Pjxicj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsi
PmBgYGphdmE8L3NwYW4+PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5A
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzI2N2Y5OTsiPlBhdGg8L3NwYW4+PHNwYW4gc3R5
bGU9ImNvbG9yOiAjMDAwMDAwOyI+KDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICNhMzE1MTU7
Ij4iL015UHJvY2VzcyI8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+KTwvc3Bh
bj48L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDBmZjsiPnB1YmxpYzwvc3Bhbj48
c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjog
IzAwMDBmZjsiPmNsYXNzPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiA8L3Nw
YW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMjY3Zjk5OyI+TXlQcm9jZXNzUmVzb3VyY2U8L3NwYW4+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IHs8L3NwYW4+PC9kaXY+PGRpdj48c3BhbiBz
dHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gIDwvc3Bhbj48L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJj
b2xvcjogIzAwMDAwMDsiPiAgQDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMyNjdmOTk7Ij5J
bmplY3Q8L3NwYW4+PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gIDwv
c3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMyNjdmOTk7Ij5Qcm9jZXNzPC9zcGFuPjxzcGFuIHN0
eWxlPSJjb2xvcjogIzAwMDAwMDsiPiZsdDs8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMjY3
Zjk5OyI+TXlQcm9jZXNzPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiZndDsg
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMTA4MDsiPnA8L3NwYW4+PHNwYW4gc3R5bGU9
ImNvbG9yOiAjMDAwMDAwOyI+Ozwvc3Bhbj48L2Rpdj48YnI+PGRpdj48c3BhbiBzdHlsZT0iY29s
b3I6ICMwMDAwMDA7Ij4gIEA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMjY3Zjk5OyI+UE9T
VDwvc3Bhbj48L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiAgPC9zcGFu
PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDBmZjsiPnB1YmxpYzwvc3Bhbj48c3BhbiBzdHlsZT0i
Y29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzI2N2Y5OTsiPk15
UHJvY2Vzczwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPjxzcGFu
IHN0eWxlPSJjb2xvcjogIzc5NWUyNjsiPnN0YXJ0PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjog
IzAwMDAwMDsiPig8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMjY3Zjk5OyI+TXlQcm9jZXNz
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPiA8L3NwYW4+PHNwYW4gc3R5bGU9
ImNvbG9yOiAjMDAxMDgwOyI+ZGF0YTwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7
Ij4pIHs8L3NwYW4+PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gICAg
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogI2FmMDBkYjsiPnJldHVybjwvc3Bhbj48c3BhbiBz
dHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMTA4
MDsiPnA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+Ljwvc3Bhbj48c3BhbiBz
dHlsZT0iY29sb3I6ICM3OTVlMjY7Ij5jcmVhdGU8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
MDAwMDAwOyI+KGRhdGEpLjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICM3OTVlMjY7Ij5zdGFy
dDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4oKTs8L3NwYW4+PC9kaXY+PGRp
dj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gIH08L3NwYW4+PC9kaXY+PGJyPjxkaXY+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICBAPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xv
cjogIzI2N2Y5OTsiPkRFTEVURTwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4o
PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogI2EzMTUxNTsiPiIve2lkfSI8L3NwYW4+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+KTwvc3Bhbj48L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJj
b2xvcjogIzAwMDAwMDsiPiAgPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDBmZjsiPnB1
YmxpYzwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPjxzcGFuIHN0
eWxlPSJjb2xvcjogIzI2N2Y5OTsiPk15UHJvY2Vzczwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6
ICMwMDAwMDA7Ij4gPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzc5NWUyNjsiPmFib3J0PC9z
cGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPig8L3NwYW4+PHNwYW4gc3R5bGU9ImNv
bG9yOiAjMjY3Zjk5OyI+U3RyaW5nPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsi
PiA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAxMDgwOyI+aWQ8L3NwYW4+PHNwYW4gc3R5
bGU9ImNvbG9yOiAjMDAwMDAwOyI+KSB7PC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNv
bG9yOiAjMDAwMDAwOyI+ICAgIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICNhZjAwZGI7Ij5y
ZXR1cm48L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ID0gPC9zcGFuPjxzcGFu
IHN0eWxlPSJjb2xvcjogIzAwMTA4MDsiPnA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAw
MDAwOyI+Ljwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICM3OTVlMjY7Ij5kZWxldGU8L3NwYW4+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+KGlkKTs8L3NwYW4+PC9kaXY+PGRpdj48c3Bh
biBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gIH08L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICBAPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzI2
N2Y5OTsiPkdFVDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4oPC9zcGFuPjxz
cGFuIHN0eWxlPSJjb2xvcjogI2EzMTUxNTsiPiIve2lkfSI8L3NwYW4+PHNwYW4gc3R5bGU9ImNv
bG9yOiAjMDAwMDAwOyI+KTwvc3Bhbj48L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAw
MDAwMDsiPiAgPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDBmZjsiPnB1YmxpYzwvc3Bh
bj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xv
cjogIzI2N2Y5OTsiPkNvbGxlY3Rpb248L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAw
OyI+Jmx0Ozwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMyNjdmOTk7Ij5Qcm9jZXNzSW5zdGFu
Y2U8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+Jmx0Ozwvc3Bhbj48c3BhbiBz
dHlsZT0iY29sb3I6ICMyNjdmOTk7Ij5NeVByb2Nlc3M8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9y
OiAjMDAwMDAwOyI+Jmd0OyZndDsgPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzc5NWUyNjsi
PmFib3J0PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPig8L3NwYW4+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjMjY3Zjk5OyI+U3RyaW5nPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjog
IzAwMDAwMDsiPiA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAxMDgwOyI+aWQ8L3NwYW4+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+KSB7PC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICAgIDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICNh
ZjAwZGI7Ij5yZXR1cm48L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IDwvc3Bh
bj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDEwODA7Ij5wPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xv
cjogIzAwMDAwMDsiPi48L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjNzk1ZTI2OyI+aW5zdGFu
Y2VzPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPihpZCk7PC9zcGFuPjwvZGl2
PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICB9PC9zcGFuPjwvZGl2PjxkaXY+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+ICAuLi48L3NwYW4+PC9kaXY+PGJyPjxkaXY+
PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+fTwvc3Bhbj48L2Rpdj48ZGl2PjxzcGFuIHN0
eWxlPSJjb2xvcjogIzAwMDAwMDsiPmBgYDwvc3Bhbj48L2Rpdj48YnI+PGJyPjxkaXY+PHNwYW4g
c3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+VG9kYXksIGJvdGggdGhlIGNvZGUgdGhhdCBpcyBnZW5l
cmF0ZWQgZm9yIHJ1bi10aW1lIHJlcHJlc2VudGF0aW9ucyBhbmQgdGhlIGNvZGUgdGhhdCBpbXBs
ZW1lbnRzIFJFU1QgZW5kcG9pbnRzIGlzIGFsbCB0cmVhdGVkIGFzIGFuIDwvc3Bhbj48c3BhbiBz
dHlsZT0iY29sb3I6ICMwMDAwMDA7Zm9udC1zdHlsZTogaXRhbGljOyI+KmltcGxlbWVudGF0aW9u
IGRldGFpbCo8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+LiBJdCBpcyBvbmx5
IHZpc2libGUgaW4gdGhlIGNvbXBpbGF0aW9uIHRhcmdldCBkaXJlY3Rvcnkgb2YgeW91ciBwcm9q
ZWN0LiBBbmQgeW91IGFyZSA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwO2ZvbnQt
c3R5bGU6IGl0YWxpYzsiPl9ub3RfPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsi
PiBzdXBwb3NlZCB0byByZWx5IG9uIHRoZSBzdHJ1Y3R1cmUgb2YgdGhhdCBjb2RlIGluIHlvdXIg
b3duIGNvZGViYXNlLjwvc3Bhbj48L2Rpdj48YnI+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMw
MDAwMDA7Ij5Ib3dldmVyLCB3ZSBhbHdheXMgbWVhbnQgdGhpcyBwcm9jZWR1cmUgdG8gYmVjb21l
IGN1c3RvbWl6YWJsZSBhdCBzb21lIHBvaW50LCBwcm9tb3RpbmcgaXQgdG8gYmUgPC9zcGFuPjxz
cGFuIHN0eWxlPSJjb2xvcjogIzAwMDA4MDtmb250LXdlaWdodDogYm9sZDsiPioqc2NhZmZvbGRp
bmcqKjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4uIDwvc3Bhbj48L2Rpdj48
YnI+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5JbiB0aGUgY2FzZSBvZiBzY2Fm
Zm9sZGluZywgY29kZSBzaG91bGQgbm90IGJlIGdlbmVyYXRlZCBpbiB5b3VyIGNvbXBpbGF0aW9u
IHRhcmdldCBkaXJlY3RvcnksIGJ1dCBpbnN0ZWFkLCBpdCBzaG91bGQgYmUgcHJvbW90ZWQgdG8g
eW91ciA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwO2ZvbnQtc3R5bGU6IGl0YWxp
YzsiPl9zb3VyY2UgY29kZV88L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+IGRp
cmVjdG9yeS4gV2UgYXJlIGN1cnJlbnRseSB3b3JraW5nIG9uIGEgZ2VuZXJhbCBzb2x1dGlvbiB0
byBhbGxvdyB5b3UgdG8gb3B0LW91dCBmcm9tIGNvZGUgZ2VuZXJhdGlvbiBmb3Igc3BlY2lmaWMg
YXNzZXRzLCBhbmQgaW5zdGVhZCwgImNsYWltIiBpdCBmb3Igb3duZXJzaGlwLiBGb3IgaW5zdGFu
Y2UsIHN1cHBvc2UgdGhhdCB5b3Ugd2FudCB0byBjdXN0b21pemUgPC9zcGFuPjxzcGFuIHN0eWxl
PSJjb2xvcjogIzgwMDAwMDsiPmBNeVByb2Nlc3NgPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjog
IzAwMDAwMDsiPi4gWW91IHdpbGwgYmUgYWJsZSB0byB0ZWxsIHRoZSBjb2RlLWdlbmVyYXRpb24g
cHJvY2VkdXJlIHRoYXQgeW91IHdhbnQgY3VzdG9taXplIHRoYXQgYXNzZXQ6IHRoZSBjb2RlLWdl
bmVyYXRpb24gcHJvY2VkdXJlIHdpbGwgcnVuIG9uY2UsIGFuZCB0aGVuIHlvdSB3aWxsIGJlIGFi
bGUgdG8gZWRpdCB0aGUgZ2VuZXJhdGVkIGNvZGUgYXMgcmVndWxhciBzb3VyY2UgY29kZS48L3Nw
YW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjODAwMDAwO2ZvbnQtd2VpZ2h0
OiBib2xkOyI+IyMgQ29uY2x1c2lvbnM8L3NwYW4+PC9kaXY+PGJyPjxkaXY+PHNwYW4gc3R5bGU9
ImNvbG9yOiAjMDAwMDAwOyI+WW91IHNob3VsZCBub3cgaGF2ZSBhIGJldHRlciB1bmRlcnN0YW5k
aW5nIG9mIHRoZSByYXRpb25hbGUgZm9yIGNvZGUgZ2VuZXJhdGlvbiBpbiBLb2dpdG86IGluIHRo
ZSBmdXR1cmUgd2UgYXJlIGdvaW5nIHRvIGltcHJvdmUgb3VyIGNvZGUgZ2VuZXJhdGlvbiBwcm9j
ZWR1cmUgdG8gYWxsb3cgZXh0ZW5zaWJpbGl0eSBieSBwbHVnZ2luZyBpbnRvIHRoZSBjb2RlLWdl
bmVyYXRpb24gcHJvY2VzcywgYW5kIGN1c3RvbWl6YXRpb24gYnkgYWxsb3dpbmcgZW5kLXVzZXJz
IHRvIHByb21vdGUgY29kZSBnZW5lcmF0aW9uIHRvIHNjYWZmb2xkaW5nLjwvc3Bhbj48L2Rpdj48
YnI+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5JbiB0aGUgZnV0dXJlIHdlIHdp
bGwgZnVydGhlciBkb2N1bWVudCBob3cgd2UgcGxhbiB0byByZWZhY3RvciBvdXIgY29kZWJhc2Ug
dG8gc3VwcG9ydCB0aGVzZSBub3ZlbCB1c2UgY2FzZXMuIDwvc3Bhbj48L2Rpdj48YnI+PGRpdj48
c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5ba29naXRvXTogPC9zcGFuPjxzcGFuIHN0eWxl
PSJjb2xvcjogIzAwMDAwMDt0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsiPmh0dHBzOi8va29n
aXRvLmtpZS5vcmc8L3NwYW4+PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7
Ij5bdmRtMTldOiA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwO3RleHQtZGVjb3Jh
dGlvbjogdW5kZXJsaW5lOyI+aHR0cHM6Ly95b3V0dS5iZS9UV2ZpZ1I5d0dzQTwvc3Bhbj48L2Rp
dj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPltxY29uc3AxOV06IDwvc3Bhbj48
c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7dGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7Ij5o
dHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PUJVclk2T24xU3hNPC9zcGFuPjwvZGl2Pjxk
aXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+W2Fubm90YXRpb25zXTogPC9zcGFuPjxz
cGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDt0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsiPmh0
dHBzOi8vZG9jcy5vcmFjbGUuY29tL2VuL2phdmEvamF2YXNlLzExL2RvY3MvYXBpL2phdmEuY29t
cGlsZXIvamF2YXgvYW5ub3RhdGlvbi9wcm9jZXNzaW5nL3BhY2thZ2Utc3VtbWFyeS5odG1sPC9z
cGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+W2FzbV06IDwvc3Bh
bj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7dGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7
Ij5odHRwczovL2FzbS5vdzIuaW8vPC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9y
OiAjMDAwMDAwOyI+W2phdmFwb2V0XTogPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAw
MDt0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsiPmh0dHBzOi8vZ2l0aHViLmNvbS9zcXVhcmUv
amF2YXBvZXQ8L3NwYW4+PC9kaXY+PGRpdj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7Ij5b
amF2YXBhcnNlcl06IDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7dGV4dC1kZWNv
cmF0aW9uOiB1bmRlcmxpbmU7Ij5odHRwczovL2phdmFwYXJzZXIub3JnLzwvc3Bhbj48c3BhbiBz
dHlsZT0iY29sb3I6ICMwMDAwMDA7Ij4gPC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNv
bG9yOiAjMDAwMDAwOyI+W3JlZmxlY3Rpb25dOiA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAj
MDAwMDAwO3RleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lOyI+aHR0cHM6Ly93d3cub3B0YXBsYW5u
ZXIub3JnL2Jsb2cvMjAxOC8wMS8wOS9KYXZhUmVmbGVjdGlvbkJ1dE11Y2hGYXN0ZXIuaHRtbDwv
c3Bhbj48L2Rpdj48ZGl2PjxzcGFuIHN0eWxlPSJjb2xvcjogIzAwMDAwMDsiPltuYW5vcGFzc106
IDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6ICMwMDAwMDA7dGV4dC1kZWNvcmF0aW9uOiB1bmRl
cmxpbmU7Ij5odHRwczovL25hbm9wYXNzLm9yZy88L3NwYW4+PC9kaXY+PGRpdj48c3BhbiBzdHls
ZT0iY29sb3I6ICMwMDAwMDA7Ij5bbWljcm9uYXV0XTogPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xv
cjogIzAwMDAwMDt0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsiPmh0dHBzOi8vbWljcm9uYXV0
LmlvPC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwOyI+W3F1YXJr
dXNdOiA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiAjMDAwMDAwO3RleHQtZGVjb3JhdGlvbjog
dW5kZXJsaW5lOyI+aHR0cHM6Ly9xdWFya3VzLmlvPC9zcGFuPjwvZGl2PjxkaXY+PHNwYW4gc3R5
bGU9ImNvbG9yOiAjMDAwMDAwOyI+W2NkaWxpdGVdOiA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9y
OiAjMDAwMDAwO3RleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lOyI+aHR0cDovL3d3dy5jZGktc3Bl
Yy5vcmcvbmV3cy8yMDIwLzAzLzA5L0NESV9mb3JfdGhlX2Z1dHVyZS88L3NwYW4+PC9kaXY+PGJy
Pjxicj48L2Rpdj4=">
</div>
</div>
Edoardo Vacchihttp://www.blogger.com/profile/05676846789077609136noreply@blogger.com8tag:blogger.com,1999:blog-5869426.post-83081235939368300362020-04-14T10:25:00.000+01:002020-04-22T08:44:20.366+01:00Functional Programming in DMN: it FEELs like recursing my university studies againIn this post, I would like to share interesting insights about recursion support in DMN and highlights how specific properties of the FEEL language enable functional programming constructs to be modeled in DMN.<br />
<br />
We are going to start from a basic example, in order to demonstrate how the Business Friendliness nature of the FEEL language and DMN constructs, allow us to tame an otherwise commonly unpleasant problem: the definition of a recursive function. Then, we are going to adventure in FP land, and in the cradle of FEEL/DMN we will admire one of the best creatures of functional construct: the Y Combinator. At the end, we will find ourselves be asked the famous question again:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxtGOsz1tffd9N4TdDQx7dVXAQhGGzjoUmRK4UY7DV_NSN1LBbYIGRVwO8gYsKINmzdztiB0r75h7uLu5TOAmy1-h2iqM41STHnmWmd7ZquVKEcjzZI_E6AS5FFB9aFDCwM5NN/s1600/image4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="609" data-original-width="1125" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxtGOsz1tffd9N4TdDQx7dVXAQhGGzjoUmRK4UY7DV_NSN1LBbYIGRVwO8gYsKINmzdztiB0r75h7uLu5TOAmy1-h2iqM41STHnmWmd7ZquVKEcjzZI_E6AS5FFB9aFDCwM5NN/s320/image4.png" width="320" /></a></div>
<br />
Using the pure engineering approach, let’s dig into the matter right away!<br />
<br />
<div>
<h2>
Basic recursion example</h2>
<div>
<br /></div>
The <a href="https://drools.org/learn/dmn.html" target="_blank">Drools DMN open source engine</a> allows recursion support in DMN Business Knowledge Model nodes. This enables modeling of recursive functions very easily and <b>it is our recommended approach</b> when modeling recursive functions in DMN: allow the function to call itself by its name.<br />
<br />
Let’s take a look at a simple example: modeling the <a href="https://en.wikipedia.org/wiki/Factorial" target="_blank">factorial</a> function in DMN.<br />
<br />
We can use the <a href="https://porcelli.me/announcement/tooling/online/bpmn/dmn/2020/03/12/online-new-editors.html" target="_blank">Kogito DMN editor</a> and define the DRD as follows:<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6X8WxekkoDemh_DLYE3UtMY3hbAae3n5V5Ie3usLM_hgSVr5lsH58gqKbfK68AYkcgQpr4FUsZBKRYBJqINcoVdY2oKLQ-vOLQPnDwM3aMyCdtWOxwnOW2igipkM-sFZ0Ws9T/s1600/image3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="868" data-original-width="1201" height="462" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6X8WxekkoDemh_DLYE3UtMY3hbAae3n5V5Ie3usLM_hgSVr5lsH58gqKbfK68AYkcgQpr4FUsZBKRYBJqINcoVdY2oKLQ-vOLQPnDwM3aMyCdtWOxwnOW2igipkM-sFZ0Ws9T/s640/image3.png" width="640" /></a><br />
<br />
<br />
With the “fac” Business Knowledge Model (in short, BKM) node defining the actual Factorial function recursively as:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9n-hCEluy51Zmkm6m41WTrtvITCU1MhskJRnSSJF7PSJhqeWoLf5AeHDQ_wJUPXeYxrbCF_gQOXlGldbdZ7eCjEMHHHeMtReF7qLA6I7chCK0Lfd2Glp0Qk2lBXFrsmScfcyN/s1600/image9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="326" data-original-width="532" height="392" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9n-hCEluy51Zmkm6m41WTrtvITCU1MhskJRnSSJF7PSJhqeWoLf5AeHDQ_wJUPXeYxrbCF_gQOXlGldbdZ7eCjEMHHHeMtReF7qLA6I7chCK0Lfd2Glp0Qk2lBXFrsmScfcyN/s640/image9.png" width="640" /></a></div>
<br />
<br />
As we can notice, the function invokes itself as any other normal <a href="https://www.google.com/search?q=recursion" target="_blank">recursive</a> function, the only difference here is that it is defined as part of a DMN Boxed Expression; the name of this function is defined by the BKM node with the boxed expression construct “fac”, then the body of the function make reference and invokes itself as part of the FEEL expression “fac(n-1)”.<br />
<br />
We can use this BKM to calculate the actual result as passed by the Input Data node, as part of the “compute factorial” Decision, as:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYaqdUDUh4lO1xGWQPPshKKLeMRHZt8LxkgLHv9V3G5EcqMQSzHbSS8arKl_hp2SSEuPhgNEU3W8vMhWlxDmIsrisX6WcEFZZ3F2hHxhAb2pzY0sTLiN6jdec9jMo80ao9FXHE/s1600/image2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="330" data-original-width="564" height="374" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYaqdUDUh4lO1xGWQPPshKKLeMRHZt8LxkgLHv9V3G5EcqMQSzHbSS8arKl_hp2SSEuPhgNEU3W8vMhWlxDmIsrisX6WcEFZZ3F2hHxhAb2pzY0sTLiN6jdec9jMo80ao9FXHE/s640/image2.png" width="640" /></a></div>
<br />
<br />
This works well and gives the expected results:<br />
<span style="font-family: "courier new" , "courier" , monospace;">{</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> My number: 3</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> fac: function fac( n )</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> compute factorial: 6</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<br />
<h2>
<span style="font-family: inherit;">About currying</span></h2>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">DMN and more importantly the FEEL language allow to define and invoke <a href="https://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application" target="_blank">curried</a> functions.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">This allows us to write in FEEL something like:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">{ f : function(a) function(b) a + b, r : f(1)(2) }</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">where:</span><br />
<br />
<ul>
<li><span style="font-family: inherit;">we defined a feel:context with 2 entries</span></li>
<li><span style="font-family: inherit;">the first entry is named “f” and defines a curried function: a function of one parameter “a” that, once invoked, will return a function of one parameter “b” that, once invoked, will return the sum of a+b</span></li>
<li><span style="font-family: inherit;">the latter entry named “r” which invokes the curried function with a=1 and b=2.</span></li>
</ul>
<br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Albeit this is potentially a weird looking FEEL expression, we are not surprised once executed r = 3.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">We can do equivalently by using DMN Boxed Expression constructs:</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_-aYgDRXP0Rce13gb8dIpM7GQM4Pys_PVg4sxWBNJogFY9YhTy7wTDprCiZvjs3QAWez4yU8xzGMkNi4YFx_vPNFWaGs-oXNcmVyj3ZoUrWVOcYo9eAbenzMCZ3qVZYXiJHpK/s1600/image7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="629" data-original-width="918" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_-aYgDRXP0Rce13gb8dIpM7GQM4Pys_PVg4sxWBNJogFY9YhTy7wTDprCiZvjs3QAWez4yU8xzGMkNi4YFx_vPNFWaGs-oXNcmVyj3ZoUrWVOcYo9eAbenzMCZ3qVZYXiJHpK/s640/image7.png" width="640" /></a></div>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">This is a BKM node named “curried sum”; it is a DMN Invocable of one parameter “a” that, once invoked, will return a function of one parameter “b” that, once invoked, returns the sum of a+b.</span><br />
<span style="font-family: inherit;">Again, we are not surprised once executed </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">curried sum(1)(2) = 3</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<h2>
<span style="font-family: inherit;">Y Combinator: recursion without recursion support</span></h2>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Let’s go back for a moment to the earlier recursive function example; we overlooked the fact if it’s actually formally possible for a function to call itself by its name in DMN: the DMN specification does not explicitly support this, but it doesn’t explicitly forbid it either. In other terms, recursion support is not formally specified.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">What-if we still needed to define a recursive function, but we found the road was still under construction, missing that formal recursion support? We can use a functional device, called the “<a href="https://youtu.be/9T8A89jgeTI" target="_blank">Y Combinator</a>” which allows anonymous functions to achieve recursion without relying on self-invocation by its own (unexisting) name.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Let’s look at an example; we can define the Y Combinator in DMN as follows:</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRLiXnoQ5XdEbbL12kVXU4djI6Qv_gUhxhFMkxQhb9mKDJ7UQBerXNtmuVcvHhG9JaUwy6hc3EM3ptqqcdV0eHSv0PgqeaEmUzoeuClWhc7mFL_NpR3inVMCurECpWeq2S_a0J/s1600/image1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="629" data-original-width="918" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRLiXnoQ5XdEbbL12kVXU4djI6Qv_gUhxhFMkxQhb9mKDJ7UQBerXNtmuVcvHhG9JaUwy6hc3EM3ptqqcdV0eHSv0PgqeaEmUzoeuClWhc7mFL_NpR3inVMCurECpWeq2S_a0J/s640/image1.png" width="640" /></a></div>
<br />
<span style="font-family: inherit;">It is potentially a weird looking function :) let’s assume this was defined for us, and we can just make use of it. </span><br />
<span style="font-family: inherit;">We can use it to re-define the factorial calculation as:</span><br />
<span style="font-family: inherit;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzxi5WRqvlYnx3swfZdLgJHJRmLGICpKqkPSMLojbdN67MGU-A4w46yPLjlA6sfPTEUggS4ujHe_cwXzATGeHfDmO5VFlPP4_Iv2-L1Cq5HXc81Anbs186GOlx6lpQCoDvYDe1/s1600/image5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="629" data-original-width="918" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzxi5WRqvlYnx3swfZdLgJHJRmLGICpKqkPSMLojbdN67MGU-A4w46yPLjlA6sfPTEUggS4ujHe_cwXzATGeHfDmO5VFlPP4_Iv2-L1Cq5HXc81Anbs186GOlx6lpQCoDvYDe1/s640/image5.png" width="640" /></a></div>
<br />
<span style="font-family: inherit;">We can notice the body of the “fac” function definition is overall the same; however, this is not any longer a function invoking itself by its name: there is no trace of a call to “fac(...)” in the body of the function!</span><br />
<span style="font-family: inherit;">Naturally, there is still a form of recursion happening, but this time is leveraging the name of the parameters which are in scope of the closure: “f”. </span><br />
<span style="font-family: inherit;">The result works as expected:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">fac(3) = 6</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">We can take a look at another example, defining the Fibonacci sequence using the Y Combinator in DMN:</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2sxoJj4oJ3Daz-gpWsyzHTPscMNv47G6jnHx-Ty2SCcx12CpYFiFd58T_beX9AvLUm3PRnuE4b_RrdQOQ5iq2iLZfRENM0IFW4rM4jVO9HP3RD59WYCdhmBnOkvhXv4QcGzeC/s1600/image8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="629" data-original-width="918" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2sxoJj4oJ3Daz-gpWsyzHTPscMNv47G6jnHx-Ty2SCcx12CpYFiFd58T_beX9AvLUm3PRnuE4b_RrdQOQ5iq2iLZfRENM0IFW4rM4jVO9HP3RD59WYCdhmBnOkvhXv4QcGzeC/s640/image8.png" width="640" /></a></div>
<br />
<span style="font-family: inherit;">We notice again there is no call to “fib(...)” in the function body, yet recursion for the calculation of the Fibonacci sequence is performed thanks to the use of the Y Combinator.</span><br />
<span style="font-family: inherit;">Once again, the result works as expected:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">fib(5) = [1, 1, 2, 3, 5]</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">For extra fun, we can re-define the Y Combinator using where possible the DMN Boxed Expression forms. This is an interesting exercise to see how closures are applied in their boxed variant. The Y Combinator definition could be refactored as:</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYV8SQfcGZiwGDfXAr6bF5l_pmBpmuVt04FBRVwH6Gwl6aN6bT96ZBYbpOq9EEdsQSMIljwNSYyQ0FhYy5neQBcGimNv7pXMlXlTxg3__FAn5hUQOl_p0H5NKLKTIDlF3ZZREL/s1600/image6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="895" data-original-width="978" height="584" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYV8SQfcGZiwGDfXAr6bF5l_pmBpmuVt04FBRVwH6Gwl6aN6bT96ZBYbpOq9EEdsQSMIljwNSYyQ0FhYy5neQBcGimNv7pXMlXlTxg3__FAn5hUQOl_p0H5NKLKTIDlF3ZZREL/s640/image6.png" width="640" /></a></div>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">and that would yield again the same expected and correct results.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">For (extra (extra fun)), we can re-define once more the Y Combinator in a single FEEL expression to calculate for instance the factorial of 4:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">{ Y: function(f) (function(x) x(x))(function(y) f(function(x) y(y)(x))), fac: Y(function(f) function(n) if n > 1 then n * f(n-1) else 1), fac4: fac(4) }.fac4</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">The result is unsurprisingly: 24.</span><br />
<span style="font-family: inherit;"><br /></span>
<br />
<h2>
<span style="font-family: inherit;">Conclusion</span></h2>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">In this post, we have seen a basic example of recursion in DMN, and how to leverage recursion support in the engine is very simple to use; <b>engine recursion support is the approach we recommend</b> to achieve recursion DMN: give the function a name, and in the body of the function make use of that name to invoke itself. In the example, we have named the function “fac”, then we invoked “fac(...)” in the body of the function itself.</span><br />
<span style="font-family: inherit;">This approach is very practical, easy to model in DMN and works just fine.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">We have also seen how DMN and FEEL do indeed support curried function definition and invocation. FEEL is (also) a functional language; all these properties allow us to define in DMN and use the Y Combinator, a functional device to achieve recursion without recursion support!</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">I personally found these exercises very interesting to apply functional programming concepts in DMN, while at the same time making sure the engine worked as expected. I would like to say special thanks to my colleagues Edoardo Vacchi and Luca Molteni for their support while discussing the Y Combinator and Currying functions. </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Interested in DMN?</span><br />
<span style="font-family: inherit;">If you didn’t know about DMN before, you found this post interesting but looking for a gentle introduction to the DMN standard, we have just the right crash course on DMN, freely available for you at:</span><br />
<span style="font-family: inherit;"><a href="http://learn-dmn-in-15-minutes.com/">http://learn-dmn-in-15-minutes.com</a> </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">You can find additional information on the Drools website </span><a href="https://drools.org/learn/dmn.html" style="font-family: inherit;" target="_blank">here</a><span style="font-family: inherit;">. Don’t hesitate to contact us for more information.</span><br />
<div>
<br /></div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<br /></div>
Matteo Mortarihttp://www.blogger.com/profile/07483879118138508902noreply@blogger.com16tag:blogger.com,1999:blog-5869426.post-2039376052624946892020-03-25T21:53:00.000+00:002020-03-25T21:54:44.570+00:00Learn DMN in 15 minutes<p>Today we have a new announcement for new DMN users: the <a href="http://learn-dmn-in-15-minutes.com">learn-dmn-in-15-minutes.com</a> course!</p>
<p>DMN is already simple and easy to understand at first glance. However, new adopters generally want to check a quick overview and learn about the most important parts, before jumping on a more in-depth journey. That's the goal of this course!</p>
<p>Now newcomers can:
<li>Learn DMN in 15 minutes</li>
<li>Quickly create a DMN model on <a href="http://dmn.new">dmn.new</a></li>
<li>Execute their first decision model on <a href="https://kogito.kie.org">kogito.kie.org</a></li>
</p>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGahidrYCJ8wh5rdjfo8Z4MGjbx9qShNcjhIYIacSkfwJjPo0KZaVPKMR5BFyWGCfPBJoRd6_F2wmfKqoLU1zrdXbsAn2pK0xUwunNcuu-tvKgS1EjpfD_ofzHehTPLDVUmo83dg/s1600/learn-dmn.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGahidrYCJ8wh5rdjfo8Z4MGjbx9qShNcjhIYIacSkfwJjPo0KZaVPKMR5BFyWGCfPBJoRd6_F2wmfKqoLU1zrdXbsAn2pK0xUwunNcuu-tvKgS1EjpfD_ofzHehTPLDVUmo83dg/s1600/learn-dmn.png" data-original-width="1600" width="100%" data-original-height="998" /></a>
<p>Stay tuned for new content! 🤓</p>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-5869426.post-49598963314546534662020-03-16T14:56:00.001+00:002020-03-16T14:58:37.251+00:00Business Modeler Preview Now Available(originally posted <a href="https://porcelli.me/announcement/tooling/online/bpmn/dmn/2020/03/12/online-new-editors.html" target="_blank">here</a>)<br />
<br />
<br />
Today we have a new exciting announcement for business automation developers and users. The KIE group team is releasing a preview version of the DMN and BPMN editors online! Once again, kudos for everyone involved.<br />
<br />
This online experience is perfect for getting access to the editors without any local setup quickly. Users and developers can take advantage of it to get familiar with BPMN and DMN standards, to sketch ideas, or even to create fully-functional models.<br />
<br />
<img alt="preview-online" src="https://porcelli.me/images/blog/preview-online.png" style="border: 0px; box-sizing: border-box; color: #334455; display: block; font-family: roboto, sans-serif; font-size: 16px; height: auto; margin-left: auto; margin-right: auto; max-width: 100%; vertical-align: middle;" /><br />
<br />
<h2>
<span style="font-size: x-large;">Quick tour</span></h2>
We’ve been experimenting with the idea of an online presence for <a href="https://medium.com/kie-foundation/kogito-online-editor-is-available-now-77fe2d7d8673" target="_blank">a while</a>. After a few interactions, we consider that we’re ready to break the news, and here is a quick tour of the available features.<br />
<br />
<h3>
Samples</h3>
If you’re new to our editors or not much familiar with BPMN and DMN, the "Try Sample" link will provide you a real-world, fully functional example of both standards. You can change the sample and download your latest updates.<br />
<br />
<br />
<img src="https://porcelli.me/images/blog/try-sample.gif" style="border: 0px; box-sizing: border-box; color: #334455; display: block; font-family: roboto, sans-serif; font-size: 16px; height: auto; margin-left: auto; margin-right: auto; max-width: 100%; vertical-align: middle;" /><br />
<br />
<br />
<br />
The current online version of the editors doesn’t store the opened models anywhere, so all the changes are only available to your local browser session. In case you want to "save" your work, you’ll need to download it.<br />
<br />
<h3>
Uploading Models</h3>
In case you have downloaded your work-in-progress model, you can upload it back to the online editor and get back to editing.<br />
<br />
<br />
<img src="https://porcelli.me/images/blog/upload-model.gif" style="border: 0px; box-sizing: border-box; color: #334455; display: block; font-family: roboto, sans-serif; font-size: 16px; height: auto; margin-left: auto; margin-right: auto; max-width: 100%; vertical-align: middle;" /><br />
<br />
<br />
<h3>
Open from source code</h3>
This mechanism allows users to open a model from an external source; an example of this would be raw git access to a model. Note that you can use the URL generated in your browser to share the model.<br />
<br />
<img src="https://porcelli.me/images/blog/open-from-source.gif" style="border: 0px; box-sizing: border-box; color: #334455; display: block; font-family: roboto, sans-serif; font-size: 16px; height: auto; margin-left: auto; margin-right: auto; max-width: 100%; vertical-align: middle;" /><br />
<br />
<br />
<h4>
Sharing links from GitHub</h4>
If you have the latest GitHub extension installed, while browsing a GitHub repository and you find a BPMN or a DMN model, you’ll see an icon that will open the model in the online editor. You can also share the created link.<br />
<br />
<br />
<img src="https://porcelli.me/images/blog/github-open-on-online.gif" style="border: 0px; box-sizing: border-box; color: #334455; display: block; font-family: roboto, sans-serif; font-size: 16px; height: auto; margin-left: auto; margin-right: auto; max-width: 100%; vertical-align: middle;" /><br />
<br />
<br />
<h2>
<span style="font-size: x-large;"> What about new models? Glad you asked…</span></h2>
<br />
So far, I’ve covered multiple ways to use the editors with existing models, but what about creating new models? Of course, we have a pair of "Create new" buttons that you’re redirected to the editors.<br />
<br />
However, this is not exactly the best or most natural way to start a new model…<br />
<br />
<br />
<img src="https://porcelli.me/images/blog/create-new-model.gif" style="border: 0px; box-sizing: border-box; color: #334455; display: block; font-family: roboto, sans-serif; font-size: 16px; height: auto; margin-left: auto; margin-right: auto; max-width: 100%; vertical-align: middle;" /><br />
<br />
<br />
<h2>
<span style="font-size: x-large;"> Introducing DMN.new and BPMN.new</span></h2>
Today we’re also making publicly available the preview of <a href="https://dmn.new/" target="_blank">DMN.new</a> and <a href="https://bpmn.new/" target="_blank">BPMN.new</a>!<br />
<br />
The .new domain is a new initiative from Google to create new digital assets online. Other .new domains are <a href="https://docs.new/" target="_blank">docs.new</a>, <a href="https://sheets.new/" target="_blank">sheets.new</a>, <a href="https://slides.new/" target="_blank">slides.new</a>, <a href="https://playlist.new/" target="_blank">playlist.new</a>, and many more. To learn more about the .new domains, check this page <a href="https://whats.new/" target="_blank">whats.new</a>.<br />
<br />
There’s not much more to say about it, other than now you can type <a href="https://dmn.new/" target="_blank">DMN.new</a> and <a href="https://bpmn.new/" target="_blank">BPMN.new</a> on any browser URL bar, and you’ll be able to create new models without any additional steps! Here’s a quick video to show how simple it is.<br />
<br />
<br />
<img src="https://porcelli.me/images/blog/dot-new.gif" style="border: 0px; box-sizing: border-box; color: #334455; display: block; font-family: roboto, sans-serif; font-size: 16px; height: auto; margin-left: auto; margin-right: auto; max-width: 100%; vertical-align: middle;" /><br />
<br />
<br />
<h2>
<span style="font-size: x-large;"> There’s more, much more…</span></h2>
<br />
This new generation of KIE group tooling is keeping setting the bar higher, and we won’t stop here… we have more to come.<br />
<br />
<br />
Stay tuned!porcellihttp://www.blogger.com/profile/16803100338760212238noreply@blogger.com7tag:blogger.com,1999:blog-5869426.post-1207964104274233402020-03-10T09:00:00.000+00:002020-03-10T16:05:18.548+00:00Kogito, ergo Rules: From Knowledge To Service, Effortless<div class="markdown-here-wrapper" data-md-url="https://www.blogger.com/blogger.g?blogID=5869426#editor/target=post;postID=120796410427423340;onPublishedMenu=allposts;onClosedMenu=allposts;postNum=0;src=postname">
<div style="margin: 0px 0px 1.2em !important;">
Welcome to another episode of this blog series on the Kogito initiative and our efforts to bring Drools to the cloud. The goal of these posts is to gather early user feedback on the features we are delivering to Kogito.</div>
<div style="margin: 0px 0px 1.2em !important;">
In this post we present <b>two new ways</b> to realize a complete intelligent service:</div>
<ol style="margin: 1.2em 0px; padding-left: 2em;">
<li style="margin: 0.5em 0px;">self-contained rule services</li>
<li style="margin: 0.5em 0px;">integrated intelligent workflows with rule tasks</li>
</ol>
<h2 id="units-of-execution-in-kogito" style="border-bottom: 1px solid rgb(238, 238, 238); font-size: 1.4em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Units of Execution in Kogito</h2>
<div style="margin: 0px 0px 1.2em !important;">
As you may already know, in Kogito we are making front-and-center the new <a href="http://blog.athico.com/2019/07/kogito-ergo-rules-part-2-all.html">Unit</a> concept.</div>
<div style="margin: 0px 0px 1.2em !important;">
“Unit of execution” is the term that we use to indicate an executable piece of knowledge. A unit may be a process, a set of rules, a decision, etc… In the case of a set of rules, we call it a <i>rule unit</i>. If you opt-in to use units, <b>in Kogito</b> we will take care of all the boilerplate that is required to generate a <b>REST endpoint </b>automatically.</div>
<div style="margin: 0px 0px 1.2em !important;">
A rule unit is constituted primarily by</div>
<div style="margin: 0px 0px 1.2em !important;">
1) a data definition;<br />
2) the set of rules and queries that implement the behavior of the unit (the rules of the rule engine);<br />
3) optionally, event listeners may be attached for a number of purposes.</div>
<div style="margin: 0px 0px 1.2em !important;">
In this post we’ll focus on data definitions, rules and queries.</div>
<div style="margin: 0px 0px 1.2em !important;">
<b>Data definitions</b> are given by declaring a Java class that may contain data sources. Each data source represents a partition of the working memory that your rules will pattern match against or insert to. </div>
<div style="margin: 0px 0px 1.2em !important;">
For instance, suppose you want to declare an alerting service that receives events and produces alerts depending on some conditions. We declare <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">Event</code> and <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">Alert</code> objects as follows:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-java" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">package</span> com.acme;
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">public</span> <span class="hljs-class"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">class</span> <span class="hljs-title" style="color: #990000; font-weight: bold;">Event</span> </span>{
String type;
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">int</span> value;
<span class="hljs-comment" style="color: #999988; font-style: italic;">// getters and setters</span>
}
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">public</span> <span class="hljs-class"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">class</span> <span class="hljs-title" style="color: #990000; font-weight: bold;">Alert</span> </span>{
String severity;
String message;
<span class="hljs-comment" style="color: #999988; font-style: italic;">// getters and setters</span>
}
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
The <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">AlertingService</code> unit type declaration is a class that implements the interface <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">RuleUnitData</code>.</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-java" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">package</span> com.acme;
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">public</span> <span class="hljs-class"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">class</span> <span class="hljs-title" style="color: #990000; font-weight: bold;">AlertingService</span> <span class="hljs-keyword" style="color: #333333; font-weight: bold;">implements</span> <span class="hljs-title" style="color: #990000; font-weight: bold;">RuleUnitData</span> </span>{
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">private</span> <span class="hljs-keyword" style="color: #333333; font-weight: bold;">final</span> DataStream<Event> eventData = DataSource.createStream();
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">private</span> <span class="hljs-keyword" style="color: #333333; font-weight: bold;">final</span> DataStream<Alert> alertData = DataSource.createStream();
<span class="hljs-comment" style="color: #999988; font-style: italic;">// getters and setters</span>
}
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
<b>Rules</b> are defined in DRL files as usual, except that you have now to indicate their <b>unit</b> at the top of the file. For instance you may declare the data definition for <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">AlertingService</code> as follows: </div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-java" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">package</span> com.acme;
unit AlertingService;
rule IncomingEvent when
<span class="hljs-comment" style="color: #999988; font-style: italic;">// matches when a temperature higher than 30 °C is registered (OOPath syntax)</span>
$e : /eventData [ type == <span class="hljs-string" style="color: #dd1144;">"temperature"</span>, value >= <span class="hljs-number" style="color: teal;">30</span> ]
then
System.out.println(<span class="hljs-string" style="color: #dd1144;">"incoming event: "</span>+ $e.getMessage());
alertData.append( <span class="hljs-keyword" style="color: #333333; font-weight: bold;">new</span> Alert( <span class="hljs-string" style="color: #dd1144;">"warning"</span>, <span class="hljs-string" style="color: #dd1144;">"Temperature is too high"</span> ) );
end
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
As you can see, rules may match against or insert to the given data sources.</div>
<div style="margin: 0px 0px 1.2em !important;">
<b>Queries</b> are defined in DRL files like rules, and belong to a unit, too. If you declare at least one query, you will get <b>a REST endpoint automatically generated for free</b>. For instance:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-java" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;">query Warnings
alerts: /alertData [ severity == <span class="hljs-string" style="color: #dd1144;">"warning"</span> ]
end
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
will generate the REST endpoint <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">/warnings</code> that you will be able to invoke by POST-ing to it as follows:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-sh" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"> $ curl -X POST \
-H <span class="hljs-string" style="color: #dd1144;">'Accept: application/json'</span> \
-H <span class="hljs-string" style="color: #dd1144;">'Content-Type: application/json'</span> \
<span class="hljs-operator">-d</span> <span class="hljs-string" style="color: #dd1144;">'{ "eventData": [ { "type": "temperature", "value" : 40 } ] }'</span> \
http://localhost:<span class="hljs-number" style="color: teal;">8080</span>/warnings
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
This will generate the response:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-json" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;">[ { "<span class="hljs-attribute" style="color: teal;">severity</span>": <span class="hljs-value"><span class="hljs-string" style="color: #dd1144;">"warning"</span></span>, "<span class="hljs-attribute" style="color: teal;">message</span>" : <span class="hljs-value"><span class="hljs-string" style="color: #dd1144;">"Temperature is too high"</span> </span>} ]
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
The Java-based data definition is very familiar to programmers, but, from early user feedback, <i>we decided to provide two alternative methods to declare a rule unit</i>. We are publishing this blog post to gather more user feedback!</div>
<h2 id="type-declaration" style="border-bottom: 1px solid rgb(238, 238, 238); font-size: 1.4em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Type Declaration</h2>
<div style="margin: 0px 0px 1.2em !important;">
The <i>type declaration</i> is the DRL feature to declare Java-compatible types, in a Java-agnostic way. In the 7 series, users may declare types with the syntax:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-java" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">package</span> com.acme;
declare Event
type: String
value: <span class="hljs-keyword" style="color: #333333; font-weight: bold;">int</span>
end
declare Alert
severity: String
message: String
end
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
This makes the DRL completely self-contained: entities and rules may be all defined using DRL. However, they have few limitations; for instance, they do not support implementing interfaces and they do not support generic type fields. In other words, the following declaration, in the 7 series, is syntactically invalid:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-java" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">package</span> com.acme;
declare AlertingService extends RuleUnitData
eventData: DataStream<Event>
alertData: DataStream<Alert>
end
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
In version 0.8.0, we are lifting these limitations: we allow limited inheritance for interfaces (only one is allowed for now) and generic type declaration for fields. With these new features, the following piece of code becomes valid DRL.</div>
<div style="margin: 0px 0px 1.2em !important;">
Long story short: <b>you are now able to declare a full microservice<br />from a single DRL</b>.</div>
<div style="margin: 0px 0px 1.2em !important;">
Bootstrap your Kogito service with the archetype:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-sh" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"> mvn archetype:generate \
-DarchetypeGroupId=org.kie.kogito \
-DarchetypeArtifactId=kogito-quarkus-archetype \
-DarchetypeVersion=<span class="hljs-number" style="color: teal;">0.8</span>.<span class="hljs-number" style="color: teal;">0</span> \
-DgroupId=com.acme \
-DartifactId=sample-kogito
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
At the moment, no Quarkus version bundles Kogito 0.8.0; otherwise, you would be able to use <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">mvn io.quarkus:quarkus-maven-plugin:create</code> instead.</div>
<div style="margin: 0px 0px 1.2em !important;">
Now, clear the contents of <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">src/main</code> and then, drop this DRL to <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">src/main/resources/com/acme</code> folder instead:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-java" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">package</span> com.acme;
unit AlertingService;
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">import</span> org.kie.kogito.rules.DataStream;
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">import</span> org.kie.kogito.rules.RuleUnitData;
declare Event
type: String
value: <span class="hljs-keyword" style="color: #333333; font-weight: bold;">int</span>
end
declare Alert
severity: String
message: String
end
declare AlertingService extends RuleUnitData
eventData: DataStream<Event>
alertData: DataStream<Alert>
end
rule IncomingEvent when
<span class="hljs-comment" style="color: #999988; font-style: italic;">// matches when a temperature higher than 30 °C is registered (OOPath syntax)</span>
$e : /eventData [ type == <span class="hljs-string" style="color: #dd1144;">"temperature"</span>, value >= <span class="hljs-number" style="color: teal;">30</span> ]
then
System.out.println(<span class="hljs-string" style="color: #dd1144;">"incoming event: "</span>+ $e.getMessage());
alertData.append( <span class="hljs-keyword" style="color: #333333; font-weight: bold;">new</span> Alert( <span class="hljs-string" style="color: #dd1144;">"warning"</span>, <span class="hljs-string" style="color: #dd1144;">"Temperature is too high: "</span> + $e ) );
end
query Warnings
alerts: /alertData [ severity == <span class="hljs-string" style="color: #dd1144;">"warning"</span> ]
end
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
Now fire up the Quarkus service in developer mode with:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-sh" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"> $ mvn compile quarkus:dev
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
There you go, you are now ready to <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">curl</code> your service:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-sh" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"> $ curl -X POST \
-H <span class="hljs-string" style="color: #dd1144;">'Accept: application/json'</span> \
-H <span class="hljs-string" style="color: #dd1144;">'Content-Type: application/json'</span> \
<span class="hljs-operator">-d</span> <span class="hljs-string" style="color: #dd1144;">'{ "eventData": [ { "type": "temperature", "value" : 40 } ] }'</span> \
http://localhost:<span class="hljs-number" style="color: teal;">8080</span>/warnings
</code></pre>
<h2 id="workflow-integration" style="border-bottom: 1px solid rgb(238, 238, 238); font-size: 1.4em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Workflow Integration</h2>
<div style="margin: 0px 0px 1.2em !important;">
Another way to expose a rule-based service is through a <i>workflow</i>.</div>
<div style="margin: 0px 0px 1.2em !important;">
A <i>workflow</i> (sometimes called a “business process”) describes a sequence of steps in a diagram and it usually declares <i>variables</i>: data holders for values that are manipulated in the execution. The data type of one such variable may be <i>anything</i>: you may use Java classes, but, in this example, we will use again our declared data types. </div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-java" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">package</span> com.acme;
declare Event
type: String
value: <span class="hljs-keyword" style="color: #333333; font-weight: bold;">int</span>
end
declare Alert
severity: String
message: String
end
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
Let us call this workflow <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">com.acme.AlertingWorkflow</code>, and declare the variables <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">eventData</code> and <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">alertData</code>:</div>
<div style="margin: 0px 0px 1.2em !important;">
<img alt="workflow" height="105" src="https://raw.githubusercontent.com/evacchi/kogito-rules-example/master/imgs/variables.png" width="640" /></div>
<div style="margin: 0px 0px 1.2em !important;">
A workflow that includes a <i>rule task</i> may skip the rule unit data <i>declaration</i> altogether: in this case the rule unit is inferred directly from the structure of the process: each variable will be <b>inserted into data source of the same name</b>.</div>
<div style="margin: 0px 0px 1.2em !important;">
<img alt="workflow" height="141" src="https://raw.githubusercontent.com/evacchi/kogito-rules-example/master/imgs/workflow.png" width="640" /></div>
<div style="margin: 0px 0px 1.2em !important;">
The <i>name</i> of the unit is declared by the process, using the syntax <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">unit:com.acme.AlertingService</code>. You are still free to explicitly declare the unit <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">com.acme.AlertingService</code>; in that case, the process will pick up the declaration that you have hand-coded.</div>
<div style="margin: 0px 0px 1.2em !important;">
Note: You may have noticed that we are using the “Rule Flow Group” field. We will implement more explicit support in the UI in the future.</div>
<div style="margin: 0px 0px 1.2em !important;">
Bootstrap your Kogito service with the archetype:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-sh" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"> mvn archetype:generate \
-DarchetypeGroupId=org.kie.kogito \
-DarchetypeArtifactId=kogito-quarkus-archetype \
-DarchetypeVersion=<span class="hljs-number" style="color: teal;">0.8</span>.<span class="hljs-number" style="color: teal;">0</span> \
-DgroupId=com.acme \
-DartifactId=sample-kogito
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
<b>Caveat</b>. Support for this feature is experimental, so it may not work seamlessly with Quarkus hot code reload; we also need the following extra step to enable it, but this will change in the future.</div>
<div style="margin: 0px 0px 1.2em !important;">
Update your <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">pom.xml</code> with the following plugin declaration:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-xml" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"> <span class="hljs-tag" style="color: navy; font-weight: normal;"><<span class="hljs-title" style="color: navy; font-weight: normal;">build</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"><<span class="hljs-title" style="color: navy; font-weight: normal;">plugins</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"><<span class="hljs-title" style="color: navy; font-weight: normal;">plugin</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"><<span class="hljs-title" style="color: navy; font-weight: normal;">groupId</span>></span>org.kie.kogito<span class="hljs-tag" style="color: navy; font-weight: normal;"></<span class="hljs-title" style="color: navy; font-weight: normal;">groupId</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"><<span class="hljs-title" style="color: navy; font-weight: normal;">artifactId</span>></span>kogito-maven-plugin<span class="hljs-tag" style="color: navy; font-weight: normal;"></<span class="hljs-title" style="color: navy; font-weight: normal;">artifactId</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"><<span class="hljs-title" style="color: navy; font-weight: normal;">version</span>></span>0.8.0<span class="hljs-tag" style="color: navy; font-weight: normal;"></<span class="hljs-title" style="color: navy; font-weight: normal;">version</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"><<span class="hljs-title" style="color: navy; font-weight: normal;">executions</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"><<span class="hljs-title" style="color: navy; font-weight: normal;">execution</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"><<span class="hljs-title" style="color: navy; font-weight: normal;">goals</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"><<span class="hljs-title" style="color: navy; font-weight: normal;">goal</span>></span>generateDeclaredTypes<span class="hljs-tag" style="color: navy; font-weight: normal;"></<span class="hljs-title" style="color: navy; font-weight: normal;">goal</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"></<span class="hljs-title" style="color: navy; font-weight: normal;">goals</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"></<span class="hljs-title" style="color: navy; font-weight: normal;">execution</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"></<span class="hljs-title" style="color: navy; font-weight: normal;">executions</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"></<span class="hljs-title" style="color: navy; font-weight: normal;">plugin</span>></span>
...
<span class="hljs-tag" style="color: navy; font-weight: normal;"></<span class="hljs-title" style="color: navy; font-weight: normal;">plugins</span>></span>
<span class="hljs-tag" style="color: navy; font-weight: normal;"></<span class="hljs-title" style="color: navy; font-weight: normal;">build</span>></span>
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
You can now clear the contents of <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">src/main</code>, and then drop the process and the following DRL to <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">src/main/resources/com/acme</code> folder.</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-java" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"><span class="hljs-keyword" style="color: #333333; font-weight: bold;">package</span> com.acme;
unit AlertingService;
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">import</span> org.kie.kogito.rules.DataStream;
<span class="hljs-keyword" style="color: #333333; font-weight: bold;">import</span> org.kie.kogito.rules.RuleUnitData;
declare Event
type: String
value: <span class="hljs-keyword" style="color: #333333; font-weight: bold;">int</span>
end
declare Alert
severity: String
message: String
end
rule IncomingEvent when
<span class="hljs-comment" style="color: #999988; font-style: italic;">// matches when a temperature higher than 30 °C is registered (OOPath syntax)</span>
$e : /eventData [ type == <span class="hljs-string" style="color: #dd1144;">"temperature"</span>, value >= <span class="hljs-number" style="color: teal;">30</span> ]
then
System.out.println(<span class="hljs-string" style="color: #dd1144;">"incoming event: "</span>+ $e.getMessage());
alertData.set( <span class="hljs-keyword" style="color: #333333; font-weight: bold;">new</span> Alert( <span class="hljs-string" style="color: #dd1144;">"warning"</span>, <span class="hljs-string" style="color: #dd1144;">"Temperature is too high: "</span> + $e ) );
end
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
As you may have noticed, you are not required to declare a query explicitly: the process will display the contents of the variables as a response; it will generate the endpoint <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">/AlertingWorkflow</code>, and it accept a <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">POST</code> request of the following form:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-sh" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;"> $ curl -X POST \
-H <span class="hljs-string" style="color: #dd1144;">'Accept: application/json'</span> \
-H <span class="hljs-string" style="color: #dd1144;">'Content-Type: application/json'</span> \
<span class="hljs-operator">-d</span> <span class="hljs-string" style="color: #dd1144;">'{ "eventData": { "type": "temperature", "value" : 40 } }'</span> \
http://localhost:<span class="hljs-number" style="color: teal;">8080</span>/AlertingWorkflow
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
The reply will be:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code class="hljs language-json" style="-moz-text-size-adjust: none; background-color: #f8f8f8; background: rgb(248, 248, 248) none repeat scroll 0% 0%; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); color: #333333; display: block !important; display: block; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow-x: auto; overflow: auto; padding: 0.5em 0.7em; padding: 0.5em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;">{
"<span class="hljs-attribute" style="color: teal;">id</span>": <span class="hljs-value">...</span>,
"<span class="hljs-attribute" style="color: teal;">eventData</span>": <span class="hljs-value">{
"<span class="hljs-attribute" style="color: teal;">type</span>": <span class="hljs-value"><span class="hljs-string" style="color: #dd1144;">"temperature"</span></span>,
"<span class="hljs-attribute" style="color: teal;">value</span>": <span class="hljs-value"><span class="hljs-number" style="color: teal;">100</span>
</span>}</span>,
"<span class="hljs-attribute" style="color: teal;">alertData</span>": <span class="hljs-value">{
"<span class="hljs-attribute" style="color: teal;">severity</span>": <span class="hljs-value"><span class="hljs-string" style="color: #dd1144;">"warning"</span></span>,
"<span class="hljs-attribute" style="color: teal;">message</span>": <span class="hljs-value"><span class="hljs-string" style="color: #dd1144;">"Temperature is too high: Event( type=temperature, value=100 )"</span>
</span>}
</span>}
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
However, if you <i>do</i> declare a query, a separate endpoint will be available as well. For instance if you declare the query <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">Warnings</code> you will still be able to POST to <code style="background-color: #f8f8f8; border-radius: 3px; border: 1px solid rgb(234, 234, 234); display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap;">http://localhost:8080/warnings</code> and invoke the rule service separately as follows:</div>
<pre style="font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; font-size: 1em; line-height: 1.2em; margin: 1.2em 0px;"><code style="background-color: #f8f8f8; border-radius: 3px; border-radius: 3px; border: 1px solid rgb(204, 204, 204); border: 1px solid rgb(234, 234, 234); display: block !important; display: inline; font-family: Consolas, Inconsolata, Courier, monospace; font-size: 0.85em; margin: 0px 0.15em; overflow: auto; padding: 0.5em 0.7em; padding: 0px 0.3em; white-space: pre-wrap; white-space: pre;">$ curl -X POST \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{ "eventData": { "type": "temperature", "value" : 40 } }' \
http://localhost:8080/warnings
</code></pre>
<div style="margin: 0px 0px 1.2em !important;">
Notice that the request no longer contains a list of Events. This is because process variables are mapped to single values instead of DataStreams. </div>
<h2 id="conclusion" style="border-bottom: 1px solid rgb(238, 238, 238); font-size: 1.4em; font-weight: bold; margin: 1.3em 0px 1em; padding: 0px;">
Conclusion</h2>
<div style="margin: 0px 0px 1.2em !important;">
We have given a sneak peek on the work that we are doing to improve the getting started experience with rules and processes in Kogito. With these changes, we hope to have provided a more streamlined way to define knowledge-based services. Developers will always able to be more explicit about the data they want to process, by opting-in to writing Java; but if they want, they can embrace a fully DSL-centric development workflow.</div>
<div style="margin: 0px 0px 1.2em !important;">
<i>For the lazies, examples are available at <a href="https://github.com/evacchi/kogito-rules-example/tree/master/code">https://github.com/evacchi/kogito-rules-example/tree/master/code</a> Have fun!</i></div>
<div style="font-size: 0em; height: 0; margin: 0; max-height: 0; max-width: 0; overflow: hidden; padding: 0; width: 0;" title="MDH:PHA+PGJyPjwvcD48cD5XZWxjb21lIHRvIGFub3RoZXIgZXBpc29kZSBvZiB0aGlzIGJsb2cgc2Vy
aWVzIG9uIHRoZSBLb2dpdG8gaW5pdGlhdGl2ZSBhbmQgb3VyIGVmZm9ydHMgdG8gYnJpbmcgRHJv
b2xzIHRvIHRoZSBjbG91ZC4gVGhlIGdvYWwgb2YgdGhlc2UgcG9zdHMgaXMgdG8gZ2F0aGVyIGVh
cmx5IHVzZXIgZmVlZGJhY2sgb24gdGhlIGZlYXR1cmVzIHdlIGFyZSBkZWxpdmVyaW5nIHRvIEtv
Z2l0by48L3A+PHA+PGJyPjwvcD48cD5JbiB0aGlzIHBvc3Qgd2UgcHJlc2VudCAqKnR3byBuZXcg
d2F5cyoqIHRvIHJlYWxpemUgYSBjb21wbGV0ZSBpbnRlbGxpZ2VudCBzZXJ2aWNlOjwvcD48cD48
YnI+PC9wPjxwPjEuIHNlbGYtY29udGFpbmVkIHJ1bGUgc2VydmljZXM8L3A+PHA+Mi4gaW50ZWdy
YXRlZCBpbnRlbGxpZ2VudCB3b3JrZmxvd3Mgd2l0aCBydWxlIHRhc2tzPC9wPjxwPjxicj48L3A+
PHA+IyMgVW5pdHMgb2YgRXhlY3V0aW9uIGluIEtvZ2l0bzwvcD48cD48YnI+PC9wPjxwPkFzIHlv
dSBtYXkgYWxyZWFkeSBrbm93LCBpbiBLb2dpdG8gd2UgYXJlIG1ha2luZyBmcm9udC1hbmQtY2Vu
dGVyIHRoZSBuZXcgW1VuaXRdKGh0dHA6Ly9ibG9nLmF0aGljby5jb20vMjAxOS8wNy9rb2dpdG8t
ZXJnby1ydWxlcy1wYXJ0LTItYWxsLmh0bWwpIGNvbmNlcHQuPC9wPjxwPjxicj48L3A+PHA+IlVu
aXQgb2YgZXhlY3V0aW9uIiB0aGF0IHdlIHVzZSB0byBpbmRpY2F0ZSBhbiBleGVjdXRhYmxlIHBp
ZWNlIG9mIGtub3dsZWRnZS4gQSB1bml0IG1heSBiZSBhIHByb2Nlc3MsIGEgc2V0IG9mIHJ1bGVz
LCBhIGRlY2lzaW9uLCBldGMuLi4gSW4gdGhlIGNhc2Ugb2YgYSBzZXQgb2YgcnVsZXMsIHdlIGNh
bGwgaXQgYSAqcnVsZSB1bml0Ki4gSWYgeW91IG9wdC1pbiB0byB1c2UgdW5pdHMsICoqaW4gS29n
aXRvKiogd2Ugd2lsbCB0YWtlIGNhcmUgb2YgYWxsIHRoZSBib2lsZXJwbGF0ZSB0aGF0IGlzIHJl
cXVpcmVkIHRvIGdlbmVyYXRlIGEgKipSRVNUIGVuZHBvaW50KiogYXV0b21hdGljYWxseS48L3A+
PHA+PGJyPjwvcD48cD5BIHJ1bGUgdW5pdCBpcyBjb25zdGl0dXRlZCBieSBwcmltYXJpbHkgYnk8
L3A+PHA+PGJyPjwvcD48cD4xKSBhIGRhdGEgZGVmaW5pdGlvbjs8L3A+PHA+MikgdGhlIHNldCBv
ZiBydWxlcyBhbmQgcXVlcmllcyB0aGF0IGltcGxlbWVudCB0aGUgYmVoYXZpb3Igb2YgdGhlIHVu
aXQgKHRoZSBydWxlcyBvZiB0aGUgcnVsZSBlbmdpbmUpOyA8L3A+PHA+Mykgb3B0aW9uYWxseSwg
ZXZlbnQgbGlzdGVuZXJzIG1heSBiZSBhdHRhY2hlZCBmb3IgYSBudW1iZXIgb2YgcHVycG9zZXMu
PC9wPjxwPjxicj48L3A+PHA+SW4gdGhpcyBwb3N0IHdlJ2xsIGZvY3VzIG9uIGRhdGEgZGVmaW5p
dGlvbnMsIHJ1bGVzIGFuZCBxdWVyaWVzLjwvcD48cD48YnI+PC9wPjxwPioqRGF0YSBkZWZpbml0
aW9ucyoqIGFyZSBnaXZlbiBieSBkZWNsYXJpbmcgYSBKYXZhIGNsYXNzIHRoYXQgbWF5IGNvbnRh
aW4gZGF0YSBzb3VyY2VzLiBFYWNoIGRhdGEgc291cmNlIHJlcHJlc2VudHMgYSBwYXJ0aXRpb24g
b2YgdGhlIHdvcmtpbmcgbWVtb3J5IHRoYXQgeW91ciBydWxlcyB3aWxsIHBhdHRlcm4gbWF0Y2gg
YWdhaW5zdCBvciBpbnNlcnQgdG8uIDwvcD48cD48YnI+PC9wPjxwPkZvciBpbnN0YW5jZSwgc3Vw
cG9zZSB5b3Ugd2FudCB0byBkZWNsYXJlIGFuIGFsZXJ0aW5nIHNlcnZpY2UgdGhhdCByZWNlaXZl
cyBldmVudHMgYW5kIHByb2R1Y2VzIGFsZXJ0czwvcD48cD5kZXBlbmRpbmcgb24gc29tZSBjb25k
aXRpb25zLiBXZSBkZWNsYXJlIGBFdmVudGAgYW5kIGBBbGVydGAgb2JqZWN0cyBhcyBmb2xsb3dz
OjwvcD48cD48YnI+PC9wPjxwPmBgYGphdmE8L3A+PHA+cGFja2FnZSBjb20uYWNtZTs8L3A+PHA+
cHVibGljIGNsYXNzIEV2ZW50IHs8L3A+PHA+Jm5ic3A7Jm5ic3A7IFN0cmluZyB0eXBlOzwvcD48
cD4mbmJzcDsmbmJzcDsgaW50IHZhbHVlOzwvcD48cD4mbmJzcDsmbmJzcDsgLy8gZ2V0dGVycyBh
bmQgc2V0dGVyczwvcD48cD59PC9wPjxwPjxicj48L3A+PHA+cHVibGljIGNsYXNzIEFsZXJ0IHs8
L3A+PHA+Jm5ic3A7IFN0cmluZyBzZXZlcml0eTs8L3A+PHA+Jm5ic3A7IFN0cmluZyBtZXNzYWdl
OzwvcD48cD4mbmJzcDsgLy8gZ2V0dGVycyBhbmQgc2V0dGVyczwvcD48cD59PC9wPjxwPmBgYDwv
cD48cD5UaGUgYEFsZXJ0aW5nU2VydmljZWAgdW5pdCB0eXBlIGRlY2xhcmF0aW9uIGlzIGEgY2xh
c3MgdGhhdCBpbXBsZW1lbnRzIHRoZSBpbnRlcmZhY2UgYFJ1bGVVbml0RGF0YWAuPC9wPjxwPjxi
cj48L3A+PHA+YGBgamF2YTwvcD48cD5wYWNrYWdlIGNvbS5hY21lOzwvcD48cD5wdWJsaWMgY2xh
c3MgQWxlcnRpbmdTZXJ2aWNlIGltcGxlbWVudHMgUnVsZVVuaXREYXRhIHs8L3A+PHA+Jm5ic3A7
Jm5ic3A7IHByaXZhdGUgZmluYWwgRGF0YVN0cmVhbSZsdDtFdmVudCZndDsgZXZlbnREYXRhID0g
RGF0YVNvdXJjZS5jcmVhdGVTdHJlYW0oKTs8L3A+PHA+Jm5ic3A7Jm5ic3A7IHByaXZhdGUgZmlu
YWwgRGF0YVN0cmVhbSZsdDtBbGVydCZndDsgYWxlcnREYXRhID0gRGF0YVNvdXJjZS5jcmVhdGVT
dHJlYW0oKTs8L3A+PHA+Jm5ic3A7Jm5ic3A7IC8vIGdldHRlcnMgYW5kIHNldHRlcnM8L3A+PHA+
fTwvcD48cD5gYGA8L3A+PHA+PGJyPjwvcD48cD48YnI+PC9wPjxwPioqUnVsZXMqKiBhcmUgZGVm
aW5lZCBpbiBEUkwgZmlsZXMgYXMgdXN1YWwsIGV4Y2VwdCB0aGF0IHlvdSBoYXZlIG5vdyB0byBp
bmRpY2F0ZSB0aGVpciAqKnVuaXQqKiBhdCB0aGUgdG9wIG9mIHRoZSBmaWxlLiBGb3IgaW5zdGFu
Y2UgeW91IG1heSBkZWNsYXJlIHRoZSBkYXRhIGRlZmluaXRpb24gZm9yIGBBbGVydGluZ1NlcnZp
Y2VgIGFzIGZvbGxvd3M6IDwvcD48cD48YnI+PC9wPjxwPmBgYGphdmE8L3A+PHA+cGFja2FnZSBj
b20uYWNtZTs8L3A+PHA+dW5pdCBBbGVydGluZ1NlcnZpY2U7PC9wPjxwPnJ1bGUgSW5jb21pbmdF
dmVudCB3aGVuPC9wPjxwPiZuYnNwOyZuYnNwOyAvLyBtYXRjaGVzIHdoZW4gYSB0ZW1wZXJhdHVy
ZSBoaWdoZXIgdGhhbiAzMCDCsEMgaXMgcmVnaXN0ZXJlZCAoT09QYXRoIHN5bnRheCk8L3A+PHA+
Jm5ic3A7Jm5ic3A7ICRlIDogL2V2ZW50RGF0YSBbIHR5cGUgPT0gInRlbXBlcmF0dXJlIiwgdmFs
dWUgJmd0Oz0gMzAgXSA8L3A+PHA+dGhlbjwvcD48cD4mbmJzcDsmbmJzcDsgU3lzdGVtLm91dC5w
cmludGxuKCJpbmNvbWluZyBldmVudDogIisgJGUuZ2V0TWVzc2FnZSgpKTs8L3A+PHA+Jm5ic3A7
Jm5ic3A7IGFsZXJ0RGF0YS5hcHBlbmQoIG5ldyBBbGVydCggIndhcm5pbmciLCAiVGVtcGVyYXR1
cmUgaXMgdG9vIGhpZ2giICkgKTs8L3A+PHA+ZW5kPC9wPjxwPmBgYDwvcD48cD48YnI+PC9wPjxw
PkFzIHlvdSBjYW4gc2VlLCBydWxlcyBtYXkgbWF0Y2ggYWdhaW5zdCBvciBpbnNlcnQgdG8gdGhl
IGdpdmVuIGRhdGEgc291cmNlcy48L3A+PHA+PGJyPjwvcD48cD4qKlF1ZXJpZXMqKiBhcmUgZGVm
aW5lZCBpbiBEUkwgZmlsZXMgbGlrZSBydWxlcywgYW5kIGJlbG9uZyB0byBhIHVuaXQsIHRvby4g
PC9wPjxwPklmIHlvdSBkZWNsYXJlIGF0IGxlYXN0IG9uZSBxdWVyeSwgeW91IHdpbGwgZ2V0ICoq
YSBSRVNUIGVuZHBvaW50IGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkIGZvciBmcmVlKiouIDwvcD48
cD5Gb3IgaW5zdGFuY2U6PC9wPjxwPjxicj48L3A+PHA+PGJyPjwvcD48cD5gYGBqYXZhPC9wPjxw
PnF1ZXJ5IFdhcm5pbmdzPC9wPjxwPiZuYnNwOyZuYnNwOyBhbGVydHM6IC9hbGVydERhdGEgWyBz
ZXZlcml0eSA9PSAid2FybmluZyIgXTwvcD48cD5lbmQ8L3A+PHA+YGBgPC9wPjxwPjxicj48L3A+
PHA+d2lsbCBnZW5lcmF0ZSB0aGUgUkVTVCBlbmRwb2ludCBgL3dhcm5pbmdzYCB0aGF0IHlvdSB3
aWxsIGJlIGFibGUgdG8gaW52b2tlIGJ5IFBPU1QtaW5nIHRvIGl0IGFzIGZvbGxvd3M6PC9wPjxw
Pjxicj48L3A+PHA+PGJyPjwvcD48cD5gYGBzaDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsgJCBj
dXJsIC1YIFBPU1QgXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgLUggJ0FjY2VwdDogYXBwbGljYXRpb24vanNvbicgXDwv
cD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsgLUggJ0NvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbicgXDwvcD48cD4mbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsg
LWQgJ3sgImV2ZW50RGF0YSI6IFsgeyAidHlwZSI6ICJ0ZW1wZXJhdHVyZSIsICJ2YWx1ZSIgOiA0
MCB9IF0gfScgXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsgaHR0cDovL2xvY2FsaG9zdDo4MDgwL3dhcm5pbmdzPC9wPjxw
PmBgYDwvcD48cD48YnI+PC9wPjxwPlRoaXMgd2lsbCBnZW5lcmF0ZSB0aGUgcmVzcG9uc2U6PC9w
PjxwPjxicj48L3A+PHA+YGBganNvbjwvcD48cD5bIHsgInNldmVyaXR5IjogIndhcm5pbmciLCAi
bWVzc2FnZSIgOiAiVGVtcGVyYXR1cmUgaXMgdG9vIGhpZ2giIH0gXTwvcD48cD5gYGA8L3A+PHA+
PGJyPjwvcD48cD5UaGUgSmF2YS1iYXNlZCBkYXRhIGRlZmluaXRpb24gaXMgdmVyeSBmYW1pbGlh
ciB0byBwcm9ncmFtbWVycywgYnV0LCBmcm9tIGVhcmx5IHVzZXIgZmVlZGJhY2ssICp3ZSBkZWNp
ZGVkIHRvIHByb3ZpZGUgdHdvIGFsdGVybmF0aXZlIG1ldGhvZHMgdG8gZGVjbGFyZSBhIHJ1bGUg
dW5pdCouIFdlIGFyZSBwdWJsaXNoaW5nIHRoaXMgYmxvZyBwb3N0IHRvIGdhdGhlciBtb3JlIHVz
ZXIgZmVlZGJhY2shPC9wPjxwPjxicj48L3A+PHA+IyMgVHlwZSBEZWNsYXJhdGlvbjwvcD48cD48
YnI+PC9wPjxwPlRoZSAqdHlwZSBkZWNsYXJhdGlvbiogaXMgdGhlIERSTCBmZWF0dXJlIHRvIGRl
Y2xhcmUgSmF2YS1jb21wYXRpYmxlIHR5cGVzLDwvcD48cD5pbiBhIEphdmEtYWdub3N0aWMgd2F5
LiBJbiB0aGUgNyBzZXJpZXMsIHVzZXJzIG1heSBkZWNsYXJlIHR5cGVzIHdpdGggdGhlIHN5bnRh
eDo8L3A+PHA+PGJyPjwvcD48cD5gYGBqYXZhPC9wPjxwPnBhY2thZ2UgY29tLmFjbWU7PC9wPjxw
Pjxicj48L3A+PHA+ZGVjbGFyZSBFdmVudDwvcD48cD4mbmJzcDsmbmJzcDsgdHlwZTombmJzcDsg
U3RyaW5nPC9wPjxwPiZuYnNwOyZuYnNwOyB2YWx1ZTogaW50PC9wPjxwPmVuZDwvcD48cD48YnI+
PC9wPjxwPmRlY2xhcmUgQWxlcnQ8L3A+PHA+Jm5ic3A7IHNldmVyaXR5OiBTdHJpbmc8L3A+PHA+
Jm5ic3A7IG1lc3NhZ2U6Jm5ic3A7IFN0cmluZzwvcD48cD5lbmQ8L3A+PHA+YGBgPC9wPjxwPjxi
cj48L3A+PHA+VGhpcyBtYWtlcyB0aGUgRFJMIGNvbXBsZXRlbHkgc2VsZi1jb250YWluZWQ6IGVu
dGl0aWVzIGFuZCBydWxlcyBtYXkgYmUgYWxsIGRlZmluZWQgdXNpbmcgRFJMLiBIb3dldmVyLCB0
aGV5IGhhdmUgZmV3IGxpbWl0YXRpb25zOyBmb3IgaW5zdGFuY2UsPC9wPjxwPnRoZXkgZG8gbm90
IHN1cHBvcnQgaW1wbGVtZW50aW5nIGludGVyZmFjZXMgYW5kIHRoZXkgZG8gbm90IHN1cHBvcnQg
Z2VuZXJpYyB0eXBlIGZpZWxkcy4gSW4gb3RoZXIgd29yZHMsIHRoZSBmb2xsb3dpbmcgZGVjbGFy
YXRpb24sIHVzZWQgdG8gYmUgc3ludGFjdGljYWxseSBpbnZhbGlkOjwvcD48cD48YnI+PC9wPjxw
PmBgYGphdmE8L3A+PHA+cGFja2FnZSBjb20uYWNtZTs8L3A+PHA+ZGVjbGFyZSBBbGVydGluZ1Nl
cnZpY2UgZXh0ZW5kcyBSdWxlVW5pdERhdGE8L3A+PHA+Jm5ic3A7Jm5ic3A7IGV2ZW50RGF0YTog
RGF0YVN0cmVhbSZsdDtFdmVudCZndDs8L3A+PHA+Jm5ic3A7Jm5ic3A7IGFsZXJ0RGF0YTogRGF0
YVN0cmVhbSZsdDtBbGVydCZndDs8L3A+PHA+ZW5kPC9wPjxwPmBgYDwvcD48cD48YnI+PC9wPjxw
PkluIHZlcnNpb24gMC44LjAsIHdlIGFyZSBsaWZ0aW5nIHRoZXNlIGxpbWl0YXRpb25zOiB3ZSBh
bGxvdyBsaW1pdGVkIGluaGVyaXRhbmNlIGZvciBpbnRlcmZhY2VzIChvbmx5IG9uZSBpcyBhbGxv
d2VkIGZvciBub3cpIGFuZCBnZW5lcmljIHR5cGUgZGVjbGFyYXRpb24gZm9yIGZpZWxkcy4gV2l0
aCB0aGVzZSBuZXcgZmVhdHVyZXMsIHRoZSBmb2xsb3dpbmcgcGllY2Ugb2YgY29kZSBiZWNvbWVz
IHZhbGlkIERSTC48L3A+PHA+PGJyPjwvcD48cD5Mb25nIHN0b3J5IHNob3J0OiAqKnlvdSBhcmUg
bm93IGFibGUgdG8gZGVjbGFyZWQgYSBmdWxsIG1pY3Jvc2VydmljZTwvcD48cD5mcm9tIGEgc2lu
Z2xlIERSTCoqLjwvcD48cD48YnI+PC9wPjxwPkJvb3RzdHJhcCB5b3VyIEtvZ2l0byBzZXJ2aWNl
IHdpdGggdGhlIGFyY2hldHlwZTo8L3A+PHA+PGJyPjwvcD48cD5gYGBzaDwvcD48cD4mbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgbXZuIGFyY2hldHlwZTpnZW5lcmF0ZSBcPC9wPjxwPiZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAtRGFyY2hldHlw
ZUdyb3VwSWQ9b3JnLmtpZS5rb2dpdG8gXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgLURhcmNoZXR5cGVBcnRpZmFjdElkPWtvZ2l0by1xdWFy
a3VzLWFyY2hldHlwZSBcPC9wPjxwPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyAtRGFyY2hldHlwZVZlcnNpb249MC44LjAgXDwvcD48cD4mbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgLURncm91cElkPWNvbS5hY21l
IFw8L3A+PHA+Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7
IC1EYXJ0aWZhY3RJZD1zYW1wbGUta29naXRvPC9wPjxwPmBgYDwvcD48cD48YnI+PC9wPjxwPkF0
IHRoZSBtb21lbnQsIG5vIFF1YXJrdXMgdmVyc2lvbiBidW5kbGVzIEtvZ2l0byAwLjguMDsgb3Ro
ZXJ3aXNlLCB5b3Ugd291bGQgYmUgYWJsZSB0byB1c2UgYG12biBpby5xdWFya3VzOnF1YXJrdXMt
bWF2ZW4tcGx1Z2luOmNyZWF0ZWAgaW5zdGVhZC48L3A+PHA+PGJyPjwvcD48cD5Ob3csIGNsZWFy
IHRoZSBjb250ZW50cyBvZiBgc3JjL21haW5gIGFuZCB0aGVuLCBkcm9wIHRoaXMgRFJMIHRvIGBz
cmMvbWFpbi9yZXNvdXJjZXMvY29tL2FjbWVgIGZvbGRlciBpbnN0ZWFkOjwvcD48cD48YnI+PC9w
PjxwPmBgYGphdmE8L3A+PHA+cGFja2FnZSBjb20uYWNtZTs8L3A+PHA+dW5pdCBBbGVydGluZ1Nl
cnZpY2U7PC9wPjxwPjxicj48L3A+PHA+aW1wb3J0IG9yZy5raWUua29naXRvLnJ1bGVzLkRhdGFT
dHJlYW07PC9wPjxwPmltcG9ydCBvcmcua2llLmtvZ2l0by5ydWxlcy5SdWxlVW5pdERhdGE7PC9w
PjxwPjxicj48L3A+PHA+ZGVjbGFyZSBFdmVudDwvcD48cD4mbmJzcDsmbmJzcDsgdHlwZTombmJz
cDsgU3RyaW5nPC9wPjxwPiZuYnNwOyZuYnNwOyB2YWx1ZTogaW50PC9wPjxwPmVuZDwvcD48cD48
YnI+PC9wPjxwPmRlY2xhcmUgQWxlcnQ8L3A+PHA+Jm5ic3A7IHNldmVyaXR5OiBTdHJpbmc8L3A+
PHA+Jm5ic3A7IG1lc3NhZ2U6Jm5ic3A7IFN0cmluZzwvcD48cD5lbmQ8L3A+PHA+PGJyPjwvcD48
cD5kZWNsYXJlIEFsZXJ0aW5nU2VydmljZSBleHRlbmRzIFJ1bGVVbml0RGF0YTwvcD48cD4mbmJz
cDsmbmJzcDsgZXZlbnREYXRhOiBEYXRhU3RyZWFtJmx0O0V2ZW50Jmd0OzwvcD48cD4mbmJzcDsm
bmJzcDsgYWxlcnREYXRhOiBEYXRhU3RyZWFtJmx0O0FsZXJ0Jmd0OzwvcD48cD5lbmQ8L3A+PHA+
PGJyPjwvcD48cD5ydWxlIEluY29taW5nRXZlbnQgd2hlbjwvcD48cD4mbmJzcDsmbmJzcDsgLy8g
bWF0Y2hlcyB3aGVuIGEgdGVtcGVyYXR1cmUgaGlnaGVyIHRoYW4gMzAgwrBDIGlzIHJlZ2lzdGVy
ZWQgKE9PUGF0aCBzeW50YXgpPC9wPjxwPiZuYnNwOyZuYnNwOyAkZSA6IC9ldmVudERhdGEgWyB0
eXBlID09ICJ0ZW1wZXJhdHVyZSIsIHZhbHVlICZndDs9IDMwIF0gPC9wPjxwPnRoZW48L3A+PHA+
Jm5ic3A7Jm5ic3A7IFN5c3RlbS5vdXQucHJpbnRsbigiaW5jb21pbmcgZXZlbnQ6ICIrICRlLmdl
dE1lc3NhZ2UoKSk7PC9wPjxwPiZuYnNwOyZuYnNwOyBhbGVydERhdGEuYXBwZW5kKCBuZXcgQWxl
cnQoICJ3YXJuaW5nIiwgIlRlbXBlcmF0dXJlIGlzIHRvbyBoaWdoOiAiICsgJGUgKSApOzwvcD48
cD5lbmQ8L3A+PHA+PGJyPjwvcD48cD5xdWVyeSBXYXJuaW5nczwvcD48cD4mbmJzcDsmbmJzcDsg
YWxlcnRzOiAvYWxlcnREYXRhIFsgc2V2ZXJpdHkgPT0gIndhcm5pbmciIF08L3A+PHA+ZW5kPC9w
PjxwPmBgYDwvcD48cD48YnI+PC9wPjxwPk5vdyBmaXJlIHVwIHRoZSBRdWFya3VzIHNlcnZpY2Ug
aW4gZGV2ZXZlbG9wZXIgbW9kZSB3aXRoOjwvcD48cD48YnI+PC9wPjxwPmBgYHNoPC9wPjxwPiZu
YnNwOyZuYnNwOyZuYnNwOyAkIG12biBjb21waWxlIHF1YXJrdXM6ZGV2PC9wPjxwPmBgYDwvcD48
cD48YnI+PC9wPjxwPlRoZXJlIHlvdSBnbywgeW91IGFyZSBub3cgcmVhZHkgdG8gYGN1cmxgIHlv
dXIgc2VydmljZTo8L3A+PHA+PGJyPjwvcD48cD5gYGBzaDwvcD48cD4mbmJzcDsmbmJzcDsmbmJz
cDsgJCBjdXJsIC1YIFBPU1QgXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgLUggJ0FjY2VwdDogYXBwbGljYXRpb24vanNv
bicgXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsgLUggJ0NvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbicgXDwvcD48
cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsgLWQgJ3sgImV2ZW50RGF0YSI6IFsgeyAidHlwZSI6ICJ0ZW1wZXJhdHVyZSIsICJ2YWx1
ZSIgOiA0MCB9IF0gfScgXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgaHR0cDovL2xvY2FsaG9zdDo4MDgwL3dhcm5pbmdz
PC9wPjxwPmBgYDwvcD48cD48YnI+PC9wPjxwPiMjIFdvcmtmbG93IEludGVncmF0aW9uPC9wPjxw
Pjxicj48L3A+PHA+QW5vdGhlciB3YXkgdG8gZXhwb3NlIGEgcnVsZS1iYXNlZCBzZXJ2aWNlIGlz
IHRocm91Z2ggYSAqd29ya2Zsb3cqLjwvcD48cD48YnI+PC9wPjxwPkEgKndvcmtmbG93KiAoc29t
ZXRpbWVzIGNhbGxlZCBhICJidXNpbmVzcyBwcm9jZXNzIikgZGVzY3JpYmVzIGEgc2VxdWVuY2Ug
b2YgPC9wPjxwPnN0ZXBzIGluIGEgZGlhZ3JhbSBhbmQgaXQgdXN1YWxseSBkZWNsYXJlcyAqdmFy
aWFibGVzKjogZGF0YSBob2xkZXJzIGZvcjwvcD48cD52YWx1ZXMgdGhhdCBhcmUgbWFuaXB1bGF0
ZWQgaW4gdGhlIGV4ZWN1dGlvbi4gVGhlIGRhdGEgdHlwZSBvZiBvbmUgc3VjaCB2YXJpYWJsZTwv
cD48cD5tYXkgYmUgKmFueXRoaW5nKjogeW91IG1heSB1c2UgSmF2YSBjbGFzc2VzLCBidXQsIGlu
IHRoaXMgZXhhbXBsZSwgd2Ugd2lsbDwvcD48cD51c2UgYWdhaW4gb3VyIGRlY2xhcmVkIGRhdGEg
dHlwZXMuIDwvcD48cD48YnI+PC9wPjxwPmBgYGphdmE8L3A+PHA+cGFja2FnZSBjb20uYWNtZTs8
L3A+PHA+PGJyPjwvcD48cD5kZWNsYXJlIEV2ZW50PC9wPjxwPiZuYnNwOyZuYnNwOyB0eXBlOiZu
YnNwOyBTdHJpbmc8L3A+PHA+Jm5ic3A7Jm5ic3A7IHZhbHVlOiBpbnQ8L3A+PHA+ZW5kPC9wPjxw
Pjxicj48L3A+PHA+ZGVjbGFyZSBBbGVydDwvcD48cD4mbmJzcDsgc2V2ZXJpdHk6IFN0cmluZzwv
cD48cD4mbmJzcDsgbWVzc2FnZTombmJzcDsgU3RyaW5nPC9wPjxwPmVuZDwvcD48cD5gYGA8L3A+
PHA+PGJyPjwvcD48cD5MZXQgdXMgY2FsbCB0aGlzIHdvcmtmbG93IGBjb20uYWNtZS5BbGVydGlu
Z1dvcmtmbG93YCwgYW5kIGRlY2xhcmUgdGhlIHZhcmlhYmxlcyBgZXZlbnREYXRhYCBhbmQgYGFs
ZXJ0RGF0YWA6PC9wPjxwPjxicj48L3A+PHA+IVt3b3JrZmxvd10oaHR0cHM6Ly9yYXcuZ2l0aHVi
dXNlcmNvbnRlbnQuY29tL2V2YWNjaGkva29naXRvLXJ1bGVzLWV4YW1wbGUvbWFzdGVyL2ltZ3Mv
dmFyaWFibGVzLnBuZyk8L3A+PHA+PGJyPjwvcD48cD48YnI+PC9wPjxwPkEgd29ya2Zsb3cgdGhh
dCBpbmNsdWRlcyBhICpydWxlIHRhc2sqIG1heSBza2lwIHRoZSBydWxlIHVuaXQgZGF0YSAqZGVj
bGFyYXRpb24qIGFsdG9nZXRoZXI6IGluIHRoaXMgY2FzZSB0aGUgcnVsZSB1bml0IGlzIGluZmVy
cmVkIGRpcmVjdGx5IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHByb2Nlc3M6IGVhY2ggdmFyaWFibGUg
d2lsbCBiZSAqKmluc2VydGVkIGludG8gZGF0YSBzb3VyY2Ugb2YgdGhlIHNhbWUgbmFtZSoqLjwv
cD48cD48YnI+PC9wPjxwPiFbd29ya2Zsb3ddKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50
LmNvbS9ldmFjY2hpL2tvZ2l0by1ydWxlcy1leGFtcGxlL21hc3Rlci9pbWdzL3dvcmtmbG93LnBu
Zyk8L3A+PHA+PGJyPjwvcD48cD5UaGUgKm5hbWUqIG9mIHRoZSB1bml0IGlzIGRlY2xhcmVkIGJ5
IHRoZSBwcm9jZXNzLCB1c2luZyB0aGUgc3ludGF4IGB1bml0OmNvbS5hY21lLkFsZXJ0aW5nU2Vy
dmljZWAuPC9wPjxwPllvdSBhcmUgc3RpbGwgZnJlZSB0byBleHBsaWNpdGx5IGRlY2xhcmUgdGhl
IHVuaXQgYGNvbS5hY21lLkFsZXJ0aW5nU2VydmljZWA7IGluIHRoYXQgY2FzZSwgdGhlIHByb2Nl
c3Mgd2lsbCB0aGUgZGVjbGFyYXRpb24gdGhhdCB5b3UgaGF2ZSBoYW5kLWNvZGVkLjwvcD48cD48
YnI+PC9wPjxwPk5vdGU6IFlvdSBtYXkgaGF2ZSBub3RpY2VkIHRoYXQgd2UgYXJlIHVzaW5nIHRo
ZSAiUnVsZSBGbG93IEdyb3VwIiBmaWVsZC4gV2Ugd2lsbCBhIG1vcmUgZXhwbGljaXQgc3VwcG9y
dCB0byB0aGUgVUkgaW4gdGhlIGZ1dHVyZS48L3A+PHA+PGJyPjwvcD48cD5Cb290c3RyYXAgeW91
ciBLb2dpdG8gc2VydmljZSB3aXRoIHRoZSBhcmNoZXR5cGU6PC9wPjxwPjxicj48L3A+PHA+YGBg
c2g8L3A+PHA+Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IG12biBhcmNoZXR5cGU6Z2Vu
ZXJhdGUgXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsgLURhcmNoZXR5cGVHcm91cElkPW9yZy5raWUua29naXRvIFw8L3A+PHA+Jm5ic3A7Jm5i
c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IC1EYXJjaGV0eXBlQXJ0aWZh
Y3RJZD1rb2dpdG8tcXVhcmt1cy1hcmNoZXR5cGUgXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgLURhcmNoZXR5cGVWZXJzaW9uPTAuOC4wIFw8
L3A+PHA+Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IC1E
Z3JvdXBJZD1jb20uYWNtZSBcPC9wPjxwPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyZuYnNwOyZuYnNwOyAtRGFydGlmYWN0SWQ9c2FtcGxlLWtvZ2l0bzwvcD48cD5gYGA8L3A+
PHA+PGJyPjwvcD48cD4qKkNhdmVhdCoqLiBTdXBwb3J0IGZvciB0aGlzIGZlYXR1cmUgaXMgZXhw
ZXJpbWVudGFsLCBzbyBpdCBtYXkgbm90IHdvcmsgc2VhbWxlc3NseTwvcD48cD53aXRoIFF1YXJr
dXMgaG90IGNvZGUgcmVsb2FkOyB3ZSBhbHNvIG5lZWQgdGhlIGZvbGxvd2luZyBleHRyYSBzdGVw
IHRvIGVuYWJsZSBpdCwgYnV0IHRoaXMgd2lsbCBjaGFuZ2UgaW4gdGhlIGZ1dHVyZS48L3A+PHA+
PGJyPjwvcD48cD5VcGRhdGUgeW91ciBgcG9tLnhtbGAgd2l0aCB0aGUgZm9sbG93aW5nIHBsdWdp
biBkZWNsYXJhdGlvbjo8L3A+PHA+PGJyPjwvcD48cD5gYGB4bWw8L3A+PHA+Jm5ic3A7ICZsdDti
dWlsZCZndDs8L3A+PHA+Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZsdDtwbHVnaW5zJmd0OzwvcD48cD4m
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgJmx0O3BsdWdpbiZndDs8L3A+PHA+Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZsdDtncm91cElkJmd0O29yZy5r
aWUua29naXRvJmx0Oy9ncm91cElkJmd0OzwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsgJmx0O2FydGlmYWN0SWQmZ3Q7a29naXRvLW1hdmVuLXBsdWdpbiZs
dDsvYXJ0aWZhY3RJZCZndDs8L3A+PHA+Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
c3A7Jm5ic3A7ICZsdDt2ZXJzaW9uJmd0OzAuOC4wJmx0Oy92ZXJzaW9uJmd0OzwvcD48cD4mbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgJmx0O2V4ZWN1dGlvbnMmZ3Q7
PC9wPjxwPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
YnNwOyAmbHQ7ZXhlY3V0aW9uJmd0OzwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgJmx0O2dvYWxzJmd0OzwvcD48
cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgJmx0O2dvYWwmZ3Q7Z2VuZXJhdGVEZWNsYXJlZFR5cGVz
Jmx0Oy9nb2FsJmd0OzwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgJmx0Oy9nb2FscyZndDs8L3A+PHA+Jm5ic3A7
Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZsdDsvZXhl
Y3V0aW9uJmd0OzwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsgJmx0Oy9leGVjdXRpb25zJmd0OzwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsgJmx0Oy9wbHVnaW4mZ3Q7PC9wPjxwPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAu
Li48L3A+PHA+Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZsdDsvcGx1Z2lucyZndDs8L3A+PHA+Jm5ic3A7
Jm5ic3A7ICZsdDsvYnVpbGQmZ3Q7PC9wPjxwPjxicj48L3A+PHA+YGBgPC9wPjxwPjxicj48L3A+
PHA+WW91IGNhbiBub3cgY2xlYXIgdGhlIGNvbnRlbnRzIG9mIGBzcmMvbWFpbmAsIGFuZCB0aGVu
IGRyb3AgdGhlIHByb2Nlc3MgYW5kIHRoZSBmb2xsb3dpbmcgRFJMIHRvIGBzcmMvbWFpbi9yZXNv
dXJjZXMvY29tL2FjbWVgIGZvbGRlci48L3A+PHA+PGJyPjwvcD48cD5gYGBqYXZhPC9wPjxwPnBh
Y2thZ2UgY29tLmFjbWU7PC9wPjxwPnVuaXQgQWxlcnRpbmdTZXJ2aWNlOzwvcD48cD48YnI+PC9w
PjxwPmltcG9ydCBvcmcua2llLmtvZ2l0by5ydWxlcy5EYXRhU3RyZWFtOzwvcD48cD5pbXBvcnQg
b3JnLmtpZS5rb2dpdG8ucnVsZXMuUnVsZVVuaXREYXRhOyA8L3A+PHA+PGJyPjwvcD48cD5kZWNs
YXJlIEV2ZW50PC9wPjxwPiZuYnNwOyZuYnNwOyB0eXBlOiZuYnNwOyBTdHJpbmc8L3A+PHA+Jm5i
c3A7Jm5ic3A7IHZhbHVlOiBpbnQ8L3A+PHA+ZW5kPC9wPjxwPjxicj48L3A+PHA+ZGVjbGFyZSBB
bGVydDwvcD48cD4mbmJzcDsgc2V2ZXJpdHk6IFN0cmluZzwvcD48cD4mbmJzcDsgbWVzc2FnZTom
bmJzcDsgU3RyaW5nPC9wPjxwPmVuZDwvcD48cD48YnI+PC9wPjxwPjxicj48L3A+PHA+cnVsZSBJ
bmNvbWluZ0V2ZW50IHdoZW48L3A+PHA+Jm5ic3A7Jm5ic3A7IC8vIG1hdGNoZXMgd2hlbiBhIHRl
bXBlcmF0dXJlIGhpZ2hlciB0aGFuIDMwIMKwQyBpcyByZWdpc3RlcmVkIChPT1BhdGggc3ludGF4
KTwvcD48cD4mbmJzcDsmbmJzcDsgJGUgOiAvZXZlbnREYXRhIFsgdHlwZSA9PSAidGVtcGVyYXR1
cmUiLCB2YWx1ZSAmZ3Q7PSAzMCBdPC9wPjxwPnRoZW48L3A+PHA+Jm5ic3A7Jm5ic3A7IFN5c3Rl
bS5vdXQucHJpbnRsbigiaW5jb21pbmcgZXZlbnQ6ICIrICRlLmdldE1lc3NhZ2UoKSk7PC9wPjxw
PiZuYnNwOyZuYnNwOyBhbGVydERhdGEuc2V0KCBuZXcgQWxlcnQoICJ3YXJuaW5nIiwmbmJzcDsg
IlRlbXBlcmF0dXJlIGlzIHRvbyBoaWdoOiAiICsgJGUgKSApOzwvcD48cD5lbmQ8L3A+PHA+YGBg
PC9wPjxwPjxicj48L3A+PHA+QXMgeW91IG1heSBoYXZlIG5vdGljZWQsIHlvdSBhcmUgbm90IHJl
cXVpcmVkIHRvIGRlY2xhcmUgYSBxdWVyeSBleHBsaWNpdGx5OiB0aGUgcHJvY2VzcyB3aWxsIGRp
c3BsYXk8L3A+PHA+dGhlIGNvbnRlbnRzIG9mIHRoZSB2YXJpYWJsZXMgYXMgYSByZXNwb25zZTsg
aXQgd2lsbCBnZW5lcmF0ZSB0aGUgZW5kcG9pbnQgYC9BbGVydGluZ1dvcmtmbG93YCwgYW5kIGl0
IGFjY2VwdCBhIGBQT1NUYCByZXF1ZXN0IG9mIHRoZSBmb2xsb3dpbmcgZm9ybTo8L3A+PHA+PGJy
PjwvcD48cD5gYGBzaDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsgJCBjdXJsIC1YIFBPU1QgXDwv
cD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsgLUggJ0FjY2VwdDogYXBwbGljYXRpb24vanNvbicgXDwvcD48cD4mbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgLUggJ0Nv
bnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbicgXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgLWQgJ3sgImV2ZW50RGF0
YSI6IHsgInR5cGUiOiAidGVtcGVyYXR1cmUiLCAidmFsdWUiIDogNDAgfSB9JyBcPC9wPjxwPiZu
YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
OyBodHRwOi8vbG9jYWxob3N0OjgwODAvQWxlcnRpbmdXb3JrZmxvdzwvcD48cD5gYGA8L3A+PHA+
PGJyPjwvcD48cD5UaGUgcmVwbHkgd2lsbCBiZTo8L3A+PHA+PGJyPjwvcD48cD48YnI+PC9wPjxw
PmBgYGpzb248L3A+PHA+ezwvcD48cD4mbmJzcDsgImlkIjogLi4uLDwvcD48cD4mbmJzcDsgImV2
ZW50RGF0YSI6IHs8L3A+PHA+Jm5ic3A7Jm5ic3A7Jm5ic3A7ICJ0eXBlIjogInRlbXBlcmF0dXJl
Iiw8L3A+PHA+Jm5ic3A7Jm5ic3A7Jm5ic3A7ICJ2YWx1ZSI6IDEwMDwvcD48cD4mbmJzcDsgfSw8
L3A+PHA+Jm5ic3A7ICJhbGVydERhdGEiOiB7PC9wPjxwPiZuYnNwOyZuYnNwOyZuYnNwOyAic2V2
ZXJpdHkiOiAid2FybmluZyIsPC9wPjxwPiZuYnNwOyZuYnNwOyZuYnNwOyAibWVzc2FnZSI6ICJU
ZW1wZXJhdHVyZSBpcyB0b28gaGlnaDogRXZlbnQoIHR5cGU9dGVtcGVyYXR1cmUsIHZhbHVlPTEw
MCApIjwvcD48cD4mbmJzcDsgfTwvcD48cD59PC9wPjxwPmBgYDwvcD48cD48YnI+PC9wPjxwPkhv
d2V2ZXIsIGlmIHlvdSAqZG8qIGRlY2xhcmUgYSBxdWVyeSwgYSBzZXBhcmF0ZSBlbmRwb2ludCB3
aWxsIGJlIGF2YWlsYWJsZSBhcyB3ZWxsLiBGb3IgaW5zdGFuY2U8L3A+PHA+aWYgeW91IGRlY2xh
cmUgdGhlIHF1ZXJ5IGBXYXJuaW5nc2AgeW91IHdpbGwgc3RpbGwgYmUgYWJsZSB0byBQT1NUIHRv
IGBodHRwOi8vbG9jYWxob3N0OjgwODAvd2FybmluZ3NgIGFuZCBpbnZva2UgdGhlIHJ1bGUgc2Vy
dmljZSBzZXBhcmF0ZWx5PC9wPjxwPmFzIGZvbGxvd3M6PC9wPjxwPjxicj48L3A+PHA+PGJyPjwv
cD48cD4mbmJzcDsmbmJzcDsmbmJzcDsgJCBjdXJsIC1YIFBPU1QgXDwvcD48cD4mbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgLUggJ0Fj
Y2VwdDogYXBwbGljYXRpb24vanNvbicgXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm
bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgLUggJ0NvbnRlbnQtVHlwZTogYXBw
bGljYXRpb24vanNvbicgXDwvcD48cD4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgLWQgJ3sgImV2ZW50RGF0YSI6IHsgInR5cGUiOiAi
dGVtcGVyYXR1cmUiLCAidmFsdWUiIDogNDAgfSB9JyBcPC9wPjxwPiZuYnNwOyZuYnNwOyZuYnNw
OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBodHRwOi8vbG9jYWxo
b3N0OjgwODAvd2FybmluZ3M8L3A+PHA+PGJyPjwvcD48cD5Ob3RpY2UgdGhhdCB0aGUgcmVxdWVz
dCBubyBsb25nZXIgY29udGFpbnMgYSBsaXN0IG9mIEV2ZW50cy4gVGhpcyBpcyBiZWNhdXNlIHBy
b2Nlc3MgdmFyaWFibGVzIGFyZSBtYXBwZWQgdG8gc2luZ2xlIHZhbHVlcyBpbnN0ZWFkIG9mIERh
dGFTdHJlYW1zLiA8L3A+PHA+PGJyPjwvcD48cD4jIyBDb25jbHVzaW9uPC9wPjxwPjxicj48L3A+
PHA+V2UgaGF2ZSBnaXZlbiBhIHNuZWFrIHBlZWsgb24gdGhlIHdvcmsgdGhhdCB3ZSBhcmUgZG9p
bmcgdG8gaW1wcm92ZSB0aGUgZ2V0dGluZyBzdGFydGVkIGV4cGVyaWVuY2Ugd2l0aCBydWxlcyBh
bmQgcHJvY2Vzc2VzIGluIEtvZ2l0by4gV2l0aCB0aGVzZSBjaGFuZ2VzLCB3ZSBob3BlIHRvIGhh
dmUgcHJvdmlkZWQgYSBtb3JlIHN0cmVhbWxpbmVkIHdheSB0byBkZWZpbmUga25vd2xlZGdlLWJh
c2VkIHNlcnZpY2VzLiBEZXZlbG9wZXJzIHdpbGwgYWx3YXlzIGFibGUgdG8gYmUgbW9yZSBleHBs
aWNpdCBhYm91dCB0aGUgZGF0YSB0aGV5IHdhbnQgdG8gcHJvY2VzcywgYnkgb3B0aW5nLWluIHRv
IHdyaXRpbmcgSmF2YTsgYnV0IGlmIHRoZXkgd2FudCwgdGhleSBjYW4gZW1icmFjZSBhIGZ1bGx5
IERTTC1jZW50cmljIGRldmVsb3BtZW50IHdvcmtmbG93LjwvcD48cD48YnI+PC9wPjxwPjxicj48
L3A+PHA+X0ZvciB0aGUgbGF6aWVzLCBleGFtcGxlcyBhcmUgYXZhaWxhYmxlIGF0IGh0dHBzOi8v
Z2l0aHViLmNvbS9ldmFjY2hpL2tvZ2l0by1ydWxlcy1leGFtcGxlL3RyZWUvbWFzdGVyL2NvZGUg
SGF2ZSBmdW4hXzwvcD4=">
</div>
</div>
Edoardo Vacchihttp://www.blogger.com/profile/05676846789077609136noreply@blogger.com3tag:blogger.com,1999:blog-5869426.post-29137822900019762832020-02-20T09:46:00.000+00:002020-02-20T09:46:31.056+00:00PMML revisitedHi folks! The beginning of this year brings with it the initiative to re-design the Drools PMML module.<br />
In this post I will describe how we are going to approach it, what's the current status, ideas for future development, etc. etc so... stay tuned!<br />
<h2>
</h2>
<h2>
Background</h2>
<a href="https://en.wikipedia.org/wiki/Predictive_Model_Markup_Language" rel="noopener" target="_blank">PMML</a> is a standard whose aim is to "<em>provide a way for analytic applications to describe and exchange predictive models produced by data mining and machine learning algorithms.</em>" <a href="http://dmg.org/pmml/v4-4/GeneralStructure.html" rel="noopener" target="_blank">PMML standard</a> defines a series of models that are managed, and we will refer to them as "Model".<br />
The maybe-not so obvious consequence of this is that, said differently, PMML may be thought as an <i>orchestrator</i> of different predictive models, each of which with different requirements.<br />
Drools has its own PMML implementation. The original design of it was 100% drools-engine based, but in the long term this proved to be not so satisfactory for all the models, so a decision has taken to implement a new version with a different approach. And here the current story begin...<br />
<h2>
Requirements</h2>
To the bare-bone essence, what a PMML implementation should allow is to:<br />
<ol>
<li>load a PMML file (xml format)</li>
<li>submit input data to it</li>
<li>returns predicted values</li>
</ol>
<div>
Sounds simple, doesn't it? </div>
<h2>
Approach</h2>
The proposed architecture aims at fulfilling the requirements in a modular way, following <a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html">“Clean Architecture”</a> principles.<br />
To achieve that, components are defined with clear boundaries and visibility.<br />
General idea is that there are specific tasks strictly related to the core functionality that should be kept agnostic by other “outer” features.<br />
Whoever wanting to deep delve in the matter may read the book "Clean Architecture" by R. C. Martin, but in the essence it is just a matter to apply good-ol' design principles to the overall architecture.<br />
With this target clearly defined, the steps required to achieve it are:<br />
<ol>
<li>identify the core-logic and the implementation details (model-specific)</li>
<li>implement the core-logic inside "independent" modules</li>
<li>write code for the model-specific modules</li>
</ol>
We choose to implement a <a href="https://martinfowler.com/eaaCatalog/plugin.html" rel="noopener" target="_blank">plugin pattern </a> to bind the core-logic to the model-specific implementations mostly for two reasons:<br />
<ol>
<li>incremental development and overall code-management: the core module itself does not depend on any of the model-specific implementations, so the latter may be provided/updated/replaced incrementally without any impact on the core</li>
<li>possibility to replace the provided implementation with a custom one</li>
<li>we also foresee the possibility to choose an implementation at runtime, depending on the original PMML structure (e.g. it may make sense to use a different implementation depending on the size of the given PMML)</li>
</ol>
<div>
(I cheated: those are three) </div>
<br />
<br />
<h2>
<b>Models</b></h2>
<h4>
<b>KiePMMLModel</b></h4>
<ol>
<li>This is the definition of Kie-representation of the original PMML model.</li>
<li>For every actual model there is a specific implementation, and it may be any kind of object (java map, drools rule, etc).</li>
</ol>
<div>
Could we avoid it? Maybe. We could use the model directly generated by the specification' xsd. But this has been designed to describe <i>all</i> the predictive models, while any of them may use it in different way and with different convention; so this <i>internal view</i> will represent exactly what is needed for each specific model.</div>
<h4>
Components</h4>
We identified the following main functional components:<br />
<ol>
<li>Compiler</li>
<li>Assembler</li>
<li>Executor</li>
</ol>
<h4>
Compiler</h4>
This component read the original PMML file and traslate it to our internal format.<br />
The core-side of it simply unmarshall the xml data into Java object. Then, it uses java SPI to retrieve the model-compiler specific for the given PMML model (if it does not find one, the PMML is simply ignored).<br />
Last, the retrieved model-compiler will “translate” the original PMML model to our model-specific representation (<em>KiePMMLModels</em>).<br />
The <em>core-side</em> part of this component has no direct dependence on any specific <i>Model Compiler implementation</i> and not even with anything drools/kie related - so basically it is a lightweight/standalone library.<br />
This component may be invoked at <em>runtime </em>(i.e. during the execution of the customer project), if its execution is not time-consuming, or during the compilation of the kjar (e.g. for drools-implemented models).<br />
<h4>
Assembler</h4>
This component stores <em>KiePMMLModels</em> created by the <i>Compiler</i> inside KIE knowledge base. None of the other components should have any dependency/knowledge of this one.<br />
In turns, it must not have any dependency/knowledge/reference on actual <i>Model Compiler implementations.</i><br />
<h4>
<b>Executor</b></h4>
This component is responsible for actual execution of PMML models. It receives the PMML input data, retrieves the KiePMMLModel specific for the input data and calculates the output.<br />
For each model there will be a specific “executor”, to allow different kinds of execution implementation (drools, external library, etc) depending on the model type.<br />
The core-side of it simply receives the input data and retrieve the model-executor specific for the given PMML model (if it does not find one, the PMML is simply ignored).<br />
Last, the retrieved model-executor will evaluate the prediction based on the input data.<br />
The <em>core-side</em> part of this component has no direct dependence on any specific <i>Model Executor implementation,</i> but of course is strictly dependent on the drool runtime.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><img alt="CleanPMMLArchitecture" class="alignnone wp-image-703" height="632" src="https://blogtechcardosi.files.wordpress.com/2020/02/cleanpmmlarchitecture.png" style="margin-left: auto; margin-right: auto;" width="632" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Overall Architecture</td></tr>
</tbody></table>
<br />
<br />
<h2>
Model implementations</h2>
<h3>
Drools-based models</h3>
<div>
Some models will delegate to the drools-engine to allow best performance under heavy load. Here are some details about general scheme for such implementations.</div>
<div>
<ol>
<li>the <i>compiler</i> is invoked at kjar generation (or during runtime for hot-loading of PMML file)</li>
<li>the <i>compiler</i> reads the PMML file and transform it to "descr" object (see <a href="https://github.com/kiegroup/drools/blob/master/drools-compiler/src/main/java/org/drools/compiler/lang/descr/BaseDescr.java" rel="noopener" target="_blank">BaseDescr</a>, <a href="https://github.com/kiegroup/drools/blob/master/drools-compiler/src/main/java/org/drools/compiler/lang/api/DescrFactory.java" rel="noopener" target="_blank">DescrFactory</a>, <a href="https://github.com/kiegroup/drools/blob/master/drools-compiler/src/test/java/org/drools/compiler/lang/api/DescrBuilderTest.java" rel="noopener" target="_blank">DescrBuilderTest</a>)</li>
<li>regardless of how the <i>model-compiler</i> is invoked, the <i>drools compiler</i> must be invoked soon after it to have java-class generated based on the <em>descr</em> object</li>
<li>the <i>assembler</i> put the generated classes in the kie base</li>
<li>the <i>executor</i> loads the "drools-model" generated and invoke it with the input parameters</li>
</ol>
<h4>
DRL details</h4>
<ul>
<li>for each field in the DataDictionary, a specific DataType has to be defined</li>
<li>for each branch/leaf of the tree, a full-path rule has to be generated (i.e. a rule with the path to get to it - e.g. "sunny", "sunny_temperature", "sunny_temperature_humidity")</li>
<li>a "status-holder" object is created and contains the value of the rule fired - changing that value will fire the children branch/leaf rules matching it (e.g. the rule "sunny" will fire "sunny_temperature" that - in turns - will fire "sunny_temperature_humidity")</li>
<li>such "status-holder" <em>may</em> contain informations/partial result of evaluation, to be eventually used where combination of results is needed</li>
<li>missing value strategy <em>may</em> be implemented inside the status holder or as exploded rules</li>
</ul>
</div>
<div>
<br /></div>
<h3>
Testing</h3>
<div>
For each model there will be a set of standard unit tests to mostly verify individual units of code. Beside that, inside the model-specific module (yes, it <b>is</b> a tongue twister) there will be an <i>integration-test </i>submodule. This latter will verify the overall correct execution of different, more or less complex, PMML files, to simulate as much as possible what may happen in real-world scenarios.</div>
<div>
<br /></div>
<h3>
Regression</h3>
Regression model is the first one to have been implemented. Due to its inherent simplicity, we choose to provide a pure java-based implementation for it. For the moment being it is still under PR, and new full tests are being added.<br />
<h3>
Tree</h3>
After evaluating all the pros/cons, we decided that this model could be a good candidate to be implemented with a drools-based approach. Being also a simple model to follow, we choose to use it as first test for drools approach.<br />
<br />
<h2>
TO-DOs</h2>
This is a list of missing features that are not implemented, yet, and not strictly-related to a specific model. It will be (well, it should be) updated during the development:<br />
<ul>
<li>Setup <i>Benchmarking</i> skeleton project (see <a href="https://github.com/kiegroup/kie-benchmarks/tree/master/drools-benchmarks" target="_blank">Drools Benchmark</a>)</li>
<li>Manage <i>Extension</i> tags (see <a href="http://dmg.org/pmml/v4-4/GeneralStructure.html#xsdElement_Extension" target="_blank">xsdElement_Extension</a>)</li>
<li>Manage <i>SimpleSetPredicate</i> tags (see <a href="http://dmg.org/pmml/v4-4/TreeModel.html#xsdElement_SimplePredicate" target="_blank">SimpleSetPredicate</a>)</li>
<li>Implement <a href="http://dmg.org/pmml/v4-4/MultipleModels.html#xsdElement_VariableWeight" target="_blank">VariableWeight</a> inside <i>Segment</i> (dynamic alternative to static "weight" value)</li>
</ul>
<div>
<br /></div>
<div>
Needless to say that any comment (especially nice ones) and suggestion will be greatly appreciated.</div>
<div>
<br /></div>
<div>
Come back in the following days and see what's next! </div>
<div>
Bye!</div>
Gabriele Cardosihttp://www.blogger.com/profile/18332879885377765817noreply@blogger.com4tag:blogger.com,1999:blog-5869426.post-22807991750585945272020-02-03T23:34:00.000+00:002020-02-03T23:34:57.631+00:00KIE Decision Tooling blog <p>
KIE Decision Tooling is the team responsible for building web editors to support business decisions, and now it has a blog.
</p>
<p>
We're still cross-posting feature releases here. But, you can also find specific content regarding the technologies that orbit the web tooling there.
</p>
<p>
In our first post, we're presenting the new code completion feature in the DMN editor, check it out:
<a href="https://medium.com/kie-decision-tooling/feel-functions-and-the-dmn-editor-7f4462f9f012">https://medium.com/kie-decision-tooling/feel-functions-and-the-dmn-editor-7f4462f9f012</a>
</p>
<p>
Follow the RSS here: <a href="https://medium.com/feed/kie-decision-tooling">https://medium.com/feed/kie-decision-tooling</a>.
</p>
<p>
Stay tuned for the next posts! :-)
</p>
Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-5869426.post-84151235983745338872019-08-12T19:24:00.001+01:002019-11-28T15:40:15.065+00:00Recent Drools DMN open source engine performance improvements<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">We are always looking to improve the performance of the <a href="https://drools.org/learn/dmn.html" target="_blank">Drools DMN open source engine</a>. We have recently reviewed a DMN use-case where the actual input population of Input Data nodes varied to some degree; this highlighted a suboptimal behavior of the engine, which we improved in recent releases. I would like to share our findings!</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<h2 style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;">Benchmark development</span></h2>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">As we started running a supporting benchmark for this use-case, especially when investigating the scenario of large DMN models with sparse-populated input data nodes, we noticed some strange results: the flamegraph data highlighted a substantial performance hit when logging messages, consuming very significant time in comparison to the application logic itself.</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4hJZ-AL00HS5rgR_dcMzg2wGl2qFI6i3RWks6AvC5WjO6hcmpqm9FWawmGlWqWLq5PeT861BGOEvs6oqA5sWzPXhbei8uWoHT5LSRfPdSinZukYBUMp_pZYZpx4pVsdfvO_4o/s1600/flamegraph.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="742" data-original-width="1200" height="393" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4hJZ-AL00HS5rgR_dcMzg2wGl2qFI6i3RWks6AvC5WjO6hcmpqm9FWawmGlWqWLq5PeT861BGOEvs6oqA5sWzPXhbei8uWoHT5LSRfPdSinZukYBUMp_pZYZpx4pVsdfvO_4o/s640/flamegraph.png" width="640" /></a></div>
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">This flamegraph highlight specifically that a large portion of time is consumed by stacktrace synthesis, artificially induced by the logging framework. The correction, in this case, was to tune the logging configuration to avoid this problem; specifically, we disabled a feature of the logging framework which is very convenient during debugging activities, enabling to quickly locate the original calling class and methods: unfortunately this feature come at the expense of synthesizing stacktraces, which originally contaminated the benchmark results. Lesson learned here: always check first if non-functional requirements are actually masking the real issue!</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">This was a necessary and propaedeutic step, before proceeding to investigate the use-case in more details.</span></span><br />
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span>
<br />
<h2>
<span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;">Improving performance</span></h2>
</div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span>
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">Moving on and focusing now on DMN optimizations, we specifically developed a benchmark to be general enough, but also highlighting the use-case which was presented to us. This benchmark consists of a DMN model with many (500) decision nodes to be evaluated. Another parameter controls sparseness of input data nodes valorization for evaluation; ranging from a value of 1 where all inputs are populated, to 2 where only one out of two inputs is actually populated, etc.</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">This specific benchmark proved to be a very instrumental tool to highlight some potential improvements. </span></span><br />
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">Setting the comparison baseline to Drools release 7.23.0.Final, the first optimization implemented with <a href="https://issues.jboss.org/browse/DROOLS-4204" target="_blank">DROOLS-4204</a> focused on improving context handling while evaluating FEEL expressions and demonstrated to offer a ~3x improvement, while further optimization implemented with <a href="https://issues.jboss.org/browse/DROOLS-4266" target="_blank">DROOLS-4266</a> focusing on specific case for decision table input clauses demonstrated an additional ~2x improvement on top of DROOLS-4204.</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">We also collected these measurements in the following graphs.</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYij37PXTobHBleDdi-UA60_wfPpjV_AdRdrkmyadKhg-kzq8egWa-aHxcMGLtxwyazZPNZ98NPXF0_sOEbZMMFRk7OEDfxARGhvEVdILuUUkX2q3eBtTENiQBnDrOa136_dZW/s1600/chart+%25283%2529.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="371" data-original-width="600" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYij37PXTobHBleDdi-UA60_wfPpjV_AdRdrkmyadKhg-kzq8egWa-aHxcMGLtxwyazZPNZ98NPXF0_sOEbZMMFRk7OEDfxARGhvEVdILuUUkX2q3eBtTENiQBnDrOa136_dZW/s640/chart+%25283%2529.png" width="640" /></a></div>
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;">This graph highlights the compounding improvements in the case of sparseness factor equal to 1, where all inputs are populated; this was a very important result, as in fact it did represent the <b>main</b>, “happy path” scenario in the original use-case.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">In other words, we achieved a ~6x improvement in comparison to running the same use-case on </span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">7.23.0.Final. The lesson I learned here is to always strive for these kind of <i>compounding</i> improvements when possible, as they really build on top of each other, for greater results!</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">For completeness, we repeated the analysis with sparseness factor equals to 2 (1 every 2 inputs is actually populate) and 50 (1 every 50 inputs is actually populated) with the following measurements:</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibu2wdRKMng5YYKC54bJqdAg6Y9rHrURJrIuk4HgLfyx-aBTToYBrefhian8XAFSdNZw0-sqzxpjZpYh8IT-942x3xQ0xgy42lMO4GpGx1BxqdM_sNnZU4IlGHLoWBVg83tNSi/s1600/chart+%25282%2529.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="371" data-original-width="600" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibu2wdRKMng5YYKC54bJqdAg6Y9rHrURJrIuk4HgLfyx-aBTToYBrefhian8XAFSdNZw0-sqzxpjZpYh8IT-942x3xQ0xgy42lMO4GpGx1BxqdM_sNnZU4IlGHLoWBVg83tNSi/s640/chart+%25282%2529.png" width="640" /></a></div>
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial"; font-size: 14.6667px; white-space: pre-wrap;">Results show that the optimizations were also significant for sparseness factor equal to 2, but not as relevant improvements as this factor grows -- which is expected, as the impact of the decision nodes evaluations on the overall logic of execution become now less relevant. </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">For completeness, analysis was also performed with another, already existing benchmark for single decision table consisting of many rules rows:</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnj8gkfyAguC53J6phoJh6yMi2LlPqiMNW4f54ZDvX5IEx3uCwY-0iKykB-ZXhdG7NjvfmD76Q-1nIe_6nVdJ4mxkr83A26wMGg7XDjrPYIRas5pMoOC6S0zaCblmxqzfD7rbw/s1600/chart+%25284%2529.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="371" data-original-width="600" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnj8gkfyAguC53J6phoJh6yMi2LlPqiMNW4f54ZDvX5IEx3uCwY-0iKykB-ZXhdG7NjvfmD76Q-1nIe_6nVdJ4mxkr83A26wMGg7XDjrPYIRas5pMoOC6S0zaCblmxqzfD7rbw/s640/chart+%25284%2529.png" width="640" /></a></div>
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">Results show that these code changes considered as a whole, still offered a relevant improvement; although clearly not of the same <i>magnitude</i> as for the original use-case. This was another important check to ensure that these improvements were not overfitting on the specific use-case.</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<h2>
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">Conclusions</span></span></h2>
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">Considering Drools release 7.23.0.Final as the baseline, and a reference benchmark consisting of a DMN model with many decision nodes to be evaluated, we implemented several optimizations that once combined demonstrated to offer a total of ~6x speed-up on that specific use case!</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">I hope this was an interesting post to highlight some of the dimensions were to look into to achieve better performances; let us know you thoughts and feedback.</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;">You can already benefit today from these Kie <a href="https://drools.org/learn/dmn.html" target="_blank">DMN open source engine</a> improvements in the most recent releases of Drools! </span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: "arial";"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
Matteo Mortarihttp://www.blogger.com/profile/07483879118138508902noreply@blogger.com10tag:blogger.com,1999:blog-5869426.post-79120279779764366702019-07-29T10:18:00.000+01:002019-07-29T16:30:21.899+01:00Kogito, ergo Rules — Part 2: An All-Encompassing Execution Model for Rules<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://raw.githubusercontent.com/kiegroup/kogito-runtimes/master/docsimg/kogito.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="228" data-original-width="800" height="180" src="https://raw.githubusercontent.com/kiegroup/kogito-runtimes/master/docsimg/kogito.png" width="640" /></a></div>
<div style="margin-bottom: 0in;">
<span style="font-family: inherit;">This is the <i>second post </i>of a <a href="http://blog.athico.com/2019/07/kogito-ergo-rules-part-1-bringing.html">series of updates</a> on the Kogito initiative and our efforts to bring Drools to the cloud. In this post we delve into the details of <b>rule units</b> and show you why we are excited about them.</span><br />
<br /></div>
<h2 class="western"><span style="font-size: 1.5em; font-weight:400">An All-Encompassing Execution Model for Rules</span></h2>
<div>If you’ve been carefully scrutinising the Drools manual looking for
new features at every recent release, you may have noticed that the
term <b>rule unit</b> has been sitting there for a while, as an
<i>extremely experimental feature</i>. In short, a rule unit is both
a <b>module</b> for rules and a <b>unit of execution</b>—the reason
why we are not calling them <i>modules</i> is to avoid confusion with
<i>JVM modules</i>. In Kogito, we are revisiting and expanding upon
our original prototype.
</div>
<div style="margin-bottom: 0in;">
A <b>rule unit</b> collects a set of
rules together with the description of the working memory such rules
act upon. The description of the working memory is written as a
regular Java class, with <i>DataSource</i> fields. Each data source
represents a <i>typed partition</i> of the working memory, and
different types of data sources exist, with different features. For
instance, in the following example we used an append-only data
source, called <i>data stream.</i></div>
<div style="margin-bottom: 0in;">
<script src="https://gist.github.com/evacchi/2efedbd1227519176e52bb8d1e2c97d1.js?file=MonitoringService.java"></script>
<br />
<div style="margin-bottom: 0in;">
Rules of a given rule unit are collected in DRL files with the <span style="font-family: "roboto mono" , monospace;"><b>unit</b></span>
declaration</div>
<script src="https://gist.github.com/evacchi/2efedbd1227519176e52bb8d1e2c97d1.js?file=MonitoringService.drl.java"></script>
<br />
<div style="margin-bottom: 0in;">
Each rule in a unit has visibility over <i>all</i> the data sources
that have been declared in the corresponding class. In fact, the
class and the collection of DRL files of a unit form a <i>whole</i>:
you can think of such a whole as of <i>one single</i> <i>class</i>
where <i>fields</i> are <i>globals </i>that are scoped to the current
unit, and <i>methods </i>are <i>rules</i>. In fact, the use of fields
supersedes the use of DRL globals.</div>
<div class="separator" style="clear: both; margin: 1em; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2jTRGYRSmfvW8MbA4sOikbPh6FE8gsWJ18RxYE52-aiWWBQqsePNl3a4q96rTGxPsL2cD_CC53vPhJzyd4eFV6X0vUt5aa4YwUIPHnJCUv4UKAvBlNGp5Nu4cBpZbPHQYiF5v/s1600/kogito-part2-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="465" data-original-width="1152" height="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2jTRGYRSmfvW8MbA4sOikbPh6FE8gsWJ18RxYE52-aiWWBQqsePNl3a4q96rTGxPsL2cD_CC53vPhJzyd4eFV6X0vUt5aa4YwUIPHnJCUv4UKAvBlNGp5Nu4cBpZbPHQYiF5v/s640/kogito-part2-1.png" width="640" /></a></div>
<div align="left" style="margin-bottom: 0in;">
A rule unit is submitted
for execution to a <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj85Oc4sQltYirS5QGhDqQumDH3CzocIIy44RvGXqwK2vN87Noyg5LQQcgjO1_F86lS_K2h4pHmfhkB5hfBQo6JMYLDLZf2_g0E5l9B7Z9i3kxv_MTizNoVIQot4cV4Ku8jBX0i/s1600/unitsm.png"><b>scheduler</b></a><b>.
</b>Rule units may decide to <b>yield</b> their execution to other
rule units, effectively putting them into execution.
For instance:</div>
<script src="https://gist.github.com/evacchi/2efedbd1227519176e52bb8d1e2c97d1.js?file=IncomingEvent.drl.java"></script>
<br />
<div align="left" style="margin-bottom: 0in;">
But rule units may be also put in a <b>long-running state</b>. In
this case, <i>other rule units</i> may be run <i>concurrently at the
same time</i>; because DataSources can be <b>shared</b> across units,
units can be coordinated by exchanging messages.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi79cHPMwr90UewWJscS4k6MFEKT2zAznVd1WeLsc54iUU-prZgSKteybK-w7C6xWpMVR78aCuQHmHcagHoErdIDCSSPhjN_Lil0Mgol0kMt6dZfRHFV9B_vWo4Hcga3zEUY_4Z/s1600/kogito-part2-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="388" data-original-width="806" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi79cHPMwr90UewWJscS4k6MFEKT2zAznVd1WeLsc54iUU-prZgSKteybK-w7C6xWpMVR78aCuQHmHcagHoErdIDCSSPhjN_Lil0Mgol0kMt6dZfRHFV9B_vWo4Hcga3zEUY_4Z/s640/kogito-part2-2.png" width="640" /></a></div>
<div>
Consider the
following example:</div>
<script src="https://gist.github.com/evacchi/2efedbd1227519176e52bb8d1e2c97d1.js?file=MonitoringService.drl.java"></script>
<br />
<div style="margin-bottom: 0in;">
In a certain way, <b>rule units behave as “actors” exchanging
messages</b>. However, in a very distinctive way, rule units allow
for much more complex chains of executions, that are proper to
rule-based reasoning. For instance, <a href="https://doc.akka.io/docs/akka/2.5.23/guide/tutorial_3.html"><span style="color: #1155cc;"><u>consider
this example from Akka's manual</u></span></a>:</div>
<script src="https://gist.github.com/evacchi/2efedbd1227519176e52bb8d1e2c97d1.js?file=akka.scala"></script>
<br />
<div style="margin-bottom: 0in;">
As you can see, pattern matches in Akka are strictly over <b>single
messages</b>. This is unsurprising, because actors process one
message at a time. In a rule engine, we are allowed to write several
rules, reacting upon the <b>entire state of the working memory </b>at
the execution time: this significantly departs from a pure actor
model design, but at the same time gives a great deal of flexibility
in the way you may write the business logic of your application.</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
<h4>Data Sources </h4>
It is worth to
spend a few words on data sources as well. The data source construct
can be seen as both a <b>partition</b> and an<b> abstraction</b> over
the traditional working memory. Different kinds of data sources will
be available: full-featured <b>data stores</b> may support to add,
remove and update values, allowing for more traditional operations
over the working memory; while the more constrained append-only <b>data
streams</b> would be easier to integrate with external data sources
and data sinks, such as Camel connectors; such constraints would be
also valuable to enable more advanced use cases, such as<b> parallel,
thread-safe execution</b> and <b>persisted shared channel </b>(e.g.:
Kafka) across nodes of an<b> OpenShift cluster</b>, realizing a fully
<b>distributed rule engine.</b></div>
<div style="margin-bottom: 0in;">
<style type="text/css">p { margin-bottom: 0.1in; line-height: 115%; background: transparent none repeat scroll 0% 0%; }a:link { color: rgb(0, 0, 128); text-decoration: underline; }</style></div>
<div style="margin-bottom: 0in;">
</div>
</div>
<div style="margin-bottom: 0in;">
<br />
<h2 class="western" style="font-size:1.5em; font-weight:400">
Kogito: ergo Cloud</h2>
<div style="margin-bottom: 0in;">
The parallel and distributed use cases
are <i>intriguing</i>, but we need to get there with <i>baby steps.</i>
However, this does not mean that the first steps won't be as exciting
in their own way.</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
For <a href="http://kogito.kie.org/"><span style="color: #1155cc;"><u><b>Kogito</b></u></span></a>
we want to stress the cloud-native, stateless use case, where <b>control
flow</b> is <b>externalized</b> using <b>processes</b> and, with the
power of <a href="https://quarkus.io/"><span style="color: #1155cc;"><u>Quarkus</u></span></a>
we can compile this into super-fast native binaries. This is why in
the next few weeks we will complete and release rule units for
<i>automated REST service implementation</i>.
</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
In this use case, the typed, Java-based
declaration of a<b> rule unit</b> is <b>automatically </b>mapped to
the signature of a REST endpoint. <b>POST</b>ing to the endpoint
implies instantiating the unit, inserting data into the data sources,
firing rules, returning the response payload. The response is
computed using a <i>user-provided query</i>.
For instance, consider this example:</div>
<script src="https://gist.github.com/evacchi/2efedbd1227519176e52bb8d1e2c97d1.js?file=query.drl.java"></script>
<br />
<div style="margin-bottom: 0in;">
Users may post events using the auto-generated <span style="font-family: "roboto mono" , monospace;">/monitoring-service</span>
endpoint.</div>
</div>
<script src="https://gist.github.com/evacchi/2efedbd1227519176e52bb8d1e2c97d1.js?file=req.json"></script>
<br />
<div style="margin-bottom: 0in;">
the reply will be the result of the query. In our case:</div>
<script src="https://gist.github.com/evacchi/2efedbd1227519176e52bb8d1e2c97d1.js?file=resp.json"></script>
<br />
<h2 style="font-size:1.5em; font-weight:400">Cloudy with a Chance of Rules</h2>
<div style="margin-bottom: 0in;">
We have presented our vision
for the next generation of our rule engine in Kogito and beyond. The
stateless use case is only the first step towards what we think will
be a truly innovative take on rule engines. In the following months
we will work on delivering better support for scheduling and
deploying units in parallel (local) and distributed (on Openshift),
so stay tuned for more. In the meantime, we do want to hear from you
about the direction we are taking.
</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
The future of Drools is cloudy… and
bright!</div>
<div style="margin-bottom: 0in;">
<br /></div>
<style type="text/css">p { margin-bottom: 0.1in; line-height: 115%; background: transparent none repeat scroll 0% 0%; }a:link { color: rgb(0, 0, 128); text-decoration: underline; }</style></div>
<style type="text/css">p { margin-bottom: 0.1in; line-height: 115%; background: transparent none repeat scroll 0% 0%; }a:link { color: rgb(0, 0, 128); text-decoration: underline; }</style>Edoardo Vacchihttp://www.blogger.com/profile/05676846789077609136noreply@blogger.com18tag:blogger.com,1999:blog-5869426.post-20204820830212214982019-07-18T12:51:00.001+01:002019-08-13T08:14:51.463+01:00Kogito, ergo Rules — Part 1: Bringing Drools Further<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://raw.githubusercontent.com/kiegroup/kogito-runtimes/master/docsimg/kogito.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="228" data-original-width="800" height="180" src="https://raw.githubusercontent.com/kiegroup/kogito-runtimes/master/docsimg/kogito.png" width="640" /></a></div>
<br />
<br />
<span style="font-family: inherit;">The Kogito initiative is our pledge to bring our business automation
suite to the cloud and the larger Kubernetes ecosystem. But what does
this mean for our beloved rule engine, Drools? In this post we
introduce modular rule bases using <b>rule units</b>:<b> </b>a
feature that has been <i>experimental</i> for a while in Drools 7,
but that will be <i>instrumental</i> for Kogito, where it will play a
much bigger role. This is the first post of a series where we will
give you an overview of this feature (<i><a href="http://blog.athico.com/2019/07/kogito-ergo-rules-part-2-all.html">read part 2</a></i>)</span></div>
<span style="font-family: inherit;">
</span>
<br />
<h2 class="western">
<span style="font-family: inherit;"><a href="https://draft.blogger.com/u/2/null" name="_vimpptao8nz"></a>Bringing Drools
Further
</span></h2>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;"><b>Drools</b>
is our state-of-the-art, high-performance, feature-rich open source
<b>rule engine</b>. People love it because it is a <i>swiss-army knife</i> to the
many problems that can be solved using rule-based artificial
intelligence. But as the computer programming landscape evolves, we
need to think of ways to bring further Drools as well. As you may
already know, <a href="https://github.com/kiegroup/kogito-runtimes/">Kogito</a> is our effort to make Drools and jBPM really
cloud-native, and well-suited for serverless deployments: we are
embracing the <a href="https://quarkus.io/">Quarkus</a> framework and <a href="https://www.graalvm.org/">GraalVM</a>’s native binary
compilation for super-fast startup times and low memory footprint;
but we are not stopping there.</span></div>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;">The
way we want to bring further Drools evolution is <b>twofold</b>: on the one
hand, we want to make our programming model <i>easier to reason
about</i>, by providing better ways to define boundaries in a rule
base with a better concept of <b>module; </b>on the other hand, the
concept of modular programming dates back at least to the 1970s and
to <a href="https://dl.acm.org/citation.cfm?id=361623"><span style="color: #1155cc;"><u>Parnas’
original seminal paper</u></span></a>. Needless to say, if our
contribution stopped there, we would be bringing nothing new to the
plate. In the last few years, computing has evolved, slowly but
steadily embracing the <b>multicore and distributed revolution</b>;
yet, to this day, many general-purpose programming languages do not
really make it simple to write parallel or distributed programs.
rule-based programming system we have the chance to propose <b>something
different</b>: a rule engine that is <i>great</i> when <i>stand-alone</i>,
but <b>outstanding</b> in the <b>cloud</b>.</span></div>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<b style="font-family: inherit;">Modular
Rule Bases.</b><span style="font-family: inherit;"> As you already know, Drools provides a convenient way
to partition set of rules into </span><i style="font-family: inherit;">knowledge bases</i><span style="font-family: inherit;">. Such knowledge
bases can be </span><i style="font-family: inherit;">composed</i><span style="font-family: inherit;"> together, yielding larger sets of rules.
When a knowledge base is instantiated (the so-called </span><i style="font-family: inherit;">session</i><span style="font-family: inherit;">),
rules are put together in the same execution environment (the
</span><i style="font-family: inherit;">production memory</i><span style="font-family: inherit;">), and values (the </span><i style="font-family: inherit;">facts</i><span style="font-family: inherit;">) are all
inserted together in the same </span><i style="font-family: inherit;">working memory</i><span style="font-family: inherit;">.</span></div>
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
</div>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;">This
model is <i>very simple and powerful</i> but in some senses it is
also <i>very limited</i>. It is very simple, because, as a user of
the rule base, you just worry about your data: the values are
inserted into the working memory, and the engine does its magic. It
is very powerful, because, as a rule author, you can rely upon the
rules you have written to realize complex flows of reasoning, without
worrying about how and when they will trigger.</span></div>
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
</div>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;">At
the same time, such an execution model lacks all of the principles,
that over the years we have been learning are good programming
practice. For instance, there is no proper notion of a <b>module</b>:
it is not possible to perfectly isolate one rule from another, or to
properly partition the working memory. As the rule base scales up in
complexity, it may become harder to understand which rules trigger
and why.
In some senses, it is as if you were programming in an odd world
where proper encapsulation of state does not exist, as if years of
programming language evolution had not happened.</span></div>
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
</div>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;"><b>Object-Oriented
Programming.</b> The term object-oriented programming has been
overloaded over the years to mean a lot of different things; it has
to do both with <i>inheritance</i>, with <i>encapsulation of state</i>,
with <i>code reuse</i>, with <i>polymorphism</i>. All these terms get
often confused, but they are not really related: you can reuse code
without inheritance, you can encapsulate state without objects, you
can write polymorphic code without classes. Very recent, imperative
programming languages such as Go and Rust do not come with proper
classes, yet they support a form of object-orientation; there is even
<a href="https://www.youtube.com/watch?v=xcpSLRpOMJM"><span style="color: #1155cc;"><u>a
beautiful 2015 talk from C++’s dad, Bjarne Stroustrup, showing how
his child supports object-orientation without inheritance</u></span></a>.</span></div>
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
</div>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;">Alan
Kay, who fathered the term in his Smalltalk days at Xerox, <a href="https://www.youtube.com/watch?v=oKg1hTOQXoY"><span style="color: #1155cc;"><u>in
his inspiring lecture at OOPSLA 1997 said «I made up the term
"object-oriented", and I can tell you I did not have C++ in
mind»</u></span></a>. In fact, the idea of<b> objects</b> that Alan
Kay pioneered was more similar to the concept of <b>actors</b> and
<b>microservices</b>. In <i>proper</i> object-oriented programming,
objects encapsulate their internal state and expose their behavior by
exchanging <i>messages</i> (usually called methods) with the external
world.</span></div>
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
</div>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;">Today
actor systems have seen a renaissance, message buses are very central
to what today we call <i>reactive programming</i>, microservices are
almost given for granted. So, we wondered, what would it mean for
Drools to become a first-class citizen of this new programming
landscape?</span></div>
<span style="font-family: inherit;">
</span>
<br />
<h2 class="western">
<span style="font-family: inherit;"><a href="https://draft.blogger.com/u/2/null" name="_h34vfy931cyy"></a>Kogito, ergo Cloud</span></h2>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;">In
the next post we will see our take on rule-based, modular
programming, using <b>rule units</b>. Rule units will provide an
alternative to plain knowledge base composition and an extended model
of execution. We believe that rule units will make room for a wider
spectrum of use cases, including <b>parallel</b> and <b>distributed</b>
architectures. Stay tuned to read how they fit in the Kogito story,
and the exciting possibilities that they may open for the future of
our automation platform.</span></div>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;"><br /></span>
</div>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;"><br /></span>
</div>
<span style="font-family: inherit;">
</span>
<br />
<div align="left" style="margin-bottom: 0in; orphans: 2; widows: 2;">
<span style="font-family: inherit;"><br /></span>
</div>
<span style="font-family: inherit;">
</span><style type="text/css"><span style="font-family: inherit;">h3 { margin-top: 0.22in; margin-bottom: 0.06in; direction: ltr; color: rgb(67, 67, 67); line-height: 100%; text-align: left; break-inside: avoid; background: transparent none repeat scroll 0% 0%; break-after: avoid; }h3.western { font-size: 14pt; font-weight: normal; }h3.cjk { font-size: 14pt; font-weight: normal; }h3.ctl { font-size: 14pt; }h2 { margin-top: 0.25in; margin-bottom: 0.08in; direction: ltr; line-height: 100%; text-align: left; break-inside: avoid; background: transparent none repeat scroll 0% 0%; break-after: avoid; }h2.western { font-size: 16pt; font-weight: normal; }h2.cjk { font-size: 16pt; font-weight: normal; }h2.ctl { font-size: 16pt; }p { margin-bottom: 0.1in; line-height: 115%; background: transparent none repeat scroll 0% 0%; }a:link { color: rgb(0, 0, 128); text-decoration: underline; }</span></style>Edoardo Vacchihttp://www.blogger.com/profile/05676846789077609136noreply@blogger.com16tag:blogger.com,1999:blog-5869426.post-84781203546014052352019-06-19T17:46:00.000+01:002019-06-19T17:46:59.223+01:00Webinar: Re-imagining business automation: Convergence of decisions, workflow, AI/ML, RPA — vision and futures<div dir="ltr" style="text-align: left;" trbidi="on">
WEBINAR
<br />
<br />
Title: Re-imagining business automation: Convergence of decisions, workflow, AI/ML, RPA—vision and futures<br />
<br />
Time: June 20, 2019, 5:00 p.m. BST (UTC+ 1)<br />
<br />
Registration <a href="https://www.redhat.com/en/events/webinar/re-imagining-business-automation-convergence-decisions-workflow-aiml-rpa%E2%80%94vision-and-futures">https://www.redhat.com/en/events/webinar/re-imagining-business-automation-convergence-decisions-workflow-aiml-rpa%E2%80%94vision-and-futures</a></div>
Mark Proctorhttp://www.blogger.com/profile/03304277188725220501noreply@blogger.com13tag:blogger.com,1999:blog-5869426.post-44621737042295492712019-03-25T16:48:00.000+00:002019-03-25T16:50:22.822+00:00drools.js: Towards a Polyglot Drools on GraalVM (with Bonus Tech-Lead Prank)<div class="separator" style="clear: both; text-align: center;">
<a href="https://draft.blogger.com/blogger.g?blogID=5869426" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"></a></div>
<div align="center" style="margin-bottom: 0in;">
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK6O5sLEU2Vad-K2ZKU1BFtatWXdlCJ_dB_rX5-N6v-z2g7uQ0RO0lO7SYm5A7yshLRh2MJ8xwuICBmDi9wnZPaDjvJtoLw6gYcZ-w4ZpfaKvt5oj2hyphenhyphenGHBH5VSpO1PAiy-Srw/s1600/rule-engines-nodejs.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="700" data-original-width="500" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK6O5sLEU2Vad-K2ZKU1BFtatWXdlCJ_dB_rX5-N6v-z2g7uQ0RO0lO7SYm5A7yshLRh2MJ8xwuICBmDi9wnZPaDjvJtoLw6gYcZ-w4ZpfaKvt5oj2hyphenhyphenGHBH5VSpO1PAiy-Srw/s640/rule-engines-nodejs.jpg" width="456" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><div align="center" style="margin-bottom: 0in;">
<i>Image courtesy of
</i><a href="https://twitter.com/desmax74/status/730344025492992000/photo/1"><span style="color: #1155cc;"><i><u>Massimiliano
Dessì</u></i></span></a></div>
</td></tr>
</tbody></table>
</div>
<div align="center" style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
<i>You can find the full source code
for this blog post in the </i><a href="https://github.com/kiegroup/submarine-examples"><span style="color: #1155cc;"><i><u>submarine-examples</u></i></span></a><i>
repository. </i>
</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
Different programming languages are
better for different purposes. Imagine how hard would it be to query
a database using an imperative language: luckily, we use SQL for
that. Now, imagine how useless would a rule engine be, if defining
rules were not convenient! This is the reason why Drools comes with
its own custom language, the DRL. The <i>Drools Rule Language</i> is
in a so-called <i>domain-specific language</i>, a special-purpose
programming language specifically designed to make interaction with a
rule engine easier.</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
In particular, a rule is made of two
main parts, the<i> condition</i> and the<i> consequence.</i></div>
<script src="https://gist.github.com/evacchi/f2afe12813146061aa43b2cd89c2cd71.js?file=rule.drl"></script><br />
<div style="margin-bottom: 0in;">
The condition is a list of logic
predicates, usually pattern matches, while the consequence is written
using an imperative language, usually Java.</div>
<h2 class="western">
<a href="https://draft.blogger.com/null" name="_g2evelohutii"></a>An Abstract Rule
Engine</h2>
<div style="margin-bottom: 0in;">
Rules are what really <i>make</i> a
rule engine. After all, that's what a <i>rule</i> engine does:
processing rules. Thus, it might sound <i>kind</i> of logical for the
<i>engine</i> to be a bit entangled with the<i> language</i> for rule
definitions. Our engine is<i> not</i> specially tied to the DRL; but
it used to.</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
In the last year or so, we spent a lot
of time unbundling the innards of the DRL from the guts of the Drools
core. The result of this effort is what we called the <b>Canonical
Model</b>; that is, an abstract representation of the components that
make up a rule engine, including rule definitions. Incidentally, this
also paved the way for supporting <a href="http://www.graalvm.org/"><span style="color: #1155cc;"><u>GraalVM</u></span></a>
and the <a href="https://quarkus.io/"><span style="color: #1155cc;"><u>Quarkus</u></span></a>
framework; but our goal was also different. We wanted to <b>abstract
our engine from the rule language</b>.
</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://draft.blogger.com/blogger.g?blogID=5869426" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"></a></div>
Internally, the DRL is now translated
into the <b>canonical representation</b>; but, <a href="http://blog.athico.com/2019/03/quarking-drools-how-we-turned-13-year.html"><span style="color: #1155cc;"><u>as
we said previously</u></span></a>, this canonical model is described
using Java code. While this representation is <b>not currently
intended to be hand-coded</b>, it is very possible to do so. The
following is a simple rewriting of the previous DRL rule.
</div>
<script src="https://gist.github.com/evacchi/f2afe12813146061aa43b2cd89c2cd71.js?file=rule.java"></script><br />
<div style="margin-bottom: 0in;">
As you can see, although the rule
definition is now <i>embedded</i> in a Java "host"
language, it still shows the main features of a DRL definition,
namely, the <i>logic condition</i> and the <i>imperative consequence</i>
(introduced by the <span style="font-family: "roboto mono" , serif;">on...execute</span>
pair) In other words, this is a so-called <i>embedded or </i><a href="https://martinfowler.com/bliki/DomainSpecificLanguage.html"><span style="color: #1155cc;"><i><u>internal
domain-specific language</u></i></span></a>.</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
A small <b>disclaimer</b> applies: the
code above works, but our translator takes extra steps for best
performance, such as introducing <b>indexes</b>. In fact, one of the
reasons why we<b> do not </b>intend this API for public consumption
is that, currently, a naive rewrite like this may produce inefficient
rules.</div>
<h2 class="western">
<a href="https://draft.blogger.com/null" name="_7mg637k1x7h6"></a>A Polyglot Automation
Platform</h2>
<div style="margin-bottom: 0in;">
As part of our journey experimenting
with our programming model, we wanted to see whether it was feasible
to<b> interact with our engine using different programming languages</b>.
DRL aside, the canonical model rule definition API is pure-Java.
</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
But GraalVM is <i>not</i> only a tool
to generate <i>native binaries</i>: in fact, this is only <i>one</i>
of the capabilities of this terrific project. GraalVM is, first and
foremost, the <a href="https://dl.acm.org/citation.cfm?id=2509581"><span style="color: #1155cc;"><i><u>one
VM to rule them all</u></i></span></a>: that is, a <b>polyglot</b>
runtime, with first-class support for both JVM languages and many
other dynamic programming languages, with a state-of-the-art <b>JIT</b>
compiler, that <a href="https://youtu.be/mMmOntDWSgw?t=611"><span style="color: #1155cc;"><u>easily
compares or exceeds the performance of the industry standards</u></span></a>.
For instance, there is already support for R, Ruby, JavaScript and
Python; and, compared to writing a JIT compiler from scratch, the
<a href="https://www.graalvm.org/docs/graalvm-as-a-platform/implement-language/"><span style="color: #1155cc;"><u>Truffle
framework</u></span></a> makes it terribly easy to write your own,
and fine-tuning it to perfection.</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://draft.blogger.com/blogger.g?blogID=5869426" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"></a></div>
GraalVM gave us <b>a great occasion</b>
to show how easy could it be to<b> make Drools polyglot</b>, and,
above all, to <b>play an awful practical joke</b> on our beloved,
hard-working, conference-speaking, JavaScript-hating, resident Java
Champion and tech lead <b>Mario</b>!</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
Enter <a href="https://github.com/kiegroup/submarine-examples"><span style="color: #1155cc;"><u><b>drools.js</b></u></span></a><b>:
</b>
</div>
<script src="https://gist.github.com/evacchi/f2afe12813146061aa43b2cd89c2cd71.js?file=drools.js"></script><br />
<div style="margin-bottom: 0in;">
And here's a picture of Mario screaming
in fear at the monster we have created<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8DhPE3OiTzdC3yU7xosU_kexJ6N1WFmOvei1HQwXq72zcyHBIGSIsi5htZ69jnPKRBlLV-lC9TlRkBjTNB_UHFDlvLFyvnMan6PBvw_SbejfHstUL2ZJfJNHaUxNKd0x3sBBJ/s1600/IMG-20190305-WA0006.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="739" data-original-width="1600" height="294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8DhPE3OiTzdC3yU7xosU_kexJ6N1WFmOvei1HQwXq72zcyHBIGSIsi5htZ69jnPKRBlLV-lC9TlRkBjTNB_UHFDlvLFyvnMan6PBvw_SbejfHstUL2ZJfJNHaUxNKd0x3sBBJ/s640/IMG-20190305-WA0006.jpg" width="640" /></a></div>
</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div align="center" style="margin-bottom: 0in;">
</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
Jokes aside, this experiment is a
window over one of the many possible futures of our platform. The
world of application development today is <i>polyglot</i>. We cannot
ignore this, and we are trying to understand how to reach a wider
audience with our technologies, be it our rule engine, or our
workflow orchestration engine; in fact, we are doing the same
experiments with other parts of the platform, such as <b>jBPM</b>.
</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
jBPM provides its own DSL for workflow
definition. Although this is, again, work in progress, it shows a lot
of promise as well. Behold: <b>jbpm.js</b>!</div>
<script src="https://gist.github.com/evacchi/f2afe12813146061aa43b2cd89c2cd71.js?file=jbpm.js"></script><br />
<h2 class="western">
<a href="https://draft.blogger.com/null" name="_mi7kkvytuldz"></a>Conclusion</h2>
<div style="margin-bottom: 0in;">
The DRL has served its purpose for a
very long time, but we are already providing different ways to
interact with our powerful engine, such as DMN and PMML; but power
users will always want to reach for finer tuning and write their own
rules.
</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
The canonical model API is still a
work-in-progress, and, above all, an internal API that is <i><u>not</u></i>
intended for human consumption; but, if there is enough interest, we<i>
do</i> plan to work further to provide a more convenient embedded DSL
for rule definition. Through the power of GraalVM, we will be able to
realize an embedded DSL that is just as writable in Java as <i>any
</i>other language that GraalVM supports.
</div>
<div style="margin-bottom: 0in;">
<br /></div>
<div style="margin-bottom: 0in;">
And this includes JavaScript; sorry
Mario!</div>
<div style="margin-bottom: 0in;">
<br /></div>
<style type="text/css">h2 { margin-top: 0.25in; margin-bottom: 0.08in; direction: ltr; line-height: 100%; text-align: left; break-inside: avoid; background: transparent none repeat scroll 0% 0%; break-after: avoid; }h2.western { font-size: 16pt; font-weight: normal; }h2.cjk { font-size: 16pt; font-weight: normal; }h2.ctl { font-size: 16pt; }p { margin-bottom: 0.1in; line-height: 115%; background: transparent none repeat scroll 0% 0%; }a:link { color: rgb(0, 0, 128); text-decoration: underline; }</style>Edoardo Vacchihttp://www.blogger.com/profile/05676846789077609136noreply@blogger.com27tag:blogger.com,1999:blog-5869426.post-30945692315433799142019-03-14T13:31:00.000+00:002019-03-14T13:33:07.294+00:00Quarking Drools: How we turned a 13-year-old Java project into a first-class serverless component<div class="selectionShareable" style="text-align: right;">
<i>“The
question of whether a computer can think is no more interesting</i></div>
<div class="selectionShareable" style="text-align: right;">
<i>than the
question of whether a submarine can swim.”</i></div>
<div class="selectionShareable" style="text-align: right;">
<i>- Edsger W. Dijkstra</i></div>
<div class="selectionShareable" style="text-align: center;">
<br /></div>
<div class="selectionShareable">
Rule-based artificial intelligence (AI) is
often overlooked, possibly because people think it’s only useful in
heavyweight enterprise software products. However, that’s not
necessarily true. Simply put, a rule engine is just a piece of software
that allows you to separate domain and business-specific constraint from
the main application flow. We are part of the team developing and
maintaining <a href="https://www.drools.org/">Drools</a>—the world’s
most popular open source rule engine and part of Red Hat—and, in this
article, we will describe how we are changing Drools to make it part of
the cloud and serverless revolution.<span id="more-572587"></span></div>
<h2>
Technical overview</h2>
<div class="selectionShareable">
Our main goal was to make the core of the
rule engine lighter, isolated, easily portable across different
platforms, and well-suited to run in a container. The software
development landscape has changed a lot in the past 20 years. We are
moving more and more toward a polyglot world, which is one reason why we
are working to make our technology work across a lot of different
platforms. This is also why we started looking into <a href="https://www.graalvm.org/">GraalVM</a>, the new Oracle Labs polyglot virtual machine (VM) ecosystem, consisting of:</div>
<ul>
<li>A polyglot VM runtime, alternative to the <a href="https://developers.redhat.com/topics/enterprise-java/">Java</a>
virtual machine (JVM) with a just-in-time (JIT) compiler that improves
efficiency and speed of applications over traditional HotSpot. This is
also the “proper” GraalVM.</li>
<li>A framework to write efficient dynamic programming languages (e.g.,
JavaScript, Python, and R) and to mix and match them (Truffle).</li>
<li>A tool to compile programs ahead-of-time (AOT) into a native executable.</li>
</ul>
<div class="selectionShareable">
Meanwhile at Red Hat, another team was
already experimenting with GraalVM and native binary generation for
application development. This effort has been realized in a new project
you may have heard of called <a href="https://developers.redhat.com/blog/2019/03/07/quarkus-next-generation-kubernetes-native-java-framework/">Quarkus</a>.
The Quarkus project is a best-of-breed Java stack that works on good
old JVM but is also especially tailored for GraalVM, native binary
compilation, and cloud-native application development.</div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
GraalVM is an amazing tool, but it also comes with some (understandable) <a href="https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md">limitations</a>.
Thus, Quarkus is designed to integrate seamlessly with GraalVM and
native image generation, as well as provide useful utilities to overcome
any related limitations. In particular, Drools used to make extensive
use of dynamic class generation, class-loading, and quite a bit of
reflection. To produce fast, efficient, and small native executables,
Graal performs aggressive inlining and dead-code elimination, and it
operates under a <b>closed-world assumption</b>: that is, the
compiler removes any references to class and methods that cannot be
statically reachable in the code. In other words, unrestricted
reflective calls and dynamic class loading are a no-go. Although this
may at first sound like a showstopper, here we will document in detail
how we modified the core of Drools to overcome such limitations, and we
will explain why such limitations are not evil and can be liberating.</div>
<div class="selectionShareable">
<br /></div>
<h2>
The Executable Model</h2>
<div class="selectionShareable">
In a rule engine, <b>facts</b> are inserted into a <b>working memory.</b> <b>Rules</b> describe <b>actions</b> to take when certain <b>constraints</b> over the facts that are inserted into the working memory become <b>true</b>. For instance, the sentence “<b>when</b> <i>the sun goes down </i><b>:</b> <i>turn on the lights</i>” expresses a rule over the sun. The <i>fact</i> is that the sun is going down. The <i>action</i> is to turn on the lights. In a rule engine, we <i>insert </i>the “sun is going down” fact inside the working memory. When we <i>fire</i> the rules, the action of <i>turning on the lights</i> will execute.</div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
A rule definition has the form</div>
<div class="selectionShareable" style="text-align: left;">
<br /></div>
<div class="selectionShareable" style="text-align: center;">
<i>constraints</i> → <i>consequence</i></div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
The <i>constraints</i> part, also called the <i>left-hand side </i>of the rule, describes the constraints that activate the rule and make it ready to <i>fire</i>; the <i>consequence</i> part, also called the <i>right-hand side</i> of the rule, contains the action that rule will take when the rule is fired.</div>
<div class="selectionShareable">
In Drools, a rule is written using the Drools Rule Language (in short, DRL), and it has the form:</div>
<div class="selectionShareable">
<br /></div>
<pre class="notranslate"><b>rule</b> R1 <b>when</b>
$r : Result() // constraints
$p : Person( age >= 18 )
<b>then</b>
$r.setValue( $p.getName() + " can drink"); // consequence
<b>end</b></pre>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
Constraints are written using a form of
pattern-matching over the data (Java objects) that is inserted into the
working memory. Actions are basically a block of Java code with a few
Drools-specific extensions.</div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
Historically, the DRL used to be a dynamic
language that was interpreted at runtime by the Drools engine. In
particular, the pattern matching syntax had a major drawback: it made
extensive use of reflection unless the engine detected a constraint was
“hot” enough for further optimization; that is, if it had evaluated a
certain number of times; in that case the engine would compile it into
bytecode on-the-fly.</div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
About one year ago, for performance
reasons, we decided to go away with runtime reflection and dynamic code
generation and completed the implementation of what we called the <a href="http://blog.athico.com/2018/02/the-drools-executable-model-is-alive.html">Drools Executable Model</a>,
providing a pure Java-based representation of a rule set, together with
a convenient Java DSL to programmatically define such model.</div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
To give an idea of how this Java API
looks, like let’s consider again the simple Drools rule reported above.
The rule will fire if the working memory contains any Result instance
and any instance of Person where the age field is greater or equal to
18. The consequence is to set the value of the Result object to a String
saying that the person can drink. The equivalent rule expressed with
the executable model API looks like the following (pretty-printed for
readability):</div>
<div class="selectionShareable">
<br /></div>
<pre class="notranslate">var r = declarationOf(Result.class, "$r");
var p = declarationOf(Person.class, "$p");
var rule =
rule("com.example", "R1").build(
pattern(r),
pattern(p).expr("e", p -> p.getAge() >= 18),
alphaIndexedBy(int.class, GREATER_OR_EQUAL, 1, this::getAge, 18),
reactOn("age")),
on(p, r).execute(($p, $r) ->
$r.setValue($p.getName() + " can drink")));</pre>
<pre class="notranslate"> </pre>
<div class="selectionShareable">
As you can see, this representation is
more verbose and harder to understand, partly because of the Java
syntax, but mostly because it explicitly contains lots of details, such
as the specification of how Drools should internally index a given
constraint, which was implicit in the corresponding DRL. We did this on
purpose because we wanted a totally explicit rule representation that
did not require any convoluted inference or reflection sorcery. However,
we knew it would be crazy to ask users to be aware of all such
intricate details, so we wrote a compiler to translate DRL into the
equivalent Java code. We achieved this using <a href="http://javaparser.org/">JavaParser</a>, a really nice open source library that allows to parse, modify, and generate any Java source code through a convenient API.</div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
In all honesty, when we designed and
implemented the executable model, we didn’t have strictly GraalVM in
mind. We simply wanted an intermediate and pure Java representation of
the rule that could be efficiently interpreted and executed by the
engine. Yet, by completely avoiding reflection and dynamic code
generation, the executable model was key to allowing us to support
native binary generation with Graal. For instance, because the new model
expresses all constraints as lambda predicates, we don’t need to
optimize the constraints evaluators through bytecode generation and
dynamic classloading, which are totally forbidden in native image
generation.</div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
The design and implementation of
executable model taught us an important lesson in the process of making
Drools compatible with Graal: any limitation can be overcome with a
sufficient amount of code generation. We will further discuss this in
the next section.</div>
<h2>
Overcoming other Graal limitations</h2>
<div class="selectionShareable">
Having a plain Java model of a Drools rule
base was a very good starting point, but more work was needed to make
our project compatible with native binary generation.</div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
The executable model makes reflection
largely unnecessary; however, our engine still needs reflection for one
last feature called<a href="http://docs.jboss.org/drools/release/7.17.0.Final/drools-docs/html_single/#_fine_grained_property_change_listeners"> property reactivity</a>.
Our plans are to get rid of reflection altogether, but, because the
change is nontrivial, for this time we resorted to a handy feature of
the binary image compiler. This feature<i> does</i> support a form of
reflection, provided that we can declare upfront the classes we will
need to reflect upon at runtime. This can be supplied by providing a<a href="https://github.com/oracle/graal/blob/master/substratevm/REFLECTION.md#manual-configuration"> JSON descriptor</a> file to the compiler, or, if you are using Quarkus, you can just <a href="https://quarkus.io/guides/rest-json-guide">annotate the domain classes</a>. For instance, in the rule shown above, our domain classes would be Result and Person. Then we can write:</div>
<div class="selectionShareable">
<br /></div>
<pre class="notranslate">[
{
"name" : "org.drools.simple.project.Person",
"allPublicMethods" : true
},
{
"name" : "org.drools.simple.project.Result",
"allPublicMethods" : true
}
]</pre>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
Then, we can instruct the native binary compiler with the flag</div>
<pre class="notranslate">-H:ReflectionConfigurationFiles=reflection.json</pre>
<div class="selectionShareable">
We segregated other redundant reflection trickery to a <i>dynamic</i> module and implemented an alternative <i>static</i>
version of the same components that users can choose to import into
their project. This approach is especially useful for binary image
generation, but it has benefits for regular use cases as well. In
particular, avoiding reflection and dynamic loading can result in faster
startup time and improved run-time.</div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
At startup time, Drools projects read an XML descriptor called the <i>kmodule</i>,
where the user declaratively defines the configuration of the project.
Usually, we parse this XML file and load it into memory, but our current
XStream-based parser uses a lot of reflection; so, first, we can load
the XML with an alternative strategy that avoids reflection. However, we
can go further: if we can guarantee that the in-memory representation
of the XML will never change across runs, and we can afford to run a
quick code-generation phase before repackaging a project for deployment,
then we can avoid loading the XML at each boot-up altogether. In fact,
we are now able to translate the XML file into a class file that will be
loaded at startup time, like any other hand-coded class. Here’s a
comparison of the XML with a snippet of the generated code (again,
pretty-printed for readability). The generated code is more verbose
because it makes explicit all of the configuration defaults.</div>
<div class="selectionShareable">
<br /></div>
<table style="height: 203px; width: 888px;">
<tbody>
<tr>
<td><pre class="notranslate"><kbase name="simpleKB"
packages="org.drools.simple.project">
<ksession name="simpleKS" default="true"/>
</kbase></pre>
</td>
<td><pre class="notranslate">var m = KieServices.get().newKieModuleModel();
var kb = m.newKieBaseModel("simpleKB");
kb.setEventProcessingMode(CLOUD);
kb.addPackage("org.drools.simple.project");
var ks = kb.newKieSessionModel("simpleKS");
ks.setDefault(true);
ks.setType(STATEFUL);
ks.setClockType(ClockTypeOption.get("realtime"));</pre>
</td>
</tr>
</tbody>
</table>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
Another issue with startup time is dynamic classpath scanning. Drools supports alternate ways to take <i>decisions</i> other than DRL-based rules, such as <i>decision-tables, </i>the <i>Decision Model and Notation (DMN) </i>or <i>predictive models </i>using the <i>Predictive Model Markup Language </i>(<i>PMML</i>).
Such extensions are implemented as dynamically loadable modules, that
are hooked into the core engine by scanning the classpath at boot-time.
Although this is extremely flexible, it is not essential: even in this
case, we can avoid runtime classpath scanning and provide <i>static </i>wiring
of the required components either by generating code at build-time, or
by providing an explicit API to end users to hook components manually.
We resorted to provide a pre-built static module with a minimal core.</div>
<div class="selectionShareable">
<br /></div>
<pre class="notranslate">private Map<Class<?>, Object> serviceMap = new HashMap<>();
private void wireServices() {
serviceMap.put(ServiceInterface.class,
Class.forName("org.drools.ServiceImpl").newInstance());
// … more services here
}</pre>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
Note that, although here we are using
Class.forName(), the compiler is smart enough to recognize the constant
and substitute it with an actual constructor. Of course, it is possible
to simplify this further by generating a chain of <b>if</b> statements.</div>
<div class="selectionShareable">
Finally, we tied everything together by
getting rid of the last few pre-executable model leftovers: the legacy
Drools class-loader. This was the culprit behind the following
apparently cryptic error message:</div>
<div class="selectionShareable">
<br /></div>
<pre class="notranslate">Error: unsupported features in 2 methods
Detailed message:
Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException:</pre>
<pre class="notranslate">Unsupported method java.lang.ClassLoader.defineClass(String, byte[], int, int, ProtectionDomain)</pre>
<pre class="notranslate">is reachable: The declaring class of this element has been substituted, but this element is not</pre>
<pre class="notranslate">present in the substitution class
To diagnose the issue, you can add the option --report-unsupported-elements-at-runtime. The </pre>
<pre class="notranslate">unsupported element is then reported at run time when it is accessed the first time.
Trace:
at parsing org.drools.dynamic.common.DynamicComponentsSupplier$DefaultByteArrayClassLoader.defineClass(DynamicComponentsSupplier.java:49)
Call path from entry point to org.drools.dynamic.common.DynamicComponentsSupplier$DefaultByteArrayClassLoader.defineClass(String, byte[], ProtectionDomain):</pre>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
Really, however, the message is pretty clear: our custom class-loader is able to dynamically <i>define</i> a class, which is useful when you generate bytecode at <i>run-time.</i>
But, if the codebase relies completely on the executable model, we can
avoid this altogether, so we isolated the legacy class-loader into the <i>dynamic </i>module.</div>
<div class="selectionShareable">
<br /></div>
<div class="selectionShareable">
This is the last step that was necessary
to successfully generate a native image of our simple test project, and
the results exceeded our expectations, thereby confirming that the time
and efforts we spent in this experiment were well invested. Indeed,
executing the main class of our test case with a normal JVM takes 43
milliseconds with a occupation of 73M of memory. The corresponding
native image generated by Graal lasted is timed at less than 1
millisecond and uses only 21M of memory.</div>
<h2>
Integrating with Quarkus</h2>
<div class="selectionShareable">
Once we had a first version of Drools
compatible with Graal native binary generation, the next natural step
was to start leveraging the features provided by Quarkus and try to
create a simple web service with it. We noticed that Quarkus offers a
different and simpler mechanism to let the compiler know that we need
reflection on a specific class. In fact, instead of having to declare
this in a JSON file as before, you can annotate the class of your domain
model as follows:</div>
<div class="selectionShareable">
<br /></div>
<pre class="notranslate">@RegisterForReflection
public class Person { … }</pre>
<pre class="notranslate"> </pre>
<div class="selectionShareable">
We also decided to go one small step
forward with our code generation machinery. In particular, we added one
small interface to Drools code</div>
<div class="selectionShareable">
<br /></div>
<pre class="notranslate">public interface KieRuntimeBuilder {
KieSession newKieSession();
KieSession newKieSession(String sessionName);
}</pre>
<pre class="notranslate"> </pre>
<div class="selectionShareable">
so that when the Drools compiler creates
the executable model from the DRL files it also generates an
implementation of this class. This implementation has the purpose of
supplying a Drools session automatically configured with the rules and
the parameters defined by the user.</div>
<div class="selectionShareable">
After that, we were ready to put both
dependency injection and REST support provided by Quarkus to work, and
we developed a simple web service exercising the Drools runtime.</div>
<div class="selectionShareable">
<br /></div>
<pre class="notranslate">@Path("/candrink/{name}/{age}")
public class CanDrinkResource {
@Inject
KieRuntimeBuilder runtimeBuilder;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String canDrink( @PathParam("name") String name,
@PathParam("age") int age ) {
KieSession ksession = runtimeBuilder.newKieSession();
Result result = new Result();
ksession.insert(result);
ksession.insert(new Person( name, age ));
ksession.fireAllRules();
return result.toString();
}
}</pre>
<pre class="notranslate"> </pre>
<div class="selectionShareable">
The example is straightforward enough to
not require any further explanation and is fully deployable as a
microservice in an OpenShift cluster. Thanks to the extremely low
startup time—due to the work we did on Drools and the low overhead of
Quarkus—this microservice is fast enough to be deployable in a <a href="https://cloud.google.com/knative/">KNative</a> cloud. You can find the full source code on <a href="https://github.com/kiegroup/submarine-examples">GitHub</a>.</div>
<h2>
Introducing Submarine</h2>
<div class="selectionShareable">
These days, rule engines are seldom a matter of discussion. This is because they <i>just work</i>.
A rule engine is not necessarily antithetical to a cloud environment,
but work might be needed to fit the new paradigm. This was the story of
our journey. We started with courage and curiosity. In the next few
months, we will push this work forward to become more than a simple
prototype, to realize a complete suite of business automation tools
ready for the cloud. The name of the initiative is <b>Submarine, </b>from the famous Dijkstra quote. So, sit tight, and get ready to dive in.<br />
<br />
This article has been originally published on the Red Hat Developer blog <a href="https://developers.redhat.com/blog/2019/03/14/quarking-drools-how-we-turned-a-13-year-old-java-project-into-a-first-class-serverless-component/" target="_blank">here</a></div>
<div class="selectionShareable">
<br /></div>
Mario Fuscohttp://www.blogger.com/profile/05495580929866102756noreply@blogger.com5tag:blogger.com,1999:blog-5869426.post-53733758108342923742018-11-30T11:39:00.000+00:002018-12-06T12:53:10.722+00:00Workbench is now Business Central!<div id="preamble">
<div class="sectionbody">
<div class="paragraph first-letter-capital">
Article originally posted <a href="http://porcelli.me/rhba/business-central/2018/11/29/business-central-consolidation.html" target="_blank">here</a> by Alex Porcelli <br />
<br />
5 years ago, on November 2013 we released <a href="https://search.maven.org/artifact/org.kie/kie-wb/6.0.0.Final/pom" rel="noopener" target="_blank">6.0.0.Final</a>,
that included the first version of the Workbench. It has been a long
journey so far, but today we’re announcing that we’re retiring the
Workbench brand and officially adopting Business Central as the new
brand!</div>
</div>
</div>
<div class="sect1">
<h2 id="historical-context">
Historical Context</h2>
<div class="sectionbody">
<div class="paragraph">
The
KIE group has been developing web tooling for more than a decade now.
The first public release that shipped a browser based tool was <a href="https://search.maven.org/artifact/org.drools/drools-guvnor/5.0.1/war" rel="noopener" target="_blank">5.0.1</a> (May of 2009), but its R&D started way before that.</div>
<div class="admonitionblock tip">
<table><tbody>
<tr><td class="icon"><div class="title">
Tip</div>
</td><td class="content">KIE stands for <b>Knowledge Is Everything</b>, and it is pronounced exactly the word <b>key</b> in English: <i>/kē/</i> .</td></tr>
</tbody></table>
</div>
<div class="paragraph">
The
first experiments of a web-based tool to manage a central repository
for business rules that provided an intuitive user interface to create
and package rules started back in <a href="https://github.com/kiegroup/guvnor/commit/141aabe8b3c2629eb3762e966ebc7de6a5d90a94" rel="noopener" target="_blank">September 2006</a> as jbrms. After a couple of years, it was renamed to <a href="https://github.com/kiegroup/guvnor/tree/0b8044cd73a61b2fb0283e3ca880d1e38231d126" rel="noopener" target="_blank">Guvnor</a>, and this is the name that would become known as the official name of our first web tooling.<br />
<br /></div>
<div class="imageblock" id="img-guvnor" style="text-align: center;">
<div class="content">
<img alt="guvnor" src="http://porcelli.me/images/blog/guvnor.png" /></div>
<div class="title">
Figure 1. Guvnor Guided Rule Editor User Interface.</div>
</div>
<div class="paragraph">
<br />
The next generation that became known as Workbench started its R&D in <a href="https://github.com/AppFormer/uberfire/tree/5c9a67e9eb6cce2e27a96d2fa3c272f0fbdbb33c" rel="noopener" target="_blank">May of 2012</a> with multiple goals and challenges that could be summarized in the following major two key points:</div>
<div class="ulist">
<ul>
<li>A modular, plug-in based, composable tooling, to avoid the single project/repo that Guvnor became over the years</li>
<li>A Virtual File System based storage, to avoid getting stuck with a technology like <a href="https://www.jcp.org/en/jsr/detail?id=170" rel="noopener" target="_blank">JCR</a><br />
</li>
</ul>
</div>
<div class="imageblock" id="img-workbench" style="text-align: center;">
<div class="content">
<img alt="workbench" src="http://porcelli.me/images/blog/workbench.png" /></div>
<div class="title">
Figure 2. Workbench Original NSEW Compass Drag-and-Drop</div>
</div>
<div class="paragraph">
<br />
If you’re feeling nostalgic, you can play <a href="https://www.youtube.com/watch?v=ckAznbOOV-4" rel="noopener" target="_blank">this </a>
video, and get back to May of 2013, a few months before the release.
But if you have time, and want to see how our fresh released second
generation looked like in practice, you have a full <a href="https://www.youtube.com/playlist?list=PLb9jQNHBKBRj9IJkc_F5nCJAvXaegOGW8" rel="noopener" target="_blank">playlist</a>.</div>
</div>
</div>
<div class="sect1">
<h2 id="evolution">
Evolution</h2>
<div class="sectionbody">
<div class="paragraph">
The
Workbench has been distributed in two flavors: KIE Drools Workbench and
KIE Workbench. Initially, the KIE Workbench used to be shipped with an
embedded jBPM engine, what made the distributions significantly
different. However, with the KIE-Server release and the engine
unification, the embedded jBPM engine was removed from Workbench, and
the differences between the two distros became just a matter of
show/hide some user interface items.</div>
<div class="paragraph">
It’s
also clear that the current Workbench has very little in common with
its original format. Over the years it not only get more polished and
stable, but the target audience has evolved from a developer focused to a
collaborative platform between practitioners and developers.</div>
<div class="paragraph">
Based
on the above facts and also looking for a more concise branding
strategy a decision was made: unify the distributions and re-brand it as
<b>Business Central</b>!</div>
</div>
</div>
<div class="sect1">
<h2 id="business-central">
Business Central</h2>
<div class="sectionbody">
<div class="paragraph">
So
what’s in the new name? The major positive impact is that we have now a
single distribution and terminology to reference the KIE group web
tooling, that also unifies the product and community terminology.</div>
<div class="paragraph">
Here’s a quick walkthrough of the changes you’ll see in the new Business Central:<br />
<br /></div>
<div class="imageblock" id="img-business-central" style="text-align: center;">
<div class="content">
<img alt="business-central" src="http://porcelli.me/images/blog/new-business-central.gif" height="427" width="640" /></div>
</div>
<div class="sect2">
<h3 id="profiles-and-entitlements">
Profiles and Entitlements</h3>
<div class="paragraph">
By
default Business Central bootstrap with all the features enabled, that
includes Drools, OptaPlanner, and jBPM. However, for those that are not
taking advantage of our jBPM engine, we provide in settings a Profiles
option that allows admins to adjust Business Central to display only the
relevant profile to your needs.</div>
<div class="paragraph">
The default profile can be also be defined in the startup using the <code>org.kie.workbench.profile</code> environment variable with the following possible values:</div>
<div class="ulist">
<ul>
<li>FULL</li>
<li>PLANNER_AND_RULES</li>
<li>FORCE_FULL</li>
<li>FORCE_PLANNER_AND_RULES</li>
</ul>
</div>
<div class="paragraph">
The main difference between the "FORCE_" values is that it will hide the settings configuration, forcing the chosen profile.</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="conclusion">
Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
After
five years, the KIE group has decided that was time to retire the
Workbench brand. Our web tooling evolved quite a lot and the use of the
word Workbench, a common term for developers, didn’t reflect the current
state of it.</div>
<div class="paragraph">
The consolidation and
re-branding to Business Central aims to provide a clear message about
its targeted audience with a concise communication strategy. If you’re
interested in giving it a try, Business Central is available to <a href="https://repository.jboss.org/nexus/content/groups/public/org/kie/business-central/7.15.0.Final/business-central-7.15.0.Final-wildfly14.war" rel="noopener" target="_blank">download</a> today!</div>
</div>
</div>
Mario Fuscohttp://www.blogger.com/profile/05495580929866102756noreply@blogger.com80tag:blogger.com,1999:blog-5869426.post-85362303855839446892018-10-18T18:46:00.000+01:002018-10-18T20:29:11.181+01:00New DMN Editor Preview<p>
The Workbench 7.13.0.Final was released Tuesday, October 16, and this version brings a lot of interesting features and important fixes. One of the highlights is the new DMN Editor as a tech preview feature that is still under development but that you can begin using.
</p>
<p>
In this article, you'll learn how to enable the DMN Editor Preview, create a simple DMN model, and execute it via a REST API.
</p>
<p>
Let's get started :-)
</p>
<h3>1) Enabling the Preview editor</h3>
<p>
Since the feature is available as a tech preview, it's hidden by default. To enable it, go to <code>Settings -> Roles</code>, select the role you're logged in (for example, "admin") and remove the "DMN Designer" exception in the "Permissions" section. Take a look at the steps:
</p>
<div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilB9iuT21r1E0y8AhqDE0oRSwNdxhXr26omH3MH-wFbVVtqOJab7huhF3D9MRN8l_oiqbygjKlExT0sWp_5ds_G8b1k_LpdxaVXsJ1pUx-rRHDi-9MVRc6xPmVsYD7aMaXAYBncQ/s1600/steps.gif" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilB9iuT21r1E0y8AhqDE0oRSwNdxhXr26omH3MH-wFbVVtqOJab7huhF3D9MRN8l_oiqbygjKlExT0sWp_5ds_G8b1k_LpdxaVXsJ1pUx-rRHDi-9MVRc6xPmVsYD7aMaXAYBncQ/s1600/steps.gif" width="80%" data-original-width="1600" data-original-height="1007" /></a>
</div>
<br />
<h3>2) Creating a DMN model</h3>
<p>
Now that you have the DMN Editor enabled, let's create a new project: Go to "Projects", click on "Add asset" and then open the "DMN Preview". Here you can explore the editor and create your DMN file with your own rules or you can follow the steps provided by this video:
</p>
<iframe width="80%" height="315" src="https://www.youtube.com/embed/USok3wjCQHU" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<p>
Notice that two input nodes ("Number of branches" and "Branches dispersion") and one decision node ("Branches distribution") were inserted. Additionally, we created a Decision Table in the "Branches distribution" node to write some rules.
</p>
<p>
The DMN file created in the video can be downloaded <a href="https://gist.github.com/karreiro/f1b862396a544620fbc14df694348478">here</a>.
</p>
<h3>3) Executing the DMN model</h3>
<p>
With the DMN file created and saved, it's time to deploy the DMN model. Go to <code>Projects -> Your project</code> and click on "Deploy" to deploy your project in a KIE Server. Now, access your instance with the "/dmn" suffix, in my case the URL is:
<a href="http://localhost:8080/kie-server/services/rest/server/containers/DMNSample_1.0.0/dmn">http://localhost:8080/kie-server/services/rest/server/containers/DMNSample_1.0.0/dmn</a>.
</p>
<p>
If you follow the steps above correctly, you'll see something like this:
</p>
<div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTx3B4hqAzf0bJer4UaAeUUQhe1wrQHbTS9KCzuQCgt4V08_sjnCMrEugVBgmIF_9qYGs4JY_6JTPDVI0wCL0rdHkjcGHoAMRT3qCRv2kmrsL_FSk9A02M2qzX9jADMsGw6r5Mng/s1600/response.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTx3B4hqAzf0bJer4UaAeUUQhe1wrQHbTS9KCzuQCgt4V08_sjnCMrEugVBgmIF_9qYGs4JY_6JTPDVI0wCL0rdHkjcGHoAMRT3qCRv2kmrsL_FSk9A02M2qzX9jADMsGw6r5Mng/s1600/response.png" width="80%" data-original-width="1600" data-original-height="1009" /></a>
</div>
<br />
<p>
Notice the <code>model-namespace</code> and the <code>model-name</code> values, they will be useful in the next step.
</p>
<p>
Now, we can make requests to execute rules in our KIE Server instance. See the example below:
</p>
<script src="https://gist.github.com/karreiro/b09c9aa6b6339c95f18233b10b5460ed.js"></script>
<p>
Replace the URL, the <code>model-namespace</code> and the <code>model-name</code> with your own information, and try it locally. The rules will be executed by the KIE Server with the DMN model you've created, and the response will be something like this:
</p>
<script src="https://gist.github.com/karreiro/a19e77b9d23bbd0efd497ee379d2d9fd.js"></script>
<p>
This article describes a small part of all the functionality of the DMN Editor. You can write even more complex rules by applying different structures. If you want to read more about the DMN specification, see the <a href="http://blog.athico.com/2018/04/the-dmn-cookbook-is-published.html">DMN Cookbook</a>.
</p>
<p>
The DMN Editor is still under development. New features and enhancements are to come. Stay tuned ;-)
</p>
Unknownnoreply@blogger.com11tag:blogger.com,1999:blog-5869426.post-34278413675760220572018-10-17T15:09:00.001+01:002018-10-17T15:09:28.577+01:00Last call for DMN webinar on October 18, 2018Are you interested to know more on how Drools provides an open source execution engine with full DMN support at conformance level 3? This is your last change to register for tomorrow's <a href="https://middlewareblog.redhat.com/2018/09/27/decision-model-notation-a-new-approach-to-business-rules/" target="_blank">free webinar</a> presented by <span class="author-wrap"><span class="byline"><span class="author vcard">Phil Simpson and </span></span></span><span class="author-wrap"><span class="byline"><span class="author vcard">Denis Gagne </span></span></span><span class="author-wrap"><span class="byline"><span class="author vcard"><span class="author-wrap"><span class="byline"><span class="author vcard">on October 18 at 1pm ET.</span></span></span></span></span></span><br />
<br />
<span class="author-wrap"><span class="byline"><span class="author vcard"><span class="author-wrap"><span class="byline"><span class="author vcard">Don't miss it! </span></span></span></span></span></span>Mario Fuscohttp://www.blogger.com/profile/05495580929866102756noreply@blogger.com0tag:blogger.com,1999:blog-5869426.post-46358306717093372952018-10-09T21:49:00.001+01:002018-10-09T21:49:06.396+01:00Early video of #jBPM Case ModellerEarly video of #jBPM Case Modeller :) UX and L&F improvements to come <a href="https://youtu.be/AjSSKdbM_Ns">https://youtu.be/AjSSKdbM_Ns </a><br /><br />
<br /><br />
<iframe allowfullscreen="" frameborder="0" height="270" src="https://www.youtube.com/embed/AjSSKdbM_Ns" width="480"></iframe>Mark Proctorhttp://www.blogger.com/profile/03304277188725220501noreply@blogger.com1tag:blogger.com,1999:blog-5869426.post-75652388045604225232018-10-02T16:27:00.001+01:002018-10-02T16:29:57.933+01:00DMN webinar on October 18, 2018<br />
Rule engines are a powerful yet flexible tool to define and implement huge sets of business requirements and constraints. While Drools Rule Language (DRL) may be appealing to define business rules for technically savvy domain experts, a new visual based standard has emerged in the Decision Management space to bridge the gap between technical and business analyst: the Object Management Group published in 2015 the Decision Model & Notation, a specification for a
graphical decision language, expressly designed for business users.<br />
<br />
Drools provides an open source execution engine with full DMN support at conformance level 3. If you're curious to know more about this there's no better way than joining <span class="author-wrap"><span class="byline"><span class="author vcard">Phil Simpson and </span></span></span><span class="author-wrap"><span class="byline"><span class="author vcard">Denis Gagne </span></span></span><span class="author-wrap"><span class="byline"><span class="author vcard">in his</span></span></span> <a href="https://middlewareblog.redhat.com/2018/09/27/decision-model-notation-a-new-approach-to-business-rules/" target="_blank">free webinar</a> <span class="author-wrap"><span class="byline"><span class="author vcard">on October 18 at 1pm ET</span></span></span> where he will explore in details the features of this new standard.<br />
Mario Fuscohttp://www.blogger.com/profile/05495580929866102756noreply@blogger.com0tag:blogger.com,1999:blog-5869426.post-86693459116414423872018-07-09T19:09:00.000+01:002018-07-09T19:27:32.735+01:00Mario Fusco is the new Drools Project Lead<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwkISTgnH-YZ13Mr85pxhdR6zQrwm3Ies5WCaZ80RV6wNzE2eGMWAyZJ37B8t0FgWV62COV1c8X5eDwPAIbTT7_LSqsIe7CjgW8NcvnO4tIGPrXOd3wn_qhkJxjnNCt0wbOKn0/s1600/mario_fusco.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="256" data-original-width="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwkISTgnH-YZ13Mr85pxhdR6zQrwm3Ies5WCaZ80RV6wNzE2eGMWAyZJ37B8t0FgWV62COV1c8X5eDwPAIbTT7_LSqsIe7CjgW8NcvnO4tIGPrXOd3wn_qhkJxjnNCt0wbOKn0/s1600/mario_fusco.jpg" /></a></div>
It is my honor to announce that <a href="https://www.linkedin.com/in/mario-fusco-3467213/" target="_blank">Mario Fusco</a> will be taking over as the new Drools Project Lead.<br />
<br />
Mario is a Principal Software Engineer at Red Hat, working on the development of the Drools core. He has vast experience as a Java developer, and among other accomplishments, was <a href="https://blogs.oracle.com/java/new-java-champion-mario-fusco" target="_blank">nominated a Java Champion in 2016</a>. Mario previously created and led the open source Lambdaj project and has been involved in (and often leads) many enterprise-level projects in several industries ranging from media companies to the financial sector.<br />
<br />
Mario is a frequent speaker at conferences, like the Red Hat Summit, Devoxx, Voxxed, JavaOne, LambaWorld and others. Mario authored several articles for InfoQ and DZone, and co-authored the “<a href="https://www.manning.com/books/java-8-in-action" target="_blank">Java 8 in Action</a>” book published by Manning. His <a href="https://www.manning.com/books/java-8-in-action" target="_blank">tweeter following</a> is another hint at his popularity, and if you would like to keep up with his latest insights, I suggest you hit that button.<br />
<br />
Mario joined Red Hat in 2011 to work on the core engine of Drools and has since made invaluable contributions, including the development and improvement of the latest core algorithm. Among his interests are also functional programming and domain specific languages.<br />
<br />
If you ever have the opportunity to interact with him in person, you will experience firsthand how nice of a person he is and how pleasant it is to have a talk with him. You can even offer him a beer, he will like that, but whatever you do, make sure you follow proper Italian etiquette (or is that Mario’s etiquette?): no pineapple on your pizza and no cappuccinos after meals.<br />
<br />
Please join me in congratulating Mario on his new role as the Drools Project lead.<br />
<br />
Edson Tirelli<br />
<br />
<br />Edson Tirellihttp://www.blogger.com/profile/06799293335230465902noreply@blogger.com6tag:blogger.com,1999:blog-5869426.post-68026084971750638062018-04-18T19:25:00.000+01:002018-04-18T19:29:37.579+01:00The DMN Cookbook has been published<div class="separator" style="clear: both; text-align: center;">
<a href="https://methodandstyle.com/wp-content/uploads/dmncookbook-1-400x491.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="491" data-original-width="400" height="320" src="https://methodandstyle.com/wp-content/uploads/dmncookbook-1-400x491.jpg" width="260" /></a></div>
The Decision Model and Notation (DMN) Standard offers something no previous attempt at standardization of decision modelling did: a simple, graphical effective language for the documentation and modelling of business decisions. It defines both the syntax and the semantics of the model, allowing IT and Business teams to "speak the same language". It also ensures interoperability between vendor tools that support the standard, and protect customer's investment and IP.<br />
<br />
It was an honour to work with accomplished author <a href="https://methodandstyle.com/" target="_blank">Bruce Silver</a> to write the "<a href="https://methodandstyle.com/dmn-cookbook/" target="_blank">DMN Cookbook</a>", a book that explains the features of the standard by examples, showing solutions for real modelling problems. It discusses what DMN offers that is different from traditional rules authoring languages, as well as how to leverage its features to create robust solutions.<br />
<br />
Topics covered include:<br />
<br />
<div class="content-container" style="-webkit-text-stroke-width: 0px; box-sizing: border-box; color: #747474; font-family: "PT Sans", Arial, Helvetica, sans-serif; font-size: 13px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin-bottom: 20px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;">
<ul style="box-sizing: border-box;">
<li style="box-sizing: border-box;">What is DMN?</li>
<li style="box-sizing: border-box;">How DMN differs from traditional rule languages</li>
<li style="box-sizing: border-box;">DMN Basics<ul style="box-sizing: border-box;">
<li style="box-sizing: border-box;">DRG elements and DRDs</li>
<li style="box-sizing: border-box;">Decision tables and other boxed expressions</li>
<li style="box-sizing: border-box;">FEEL</li>
</ul>
</li>
<li style="box-sizing: border-box;">Decision services</li>
<li style="box-sizing: border-box;">Practical examples</li>
<ul>
<li style="box-sizing: border-box;">Uniform Residential Loan Application: validation, handling null values, handling XML input</li>
<li style="box-sizing: border-box;">GSE Mortgage Eligibility: variations using a central registry</li>
<li style="box-sizing: border-box;">Canadian Sales Tax: variations without a central registry (dynamic and static composition)</li>
<li style="box-sizing: border-box;">Timing the Stock Market: modeling a state chart with DMN</li>
<li style="box-sizing: border-box;">Land Registry: DMN-enhanced Smart Contract</li>
<li style="box-sizing: border-box;">Decision Service Deployment: automated and manual</li>
<li style="box-sizing: border-box;">Decision Service Orchestration: BPMN or Microsoft Flow</li>
</ul>
</ul>
</div>
<br />
More information on the <a href="https://methodandstyle.com/dmn-cookbook/" target="_blank">book website</a>.<br />
<br />
Available on <a href="https://www.amazon.com/dp/0982368186" target="_blank">Amazon</a>.<br />
<br />Edson Tirellihttp://www.blogger.com/profile/06799293335230465902noreply@blogger.com6tag:blogger.com,1999:blog-5869426.post-13487255760152678972018-04-18T16:50:00.001+01:002018-04-18T18:07:08.113+01:00bpmNext 2018 day 1 videos are already online!The organization of <a href="http://bpmnext.com/" target="_blank">bpmNEXT 2018</a> is outdoing themselves! The videos from the first day of the conference are already available.<br />
<br />
In particular, the presentations from Denis Gagné, Bruce Silver and Edson Tirelli are directly related to Drools with content related to DMN. I also recommend the presentation from Vanessa Bridge, as it is related to BPM and the research we've been doing on blockchain.<br />
<br />
<br />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">Smarter Contracts with DMN: Edson Tirelli, Red Hat </b><a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/tdpZgbQbF9Q&source=gmail&ust=1524149143349000&usg=AFQjCNHrw6kWC9xtTRY6TI1NnZbkojTjdg" href="https://youtu.be/tdpZgbQbF9Q" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/tdpZgbQbF9Q</a><br />
<br style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;" />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">Timing the Stock Market with DMN: Bruce Silver, <a data-saferedirecturl="https://www.google.com/url?hl=en&q=http://methodandstyle.com&source=gmail&ust=1524149143349000&usg=AFQjCNGsCuJX7JRVtDIPrApn71NAYKUuLQ" href="http://methodandstyle.com/" style="color: #1155cc;" target="_blank">methodandstyle.com</a> </b><a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/vHCIC1HGbHQ&source=gmail&ust=1524149143349000&usg=AFQjCNFPSgrH0YY_1GUKU_9ZHfvpKjj_eg" href="https://youtu.be/vHCIC1HGbHQ" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/vHCIC1HGbHQ</a><br />
<br style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;" />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">Decision as a Service (DaaS): The DMN Platform Revolution: Denis Gagné, Trisotech </b><a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/sYAIcBhVhIc&source=gmail&ust=1524149143350000&usg=AFQjCNEYn4bfBWzvB16Poid-YIqXEhlTqA" href="https://youtu.be/sYAIcBhVhIc" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/sYAIcBhVhIc</a><br />
<br />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">Secure, Private, Decentralized Business Processes for Blockchains: Vanessa Bridge, ConsenSys </b><br />
<a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/oww8zMzxvZA&source=gmail&ust=1524149143349000&usg=AFQjCNGp4DTjz9zJim3VWMBC6jBADOElsg" href="https://youtu.be/oww8zMzxvZA" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/oww8zMzxvZA</a><br />
<br style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;" />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">The Future of Process in Digital Business: Jim Sinur, Aragon Research </b><a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/iBJBbXeVYUA&source=gmail&ust=1524149143349000&usg=AFQjCNHYueURWpzaf3iu_bqYeunExR63Pw" href="https://youtu.be/iBJBbXeVYUA" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/iBJBbXeVYUA</a><br />
<br style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;" />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">A New Architecture for Automation: Neil Ward-Dutton, MWD Advisors </b><a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/-AeijpL4b98&source=gmail&ust=1524149143349000&usg=AFQjCNFCTUPNqsUwEGzPC5ch8mG-GVCUwQ" href="https://youtu.be/-AeijpL4b98" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/-AeijpL4b98</a><br />
<br style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;" />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">Turn IoT Technology into Operational Capability: Pieter van Schalkwyk, XMPro </b><a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/G7C01e8qyac&source=gmail&ust=1524149143349000&usg=AFQjCNHomOSLolue57guxlGp2OUmE_vA2A" href="https://youtu.be/G7C01e8qyac" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/G7C01e8qyac</a><br />
<br style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;" />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">Business Milestones as Configuration: Joby O'Brien and Scott Menter, BPLogix </b><a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/D_heO33fyC0&source=gmail&ust=1524149143349000&usg=AFQjCNG-SCjAtu0Uk-lF-GywzgN2h7trBg" href="https://youtu.be/D_heO33fyC0" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/D_heO33fyC0</a><br />
<br style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;" />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">Designing the Data-Driven Company: Elmar Nathe, MID GmbH </b><a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/zb__xVsOEA0&source=gmail&ust=1524149143350000&usg=AFQjCNH3wu7eWkQlw8V9fCMML6Unjhh8KQ" href="https://youtu.be/zb__xVsOEA0" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/zb__xVsOEA0</a><br />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;"><br />Using Customer Journeys to Connect Theory with Reality: Till Reiter and Enrico Teterra, Signavio </b><br />
<a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/ov0SqJCMmoY&source=gmail&ust=1524149143350000&usg=AFQjCNF8IFtLFABi7OVrSu2BLTePYAwQoQ" href="https://youtu.be/ov0SqJCMmoY" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/ov0SqJCMmoY</a><br />
<br style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;" />
<b style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">Discovering the Organizational DNA: Jude Chagas Pereira, IYCON; Frank Kowalkowski, KCI </b><a data-saferedirecturl="https://www.google.com/url?hl=en&q=https://youtu.be/NsCDgKPsTCs&source=gmail&ust=1524149143350000&usg=AFQjCNEKTZqJThUFSdWwyah-PskzLS22RA" href="https://youtu.be/NsCDgKPsTCs" style="background-color: white; color: #1155cc; font-family: arial, sans-serif; font-size: 12.8px;" target="_blank">https://youtu.be/NsCDgKPsTCs</a><br />
<div>
<br /></div>
<div>
Enjoy!</div>
<div class="yj6qo" style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
</div>
Edson Tirellihttp://www.blogger.com/profile/06799293335230465902noreply@blogger.com2tag:blogger.com,1999:blog-5869426.post-79648429642711095862018-02-26T15:29:00.000+00:002018-02-26T15:29:57.183+00:00The Drools Executable Model is alive<h3>
Overview</h3>
The purpose of the executable model is to provide a pure Java-based representation of a rule set, together with a convenient Java DSL to programmatically create such model. The model is low level and designed for the user to provide all the information it needs, such as the lambda’s for the index evaluation. This keeps it fast and avoids building in too many assumptions at this level. It is expected higher level representations can layer on in the future, that may be more end-user focused. This work also highly compliments the unit work, which provides a java-oriented way to provide data and control orchestration.<br />
<br />
<h3>
Details</h3>
This model is generic enough to be independent from Drools but can be compiled into a plain Drools knowledge base. For this reason the implementation of the executable model has been split in 2 subprojects:<br />
<ol>
<li><b>drools-canonical-model</b> is the canonical representation of a rule set model which is totally independent from Drools</li>
<li><b>drools-model-compiler</b> compiles the canonical model into Drools internal data structures making it executable by the engine</li>
</ol>
The introduction of the executable model brings a set of benefits in different areas:<br />
<ul>
<li><b>Compile time</b>: in Drools 6 a kjar contained the list of drl files and other Drools artifacts defining the rule base together with some pre generated classes implementing the constraints and the consequences. Those drl files needed to be parsed and compiled from scratch, when the kjar is downloaded from the Maven repository and installed in a KieContainer, making this process quite slow especially for large rules sets. Conversely it is now possible to package inside the kjar the Java classes implementing the executable model of the project rule base and recreate the KieContainer and its KieBases out of it in a much faster way. The kie-maven-plugin automatically generates the executable model sources from the drl files during the compilation process.</li>
<li><b>Runtime</b>: in the executable model all constraints are defined as Java lambda expressions. The same lambdas are also used for constraints evaluation and this allows to get rid of both mvel for interpreted evaluation and the jitting process transforming the mvel-based constraints in bytecode, resulting in a slow warming up process.</li>
<li><b>Future research</b>: the executable model will allow to experiment new features of the rule engine without the need of encoding them in the drl format and modify the drl parser to support them. </li>
</ul>
<br />
<ul>
</ul>
<h3>
Executable Model DSLs</h3>
One goal while designing the first iteration of the DSL for the executable model was to get rid of the notion of pattern and to consider a rule as a flow of expressions (constraints) and actions (consequences). For this reason we called it Flow DSL. Some examples of this DSL are available <a href="https://github.com/kiegroup/drools/blob/master/drools-model/drools-model-compiler/src/test/java/org/drools/modelcompiler/FlowTest.java#L134" target="_blank">here</a>. <br />
However after having implemented the Flow DSL it became clear that the decision of avoiding the explicit use of patterns obliged us to implement some <a href="https://github.com/kiegroup/drools/blob/master/drools-model/drools-canonical-model/src/main/java/org/drools/model/impl/ViewFlowBuilder.java" target="_blank">extra-logic</a> that had both a complexity and a performance cost, since in order to properly recreate the data structures expected by the Drools compiler it is necessary to put together the patterns out of those apparently unrelated expressions.<br />
For this reason it has been decided to reintroduce the patterns in a second DSL that we called <a href="https://github.com/kiegroup/drools/blob/master/drools-model/drools-model-compiler/src/test/java/org/drools/modelcompiler/PatternDSLTest.java#L87" target="_blank">Pattern DSL</a>. This allowed to bypass that algorithm grouping expressions that has to fill an artificial semantic gap and that is also time consuming at runtime. <br />
We believe that both DSLs are valid for different use cases and then we decided to keep and support both. In particular the Pattern DSL is safer and faster (even if more verbose) so this will be the DSL that will be automatically generated when creating a kjar through the kie-maven-plugin. Conversely the Flow DSL is more succinct and closer to the way how an user may want to programmatically define a rule in Java and we planned to make it even less verbose by generating in an automatic way through a post processor the parts of the model defining the indexing and property reactivity. In other terms we expect that the Pattern DSL will be written by machines and the Flow DSL eventually by human.<br />
<br />
<br />
<h3>
</h3>
<h3>
Programmatic Build</h3>
As evidenced by the test cases linked in the former section it is possible to programmatically define in Java one or more rules and then add them to a Model with a fluent API<br />
<br />
<pre class="brush: java">Model model = new ModelImpl().addRule( rule );</pre>
<br />
Once you have this model, which as explained is totally independent from Drools algorithms and data structures, it’s possible to create a KieBase out of it as it follows<br />
<br />
<pre class="brush: java">KieBase kieBase = KieBaseBuilder.createKieBaseFromModel( model );</pre>
<br />
Alternatively, it is also possible to create an executable model based kieproject by starting from plain drl files, adding them to a KieFileSystem as usual<br />
<br />
<pre class="brush: java">KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem()
.write( "src/main/resources/r1.drl", createDrl( "R1" ) );
KieBuilder kieBuilder = ks.newKieBuilder( kfs );</pre>
<br />
and then building the project using a new overload of the buildAll() method that accepts a class specifying which kind of project you want to build<br />
<br />
<pre class="brush: java">kieBuilder.buildAll( ExecutableModelProject.class );</pre>
<br />
Doing so the KieBuilder will generate the executable model (based on the Pattern DSL) and then the resulting KieSession<br />
<br />
<pre class="brush: java">KieSession ksession = ks.newKieContainer(ks.getRepository()
.getDefaultReleaseId())
.newKieSession();</pre>
<br />
will work with lambda expression based constraint as described in the first section of this document. In the same way it is also possible to generate the executable model from the Flow DSL by passing a different project class to the KieBuilder<br />
<br />
<pre class="brush: java">kieBuilder.buildAll( ExecutableModelFlowProject.class );</pre>
<br />
but, for what explained when discussing the 2 different DSLs, it is better to use the pattern-based one for this purpose.<br />
<br />
<h3>
Kie Maven Plugin</h3>
In order to generate a kjar embedding the executable model using the kie-maven-plugin it is necessary to add the dependencies related to the two formerly mentioned projects implementing the model and its compiler in the pom.xml file:<br />
<br />
<pre class="brush: java"><dependencies>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-model-compiler</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-canonical-model</artifactId>
</dependency>
</dependencies>
</pre>
<br />
also add the plugin to the plugin section<br />
<br />
<pre class="brush: java"><build>
<plugins>
<plugin>
<groupId>org.kie</groupId>
<artifactId>kie-maven-plugin</artifactId>
<version>${project.version}</version>
<extensions>true</extensions>
</plugin>
</plugins>
</build>
</pre>
An example of a pom.xml file already prepared to generate the executable model is available <a href="https://github.com/kiegroup/droolsjbpm-integration/blob/master/kie-maven-plugin-example/pom.xml" target="_blank">here</a>. By default the kie-maven-plugin still generates a drl based kjar, so it is necessary to run the plugin with the following argument:<br />
<br />
<pre class="brush: java">-DgenerateModel=<VALUE></pre>
Where <VALUE> can be one of three values:<br />
<br />
<pre class="brush: java">YES
NO
WITHDRL</pre>
<br />
Both YES and WITHDRL will generate and add to the kjar use the Java classes implementing the executable model corresponding to the drl files in the original project with difference that the first will exclude the drl files from the generated kjar, while the second will also add them. However in this second case the drl files will play only a documentation role since the KieBase will be built from the executable model regardless.<br />
<br />
<h3>
Future developments</h3>
As anticipated one of the next goal is to make the DSLs, especially the flow one, more user friendly, in particular generating with a post-processor all the parts that could be automatically inferred, like the ones related to indexes and property reactivity. <br />
Orthogonally from the executable model we improved the modularity and orchestration of rules especially through the work done on <a href="http://docs.jboss.org/drools/release/7.5.0.Final/drools-docs/html_single/#_rule_units_2" target="_blank">rule units</a>, This focus around pojo-ification compliments this direction of research around pure java DSLs and we already have a few <a href="https://github.com/kiegroup/drools/blob/master/drools-model/drools-model-compiler/src/test/java/org/drools/modelcompiler/RuleUnitTest.java" target="_blank">simple examples</a> of how executable model and rule units can be mixed to this purpose.<br />
Mario Fuscohttp://www.blogger.com/profile/05495580929866102756noreply@blogger.com20tag:blogger.com,1999:blog-5869426.post-11685803955613716352018-02-07T15:25:00.000+00:002018-02-07T15:25:16.414+00:00Running multi Workbench modules on the latest IntelliJ Idea with live reloading (client side)<i><br /></i>
<i>NOTE: The instructions below apply only to the old version of the <span style="font-family: "courier new" , "courier" , monospace;">gwt-maven-plugin</span></i><br />
<br />
At some point in the past, IntelliJ released an update that made it impossible to run the Workbench using the GWT plugin. After exchanging ideas with people on the team and summing up solutions, some workarounds have emerged. This guide provides information to running any Errai-based applications in the latest version of IntelliJ along with other modules to take advantage of IntelliJ's (unfortunately limited) live reloading capabilities to speed the development workflow.<br />
<br />
<br />
<h3>
Table of contents</h3>
<br />
<b>1.</b> Running Errai-based apps in the latest IntelliJ<br />
<b>2.</b> Importing other modules and use live reload for client side code<br />
<b>3.</b> Advanced configurations<br />
<b><span style="white-space: pre;"> 3.</span>1.</b> Configuring your project's <span style="font-family: "courier new" , "courier" , monospace;">pom.xml</span> to download and unpack Wildfly for you<br />
<span style="white-space: pre;"> <b>3.</b></span><b>2.</b> Alternative workaround for non-patched Wildfly distros<br />
<br />
<br />
<br />
<h3>
1. Running Errai-based apps in the latest IntelliJ</h3>
<br />
As Max Barkley described on #logicabyss a while ago, IntelliJ has decided to hardcode <span style="font-family: "courier new" , "courier" , monospace;">gwt-dev</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> </span>classes to the classpath when launching Super Dev Mode in the GWT plugin. Since we're using the <span style="font-family: "courier new" , "courier" , monospace;">EmbeddedWildflyLauncher</span> to deploy the Workbench apps, these dependencies are now deployed inside our Wilfdfly instance. Nothing too wrong with that except the fact that <span style="font-family: "courier new" , "courier" , monospace;">gwt-dev</span> jar depends on <span style="font-family: "courier new" , "courier" , monospace;">apache-jsp</span>, which has a <span style="font-family: "courier new" , "courier" , monospace;">ServletContainerInitializer</span> marker file that causes the deploy to fail.<br />
<br />
To solve that issue, the code that looks to the <span style="font-family: "courier new" , "courier" , monospace;">ServletContainerIntitilizer</span> file and causes the deploy to fail was removed in custom patched versions of Wildfly that are available in Maven Central under the <span style="font-family: "courier new" , "courier" , monospace;">org.jboss.erra</span>i group id.<br />
<br />
The following steps provide a quick guide to running any Errai-based application on the latest version of IntelliJ.<br />
<br />
<br />
<b>1.</b> Download a patched version of Wildfly and unpack it into any directory you like<br />
<span style="white-space: pre;"> </span>- For Wildfly 11.0.0.Final go <a href="https://search.maven.org/#artifactdetails%7Corg.jboss.errai%7Cwildfly-dist%7C11.0.0.Final%7Cjar">here</a><br />
<br />
<b>2.</b> Import the module you want to work on (I tested with <span style="font-family: "courier new" , "courier" , monospace;">drools-wb</span>)<br />
<span style="white-space: pre;"> </span>- Open IntelliJ, go to <span style="font-family: "courier new" , "courier" , monospace;">File -> Open..</span> and select the <span style="font-family: "courier new" , "courier" , monospace;">pom.xml</span> file, hit <span style="font-family: "courier new" , "courier" , monospace;">Open</span> then choose <span style="font-family: "courier new" , "courier" , monospace;">Open as Project</span><br />
<br />
<b>3.</b> Configure the GWT plugin execution like you normally would on previous versions of IntelliJ<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/x9UoSTS.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="623" data-original-width="800" height="498" src="https://i.imgur.com/x9UoSTS.png" width="640" /></a></div>
<span style="white-space: pre;"> </span><br />
<span style="white-space: pre;"> </span>- VM Options:<br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>-Xmx6144m</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> -Xms2048m</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>-Dorg.uberfire.nio.git.dir=/tmp/drools-wb</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>-Derrai.jboss.home=/Users/tiagobento/drools-wb/drools-wb-webapp/target/wildfly-11.0.0.Final</span><br />
<span style="white-space: pre;"> </span><br />
<span style="white-space: pre;"> </span><br />
<span style="white-space: pre;"> </span>- Dev Mode parameters:<br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>-server org.jboss.errai.cdi.server.gwt.EmbeddedWildFlyLauncher</span><br />
<br />
<br />
<b>4.</b> Hit the Play button and wait for the application to be deployed<br />
<br />
<br />
<h3>
2. Importing other modules and using live reload for client side code</h3>
<br />
After being able to run a single webapp inside the latest version of IntelliJ, it might be very useful to have some of its dependencies be imported as well, so that after changing client-code on that dependency, you don't have to wait (way) too long for GWT to compile and bundle your application's JavaScript code again.<br />
<br />
Simply go to <span style="font-family: "courier new" , "courier" , monospace;">File > New > Module from existing sources..</span> and choose the <span style="font-family: "courier new" , "courier" , monospace;">pom.xml</span> of the module you want to import.<br />
If you have <span style="font-family: "courier new" , "courier" , monospace;">kie-wb-common</span> or <span style="font-family: "courier new" , "courier" , monospace;">appformer</span> imported alongside with another project, you'll most certainly have to apply a patch in the <span style="font-family: "courier new" , "courier" , monospace;">beans.xml</span> file of your webapp.<br />
<br />
For <span style="font-family: "courier new" , "courier" , monospace;">drools-wb</span> you can download the patch <a href="https://gist.githubusercontent.com/tiagobento/b03544bf22c6c631dc9b5d7c176e77ab/raw/3bac3da08fe478cc9620829a48cef3b6ad5fd134/drools-wb.diff">here</a>. For other projects such as <span style="font-family: "courier new" , "courier" , monospace;">jbpm-wb</span>, <span style="font-family: "courier new" , "courier" , monospace;">optaplanner-wb</span> or <span style="font-family: "courier new" , "courier" , monospace;">kie-wb-distributions</span>, you'll have to essentially do the same thing, but changing the directories inside the .diff file.<br />
<br />
If your webapp is up, hit the Stop button and then hit Play again. Now you should be able to re-compile any code changed inside IntelliJ much faster.<br />
<br />
<br />
<br />
<h3>
3.1. Configuring your project's <span style="font-family: "courier new" , "courier" , monospace;">pom.xml</span> to download and unpack Wildfly for you</h3>
<br />
If you are used to a less manual workflow, you can use the <span style="font-family: "courier new" , "courier" , monospace;">maven-dependency-plugin</span> to download and unpack a Wildfly instance of your choice to any directory you like.<br />
<br />
After you've added the snipped below to <span style="font-family: "times" , "times new roman" , serif;">your</span> <span style="font-family: "courier new" , "courier" , monospace;">pom.xm</span>l file, remember to add a "Run Maven Goal" before the <span style="font-family: "courier new" , "courier" , monospace;">Build</span> of your application in the "Before launch" section of your <span style="font-family: "courier new" , "courier" , monospace;">GWT Configuration</span>. Here I'm using the <span style="font-family: "courier new" , "courier" , monospace;">process-resources</span> phase, but other phases are OK too.<br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> <plugin></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <groupId>org.apache.maven.plugins</groupId></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <artifactId>maven-dependency-plugin</artifactId></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <executions></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <execution></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <id>unpack</id></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <phase>process-resources</phase></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <goals></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <goal>unpack</goal></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> </goals></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <configuration></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <artifactItems></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <artifactItem></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <!-- Using a patched version of Wildfly --></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <groupId>org.jboss.errai</groupId></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <artifactId>wildfly-dist</artifactId></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <version>11.0.0.Final</version></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <type>zip</type></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <overWrite>false</overWrite></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <!-- Unpacking it into /target/wildfly-11.0.0.Final --></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <outputDirectory>${project.build.directory}</outputDirectory></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> </artifactItem></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> </artifactItems></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <skip>${gwt.compiler.skip}</skip></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> </configuration></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> </execution></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> </executions></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> </plugin></span><br />
<br />
<br />
<br />
<h3>
3.2. Alternative workaround for non-patched Wildfly distros</h3>
<br />
If you want to try a different version of Widlfly or if you simply don't want to depend on any patched versions, you can still use official distros and exclude the <span style="font-family: "courier new" , "courier" , monospace;">ServletContainerInitializer</span> file from the <span style="font-family: "courier new" , "courier" , monospace;">apache-jsp </span>jar on your M2_REPO folder.<br />
<br />
If you're working on a Unix system, the following commands should do the job.<br />
<br />
<b>1. </b><span style="font-family: "courier new" , "courier" , monospace;">cd ~/.m2/repository/</span><br />
<br />
<b>2. </b><span style="font-family: "courier new" , "courier" , monospace;">zip -d org/eclipse/jetty/apache-jsp/{version}/apache-jsp-{version}.jar META-INF/services/javax.servlet.ServletContainerInitializer</span><br />
<br />
By excluding it manually from the <span style="font-family: "courier new" , "courier" , monospace;">apache-jsp</span> jar, Maven won't try to download it again after you remove the file. That makes this workaround permanent as long as you don't erase your <span style="font-family: "courier new" , "courier" , monospace;">~/.m2/</span> folder. Keep in mind that if you ever need the <span style="font-family: "courier new" , "courier" , monospace;">apache-jsp</span> jar to have this file back, the best option is to delete the <span style="font-family: "courier new" , "courier" , monospace;">apache-jsp</span> dependency directory and let Maven download it again.<br />
<br />
<br />
New instructions for the new version of the <span style="font-family: "courier new" , "courier" , monospace;">gwt-maven-plugin</span> are to come, stay tunned!<br />
<br />
<br />
<span style="font-family: "times" , "times new roman" , serif;"><br /></span>
<span style="font-family: "times" , "times new roman" , serif;"><br /></span>Tiago Bentohttp://www.blogger.com/profile/14236407827666629993noreply@blogger.com4tag:blogger.com,1999:blog-5869426.post-11585078203811795262017-11-10T18:20:00.000+00:002017-11-10T18:21:58.644+00:00Building Business Applications with DMN and BPMNA couple weeks ago our own Matteo Mortari delivered a joint presentation and live demo with Denis Gagné from <a href="http://www.trisotech.com/" target="_blank">Trisotech</a> at the <a href="http://bpm.com/">BPM.com</a> virtual event.<br />
<br />
During the presentation, Matteo live demo'd a BPMN process and a couple DMN decision models created using the Trisotech tooling and exported to Red Hat BPM Suite for seamless execution.<br />
<br />
Please note that no glue code was necessary for this demo. The BPMN process and the DMN models are natively executed in the platform, no Java knowledge needed.<br />
<br />
Enough talking, hit play to watch the presentation... :)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/C0u3ZDiH3ek/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/C0u3ZDiH3ek?feature=player_embedded" width="320"></iframe></div>
<br />Edson Tirellihttp://www.blogger.com/profile/06799293335230465902noreply@blogger.com11tag:blogger.com,1999:blog-5869426.post-45611162109210341372017-10-12T22:13:00.000+01:002017-10-12T22:21:28.898+01:00<h2>
<span id="docs-internal-guid-8c4fc4af-1269-8104-af7b-fdffcce77d11"><span style="font-family: "arial"; font-size: 26pt; vertical-align: baseline; white-space: pre-wrap;">5 Pillars of a Successful Java Web Application</span></span></h2>
<div>
<div style="text-align: justify;">
<span id="docs-internal-guid-348349d5-1269-ca5c-e6f1-2647144b4318"><span style="font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;">Last week, Alex Porcelli and I had the opportunity to present at JavaOne San Francisco 2017 two talks related to our work: </span><a href="https://speakerdeck.com/ederign/5-pillars-of-a-successful-java-web-application-1" style="text-decoration-line: none;" target="_blank"><span style="background-color: white; color: #1155cc; font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;">"5 Pillars of a Successful Java Web Application</span></a><span style="background-color: white; color: #222222; font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;">” and </span><a href="https://speakerdeck.com/ederign/the-hidden-secret-of-java-open-source-projects" style="text-decoration-line: none;" target="_blank"><span style="background-color: white; color: #1155cc; font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;">The Hidden Secret of Java Open Source Projects</span></a><span style="background-color: white; color: #222222; font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;">.</span></span></div>
<div style="text-align: justify;">
<span style="background-color: white; color: #222222; font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;"><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; vertical-align: baseline;"><br /></span></span></div>
<div style="text-align: justify;">
<span style="background-color: white; color: #222222; font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;"><span id="docs-internal-guid-348349d5-126a-517e-7722-d10f2ec50d05"><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; vertical-align: baseline;">It was great to share our cumulative experience over the years building the workbench and the web tooling for the Drools and jBPM platform and </span><span style="font-family: "arial"; font-size: 11pt; vertical-align: baseline;">both talks had great attendance (250+ people in the room).</span></span></span></div>
<div style="text-align: justify;">
<span style="background-color: white; color: #222222; font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "arial"; font-size: 11pt; vertical-align: baseline;"><br /></span></span></div>
<div style="text-align: center;">
<span style="background-color: white; color: #222222; font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;"><span id="docs-internal-guid-348349d5-126a-f52d-8748-845c280f70b0"><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; vertical-align: baseline;"><img height="451" src="https://lh6.googleusercontent.com/eqbHvLu1kSYeYxxbgijzGrE6qKbR5GZBIdsWDW-UcYoZJMOxyULI4rWRcXbFYnZM-I6jLlDLOkR2eVNSl2p5skLr9fxHGvzZ1g5grMK7jTENIa4g1bRxUHwAP5rXh9YhC7Ti5rOV" style="border: none; transform: rotate(0rad);" width="602" /></span></span></span></div>
<div style="text-align: center;">
<span style="background-color: white; color: #222222; font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;"><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; vertical-align: baseline;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In this series of posts, we’ll detail our "5 Pillars of a Successful Java Web Application”, trying to give you an overview of our research and also a taste of participating in a great event like Java One.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There are a lot of challenges related to building and architecting a web application, especially if you want to keep your codebase updated with modern techniques without throwing away a lot of your code every two years in favor of the latest trendy JS framework.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In our team we are able to successfully keep a 7+ year old Java application up-to-date, combining modern techniques with a legacy codebase of more than 1 million LOC, with an agile, sustainable, and evolutionary web approach. </span></div>
<div style="text-align: center;">
<span style="background-color: white; color: #222222; font-family: "arial"; font-size: 11pt; vertical-align: baseline; white-space: pre-wrap;"><span id="docs-internal-guid-348349d5-126b-cb7d-90c5-9a71a2201ccd"></span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">More than just choosing and applying any web framework as the foundation of our web application, we based our web application architecture on 5 architectural pillars that proved crucial for our platform’s success. Let's talk about them:</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<h3 style="line-height: 1.2; margin-bottom: 16pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: #666666; font-family: "arial"; font-size: 15pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">1st Pillar: Large Scale Applications</span></h3>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The first pillar is that every web application architecture should be concerned about the potential of becoming a long-lived and mission-critical application, or in other words, a large-scale application. Even if your web application is not exactly big like ours (1mi+ lines of web code, 150 sub-projects, +7 years old) you should be concerned about the possibility that your small web app will become a big and important codebase for your business. What if your startup becomes an overnight success? What if your enterprise application needs to integrate with several external systems?</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Every web application should be built as a large-scale application because it is part of a distributed system and it is hard to anticipate what will happen to your application and company in two to five years.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span id="docs-internal-guid-250d0d6e-126c-30e2-88dc-1fff8d5bbc74"><span style="font-size: 11pt; vertical-align: baseline;">And for us, a critical tool for building these kinds of distributed and large-scale applications throughout the years has been </span><span style="font-size: 11pt; font-weight: 700; vertical-align: baseline;">static typing</span><span style="font-size: 11pt; vertical-align: baseline;">.</span></span></span></div>
<h4 style="line-height: 1.2; margin-bottom: 4pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: #434343; font-family: "arial"; font-size: 13.999999999999998pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Static Typing</span></h4>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The debate of static vs. dynamic typing is very controversial. People who advocate in favor of dynamic typing usually argue that it makes the developer's job easier. This is true for certain problems.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However, static typing and a strong type system, among other advantages, simplify identifying errors that can generate failures in production and, especially for large-scale systems, make </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">refactoring</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> more effective.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Every application demands constant refactoring and cleaning. It’s a natural need. For large-scale ones, with codebases spread across multiple modules/projects, this task is even more complex. The confidence when refactoring is related to two factors: test coverage and the tooling that only a static type system is able to provide.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For instance, we need a static type system in order to find all usages of a method, in order to extract classes, and most importantly to figure out at </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">compile time</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if we accidentally broke something.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But we are in web development and JavaScript is the language of the web. How can we have static typing in order to refactor effectively in the browser?</span></div>
<h3 dir="ltr" style="line-height: 1.2; margin-bottom: 4pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: #434343; font-family: "arial"; font-size: 13.999999999999998pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Using a transpiler</span></h3>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A transpiler is a type of compiler that takes the source code of a program written in one programming language as its input and produces equivalent source code in another programming language.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is a well-known Computer Science problem and there are a </span><a href="https://github.com/jashkenas/coffeescript/wiki/list-of-languages-that-compile-to-js" style="text-decoration: none;" target="_blank"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">lot</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> of transpilers that output JavaScript. In a sense, JavaScript is the assembly of the web: the common ground across all the web ecosystems. We, as engineers, need to figure out what is the best approach to deal with JavaScript’s dynamic nature.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A Java transpiler, for instance, takes the Java code and transpiles it to JavaScript at compile time. So we have all the advantages of a statically-typed language, and its tooling, targeting the browser.</span></div>
<h3 dir="ltr" style="line-height: 1.2; margin-bottom: 4pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: #434343; font-family: "arial"; font-size: 13.999999999999998pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Java-to-JavaScript Transpilation</span></h3>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The transpiler that we use in our architecture, is GWT. This choice is a bit controversial, especially because the GWT framework was launched in 2006, when the web was a very different place.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But keep in mind that every piece of technology has its own good parts and bad parts. For sure there are some bad parts in GWT (like the Swing Style Widgets, multiple permutations per browser/language), but keep in mind that for our architecture what we are trying to achieve is static typing on the web, and for this purpose the GWT compiler is </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">amazing</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. </span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Our group is part of GWT steering committee, and the next generation of GWT is all about JUST these good parts. Basically removing or decoupling the early 2000 legacy and keeping only the good parts. In our opinion the best parts of GWT are:</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Java to JavaScript transpiler:</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> extreme JavaScript performance due to compiling optimizations and static typing in the web;</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">java.* emulation: </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">excellent emulation of the main java libraries, providing runtime behavior/consistency;</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<a href="https://speakerdeck.com/ederign/5-pillars-of-a-successful-java-web-application-1?slide=31" style="text-decoration: none;" target="_blank"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">JS Interop</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">: </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">almost transparent interoperability between Java <-> Javascript. This is a key aspect of the next generation of GWT and the Drools/jBPM platform: embrace and interop (two way) with JS ecosystem.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b id="docs-internal-guid-348349d5-126c-7906-daab-be877dbbcc99" style="font-weight: normal;"><br /></b></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Google is currently working on a new transpiler called J2CL (short for Java-to-Closure, using the Google Closure Compiler) that will be the compiler used in GWT 3, the next major GWT release. The J2CL transpiler has a different architecture and scope, allowing it to overcome many of the disadvantages of the previous GWT 2 compiler.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><b style="font-weight: normal;"><br /></b></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Whereas the GWT 2 compiler must load the entire AST of all sources (including dependencies), J2CL is not a monolithic compiler. Much like javac, it is able to individually compile source files, using class files to resolve external dependencies, leaving greater potential for incremental compilation.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">These three good parts are great and in our opinion, you should really consider using GWT as a transpiler in your web applications. But keep in mind that the most important point here is that GWT is just </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">our</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> first pillar implementation. You can consider using other transpilers like Typescript, Dart, Elm, ScalaJS, PureScript, or TeaVM.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The key point is that every web application should be handled as a large-scale application, and every large-scale application should be concerned about effective refactoring. The best way to achieve this is using statically-typed languages.</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is the first of three posts about our 5 pillars of successful web applications. Stay tuned for the next ones. </span></div>
<div>
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span> <span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span id="docs-internal-guid-348349d5-1273-9faa-a905-99eed1b7cd7a"><span style="font-family: "arial"; font-size: 11pt; vertical-align: baseline;">[I would like to thank Max Barkley and Alexandre Porcelli for kindly reviewing this article before publication, contribute with the final text and provided great feedback.]</span></span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: 11pt; vertical-align: baseline;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 10pt; text-align: justify;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
</div>
Eder Ignatowiczhttp://www.blogger.com/profile/04762106931598040277noreply@blogger.com45