Showing posts with label Script. Show all posts
Showing posts with label Script. Show all posts

Siebel cScript




Introduction

eScript is Siebel’s de-facto scripting language, but in an alternate universe, Siebel could have called its scripting language cScript, in reference to its C heritage. eScript is based on the ECMA Script standard (from which JavaScript is also based upon), and shares the same C family style syntax, but it also has uncanny similarities to C that are unparalleled by other ECMA Script derivatives.

Here are 5 good reasons, why Siebel could have called its scripting language cScript instead of eScript.

1. Compiled Code

eScript code is compiled, and runs outside of a browser, just like C.

2. Pre-processors

Pre-processor directives tell the compiler to perform specific actions before the code is actually compiled.

A typical C program is constructed like so:

#include <stdio.h>
int main(void)
{
    printf(“hi”);
}

#include is an example of a pre-processor directive.This tells compiler to import the standard IO library and make it available to the program.

Veteran Siebel programmers will also recognise that the same syntax is used in eScript for EAI purposes.

#include "eaisiebel.js"

This pre-processor isn't explicitly documented under the main eScript reference, but it is hidden away under the following section.

Siebel eScript Language Reference > Compilation Error Messages > Preprocessing Error Messages
http://docs.oracle.com/cd/B40099_02/books/eScript/eScript_Troubleshooting6.html#wp1012712

It is also mentioned in

Business Processes and Rules: Siebel Enterprise Application Integration > Data Mapping Using Scripts > EAI Data Transformation
http://docs.oracle.com/cd/B40099_02/books/EAI4/EAI4_DataMapUSScripts3.html

A small caveat. The #include directive can be written in the following two styles in C.

#include <eaisiebel.js>
#include "eaisiebel.js"

The <> brackets tell the compiler to look in a predetermined directory, while the “”(two double quotes) tell the compiler to look in the current directory as the c program, however in Siebel, when the “” is used, Siebel will look in Tools\Scripts\ for the include file. (Siebel v8+)

3. Libraries

In the above code sample under Pre-Processors, we saw the usage of a function called “printf”. printf outputs a formatted to the standard console. This isn’t part of the core C language, but was made available via the include pre-processor directive, which imports this command into the program from standard libraries.

Standard C libraries from stdio.h, stdlib.h, are also available in Siebel, but there’s no need to include them, Siebel has conveniently wrapped these libraries in Siebel and exposed them through the Clib global object.

eg.
Clib.rsprintf – returns a formatted string to the supplied variable.
Clib.fscanf – read data from file stream

The complete Clib object reference can be found here
http://docs.oracle.com/cd/B40099_02/books/eScript/eScript_JSReference109.html

4. Reference Operators

The following example shows how reference operators are used in a C program.

#include &lt;stdio.h>
 
void sub(int* main_int)
{
    *main_int=10;
    printf("Address sub:\t %d\n",&*main_int);
}
 
int main()
{
    int myInt=5;
    printf("Address main:\t %d\n",&myInt);
    printf("Before Value:\t %d\n",myInt);
    sub(&myInt);
    printf("After Value:\t %d\n",myInt);
}
//Results
/*
Address main:    2293340
Before Value:    5
Address sub:     2293340
After Value:     10
*/


In the above code, an int is given the value 5, its address reference in memory is provided to a sub function using a reference operator

sub(&myInt);

The sub function takes this reference, goes to its address in memory, and modifies the original value.

We can the same functionality in eScript with the following code

function sub(&main_int)
{
    main_int=10;
}
 
function main(Inputs, Outputs){
    var myInt=5;
    Outputs.SetProperty("Before Value",myInt);
    sub(myInt);
    Outputs.SetProperty("After Value",myInt);
}
//Results
/*
Before Value:    5
After Value:     10
*/

Note: The reference operator in this case is declared in the sub function input argument. This tells Siebel to treat &main_int as a pointer to the original value, instead of a copy.

5. Memory pointers

Like all relatives, eScript and C share common ancesters. In this case, the commonality is in the sharing of memory pointers.

The following example shows how an invoked C program can modify data inside eScript. This example is sourced from the bookshelf document on SElib
http://docs.oracle.com/cd/B31104_02/books/eScript/eScript_JSReference253.html

In summary, a couple of buffer objects are created.

    var P_CHURN_SCORE = Buffer(8);
    var R_CHURN_SCORE = Buffer(8);


SElib is used to call a DLL, passing in the reference to the buffer

SElib.dynamicLink("jddll.dll", "score", CDECL,
…
    P_CHURN_SCORE,
    R_CHURN_SCORE,
);


The following C snippet, de-references the pointers, and modifies the data at the memory address that was allocated in the above eScript code.

#include 
_declspec(dllexport) int __cdecl
score (…
    double *P_CHURN_SCORE,
    double *R_CHURN_SCORE
{
    *P_CHURN_SCORE = AGE + AVGCHECKBALANCE + AVGSAVINGSBALANCE;
    *R_CHURN_SCORE = CHURN_SCORE + CONTACT_LENGTH + HOMEOWNER;
    return(1);
}


Clib vs eScript

There is an obvious overlap between CLib and eScript functions, which causes some confusion on which is better to use. The recommendation from Siebel, is to use the eScript equivalent over Clib.

The CLib library is useful for OS level operations, and those scenarios where you need to operate at the memory level, but such usage is usually confined to edge cases, otherwise eScript provides a safer and more familiar playground for Siebel professionals.

Conclusion

Siebel designed eScript as a hybrid of ECMA Script and C, providing customers with the (not so well documented) ability to extend eScript beyond its natural abilities. Although everyday configurators may never need to touch the Clib libraries, use pre-process instructions, utilize reference operators or even call custom DLL's, but understanding these advanced features, and recognizing the C heritage provides insights for experienced developers, to maximize, and extend the product beyond its out of the box capabilities.

Finally, as for the great idea of renaming eScript, unfortunately the cScript moniker is already taken (most notably by cscript.exe from MS), but you could also argue the same for 'eScript', which is claimed by these other software companies.

eScript - Eclipse scripting language
http://wiki.eclipse.org/FAQ_What_is_eScript%3F

EScript - C++ Scripting language
http://escript.berlios.de/pmwiki/pmwiki.php

Escript – Python programming tool
https://launchpad.net/escript-finley/

escript – Erlang scripting language
http://www.erlang.org/doc/man/escript.html

eScript.api - This is the name of an Adobe plugin
http://www.processlibrary.com/en/directory/files/escript/403646/

As a consolation, we could designate eScripters who primarily use Clib, cScripters. I think this might catch on =)


Anonymous functions in Siebel

I was on a Project, that was performing an upgrade from Siebel 7 to Siebel 8, and discovered  parts of their Application was implemented using undocumented eScript features. The code was written by graduate web developers, who used their trade to write ECMA compliant code, but unfortunately some of these features were unsupported by Siebel 8.

One such feature was the usage of anonymous functions, which has the following benefits.

* Provides locally scoped variables
* Can be used as a call back function
* Allows better code readability
* Avoids extra named reference on the current scope

Unfortunately anonymous functions, or even function expressions cause a reference error in Siebel 8.


> ReferenceError:':-$753' is not defined

Siebel customers who need a viable substitute have the option of using the Function constructor, which is appropriately documented by Oracle here.
http://docs.oracle.com/cd/B40099_02/books/eScript/eScript_JSReference189.html

Let’s look at a real world scenario to see where this can come in handy.

During development, a Siebel developer might come across the need to enumerate a PropertySet. The following code shows a basic implementation of the enumerator function.


var propName = oPS.GetFirstProperty(), 
propValue ="";
while (propName != "")  {
                propValue = oPS.GetProperty(propName);

                //###  Do something with propName and propValue ###

                propName = oPS.GetNextProperty();
}

I propose that we create a utility for Siebel developers to easily loop over the properties of a single PropertySet level, without the above verbosity, using the following syntax.

1. [<PropertySet> ].psEach( <Callback> )
or
2. util.psEach( <PropertySet>, <Callback> )

The implementation of option 1 is outside the scope of this article, but it can be easily built by customers who already have a familiar construct in their Library.

However option 2 should be a little more familiar to customers who use script libraries in Siebel. util is the name space, or the local reference to a name space from an eScript library. psEach is the logical method that performs the enumeration.

The following diagram shows, how we should use the Function object in this context.


1.       ‘Class_Util_PSNodeEach’ is the literal name for util.psEach.
2.       The PropertySet that we wish to enumerate
3.       A function object that will receive the Name, Value pair.
4.       This function will receive two inputs n, v. This is optional, as the arguments object can be used just as easily.

The following screenshot of The Harness shows the definition of ‘Class_Util_PSNodeEach’, the code that was used to set up the test case, and the expected results.


Line 15. above shows where the magic happens, this API essentially replaces 9 lines 
of code (x the number of times this construct is used in your Application) with 1 line.

Just a friendly reminder that this code has been simplified for illustration purposes, it is not is not production ready or is it 
optimized to be used in the real world.

