sales@scenomics.com +1 650 396 9674

Implement Document Create Command

NOTE: This exercise assumes you have completed the previous exercise.

In this exercise you'll learn to implement a Scenome application command that creates a new document with the Octopus app. At the end of this exercise, you'll have a command that can create a new GPU compute project.

Implement Function 'GetNewDocumentString'

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named GetFilterInfo.

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function string GetFilterInfo()
    {
       return "Octopus Box Files (*.box)|*.box|All Files (*.*)|*.*||";
    }
    

    We're going to implement a new function to store UI strings.

  3. Insert the following function immediately above GetFilterInfo.

    Copy Text To Clipboard

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function string GetNewDocumentString()
    {
       return "&Workload...";
    }
    
  4. Save the script in the text editor.

Modify Function 'PopulateMenu'

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named PopulateMenu.

    We're going to change the name of the menu item in the create command popup menu.

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function int PopulateMenu( StrList p_slTitles )
    {
       p_slTitles.Add( "&New Document" );
    
       return p_slTitles.GetCount();
    }
  3. Change &New Document to GetNewDocumentString() and save the file.

    Copy Text To Clipboard

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function int PopulateMenu( StrList p_slTitles )
    {
       p_slTitles.Add( GetNewDocumentString() );
    
       return p_slTitles.GetCount();
    }
  4. Save the script in the text editor.

Modify Function 'GetIconImages'

  1. Find the function named GetIconImages.
    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function void GetIconImages( TypeInfoArray p_aoTypes, TypeArray p_aoItemImages )
    {
       auto FilePath a_oIconPath = new FilePath(
          LibAppServiceMain.GetIconsPath() );
       a_oIconPath.AppendPath( "root_icon.bmp" );
    
       for( int i = 0; i < p_aoTypes.GetCount(); ++i )
       {
          Image a_oImage = new Image;
          a_oImage.OpenFile( a_oIconPath.GetPath() );
          p_aoItemImages.Add( a_oImage );
       }
    }

    We're going to change the name of the icon presented on the left side of popup menu items.

  2. Change root_icon.bmp to create_new_workload_command.bmp and save the file.

    Copy Text To Clipboard

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function void GetIconImages( TypeInfoArray p_aoTypes, TypeArray p_aoItemImages )
    {
       auto FilePath a_oIconPath = new FilePath(
          LibAppServiceMain.GetIconsPath() );
       a_oIconPath.AppendPath( "create_new_workload_command.bmp" );
    
       for( int i = 0; i < p_aoTypes.GetCount(); ++i )
       {
          Image a_oImage = new Image;
          a_oImage.OpenFile( a_oIconPath.GetPath() );
          p_aoItemImages.Add( a_oImage );
       }
    }
  3. Save the script in the text editor.

Test Code Changes

  1. Return to the running Octopus app.
  2. Select Desktop » Refresh Scripts from the main menu. ( ALT + D + R )

    The application displays script compiler messages in the output window:

    Start loading scripts
    Done loading scripts; 10 loaded in 1.29 ms; avg 0.09
    

    If there are any script compiler errors, undo your changes in the text editor, go back to the previous step, and follow the instructions again. Here is an example of what error messages might look like:

    Start loading scripts
    D:\release6\scripts\app_shell_util.ssl(1770) : error: newline in constant
    Done loading scripts; 10 loaded in 1.29 ms; avg 0.09
    
  3. Select File » New from the main menu.

    A popup menu appears. You should see the following:

    This is a picture of the new popup menu.

    The command uses the new name and icon, so the user interface work is complete. Now it's time to make the command do some work so that we can say 'hey command, you're useful!'.

  4. Save the script in the text editor.