> new Function("n,v", "log.info(n+' = ' +v " );

The syntax above creates a new function on the fly, which expects an input of "n" and "v". It is invoked by line 5 in the screenshot above, and prints it out using a library method that outputs the result back to the UI. 


This allows us to hide the clunky looping construct that is normally required to enumerate a PropertySet in eScript, and expose a much better API through psEach.

Are there any side effects?

* Code written inside the Function constructor is supplied as a string, which has to be properly escaped

* The function constructor will run in the scope of its instantiated instance. This is normally the current Siebel event handler or Business Service, or the code library where psEach lives, but it could also be the instance of any object created by the new Operator. What this all means is that, the callback function won’t inherit the local scope of your object, and will not have access to your local function’s variables unless they are passed in

* These functions won’t appear in your Siebel eScript object explorer. This could also be an advantage.

In context of the problem that we are trying to solve, the above list doesn't apply, but it should still be taken into consideration if you want to utilize this elsewhere in your Application, and please check with your local eScript architect if you are unsure of the impacts.

Are there any speed difference with either option? Once the function is parsed, it will perform just as well as the function declaration. The following test case shows that with our set up above, there are no discernible speed advantage of using either method.



The Function constructor is possibly one of the most underused features of eScript, but when used in the right way, it can provide your project with the capability to organize, and reduce the amount of code that your developers have to write, test, and maintain. 

Further Reading Topics

Function Constructor JavaScript
Immediately Invoked Function Expressions (IIFE) or
Self Executing Anonymous Functions (SEAF).


eScript: The Siebel Stack

Does your Error Handling framework provide you with a stack trace? People have asked me whether its possible to get the stack trace, or get the name of the function when an error occurs in Siebel. I cautiously say Yes to both, because this method can be easily abused. This article is aimed at the framework designer looking to enhance their project's error handling capabilities.

Respected ex Siebel engineer Mike M Lin, wrote an article on Getting the Call Stack from eScript. In that article, he raises a Siebel exception, and scrapes the error message property to get the call stack. Unfortunately in Siebel 8, Siebel has removed the stack trace information from the error message property when using TheApplication().RaiseErrorText. Siebel has also blocked the ability to enumerate the error object, so the same test case can’t be performed.

According to bookshelf, when an operation fails, Siebel generates an Exception Object. The exception is documented with two properties: errCode, and errText

I’ve taken the Siebel example, added some log statements, and put it through The Harness



We verify that the error is indeed an instance of the Exception Object, and that the Siebel example works.

Next I modify the example to include the two properties that Mike M Lin, identified as part of his test case:

name, message.



Name turns up a blank, and message stores the same value as errText. There is no stack trace in sight, so I try the same test case with TheApplication().RaiseErrorText(), as Mike did, but unfortunately this also produces no stack trace.




Producing the Stack Trace

We can conclude that the Siebel Exception object no longer produces a stack trace, but Siebel Exception objects aren’t the only types of Error objects that are created in eScript. According to the ECMA specifications, which Siebel eScript is based on, there are other types of errors that can be thrown.



In the above example I’ve created a Reference Error, which reveals that the Stack trace is accessible with other error objects within Siebel.



Heres another example, showing the stack trace that is produced with more than 1 function. You'll notice that the stack trace at this point contains a dummy error message, but we'll see how this can be utilised a little later.



Getting The Current Function Name

Getting the stack trace is nice, but it would be great, if we could also get the name of the function that the error occurred in. We can see from the above stack trace, that it would be trivial to write a routine to extract the name of the last function.

The stack trace format is different of the Siebel 7 example, but it's not hard to parse. Heres a quick test case that I put together.



Note: In Siebel 7, the name of the current function can be accessed by "arguments.callee" in eScript, however this has been deprecated in Siebel 8.

Error Object On Steroids

Armed with the above knowledge we can now produce a stack trace at will (even for Siebel generated exceptions), throw back a custom error object containing our stack trace, and log it as part of an Error handling framework.

The concept of throwing a custom error object has been discussed before in ABS Framework - Logging & Tracing Module. The author of the ABS framework has provided some really interesting concepts around error handling, but if we strip away the message lookups, variable bindings, and the bells and whistles, we can take away the concept of throwing custom error objects, and mix it with our idea of generating a custom stack trace, plus extracting the name of the error function.

It can be boiled down to the following steps.

1. Throw an error
2. Check that the error is not an instance of our custom error
3. Cause a stack trace using the method described above
4. Scrape the relevant stack trace information, and ignore the dummy error message
5. Scrape the error function name from the stack trace, also described above
6. Create an instance of custom error with the above data
7. Insert the original error from the real error object into the custom error object
8. Re-throw the custom error
9. At your root function check for the custom error, and log the stack trace, error information


The above steps outline how to create and handle a custom error object. A framework designer can take ownership of it, and incorporate these ideas into your own in-house error handling framework.

Logger Concept

Another complimentary method is to implement a custom script logger. This was also introduced to readers, when we visited the ABS framework logging capability. For a real life example of a logger, Siebel master Mik has kindly shared his design here.

A sample logger template looks like this.


function MyFunction (){
try{
     log.begin("MyFunction");//hard coded function name
}catch(e){
     log.error(e);
}finally{
     log.end();}
}


Every function would contain the above template, in which a custom logger is called with 3 main methods.

log.begin - Pushes a string of the current function name onto a custom stack
log.end - Pops the last function from the stack.
log.error - Logs the error

When an error occurs, you know that the last function in the stack is where the error occurred, and by its very nature, the custom stack can be simply printed out, as it is just an ordinary array.

The downsides of this technique against the one described above is that it does not provide line numbers, and the developer is also responsible for hard coding the correct function name in log.begin, and also consistently calling log.end.

Conclusion

By causing Siebel to stack itself, we are able to take advantage of the extra information that is provided by the standard ECMA error objects. This provides crucial information of the events leading up to any Exception, including the exact line where it occurred. And with a little added imagination, we can collect further information from each function as the error object is bubbled up the chain, a la ABS framework.

In this article, I've shown how we can get the name of the current function, generate a stack trace at will, and its importance in error handling. Integrating it into your own framework is the fun part, this will require engagement with your core framework professionals, and will require an impact analysis.

Credits goes out to Mike M. Lin for providing the seeds for this article, Mik Branchaud for sharing his logger design, and Mr ABS for sharing his wisdom on error handling in the ABS framework.

Rapid Browser Script Development

This article was written pre Open UI and was locked up in vault, because Browser Script was becomming old school. But as an early user of Open UI, I've found the need to rapidly modify and troubleshoot browser script issues, and remembered the same technique which is used in HI, is also applicable to Open UI.

This article might be more appropriate for a Browser Script reunion party, but it has been released for those who may still struggle with Browser Script, and for Open UI customers who may still rely on legacy Browser Script.

-----------------------------------------------------------------------------------

I asked a trusty colleague to put a line of browser script behind a certain applet and perform an incremental compile on the server for me.

Colleague: What browser script command do I need to put on this applet?
Me: Anything you want, make it display an alert for me.
Colleague: Where should I put it? Applet Load? PreInvoke?
Me: It doesn't matter, just make sure it compiles.

10 minutes later, the server was rebooted, I got my new browser scripted applet and my colleague was free to continue his own work.

Unfortunately, when I took a look at the browser script behind the applet, my colleague inadvertently put a typo in the code, which caused the following error in the IEDTB console



Fortunately this doesn't matter for what we're about to do. In fact, the browser script didn't have to be valid, it can be total junk, but as long as it compiles and produces the browser script files, we're in business. What this does is forces Siebel to produce the necessary "hooks" from the UI to the external JS files.

First we're going to fix that typo. Goto the web server, and find the generated browser script JS file for that Applet.

You'll find that it will look something like this.



We can fix that typo by re-writing the browser script error on the fly and instead of displaying a dialog box on Applet PreInvoke, we will re-implement the code to use a less obtrusive console.log on Applet Load, which means we will have to introduce a new OnLoad handler.

Change your JS file to the following.

function Web_Browser_Entry_Applet_PreInvokeMethod(name, inputPropSet){
 return ("ContinueOperation");
}

//Artificial Onload method hanlder
function Web_Browser_Entry_Applet_Load(applet){
 //write to the IEDTB console
 console.info("I Love Disco");
}

function Web_Browser_Entry_Applet(applet){
 if(applet != null){
  this._applet = applet;
  applet.shado = this;
 }
 
}
new Web_Browser_Entry_Applet(null);
Web_Browser_Entry_Applet.prototype=new top.JSSAppletShadow();
Web_Browser_Entry_Applet.prototype.OnPreInvoke=Web_Browser_Entry_Applet_PreInvokeMethod;
//Attach a new handler for Onload
Web_Browser_Entry_Applet.prototype.OnLoad=Web_Browser_Entry_Applet_Load;
theApplication=top.theApplication;
TheApplication=top.theApplication;


Open the IE Developer Toolbar by pressing F12, clear your browser cache, disable script debugging, and reload the Screen. Follow those steps exactly and your new change will take effect immediately.

Your screen should look like this.



Next let’s give ourselves direct access to the Applet scope from the Browser, this will allow us to write Browser script on the fly in context of the Applet, without reloading the browser!

Change your browser script file to include the following

//recreate the function on the global scope
top.OnPreInvoke=function(name, inputPropSet){
 console.info(name);
 return ("ContinueOperation");
}

//recreate the function on the global scope
top.OnLoad=function(applet){
 //create a global reference to the current applet
 top.thisApplet=this;
 console.info("I Love Disco");
}

function Web_Browser_Entry_Applet(applet){
 if(applet != null){
  this._applet = applet;
  applet.shado = this;
 }
 
}
new Web_Browser_Entry_Applet(null);
Web_Browser_Entry_Applet.prototype=new top.JSSAppletShadow();
//repoint the prototype functions to our new globals
Web_Browser_Entry_Applet.prototype.OnPreInvoke=top.OnPreInvoke;
Web_Browser_Entry_Applet.prototype.OnLoad=top.OnLoad;
theApplication=top.theApplication;
TheApplication=top.theApplication;


There are two key pieces in play here.

1) top.OnPreInvoke;

This line shifts execution to a global function that we’ve attached to the main window. Browser Script files are loaded from a hidden frame, so it must be attached to the top, for the console to access.

This global reference allows us to modify the definition of the function, and run new code without reloading the browser.

2) top.thisAppet

This is similar to the above, but this line provides us with access to the Applet instance.

Click Query, and Cancel, to see the results of this dynamic browser script.





We now have direct access to the runtime context of the Applet, and we can develop directly from the IE console.

Overwrite the PreInvoke Handler, by pasting the following code into the console. Click “Query”, and we now see a dialog box.

top.OnPreInvoke=function(name, inputPropSet){
    console.info(name);
    switch(name){
       case "NewQuery":
          alert(name);
          break;
    }
}


Type the following code into the console, and what happens to the Description field

top.thisApplet.FindControl("Description").SetValue("I Love Disco");




We have just learned how to rewrite Browser Script on the fly, and handle events that are not defined in the repository.

The last step in this Rapid Browser Script development process, is to make sure that when you are happy with your browser script, remove those global references, copy the logic back into Tools, in the correct event handler and compile it to validate your handy work.

-----------------------------------------------------------------------------------

Browser Script: PropertySet Copy() Syntax

The author of the following post rasied a simple question.

"The following syntax to copy propertyset is not working in browser script.please let me know the correct syntax to use.

PropSet2 = PropSet1.Copy()"


The syntax is correct, but it doesn't hurt to consult the "Bible" for more details. Bookshelf confirms that the syntax is correct for Browser Script.

The example provided in bookshelf is:
var oPropSet1;
var oPropSet2;
oPropSet2 = oPropSet1.Copy();

However, the example is slightly incorrect, because the Property Set object is not instantiated.



But even if we correct it, there is still an error.



What if we try the Copy method on the destination object, and pass in the source object?



Bingo, it works.

Lets try a more substantial Property Set.


var ps=theApplication().NewPropertySet();
var psChild1=theApplication().NewPropertySet();
var psChild2=theApplication().NewPropertySet();
ps.SetType("Parent");
ps.SetValue("ParentValue");
ps.SetProperty("Mum","Georgette");
ps.SetProperty("Dad","George");
psChild1.SetType("Child 1");
psChild2.SetType("Child 2");
psChild1.SetProperty("Name","Bob");
psChild1.SetProperty("Gender","Male");
psChild2.SetProperty("Name","Jane");
psChild2.SetProperty("Gender","Female");
ps.AddChild(psChild1);
ps.AddChild(psChild2);
var ps2=theApplication().NewPropertySet();
ps2.Copy(ps);




As we would expect, the Copy method does work, but it is not correctly documented or built incorrectly, it is also inconsistent with the same object in eScript.

This test was performed on 8.1.1.5, 8.1.1.10, and the author of the original problem posted the problem back in 2008, which goes back at least 5 years. Isn’t amazing that a defect has been in the wild for so long without being detected?

Custom eScript Engine

This long overdue article, is a continuation of one of my earliest articles at Impossible Siebel, how to run eScript on a Siebel server without compiling.

The ability to write eScript, and test it without compiling, was introduced in Siebel 8 with "Fix and Go". Convenient as it sounds, Fix and Go, isn't the ultimate solution.

Even though you don't have to compile, it is still necessary to launch a debugging session from a thick client to test the code. To unit test a stand alone business service, it is more appropriate to use Business Service simulator, which allows the developer to create client side code, and test it it on the fly. Business Service Simulator is useful, but using it, is like using Notepad to write code, it suffices but isn't user friendly. Business Service Simulator by its own nature cannot test UI context, It is also quite clunky, for testing small snippets of code, which is where the original article took a point, providing the developer with an alternative to write eScript on the fly in their favourite text editor, and test it without compiling.

This article is a walk through for the advanced reader, who wants run through the implementation process to build such a tool. I'll also provide the full source code to the translation class, that makes it possible for us to emulate the Siebel eScript API.

Pre-requisites

The following will seem familiar if you've gone through my article on a creating a Java Business Service.

1. Java for Dummies

Learn some Java

2. Sun Java Software Development Kit

Goto the sun website, download and install the SDK

http://java.sun.com/javase/downloads/index.jsp

3. Java IDE

Download and install your favourite Java IDE.

4. Siebel Enterprise

This method will only allow you to run eScript on the server, and not on a local machine, so we need a Siebel Server installation to connect to.

Implementation

1. Connect to Siebel using the JDB Interface

Ensure you have read the following article on Support Web, this will provide the foundations for our eScript program.

How To Use Siebel Java Data Bean [ID 476902.1]

I've run through the instructions again and started from scratch, to re-build this program for this article, and found the Siebel documentation to be very good.

Once you have followed the instructions on this document, you should have a working Java Data Bean (JDB) connection to your Siebel server.

2. Import ECMA scripting engine

private ScriptEngineManager oScptMgr    = new ScriptEngineManager();
private ScriptEngine        jsEngine    = oScptMgr.getEngineByName("ECMAScript");//Instantiate base engine


Siebel is based on the ECMA standard, so we are importing the ECMAScript engine to provide us with the base language, to which we will add the eScript translation layer.

3. Pass Siebel Java application object into ECMA engine

jsEngine.put("oApp",m_dataBean);
//oApp is the Siebel Java Application and we want to load this into the ECMA engine


We need to pass the Siebel application reference, that we have instantiated earlier following the Siebel tutorial, into the ECMA engine instance that we created above.

This statement creates a global object inside our ECMAEngine called oApp that references the m_dataBean handle in our Java program. This allows our ECMA engine to access all the methods available in the JDB Interface, using a scripting language.

Nice! now we have an ECMA language with the Siebel JDB API as a global.

4. Create a class abstraction layer to translate the eScript language into JDB methods.

This is the custom eScript API, that I built several years ago, but never got around to publishing. It is provided as is, with no warranties, or support, and use of it, is at your own risk.
                       
/**************************************************************************************************************
* Component Name        :  Impossible Siebel eScript Translation Class
* Component Information :  Provides a wrapper for the Siebel JDB methods
* Date  Author
* 2009  Jason Le 
* ============================================================================================================
* 01MAR09 JLE  Initial version
**************************************************************************************************************/
//Define Escript Constants
var ContinueOperation = true;       var CancelOperation       = false;

//ExecuteQuery constants
var ForwardOnly       = true;       var ForwardBackward       = false;
var NewAfter          = true;       var NewBefore             = false;

//SetViewMode
var SalesRepView      = 0;          var OrganizationView      = 5;
var ManagerView       = 1;          var GroupView             = 7;
var PersonalView      = 2;          var CatalogView           = 8;
var AllView           = 3;          var SubOrganizationView   = 9;

var Inputs            = oApp.newPropertySet();
var Outputs           = oApp.newPropertySet();
var arrDefaultInput   = [];
var Appinstance       = 0;
var gApplication;

//TheApplication() Class
function TheApplication() {
  if (gApplication == null) {
    Appinstance = Appinstance+1;
    gApplication = new class_app(oApp);
  }
  return gApplication;
}

//class_app.prototype = oApp;
class_app.prototype.GetProfileAttr          = class_app_GetProfileAttr;
class_app.prototype.SetProfileAttr          = class_app_SetProfileAttr;
class_app.prototype.Trace                   = class_app_Trace;
class_app.prototype.TraceOff                = class_app_TraceOff;
class_app.prototype.TraceOn                 = class_app_TraceOn;
class_app.prototype.PositionId              = class_app_PositionId;
class_app.prototype.PositionName            = class_app_PositionName;
class_app.prototype.LoginId                 = class_app_LoginId;
class_app.prototype.LoginName               = class_app_LoginName;
class_app.prototype.InvokeMethod            = class_app_InvokeMethod;
class_app.prototype.GetBusObject            = GetBusObject;
class_app.prototype.GetService              = GetService;
class_app.prototype.NewPropertySet          = NewPropertySet;