Modify Function 'CreateOctopusDocument' — Adding Function Call Site

  1. Find the script app_octopus_create_document_scripts.ssl in the text editor.
  2. Find the function named CreateOctopusDocument.

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function void CreateOctopusDocument(
    
       ApplicationEventSource sender,
       CommandExecutionEvent event,
       string p_sMenuTitle,
       int p_nIndex
    
       )
    {
       Console.Out( "Executed document create command." );
    }
    

    At present you can see the command body prints a message to the output window and then completes. This lets us know if the command is working, but it's a long way from doing anything useful. We're going to do a fairly complicated implementation, but we're going to take it step-by-step, and we'll discuss aspects of the implementation and the code as we go.

  3. Replace the entire CreateOctopusDocument function with following code:

    Copy Text To Clipboard

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function void CreateOctopusDocument(
    
       ApplicationEventSource sender,
       CommandExecutionEvent event,
       string p_sMenuTitle,
       int p_nIndex
    
       )
    {
       if( p_sMenuTitle == LibOctopusCreateDocument.GetNewDocumentString() )
       {
          LibOctopusCreateDocument.Execute( event );
       }
    }

    This code checks if the menu name string matches the workload string (&Workload...), and calls a function that creates the new document for us. This implementation allows us to have multiple menu items that create different types of documents. For now though, we'll only have one type of document. This strategy also allows us to implement the code for document creation in separate functions, which promotes separation-of-concerns.

  4. Save the script in the text editor.

Modify Function 'CreateOctopusDocument_OnUpdate' — Update UI Hint Text

  1. Find the script app_octopus_create_document_scripts.ssl in the text editor.
  2. Find the function named CreateOctopusDocument_OnUpdate.

    function void CreateOctopusDocument_OnUpdate(
    
       ApplicationEventSource sender,
       CommandUpdateEvent event,
       string p_sMenuTitle,
       int p_nIndex
    
       )
    {
       event.Info.Status.SetHint( "Creates a new..." );
    }

    This sets the hint text when the user moves the mouse over the cursor.

  3. Replace the entire CreateOctopusDocument_OnUpdate function with following code:

    Copy Text To Clipboard

    function void CreateOctopusDocument_OnUpdate(
    
       ApplicationEventSource sender,
       CommandUpdateEvent event,
       string p_sMenuTitle,
       int p_nIndex
    
       )
    {
       if( p_sMenuTitle == LibOctopusCreateDocument.GetNewDocumentString() )
       {
          event.Info.Status.SetHint( "Creates a new CPU/GPU workload document" );
       }
    }
    

    This code checks if the menu name string matches the terrain analysis string, and sets the menu item hint text accordingly. This is the text the user sees when they move the mouse over the menu item.

  4. Save the script in the text editor.

Implement Function 'Execute'

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named GetIconImages.

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function void GetIconImages( TypeInfoArray p_aoTypes, TypeArray p_aoItemImages )
    {
       auto FilePath a_oIconPath = new FilePath(
          LibAppServiceMain.GetIconsPath() );
       a_oIconPath.AppendPath( "create_new_workload_command.bmp" );
    
       for( int i = 0; i < p_aoTypes.GetCount(); ++i )
       {
          Image a_oImage = new Image;
          a_oImage.OpenFile( a_oIconPath.GetPath() );
          p_aoItemImages.Add( a_oImage );
       }
    }
    

    We're going to implement a new function that creates the new document.

  3. Insert the following function immediately below GetIconImages.

    Copy Text To Clipboard

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function bool Execute( CommandExecutionEvent event )
    {
       Console.Out( "Executed document create command." );
    
       return true;
    }
    
  4. Save the script in the text editor.

Test Code Changes

  1. Return to the running Octopus application.
  2. Select Desktop » Refresh Scripts from the main menu.

    The application displays script compiler messages in the output window:

    Start loading scripts
    Done loading scripts; 10 loaded in 1.29 ms; avg 0.09
    

    If there are any script compiler errors, undo your changes in the text editor, go back to the previous step, and follow the instructions again.

  3. Select File » New » Workload from the main menu.

    The command runs but it doesn't appear to do anything. This is normal.

  4. Examine the output window.

    We wrote code that prints the command completion message. As you can see, the message appeared correctly.

    Executed document create command.

    It's important to understand a few things about commands. When you execute a command in a Scenome application, most of the changes are not applied to the document until command execution completes. Even though you have a scripted command, final command completion almost always happens in Scenome's C++ code, which means that certain types of changes to the document will not be finalized during Scenome Scripting Language code execution. This is generally not an issue, but it's something that can be important.

    Now that we have verified code execution, it's time to think about what should happen when we create a new file. We know we want to write an application that allows the user to build CPU/GPU compute workloads. We also want to allow the user to write script code that executes their workloads. It would be nice if the way we specified compute workloads was data-driven so that we could write a generic build script that would allow us to extend the application to many types of GPU compute without having to change the application itself.