function class_app(application)             {if(application != null){this._application = application; }}
function class_app_GetProfileAttr(v)        {return this._application.getProfileAttr(v) ;} //+ '';}
function class_app_SetProfileAttr(n,v)      {return this._application.setProfileAttr(n,v);}
function class_app_Trace(v)                 {trace(v);}
function class_app_TraceOff()               {return this._application.traceOff();}
function class_app_TraceOn(f,t,s)           {return this._application.traceOn(f,t,s);}
function class_app_PositionId()             {return this._application.positionId() ;} //+ '';}
function class_app_PositionName()           {return this._application.positionName() ;} //+ '';}
function class_app_LoginId()                {return this._application.loginId() ;} //+ '';}
function class_app_LoginName()              {return this._application.loginName() ;} //+ '';}
function class_app_NewPropertySet()         {return this._application.newPropertySet();}
function class_app_InvokeMethod(){
var sMethod = arguments[0];
var aInput  = [];
  for(i=1; i<arguments.length; i++){
    aInput.push(arguments[i])
  }
  return this._application.invokeMethod(sMethod, aInput);
}



//NewPropertySet() Class
//class_PS.prototype = new class_PS(oPS);
class_PS.prototype.PropertyExists           = class_PS_PropertyExists;
class_PS.prototype.GetProperty              = class_PS_GetProperty;
class_PS.prototype.getProperty              = class_PS_GetProperty;
class_PS.prototype.SetProperty              = class_PS_SetProperty;
class_PS.prototype.setProperty              = class_PS_SetProperty;
class_PS.prototype.GetValue                 = class_PS_GetValue;
class_PS.prototype.SetValue                 = class_PS_SetValue;
class_PS.prototype.GetType                  = class_PS_GetType;
class_PS.prototype.SetType                  = class_PS_SetType;
class_PS.prototype.Copy                     = class_PS_Copy;
class_PS.prototype.Reset                    = class_PS_Reset;
class_PS.prototype.GetChild                 = class_PS_GetChild;
class_PS.prototype.AddChild                 = class_PS_AddChild;
class_PS.prototype.RemoveChild              = class_PS_RemoveChild;
class_PS.prototype.RemoveProperty           = class_PS_RemoveProperty;
class_PS.prototype.InsertChildAt            = class_PS_InsertChildAt;
class_PS.prototype.GetFirstProperty         = class_PS_GetFirstProperty;
class_PS.prototype.GetNextProperty          = class_PS_GetNextProperty;
class_PS.prototype.GetPropertyCount         = class_PS_GetPropertyCount;

function NewPropertySet()                  {return new class_PS(this._application.newPropertySet() );}
//function NewPropertySet()                   {return new class_PS( oPS );}
function class_PS(PS)                       {if(PS != null){this._PS = PS;} }
function class_PS_PropertyExists(v)         {return this._PS.propertyExists(v);}
function class_PS_GetProperty(v)            {return this._PS.getProperty(v) ;} //+ '';}
function class_PS_SetProperty(n,v)          {return this._PS.setProperty(n,v);}
function class_PS_GetValue(v)               {return this._PS.getValue(v) ;} //+ '';}
function class_PS_SetValue(v)               {return this._PS.setValue(v);}
function class_PS_GetType(v)                {return this._PS.getType(v) ;} //+ '';}
function class_PS_SetType(v)                {return this._PS.setType(v);}
function class_PS_Copy()                    {return this._PS.copy();}
function class_PS_Reset()                   {return this._PS.reset();}
function class_PS_GetChild(i)               {return this._PS.getChild(i);}
function class_PS_AddChild(Ps)              {return this._PS.addChild(Ps);}
function class_PS_RemoveChild(i)            {return this._PS.removeChild(i);}
function class_PS_RemoveProperty(v)         {return this._PS.removeProperty(v);}
function class_PS_InsertChildAt(obj,i)      {return this._PS.insertChildAt(obj,i);}
function class_PS_GetFirstProperty()        {return this._PS.getFirstProperty() ;} //+ '';}
function class_PS_GetNextProperty()         {return this._PS.getNextProperty() ;} //+ '';}
function class_PS_GetPropertyCount()        {return this._PS.getPropertyCount();}



//GetBusObject() Class
class_BO.prototype.Name                     = class_BO_Name;
class_BO.prototype.GetBusComp               = GetBusComp;

function GetBusObject(BOName)               {return new class_BO(this._application.getBusObject(BOName));}
function class_BO(oBO)                      {if(oBO != null){this._BO = oBO; } }
function class_BO_Name()                    {return this._BO.name();}

//GetService() Class
class_Svc.prototype.Name                    = class_Svc_Name;
class_Svc.prototype.InvokeMethod            = class_Svc_InvokeMethod;
class_Svc.prototype.PropertyExists          = class_Svc_PropertyExists;
class_Svc.prototype.GetProperty             = class_Svc_GetProperty;
class_Svc.prototype.SetProperty             = class_Svc_SetProperty;

function GetService(SvcName)                {return new class_Svc(this._application.getService(SvcName));}
function class_Svc(oSvc)                    {if(oSvc != null){this._Svc = oSvc; } }
function class_Svc_Name()                   {return this._Svc.getName() ;} //+ '';}
function class_Svc_InvokeMethod(Meth,Ps1,Ps2){
  return this._Svc.invokeMethod(Meth,Ps1,Ps2);
}
function class_Svc_PropertyExists(v)        {return this._Svc.propertyExists(v);}
function class_Svc_GetProperty(v)           {return this._Svc.getProperty(v) ;} //+ '';}
function class_Svc_SetProperty(n,v)         {return this._Svc.setProperty(n,v);}


//GetBusComp() Class
class_BC.prototype.Name                     = class_BC_Name;
class_BC.prototype.ActivateField            = class_BC_ActivateField;
class_BC.prototype.ActivateMultipleFields   = class_BC_ActivateMultipleFields ;
class_BC.prototype.Associate                = class_BC_Associate;
class_BC.prototype.ClearToQuery             = class_BC_ClearToQuery;
class_BC.prototype.CountRecords             = class_BC_CountRecords;
class_BC.prototype.DeactivateFields         = class_BC_DeactivateFields;
class_BC.prototype.DeleteRecord             = class_BC_DeleteRecord;
class_BC.prototype.ExecuteQuery             = class_BC_ExecuteQuery;
class_BC.prototype.FirstRecord              = class_BC_FirstRecord;
//class_BC.prototype.GetAssocBusComp          = class_BC_GetAssocBusComp;
class_BC.prototype.GetFieldValue            = class_BC_GetFieldValue;
class_BC.prototype.GetFormattedFieldValue   = class_BC_GetFormattedFieldValue;
class_BC.prototype.GetMVGBusComp            = GetMVGBusComp;//class_BC_GetMVGBusComp;
class_BC.prototype.GetNamedSearch           = class_BC_GetNamedSearch;
class_BC.prototype.GetPicklistBusComp       = class_BC_GetPicklistBusComp;
class_BC.prototype.GetSearchExpr            = class_BC_GetSearchExpr;
class_BC.prototype.GetSearchSpec            = class_BC_GetSearchSpec;
class_BC.prototype.GetViewMode              = class_BC_GetViewMode;
class_BC.prototype.InvokeMethod             = class_BC_InvokeMethod;
class_BC.prototype.LastRecord               = class_BC_LastRecord;
class_BC.prototype.NewRecord                = class_BC_NewRecord;
class_BC.prototype.NextRecord               = class_BC_NextRecord;
class_BC.prototype.ParentBusComp            = class_BC_ParentBusComp;
class_BC.prototype.Pick                     = class_BC_Pick;
class_BC.prototype.PreviousRecord           = class_BC_PreviousRecord;
class_BC.prototype.RefineQuery              = class_BC_RefineQuery;
class_BC.prototype.SearchExpr               = class_BC_SearchExpr;
class_BC.prototype.SetFieldValue            = class_BC_SetFieldValue;
class_BC.prototype.SetFormattedFieldValue   = class_BC_SetFormattedFieldValue;
class_BC.prototype.SetSearchSpec            = class_BC_SetSearchSpec;
class_BC.prototype.SetSearchExpr            = class_BC_SetSearchExpr;
class_BC.prototype.SetSortSpec              = class_BC_SetSortSpec;
class_BC.prototype.SetViewMode              = class_BC_SetViewMode;
class_BC.prototype.UndoRecord               = class_BC_UndoRecord;
class_BC.prototype.ViewMode                 = class_BC_ViewMode;
class_BC.prototype.WriteRecord              = class_BC_WriteRecord;