Implement Function 'RewriteScript'

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named GetIconImages.

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function void GetIconImages( TypeInfoArray p_aoTypes, TypeArray p_aoItemImages )
    {
       auto FilePath a_oIconPath = new FilePath(
          LibAppServiceMain.GetIconsPath() );
       a_oIconPath.AppendPath( "create_new_workload_command.bmp" );
    
       for( int i = 0; i < p_aoTypes.GetCount(); ++i )
       {
          Image a_oImage = new Image;
          a_oImage.OpenFile( a_oIconPath.GetPath() );
          p_aoItemImages.Add( a_oImage );
       }
    }
    
    

    We're going to implement a new function that we'll use to rewrite a script.

  3. Insert the following function immediately below GetIconImages.

    Copy Text To Clipboard

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function void RewriteScript( StrList p_slScript, StrList p_slKeys, StrList p_slVals )
    {
       if( p_slKeys.GetCount() != p_slVals.GetCount() )
       {
          LibAssert.Count( Script.Name, Script.Runtime.CurrentFunction.Name );
          return;
       }
    
       for( int i = 0; i < p_slScript.GetCount(); ++i )
       {
          Str a_oLine = p_slScript.GetObjAt( i );
    
          for( int k = 0; k < p_slKeys.GetCount(); ++k )
          {
             if( a_oLine.In( p_slKeys.GetAt( k ), 0 ) )
             {
                a_oLine.Value = a_oLine.Replace(
                   p_slKeys.GetAt( k ), p_slVals.GetAt( k ) );
             }
          }
       }
    }

    This function is very simple. It replaces text keys contained in one <StrList> object with the text values from another <StrList> object. For example: a key "__MYKEY__" might be replaced with the value "MyKey". Since we rely on key value pairs, the function requires every key to have a corresponding value. Therefore this function asserts if the <StrList> objects do not have the same count.

  4. Save the script in the text editor.

Modify Function 'Execute' — Implement <PopupControlDialog> Input Wizard

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named Execute.

    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function bool Execute( CommandExecutionEvent event )
    {
       Console.Out( "Executed document create command." );
    }
    
    

    We're going to write the code that actually creates the new document.

  3. Insert the following code immediately above the line Console.Out( "Executed document create command." );.

    Copy Text To Clipboard

    ////////////////////////////////////////
    // Present a wizard so the user can enter project information.
    ////////////////////////////////////////
    
    auto ControlPopupDialog a_oDlg;
    a_oDlg.SetOkButtonEnabled( true );
    
    bool a_bEnabled = true;
    bool a_bReadOnly = false;
    int a_nInitialIndex = -1;
    int a_nInitialValue = 0;
    
    string IDS_AUTHOR_NAME   = "IDS_AUTHOR_NAME";
    string IDS_PROJECT_DESC  = "IDS_PROJECT_DESC";
    string IDS_PROJECT_NAME  = "IDS_PROJECT_NAME";
    string IDS_WORKLOAD_NAME = "IDS_WORKLOAD_NAME";
    
    int IDN_AUTHOR_NAME  = 0;
    int IDN_PROJECT_DESC  = 1;
    int IDN_PROJECT_NAME  = 2;
    int IDN_WORKLOAD_NAME = 3;
    
    LibControlPopupDialog.AddString(
       a_oDlg,
       IDS_AUTHOR_NAME,
       a_nInitialIndex,
       "Author Name:",
       "my_company",
       a_bReadOnly,
       a_bEnabled );
    
    LibControlPopupDialog.AddString(
       a_oDlg,
       IDS_PROJECT_DESC,
       a_nInitialIndex,
       "Project Description:",
       "This project...",
       a_bReadOnly,
       a_bEnabled );
    
    LibControlPopupDialog.AddString(
       a_oDlg,
       IDS_PROJECT_NAME,
       a_nInitialIndex,
       "Project Name:",
       "my_project",
       a_bReadOnly,
       a_bEnabled );
    
    LibControlPopupDialog.AddString(
       a_oDlg,
       IDS_WORKLOAD_NAME,
       a_nInitialIndex,
       "Workload Name:",
       "MyWorkload",
       a_bReadOnly,
       a_bEnabled );
    
    if( !( a_oDlg.ShowModal(
       "Create Workload", "Specify workload execution options:" ) ) )
    {
       // User cancelled.
       return false;
    }
    

    This code configures and then displays a wizard that allows the user to enter data about their project. Note that we are only collecting a few values, so the wizard will be pretty easy to use.

  4. Save the script in the text editor.

Modify Function 'Execute' — Implement Input Handling

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named Execute.
  3. Insert the following code immediately above the line Console.Out( "Executed document create command." ); (which is at the bottom of the function ).

    Copy Text To Clipboard

    ////////////////////////////////////////
    // Process the values entered by the user.
    ////////////////////////////////////////
    
    string a_sAuthorName   = a_oDlg.GetStringValue( IDN_AUTHOR_NAME );
    string a_sProjectDesc  = a_oDlg.GetStringValue( IDN_PROJECT_DESC );
    string a_sProjectName  = a_oDlg.GetStringValue( IDN_PROJECT_NAME );
    string a_sWorkloadName = a_oDlg.GetStringValue( IDN_WORKLOAD_NAME );
    
    //Console.Out( a_sProjectName );
    //Console.Out( a_sWorkloadName );
    
    string a_sLibFragment = "AppOctopusWorkload";
    string a_sLibId = "Lib" + a_sLibFragment + a_sWorkloadName;
    auto Str a_oWorkloadId = new Str( a_sLibId );
    string a_sWorkloadID = LibStr.GenerateCommandFileFromName(
       a_sLibFragment + a_sWorkloadName );
    string a_sScriptID = a_sWorkloadID + "_util.ssl";
    string a_sClassID = a_sWorkloadID + "_classes.ssl";
    
    //Console.Out( a_sLibId );
    //Console.Out( a_sWorkloadID );
    //Console.Out( a_sScriptID );
    

    This code handles input from the user. It extracts the values the user entered in the dialog and builds strings that we'll use to create the project file, scripts for the project, and to configure the project file. Note that we are using values like IDN_AUTHOR_NAME to maintain the indices from which to extract the string values.

  4. Save the script in the text editor.

Modify Function 'Execute' — Create The Project Directory

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named Execute.
  3. Insert the following code immediately above the line Console.Out( "Executed document create command." ); (which is at the bottom of the function ).

    Copy Text To Clipboard

    ////////////////////////////////////////
    // Create the project directory.
    ////////////////////////////////////////
    
    auto FilePath a_oProjectPath = new FilePath(
       LibAppServiceMain.GetLibraryPath() );
    a_oProjectPath.AppendPath( "Octopus" );
    a_oProjectPath.AppendPath( a_sProjectName );
    if( a_oProjectPath.FileExists() )
    {
       // Fail if the directory exists
       // so that we don't overwrite
       // any existing work.
       string a_sMessage = "A project named '" +
          a_sProjectName + "' already exists!";
       Console.Alert( a_sMessage );
       return false;
    }
    
    bool a_bCreatedDir = Application.CreateDirectory(
       a_oProjectPath.GetPath() );
    if( !( a_bCreatedDir ) )
    {
       // Fail if we can't create the
       // directory since we won't be
       // able to save anything.
       string a_sMessage = "Unable to create directory: " +
          a_oProjectPath.GetPath();
       Console.Alert( a_sMessage );
       return false;
    }
    

    This code creates the project directory. Notice that there are two guards: the first guard prevents the user from creating a project name if the project already exists, and the second guard informs the user if the application could not create the project directory. In both failure cases, the function informs the user of the failure by presenting a message box, and returns without doing more work.

  4. Save the script in the text editor.