function GetBusComp(BCName)                 {return new class_BC(this._BO.getBusComp(BCName));}
function class_BC(oBC)                      {if(oBC != null){this._BC = oBC; } }
function class_BC_Name()                    {return this._BC.name();}
function class_BC_ActivateField(v)          {return this._BC.activateField(v);}
function class_BC_ActivateMultipleFields(Ps){return this._BC.activateMultipleFields(Ps);}
function class_BC_Associate(i)              {return this._BC.associate(i);}
function class_BC_ClearToQuery()            {return this._BC.clearToQuery();}
function class_BC_CountRecords(){
  var oMVG = this._BC;
  var icount = 0;
  with (oMVG){
    executeQuery(ForwardBackward);

    var isRecord = firstRecord();
    if (isRecord)
    {
      while (isRecord)
      {
      icount++;
      isRecord = nextRecord();
      }
    }
    firstRecord();
  }
  
  return icount;
}
function class_BC_DeactivateFields()        {return this._BC.deactivateFields();}
function class_BC_DeleteRecord()            {return this._BC.deleteRecord();}
function class_BC_ExecuteQuery(v)           {return this._BC.executeQuery(v);}
function class_BC_FirstRecord()             {return this._BC.firstRecord();}
function class_BC_NextRecord()              {return this._BC.nextRecord();}
//function class_BC_GetAssocBusComp()         {return this._BC.getAssocBusComp();}
function class_BC_GetFieldValue(v)          {return this._BC.getFieldValue(v) + '';} //+ '';}
function class_BC_GetFormattedFieldValue(v) {return this._BC.getFormattedFieldValue(v) ;} //+ '';}
function class_BC_GetMVGBusComp(v)          {return this._BC.getMVGBusComp(v);}
function class_BC_GetNamedSearch(v)         {return this._BC.getNamedSearch(v);}
function class_BC_GetPicklistBusComp(v)     {return this._BC.getPicklistBusComp(v);}
function class_BC_GetSearchExpr()           {return this._BC.getSearchExpr() ;} //+ '';}
function class_BC_GetSearchSpec()           {return this._BC.getSearchSpec() ;} //+ '';}
function class_BC_GetViewMode()             {return this._BC.getViewMode() ;} //+ '';}
function class_BC_InvokeMethod(){
var sMethod = arguments[0];
var aInput  = [];
  for(i=1; i<arguments.length; i++){
    aInput.push(arguments[i])
  }
  return this._BC.invokeMethod(sMethod, aInput);
}
function class_BC_LastRecord()              {return this._BC.lastRecord();}
function class_BC_NewRecord(v)              {return this._BC.newRecord(v);}
//function class_BC_NextRecord()              {return this._BC.nextRecord();}
function class_BC_ParentBusComp()           {return this._BC.parentBusComp();}
function class_BC_Pick()                    {return this._BC.pick();}
function class_BC_PreviousRecord()          {return this._BC.previousRecord();}
function class_BC_RefineQuery()             {return this._BC.refineQuery();}
function class_BC_SearchExpr(v)             {return this._BC.searchExpr(v);}
function class_BC_SetFieldValue(n,v)        {return this._BC.setFieldValue(n,v);}
function class_BC_SetFormattedFieldValue(n,v)        {return this._BC.setFormattedFieldValue(n,v);}
function class_BC_SetSearchExpr(v)          {return this._BC.setSearchExpr(v);}
function class_BC_SetSearchSpec(n,v)          {return this._BC.setSearchSpec(n,v);}
function class_BC_SetSortSpec(v)          {return this._BC.setSortSpec(v);}
function class_BC_SetViewMode(v)            {return this._BC.setViewMode(v);}
function class_BC_UndoRecord()              {return this._BC.undoRecord();}
function class_BC_ViewMode(v)               {return this._BC.viewMode(v);}
function class_BC_WriteRecord()             {return this._BC.writeRecord();}

//GetMVGBusComp() Class
class_MvgBC.prototype.Name                     = class_MvgBC_Name;
class_MvgBC.prototype.ActivateField            = class_MvgBC_ActivateField;
class_MvgBC.prototype.ActivateMultipleFields   = class_MvgBC_ActivateMultipleFields ;
class_MvgBC.prototype.Associate                = class_MvgBC_Associate;
class_MvgBC.prototype.ClearToQuery             = class_MvgBC_ClearToQuery;
class_MvgBC.prototype.CountRecords             = class_MvgBC_CountRecords;
class_MvgBC.prototype.DeactivateFields         = class_MvgBC_DeactivateFields;
class_MvgBC.prototype.DeleteRecord             = class_MvgBC_DeleteRecord;
class_MvgBC.prototype.ExecuteQuery             = class_MvgBC_ExecuteQuery;
class_MvgBC.prototype.FirstRecord              = class_MvgBC_FirstRecord;
//class_MvgBC.prototype.GetAssocBusComp          = class_MvgBC_GetAssocBusComp;
class_MvgBC.prototype.GetFieldValue            = class_MvgBC_GetFieldValue;
class_MvgBC.prototype.GetFormattedFieldValue   = class_MvgBC_GetFormattedFieldValue;
class_MvgBC.prototype.GetMVGBusComp            = class_MvgBC_GetMVGBusComp;
class_MvgBC.prototype.GetAssocBusComp          = GetAssocBusComp;
class_MvgBC.prototype.GetNamedSearch           = class_MvgBC_GetNamedSearch;
class_MvgBC.prototype.GetPicklistBusComp       = class_MvgBC_GetPicklistBusComp;
class_MvgBC.prototype.GetSearchExpr            = class_MvgBC_GetSearchExpr;
class_MvgBC.prototype.GetSearchSpec            = class_MvgBC_GetSearchSpec;
class_MvgBC.prototype.GetViewMode              = class_MvgBC_GetViewMode;
class_MvgBC.prototype.InvokeMethod             = class_MvgBC_InvokeMethod;
class_MvgBC.prototype.LastRecord               = class_MvgBC_LastRecord;
class_MvgBC.prototype.NewRecord                = class_MvgBC_NewRecord;
class_MvgBC.prototype.NextRecord               = class_MvgBC_NextRecord;
class_MvgBC.prototype.ParentBusComp            = class_MvgBC_ParentBusComp;
class_MvgBC.prototype.Pick                     = class_MvgBC_Pick;
class_MvgBC.prototype.PreviousRecord           = class_MvgBC_PreviousRecord;
class_MvgBC.prototype.RefineQuery              = class_MvgBC_RefineQuery;
class_MvgBC.prototype.SearchExpr               = class_MvgBC_SearchExpr;
class_MvgBC.prototype.SetFieldValue            = class_MvgBC_SetFieldValue;
class_MvgBC.prototype.SetFormattedFieldValue   = class_MvgBC_SetFormattedFieldValue;
class_MvgBC.prototype.SetSearchSpec            = class_MvgBC_SetSearchSpec;
class_MvgBC.prototype.SetSearchExpr            = class_MvgBC_SetSearchExpr;
class_MvgBC.prototype.SetSortSpec              = class_MvgBC_SetSortSpec;
class_MvgBC.prototype.SetViewMode              = class_MvgBC_SetViewMode;
class_MvgBC.prototype.UndoRecord               = class_MvgBC_UndoRecord;
class_MvgBC.prototype.ViewMode                 = class_MvgBC_ViewMode;
class_MvgBC.prototype.WriteRecord              = class_MvgBC_WriteRecord;