Modify Function 'Execute' — Create The Key-Value Pairs

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named Execute.
  3. Insert the following code immediately above the line Console.Out( "Executed document create command." ); (which is at the bottom of the function ).

    Copy Text To Clipboard

    ////////////////////////////////////////
    // Create the key-value pairs.
    ////////////////////////////////////////
    
    auto StrList a_slKeys;
    a_slKeys.Add( "__AUTHOR__" );
    a_slKeys.Add( "__DESC__" );
    a_slKeys.Add( "__LIB__" );
    
    auto StrList a_slVals;
    a_slVals.Add( a_sAuthorName );
    a_slVals.Add( a_sProjectDesc );
    a_slVals.Add( a_sLibId );
    

    This code declares and initializes the key-value pairs that we'll use to rewrite the template scripts with information entered by the user.

  4. Save the script in the text editor.

Modify Function 'Execute' — Create The Classes Stub Script

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named Execute.
  3. Insert the following code immediately above the line Console.Out( "Executed document create command." ); (which is at the bottom of the function ).

    Copy Text To Clipboard

    ////////////////////////////////////////
    // Create the stub script for classes.
    ////////////////////////////////////////
    
    auto FilePath a_oClassPath = new FilePath(
       LibAppServiceMain.GetAppScriptsPath() );
    a_oClassPath.AppendPath( a_sClassID );
    if( a_oClassPath.FileExists() )
    {
       // Fail if the script already exists
       // so that we don't overwrite
       // any existing work.
       string a_sMessage = "Script already exists: " +
          a_oClassPath.GetPath();
       Console.Alert( a_sMessage );
       return false;
    }
    
    a_slKeys.Add( "__IMPORT__" );
    a_slVals.Add( a_oClassPath.GetFileName() );
    
    // Load the script template.
    auto TextFile a_oClassDoc;
    auto StrList a_slClassTemplate;
    
    auto FilePath a_oClassTemplatePath =
       new FilePath( LibAppServiceMain.GetTemplatesPath() );
    a_oClassTemplatePath.AppendPath( "SSL" );
    a_oClassTemplatePath.AppendPathWithFile( "_classes.ssl" );
    
    LibStrList.ReadFromDisk(
       a_oClassDoc, a_oClassTemplatePath, a_slClassTemplate );
    
    RewriteScript(
       a_slClassTemplate, a_slKeys, a_slVals );
    
    // Save the script template
    // with the filename we created.
    LibStrList.WriteToDisk(
       a_oClassDoc, a_oClassPath, a_slClassTemplate );
    

    This code creates a stub script to store classes that will be used by the script that executes the workload. Not all workload executions scripts need classes, but many do, including the implementation we'll write in this exercise.

  4. Save the script in the text editor.