function GetMVGBusComp(FieldName)              {return new class_MvgBC(this._BC.getMVGBusComp(FieldName));}
function class_MvgBC(oMvgBC)                   {if(oMvgBC != null){this._MvgBC = oMvgBC; } }
function class_MvgBC_Name()                    {return this._MvgBC.name();}
function class_MvgBC_ActivateField(v)          {return this._MvgBC.activateField(v);}
function class_MvgBC_ActivateMultipleFields(Ps){return this._MvgBC.activateMultipleFields(Ps);}
function class_MvgBC_Associate(i)              {return this._MvgBC.associate(i);}
function class_MvgBC_ClearToQuery()            {return this._MvgBC.clearToQuery();}
//function class_MvgBC_CountRecords()            {return this._MvgBC.countRecords();}
function class_MvgBC_CountRecords(){
  var oMVG = this._MvgBC;
  var icount = 0;
  with (oMVG){
    executeQuery(ForwardBackward);

    var isRecord = firstRecord();
    if (isRecord)
    {
      while (isRecord)
      {
      icount++;
      isRecord = nextRecord();
      }
    }
    firstRecord();
  }
  
  return icount;
}
function class_MvgBC_DeactivateFields()        {return this._MvgBC.deactivateFields();}
function class_MvgBC_DeleteRecord()            {return this._MvgBC.deleteRecord();}
function class_MvgBC_ExecuteQuery(v)           {return this._MvgBC.executeQuery(v);}
function class_MvgBC_FirstRecord()             {return this._MvgBC.firstRecord();}
function class_MvgBC_NextRecord()              {return this._MvgBC.nextRecord();}
//function class_MvgBC_GetAssocBusComp()         {return this._MvgBC.getAssocBusComp();}
function class_MvgBC_GetFieldValue(v)          {return this._MvgBC.getFieldValue(v) ;} //+ '';}
function class_MvgBC_GetFormattedFieldValue(v) {return this._MvgBC.getFormattedFieldValue(v) ;} //+ '';}
function class_MvgBC_GetMVGBusComp(v)          {return this._MvgBC.getMVGBusComp(v);}
function class_MvgBC_GetNamedSearch(v)         {return this._MvgBC.getNamedSearch(v) ;} //+ '';}
function class_MvgBC_GetPicklistBusComp(v)     {return this._MvgBC.getPicklistBusComp(v);}
function class_MvgBC_GetSearchExpr()           {return this._MvgBC.getSearchExpr() ;} //+ '';}
function class_MvgBC_GetSearchSpec()           {return this._MvgBC.getSearchSpec() ;} //+ '';}
function class_MvgBC_GetViewMode()             {return this._MvgBC.getViewMode() ;} //+ '';}
function class_MvgBC_InvokeMethod(){
var sMethod = arguments[0];
var aInput  = [];
  for(i=1; i<arguments.length; i++){
    aInput.push(arguments[i])
  }
  return this._MvgBC.invokeMethod(sMethod, aInput);
}
function class_MvgBC_LastRecord()              {return this._MvgBC.lastRecord();}
function class_MvgBC_NewRecord(v)              {return this._MvgBC.newRecord(v);}
function class_MvgBC_NextRecord()              {return this._MvgBC.nextRecord();}
function class_MvgBC_ParentBusComp()           {return this._MvgBC.parentBusComp();}
function class_MvgBC_Pick()                    {return this._MvgBC.pick();}
function class_MvgBC_PreviousRecord()          {return this._MvgBC.previousRecord();}
function class_MvgBC_RefineQuery()             {return this._MvgBC.refineQuery();}
function class_MvgBC_SearchExpr(v)             {return this._MvgBC.searchExpr(v);}
function class_MvgBC_SetFieldValue(n,v)        {return this._MvgBC.setFieldValue(n,v);}
function class_MvgBC_SetFormattedFieldValue(n,v)        {return this._MvgBC.setFormattedFieldValue(n,v);}
function class_MvgBC_SetSearchExpr(v)          {return this._MvgBC.setSearchExpr(v);}
function class_MvgBC_SetSearchSpec(n,v)        {return this._MvgBC.setSearchSpec(n,v);}
function class_MvgBC_SetSortSpec(v)            {return this._MvgBC.setSortExpr(v);}
function class_MvgBC_SetViewMode(v)            {return this._MvgBC.setViewMode(v);}
function class_MvgBC_UndoRecord()              {return this._MvgBC.undoRecord();}
function class_MvgBC_ViewMode(v)               {return this._MvgBC.viewMode(v);}
function class_MvgBC_WriteRecord()             {return this._MvgBC.writeRecord();}

//GetAssocBusComp() Class
class_AssBC.prototype.Name                     = class_AssBC_Name;
class_AssBC.prototype.ActivateField            = class_AssBC_ActivateField;
class_AssBC.prototype.ActivateMultipleFields   = class_AssBC_ActivateMultipleFields ;
class_AssBC.prototype.Associate                = class_AssBC_Associate;
class_AssBC.prototype.ClearToQuery             = class_AssBC_ClearToQuery;
class_AssBC.prototype.CountRecords             = class_AssBC_CountRecords;
class_AssBC.prototype.DeactivateFields         = class_AssBC_DeactivateFields;
class_AssBC.prototype.DeleteRecord            = class_AssBC_DeleteRecord;
class_AssBC.prototype.ExecuteQuery             = class_AssBC_ExecuteQuery;
class_AssBC.prototype.FirstRecord              = class_AssBC_FirstRecord;
//class_AssBC.prototype.GetAssocBusComp          = class_AssBC_GetAssocBusComp;
class_AssBC.prototype.GetFieldValue            = class_AssBC_GetFieldValue;
class_AssBC.prototype.GetFormattedFieldValue   = class_AssBC_GetFormattedFieldValue;
//class_AssBC.prototype.GetAssocBusComp          = class_AssBC_GetAssocBusComp;
class_AssBC.prototype.GetNamedSearch           = class_AssBC_GetNamedSearch;
class_AssBC.prototype.GetPicklistBusComp       = class_AssBC_GetPicklistBusComp;
class_AssBC.prototype.GetSearchExpr            = class_AssBC_GetSearchExpr;
class_AssBC.prototype.GetSearchSpec            = class_AssBC_GetSearchSpec;
class_AssBC.prototype.GetViewMode              = class_AssBC_GetViewMode;
class_AssBC.prototype.InvokeMethod             = class_AssBC_InvokeMethod;
class_AssBC.prototype.LastRecord               = class_AssBC_LastRecord;
class_AssBC.prototype.NewRecord                = class_AssBC_NewRecord;
class_AssBC.prototype.NextRecord               = class_AssBC_NextRecord;
class_AssBC.prototype.ParentBusComp            = class_AssBC_ParentBusComp;
class_AssBC.prototype.Pick                     = class_AssBC_Pick;
class_AssBC.prototype.PreviousRecord           = class_AssBC_PreviousRecord;
class_AssBC.prototype.RefineQuery              = class_AssBC_RefineQuery;
class_AssBC.prototype.SearchExpr               = class_AssBC_SearchExpr;
class_AssBC.prototype.SetFieldValue            = class_AssBC_SetFieldValue;
class_AssBC.prototype.SetFormattedFieldValue   = class_AssBC_SetFormattedFieldValue;
class_AssBC.prototype.SetSearchSpec            = class_AssBC_SetSearchSpec;
class_AssBC.prototype.SetSearchExpr            = class_AssBC_SetSearchExpr;
class_AssBC.prototype.SetSortSpec              = class_AssBC_SetSortSpec;
class_AssBC.prototype.SetViewMode              = class_AssBC_SetViewMode;
class_AssBC.prototype.UndoRecord               = class_AssBC_UndoRecord;
class_AssBC.prototype.ViewMode                 = class_AssBC_ViewMode;
class_AssBC.prototype.WriteRecord              = class_AssBC_WriteRecord;

function GetAssocBusComp()                {return new class_AssBC(this._MvgBC.getAssocBusComp());}
function class_AssBC(oAssBC)                   {if(oAssBC != null){this._AssBC = oAssBC; } }
function class_AssBC_Name()                    {return this._AssBC.name();}
function class_AssBC_ActivateField(v)          {return this._AssBC.activateField(v);}
function class_AssBC_ActivateMultipleFields(Ps){return this._AssBC.activateMultipleFields(Ps);}
function class_AssBC_Associate(i)              {return this._AssBC.associate(i);}
function class_AssBC_ClearToQuery()            {return this._AssBC.clearToQuery();}
function class_AssBC_CountRecords(){
  var oMVG = this._AssBC;
  var icount = 0;
  with (oMVG){
    executeQuery(ForwardBackward);

    var isRecord = firstRecord();
    if (isRecord)
    {
      while (isRecord)
      {
      icount++;
      isRecord = nextRecord();
      }
    }
    firstRecord();
  }
  
  return icount;
}
function class_AssBC_DeactivateFields()        {return this._AssBC.deactivateFields();}
function class_AssBC_DeleteRecord()            {return this._AssBC.deleteRecord();}
function class_AssBC_ExecuteQuery(v)           {return this._AssBC.executeQuery(v);}
function class_AssBC_FirstRecord()             {return this._AssBC.firstRecord();}
function class_AssBC_NextRecord()              {return this._AssBC.nextRecord();}
function class_AssBC_GetAssocBusComp()         {return this._AssBC.getAssocBusComp();}
function class_AssBC_GetFieldValue(v)          {return this._AssBC.getFieldValue(v) ;} //+ '';}
function class_AssBC_GetFormattedFieldValue(v) {return this._AssBC.getFormattedFieldValue(v) ;} //+ '';}
//function class_AssBC_GetAssocBusComp(v)          {return this._AssBC.GetAssocBusComp(v);}
function class_AssBC_GetNamedSearch(v)         {return this._AssBC.getNamedSearch(v) ;} //+ '';}
function class_AssBC_GetPicklistBusComp(v)     {return this._AssBC.getPicklistBusComp(v);}
function class_AssBC_GetSearchExpr()           {return this._AssBC.getSearchExpr() ;} //+ '';}
function class_AssBC_GetSearchSpec()           {return this._AssBC.getSearchSpec() ;} //+ '';}
function class_AssBC_GetViewMode()             {return this._AssBC.getViewMode() ;} //+ '';}
function class_AssBC_InvokeMethod(){
var sMethod = arguments[0];
var aInput  = [];
  for(i=1; i<arguments.length; i++){
    aInput.push(arguments[i])
  }
  return this._AssBC.invokeMethod(sMethod, aInput);
}
function class_AssBC_LastRecord()              {return this._AssBC.lastRecord();}
function class_AssBC_NewRecord(v)              {return this._AssBC.newRecord(v);}
function class_AssBC_NextRecord()              {return this._AssBC.nextRecord();}
function class_AssBC_ParentBusComp()           {return this._AssBC.parentBusComp();}
function class_AssBC_Pick()                    {return this._AssBC.pick();}
function class_AssBC_PreviousRecord()          {return this._AssBC.previousRecord();}
function class_AssBC_RefineQuery()             {return this._AssBC.refineQuery();}
function class_AssBC_SearchExpr(v)             {return this._AssBC.searchExpr(v);}
function class_AssBC_SetFieldValue(n,v)        {return this._AssBC.setFieldValue(n,v);}
function class_AssBC_SetFormattedFieldValue(n,v)        {return this._AssBC.setFormattedFieldValue(n,v);}
function class_AssBC_SetSearchExpr(v)          {return this._AssBC.setSearchExpr(v);}
function class_AssBC_SetSearchSpec(n,v)        {return this._AssBC.setSearchSpec(n,v);}
function class_AssBC_SetSortSpec(v)            {return this._AssBC.setSortSpec(v);}
function class_AssBC_SetViewMode(v)            {return this._AssBC.setViewMode(v);}
function class_AssBC_UndoRecord()              {return this._AssBC.undoRecord();}
function class_AssBC_ViewMode(v)               {return this._AssBC.viewMode(v);}
function class_AssBC_WriteRecord()             {return this._AssBC.writeRecord();}