Modify Function 'Execute' — Create Workload Execution Script

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named Execute.
  3. Insert the following code immediately above the line Console.Out( "Executed document create command." ); (which is at the bottom of the function ).

    Copy Text To Clipboard

    ////////////////////////////////////////
    // Create the stub script that will execute the workload.
    ////////////////////////////////////////
    
    auto FilePath a_oScriptPath = new FilePath(
       LibAppServiceMain.GetAppScriptsPath() );
    a_oScriptPath.AppendPath( a_sScriptID );
    if( a_oScriptPath.FileExists() )
    {
       // Fail if the script already exists
       // so that we don't overwrite
       // any existing work.
       string a_sMessage = "Script already exists: " +
          a_oScriptPath.GetPath();
       Console.Alert( a_sMessage );
       return false;
    }
    
    // Load the script template.
    auto TextFile a_oScriptDoc;
    auto StrList a_slTemplate;
    
    auto FilePath a_oScriptTemplatePath =
       new FilePath( LibAppServiceMain.GetTemplatesPath() );
    a_oScriptTemplatePath.AppendPath( "SSL" );
    a_oScriptTemplatePath.AppendPathWithFile( "_workload.ssl" );
    
    LibStrList.ReadFromDisk(
       a_oScriptDoc, a_oScriptTemplatePath, a_slTemplate );
    
    RewriteScript(
       a_slTemplate, a_slKeys, a_slVals );
    
    // Save the script template
    // with the filename we created.
    LibStrList.WriteToDisk(
       a_oScriptDoc, a_oScriptPath, a_slTemplate );
    
    Console.Alert( "Copied script path to clipboard: " +
       a_oScriptPath.GetPath() );
    Clipboard.SetString( a_oScriptPath.GetPath() );
    

    This code creates the script that executes the workload using a combination of CPU and GPU compute. (For now, this script is going to be a placeholder. It won't contain any code for CPU or GPU compute.) The code first checks if the script exists, and, if the script does exist, the code warns the user and returns without doing any further work. This prevents us from overwriting existing workload processing scripts. If successful, the code opens the template script and then replaces terms such as __AUTHOR__ with the string values provided by the user. Finally, at the end, we copy the new script path to the Windows® clipboard and inform the user. This makes it very easy for the user to open the new script to implement the Scenome Scripting Language code that executes their workload.

  4. Save the script in the text editor.

Modify Function 'Execute' — Save The Project To Disk

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named Execute.
  3. Insert the following function immediately above the line Console.Out( "Executed document create command." ); (which is at the bottom of the function ).

    Copy Text To Clipboard

    ////////////////////////////////////////
    // Save the project to disk.
    ////////////////////////////////////////
    
    string a_sProjectFileName = a_sProjectName + ".box";
    auto FilePath a_oProjectFilePath =
       new FilePath( a_oProjectPath.GetPath() );
    a_oProjectFilePath.AppendPathWithFile(
       a_sProjectFileName );
    
    Application.SaveFileAs( Model, a_oProjectFilePath.GetPath() );
    
    Model.Class = "v1_octopus";
    Model.DocumentInfo.ShellName = "Octopus_v1.scenomeapp";
    
    LibAppServiceShell.SetShellForClass( Model.Class );
    LibAppServiceShell.SetApp( Model );
    

    This code saves the project to disk using the project name specified by the user. With this step complete, we set the shell class, we set the shell itself, and we set the correct app binding. These functions cause the user interface to change from having only three items to having a full main menu and a complete set of context menus. Note that changing the application binding will cause new scripts to load. Since those scripts have to be compiled, there can sometimes be a short delay during document creation.

  4. Save the script in the text editor.

Modify Function 'Execute' — Create The <WorkloadNode>

  1. Go to the text editor and find the script app_octopus_create_document_util.ssl.
  2. Find the function named Execute.
  3. Insert the following function immediately above the line Console.Out( "Executed document create command." ); (which is at the bottom of the function ).

    Copy Text To Clipboard

    ////////////////////////////////////////
    // Create the WorkloadNode.
    ////////////////////////////////////////
    
    a_oScriptPath.MakeRelativeToModel( Model );
    
    WorkloadNode a_oWork = LibCreate.NewWorkloadNode();
    a_oWork.Name = a_sProjectName;
    a_oWork.ScriptPath = a_oScriptPath.GetPath();
    a_oWork.ScriptNamespace = a_sLibId;
    a_oWork.ScriptFunction = "Execute";
    
    Model.AddNode( a_oWork, Model, -1 );
    

    Since we implemented the code that saved the document in the previous section, we can now use functions like MakeRelativeToModel( ... ). We allocate a new <WorkloadNode> and configure it using the data provided by the user. We set ScriptPath to the path on disk of the new script we created. We also set ScriptNamespace and ScriptFunction so that the <WorkloadNode> knows which function to execute during the application build process. Earlier in this document, we said that it would be nice if we could implement a data-driven build process, and that's exactly what we're doing here. We store the build 'parameters' in the <WorkloadNode>, which will enable us to write a generic build function that will simply execute whatever workload is specified in the script. We'll be able to use this strategy to execute a generic CPU/GPU compute workloads without changing the application at all once the basic implementation is complete.

  4. Save the script in the text editor.

Test Code Changes

  1. Return to the running Octopus app.
  2. Select Desktop » Refresh Scripts from the main menu. ( ALT + D + R )

    The application displays script compiler messages in the output window:

    Start loading scripts
    Done loading scripts; 10 loaded in 1.29 ms; avg 0.09
    

    If there are any script compiler errors, undo your changes in the text editor, go back to the previous step, and follow the instructions again. Here is an example of what error messages might look like:

    Start loading scripts
    D:\release6\scripts\app_shell_util.ssl(1770) : error: newline in constant
    Done loading scripts; 10 loaded in 1.29 ms; avg 0.09
    
  3. Select File » New » Workload from the main menu.

    The Create Workload wizard appears:

    This is a picture of the new Create Workload wizard.

    This looks perfect!

  4. Set the value of Author Name to your name or your company name.
  5. Set the value of Project Description to the following:

    Copy Text To Clipboard

    This script executes a GPU workload that analyzes terrain for exposure to avalanches.
  6. Set the value of Project Name to the following:

    Copy Text To Clipboard

    Western-Washington-Mt-Baker-Terrain-Analysis
  7. Set the value of Workload Name to Terrain.

    Copy Text To Clipboard

    Terrain
  8. Click OK or hit ENTER when you are finished.

    The document create code executes.

    The wizard presents a message box that informs you the script path has been copied to the Windows® clipboard.

    This is a picture of a message box.

    Since we are changing the application shell, some scripts will need to be loaded. This means that the command could take a few seconds to complete.

    You'll see a new <WorkloadNode> when the command completes.

    This is a picture of the new WorkloadNode.
  9. Move the mouse over the new <WorkloadNode>.

    You can see the workload script, function namespace, and function. This information will make it possible for us to implement a data-driven build process that won't require changes to the application in order to accomodate new CPU and GPU compute workloads.

    This is a picture of the new WorkloadNode tooltip.

    Do you remember that the document create command copied a script path to the clipboard? We need to open that script.

  10. Select File » Save from the main menu.
  11. Select File » Exit to close the Octopus application.

Open The Workload Execution Script

  1. Return to the text editor and select the option to open a file from disk.
  2. Select CTRL + V to paste the script command library file path (into the place in the dialog where you specify the file to open).
  3. Open the file.

    The script appears in the text editor.

    ///////////////////////////////////////////////////////////////////////////////
    //
    // $author           Scenomics LLC
    // $description      This script executes a GPU workload that analyzes terrain for exposure to avalanches.
    //
    // Copyright 2021 Scenomics LLC. All Rights Reserved.
    //
    ///////////////////////////////////////////////////////////////////////////////
    
    library LibAppOctopusWorkloadTerrain;
    
    import library "app_service_assert_util.ssl";
    import library "app_service_console_util.ssl";
    import library "app_service_main_util.ssl";
    import library "type_file_path_algorithms.ssl";
    import library "type_float32_array_util.ssl";
    import library "type_image_channel_extract_util.ssl";
    import library "type_image_format_util.ssl";
    import library "type_image_util.ssl";
    import library "type_int32_array_util.ssl";
    import library "type_render3d_util.ssl";
    import library "type_service_enumeration_util.ssl";
    import library "type_str_list_util.ssl";
    import library "app_octopus_workload_terrain_classes.ssl";
    
    ///////////////////////////////////////////////////////////////////////////////
    // function
    ///////////////////////////////////////////////////////////////////////////////
    
    function bool Execute( FileNode p_oData, CommandPresentationModuleInfo p_oInfo, StrList p_slMessages )
    {
       p_slMessages.Add( "Executed build..." );
    
       return true;
    }
    
  4. We want this script to execute when we run the Octopus app build command. It won't execute now, and even if it did execute, we don't have any data. So let's get some data into the app and then we'll make the app build command execute the compute workload for us.

  5. Return to the Shell application.
  6. Select File » Save from the main menu.
  7. Select File » Exit to close the Shell application.

    This might take a minute while dependencies are updated.

Open The Workload Execution Classes

  1. Return to the text editor and select the option to open a file from disk.
  2. Type app_octopus_workload_terrain_classes.ssl.

    Copy Text To Clipboard

    app_octopus_workload_terrain_classes.ssl
  3. Open the file.

    The script appears in the text editor.

    ///////////////////////////////////////////////////////////////////////////////
    //
    // $author           Scenomics LLC
    // $description      This script contains class declarations
    //
    // Copyright 2021 Scenomics LLC. All Rights Reserved.
    //
    ///////////////////////////////////////////////////////////////////////////////
    
    import library "app_service_assert_util.ssl";
    import library "app_service_console_util.ssl";
    
  4. We're not going to do anything with this script at the moment, but it's convenient to open it now.

  5. Leave the text editor running and proceed to the next exercise.