function trace(v){
    oSysOut.println(v); 
}

Copy this into a file called "Impossible_eScript.js", which we will read, and load into our ECMA engine.
sEscriptToRun = readFile("\\Your path\\Impossible_eScript.js" );
jsEngine.eval(sEscriptToRun);//Load eScript class


The above statement imports a custom eScript like API into the ECMA engine. This is required because the JDB interface is slightly different from eScript syntax. This translation class converts eScript statements into calls that the JDB can understand.

Eg. eScript syntax is converted into Java style methods with initial lower case method names

TheApplication().NewPropertySet();//eScript
TheApplication().newPropertySet();//JDB Interface


The eScript translation class will create an abstraction layer that allows us to use conventional eScript against the JDB instance, it also implements some missing methods in the standard JDB API.

5. Run your eScript on the fly against the Server.

The pieces are comming together now, we have an ECMA engine, a Siebel Application instance, and an eScript API.

All we need to do is read in our eScript command file, which we can edit from any text editor, and run the code against the JDB connection.

String sEscriptToRun = readFile("\\Your path\\Your_eScript_commands.js");
//Your eScript to run
jsEngine.eval(sEscriptToRun);//run


This is the same code that we used to import the translation class in step 4.

When you run the program, it will connect to the server object manager, your eScript will then be converted to the proper Java methods, and run against this JDB session.

Next Steps

Thats all thats needed to create a tool that can run adhoc code on the server. The next step is to build a nice UI so users can open the script file, run it, and display results inline, or create a command line program that can be run from any editor, and return the results back to the console.

Another idea is to allow the user to "simulate" an existing business service from our tool. This tool can also be the foundations of a xUnit testing suite. A Java veteran will easily absorb this information, and make something more usable.

Conclusion

Hardcore readers will be quick to realize that this is not a complete eScript engine. It is probably 90% of an engine that will run most of your code, for example it dosnt implement the C Lib functions, and like the Business Service Simulator, it cannot run against the active UI instance. Non hardcore readers will think, this is too hard core, but I leave this out there for those who want to pick it, learn from the implementation or run with it further, but for time being, you have the basics of a very useful prototyping/testing tool.

InvokeMethod with Parameters

Requirement

Capture a response from client side, and send it to the server

Option 1: Use a profile attribute

Profile attributes are dirty for a number of reasons, this post by Mike M. Lin, highlights the issues very well.

Option 2: Invoke a server side business service

This option requires a business service to be exposed to the browser, and requires abit more code to invoke, but it is certainly an option, especially if you need a return value. The only caveat is that the code on the server dosnt have direct context of the BC, but it is a good way to encapsulate your logic.

Option 3: Invoke method??

InvokeMethod in server script has no parameters, InvokeMethod in browser script contains the "inputPropSet" parameter, but unfortunately it can not be used to pass data to the server side, however with a little fancy foot work, we can bend InvokeMethod to handle parameters.

The solution entails scripting, and abuse of a Siebel staple, so its not for the faint hearted, but I know if you've read this far, then you are here to see Siebel bend, so read on...

Modified Requirement

Pass an array of data eg. ["I","love","disco"] and send it from browser side to server side

Solution

1. Create a button on an Applet

2. Set the Method Invoked property = "EventMethodDataHandler"

This method is only a proxy, the real data shuttling happens in the code below

3. Create the following browser script in Applet_PreInvokeMethod

function Applet_PreInvokeMethod (name, inputPropSet)
{
var iRet="ContinueOperation";
var aArr=["I","Love","Disco"];
switch(name){
case "EventMethodDataHandler":
this.InvokeMethod("EventMethod|YourBrowserMethodName|"+aArr.join(","));
break;
}
return iRet;
}

The above code constructs a dynamic InvokeMethod that appends data to the method name itself.

4. Create the following server script in BusComp_PreInvokeMethod

function BusComp_PreInvokeMethod (MethodName){
//ComplexMethod - processing for invoked methods with args
var aComplexMethod=MethodName.split("|");
if(aComplexMethod[0]=="EventMethod"){
iRet= PreInvokeMethod_ComplexMethod(aComplexMethod);
return iRet;
}
}
function PreInvokeMethod_ComplexMethod(aComplexMethod){
var sMethod=aComplexMethod[1]; //Custom Method
var sArg1=aComplexMethod[2]; //Args
switch(sMethod){
case "YourBrowserMethodName":
var aArrFromBrower=sArg1.split(",");
//perform your processing here
break;
}
}

By using a standard namespace, we can detect whether the method invoked is a Complex method or a normal method invocation, and handle it accordingly.

In the above example. The method invoked is

EventMethod|YourBrowserMethodName|I,Love,Disco

The server code intercepts method this by detecting the namespace, and converts the method name into an array. The last argument of the array is a String representation of our data which was set dynamically by the browser. This data can be any type of object that can be serialised, but InvokeMethod was not designed to transport data, so if you do decide to use this option, restrict it to small amounts of data.

Beware that Siebel encodes HTML entities, so if you want to use these type of characters as values in your data, you'll need to build some helper utilities to deal with converting them.

This method of parametizing the InvokeMethod is not limited to browser script, but it does open doors to perform funky browser/server co-ordination and offers an alternative to abusing your profile attributes.

Cornelius' Applet Set Focus Challenge

This article continues on from the guest article on Siebel Essentials - Set Focus on an Applet by Cornelius.

When I read the article by Cornelius, and saw the ~85 lines of code, I fainted (possibly due to the heat wave on the day) and when I came to, I wondered if this solution can be made leaner?

Querying the repository is sometimes necessary, when you need to achieve non-standard functionality, but in this case I felt there had to be a better way. Using SWEApplets only works in SI, but in HI, it should be possible to read the DOM and find the first visible applet and pass it to HandleAppletClick.

I did a quick POC using the IE DTB, and got a working solution with 5 lines of code. But 5 lines was too much in my opinion, so with a re-think of the problem, I by passed HandleAppletClick, and got the solution leaner.

The result is 3 lines of code. Heres how I did it.

Before we jump into the solution, ensure you have jQuery installed on your top object. This can be done via the web templates

Insert the following line of code in a common template such as your PageContainer

<script src="<your scripts folder>jquery.min.js"></script>
<script src="<your scripts folder>common_1.00.js"></script>

Next assign the jQuery object to your top object as so in your common JS file
top.$=$;

Now you'll have access to this magic everywhere in your application.

[Solution]

Cornelius separated his solution into two parts

1. Setting focus on the applet using "HandleAppletClick"
2. Using Browser/Server script to retrieve the applet sequence from the repository

This solutions just entails 1 part

1. Goto the DOM behind the current view and click the first applet that we find =)

Line 1:

var iRows = top.$("frameset",top.SWEFindFrame(top,"_sweview").document).attr("rows");

The Siebel thin client has an array of 10 cached view frames, and randomly picks a frame to render the next view upon Application Navigate. This happens behind the scenes and is not exposed or documented. Although the frame reference is random, and the next view frame is not known, we can check to see which of the current 10 frames is visible through the "rows" attribute on the frame container.

The above line just returns a reference to the current frame index.

Line 2:

var fDoc = top.SWEFindFrame(top,"_svf"+top.$.inArray("*",iRows.split(","))).document;

With the frame index, we can grab a hold of the actual frame document, using "top.SWEFindFrame". This is an undocumented Siebel browser framework function, if you are uncomfortable using it, you can roll your own, just write a recursive function that iterates through the frames and match on the frame name or just copy the Siebel function into your own library.

Line 3:

top.$("div[onclick*='HandleAppletClick']",fDoc).first().click();

As Cornelius has discovered, Siebel uses a function called "HandleAppletClick" on the onclick handlers for its applets. My original 5 line solution involved scraping the Applet name from the DOM, and passing it to "HandleAppletClick". In this solution, I just look for the first element that has the onclick handler that fires "HandleAppletClick", and click it programmatically.

[Conclusion]

Although its not necessary to use jQuery, having it makes our solution more concise, and readable. A similiar browser script function could have been implemented, but you would be spending a lot of time performing the low level DOM work.

Applet Toggles, Personalization, and Display Visibility all affect the run time visibility of the Applet. This technique allows us to determine dynamic UI behaviour that is not available when querying the repository.

The solution is lightweight, fast and best of all, we performed a beat down of ~85 lines of browser/server script with 3 lines of "Black Magic Do" (Translation: Way of the black magic). For the non initiated, in martial arts Do, means way or road =)

Solution - Popup Applet "X" button

This is the long awaited solution to the Popup Applet X button challenge, which was solved by Master configurator Michael Feng.

[Background]

Siebel provides us with two events on popup applets, represented by the buttons "Ok" and "Cancel" which provides the neccessary hooks to capture most business requirements around closing of popup applets.

But the "X" button is an exception case, where the user forced closed the applet without completing the required interaction. In these cases, you might want to rollback any changes that were made since the applet was opened, or popup an alert to educate the user of the consequences of not closing the Applet properly.

[Siebel popup applets]

It is important to understand what happens when we click on the "X" on a popup applet in Siebel. The developer who requested help from the Oracle forums, tried attaching a custom method on window.onunload, which is a native browser event for when the current view has been navigated away from or closed.

This is the right line of thinking, and isnt far off from Michael Fengs solution below. This would normally work for traditional web apps, but Siebel dosnt close the popup applet when you click "X", it just minimizes it and hides it under your taskbar, which is why the window.unload event never fires.

The way to see this in action, is to set your taskbar to auto hide, watch what happens when you click "X" on a popup applet. You'll see it minimized to a short title bar on the bottom left of your screen, underneath where the taskbar would normally sit when displayed.

[Usability]

The reason why Siebel does this is for usability. When you log into your Siebel application, the first time you open any popup applet will always be the slowest, thats because Siebel has to spawn a new instance of an IE window. When you click "X", siebel will minimise and hide the window. The next time when you open another popup applet, Siebel will re-display and re-use this same popup window.

Re-displaying an existing window is in order or magnitudes faster than opening a brand new window, and greatly enhances the user experience in HI applications.

[Solution]

As mentioned in the original post, there are various solutions to this problem. When the popup applet is closed, focus will return back to the control/applet that invoked the popup applet, and you could, pop up a confirmation at this point, but it is ugly, if the popup applet is used in many places then you would have code on a lot of base applets.

Since the Popup applet is never closed, another idea is to set a looping timer to determine the position of the applet, and if it disappears below the taskbar then we know it has been closed. Its not a desirable solution as polling adds overhead. So the ideal solution is to trap the X event on the popup applet itself.

One alternative is to attach a custom function to the window.onmove event of the Popup applet which would give us a real time notification everytime the applet gets moved, and if it moves to the taskbar position, we know the user clicked X.

Or we could do better by detecting when the physical dimensions of the Popup applet has been shrunk by monitoring the window.onresize event.

Heres how it can be done, the following code is provided by courtesy of Michael Feng.

function Applet_Load () {
var oCon = this.FindActiveXControl("NewQuery");
var obody = oCon.document.body;
var odiv = oCon.document.createElement("script");
odiv.type = "text/javascript";
odiv.language = "javascript";
odiv.text = "window.onresize=UnloadTrigger;function UnloadTrigger(){if(document.body.clientHeight==0&&document.body.clientWidth==0){alert('You close the popup applet');}}";
obody.appendChild(odiv);
}

An interesting question is, what happens to the UnloadTrigger that is attached to our first popup window, when a second popup is called after the first? Does it still linger around, even when if its unwanted on the second window? Siebel re-renders the entire contents of the applet everytime it is "re-used", but keeps a cache of the last applet.

Base applet --> Popup Applet A --> Popup Applet B

Siebel will cache the contents of Popup Applet A when it is opened, Siebel re-uses the popup window, and renders the HTML for Popup applet B when it is opened.

When Popup Applet B is closed, Siebel will reuse the popup window, and restore Popup Applet A from its cache, therefore restoring our UnloadTrigger.

So we have to modify the solution to deal with the fact that popups can spawn other popups.

function Applet_Load () {
var oCon = this.FindActiveXControl("NewQuery");
var obody = oCon.document.body;
var odiv = oCon.document.createElement("script");
odiv.type = "text/javascript";
odiv.language = "javascript";
odiv.text = "window.onresize=UnloadTrigger;function UnloadTrigger(){if(document.body.clientHeight==0&&document.body.clientWidth==0&&!Top().SWEPopupGainFocus()){alert('You close the popup applet');}}";
obody.appendChild(odiv);
}


The above code uses and undocumented function Top().SWEPopupGainFocus() to determine if a popup is in focus or not. We only want to display a message when there is no popup open.

The last piece to this puzzle is to handle the positive events when the user click on "Ok" and "Cancel", in which event we do not want to display our message. You'll need to set profile attributes, or view variables to indicate that the applet was closed properly, and check for these variables in the unload function.

function Applet_Load () {
var oCon = this.FindActiveXControl("NewQuery");
var obody = oCon.document.body;
var odiv = oCon.document.createElement("script");
odiv.type = "text/javascript";
odiv.language = "javascript";
odiv.text = "window.onresize=UnloadTrigger;function UnloadTrigger(){if(document.body.clientHeight==0&&document.body.clientWidth==0&&!Top().SWEPopupGainFocus()&&App().GetProfileAttr('ProperlyClosed')!='Y'){alert('You close the popup applet');}}";
obody.appendChild(odiv);
}

Thanks to Michael for providing this solution, and for helping solve another impossible problem and breaking new grounds on creativity =).

Funky Town: Inline Field Validation

This post is part of the Funky Town series of articles, where we take ridiculous User Centric Design (UCD) requirements and put them into practice.

In this article, I look at another outrageous business requirement - Inline field validation.

Imagine typing in an email address, and as soon as you step off, the field turns red, and a tooltip style message appears, stating that your input does not meet the proper standard for an email address.



Inline field validation provides many benefits

1. Immediate help for the user
2. Affirmation that the user is doing the right thing
3. Assists complex data input requirements
4. Improves user experience
5. No server round trip required
6. Makes Siebel a joy to work with!

This is the sort of thing you see on fancy web forms, and only BA's will dream this requirement up because Siebel is a simple web application right?. Lets see how we can provide this functionality for them.

[Solution]

This solution will only work for form applets, so open up any form applet, and designate a field that will act as your "email address", for this exercise your field dosnt actually be an email field.

1. Put the following code in your email field control OnBlur handler
validateEmail(applet,id);

2. Add the following browser script to your applet
function validateEmail(applet,id){
    try{
        var sValue = applet.FindControl(id).GetValue();
        var oDoc = applet.FindActiveXControl(id).document;
   var oToolTip = oDoc.getElementById("Tooltip");
        if(sValue.length>0&&sValue.indexOf("@")==-1){//insert fancy email validation routine here
       if(!oToolTip){
           var oToolTip=oDoc.createElement("div");
           oToolTip.innerHTML=" Please enter a valid Email address eg. Jason@EuroDiscoFan.com";
           oToolTip.id="Tooltip";
           oToolTip.style.backgroundColor="#fff";
           oToolTip.style.color="#000";
           oToolTip.style.padding="10px 40px";
           oToolTip.style.borderStyle="solid";
oToolTip.style.borderColor="#bbb";
oToolTip.style.borderWidth="10px";
           var oHeader = oDoc.getElementById("SectionHeaderId");
           if(oHeader) {
                oHeader.parentNode.parentNode.appendChild(oToolTip);
                applet.FindControl(id).SetProperty("BgColor", "#ff0000");
            }
         }
        }else{
            if(oToolTip){
                oToolTip.parentNode.removeChild(oToolTip);
                applet.FindControl(id).SetProperty("BgColor", "#ffffff");
            }

        }
    }catch(e){
    }

}

3. Create a section header for your form, add the following in the caption override
<span id="SectionHeaderId">My Funky Form</span>

Re-compile your applet, and type in some junk in your email field. As soon as you step off, your field will turn red, and a message will appear to notify of the error.

Suffice to say, the email routine that I used above is not foolproof ^_*, but you get the idea. A more wholistic solution would look at validation from a general perspective, but that is left to the reader to run with.

[Conclusion]

1. Will it perform well?
Yes, there are no server calls.

2. Is it maintainable?
Yes, if the code is made production ready, and all the validation routines are centralised.

3. Can it be upgraded?
Yes, as it does not use any undocumented methods

and

4. Is it sexy?
Yes, its a BA's dream come true