Academic Company Events NI Developer Zone Support Solutions Products & Services Contact NI MyNI
What is Developer Zone?
United States

Document TypeTutorial
NI Supported: Yes
Publish Date: Aug 17, 2012


Feedback


Yes No

Related Categories

Products

Related Links - Developer Zone

Related Links -Products and Services

Actor Framework Template Documentation

0 Ratings | 0.00 out of 5
Read in  |  Print |  PDF

Overview

The Actor Framework is a template for creating LabVIEW applications that consist of multiple, independent tasks that need to communicate with each other. This framework was designed to address common development scenarios that can lead to significant duplication of code when extending functionality or adding additional processes. Each actor is defined by a LabVIEW class that is instantiated by launching an instance of the actor, which is represented by a LabVIEW object. All descendants of the base actor class (Actor) contain the Actor Core method, which serves as a queued message handler. This VI receives and responds to messages and data sent to it by other actors in the system. However, because actors are LabVIEW classes, actors are far more reusable and scalable than traditional queued message handlers.

Table of Contents

  1. Example
  2. Developer Walkthrough
  3. System Requirements
  4. Use Cases
  5. Running this Template
  6. Understanding the Components of the Actor Framework
  7. Understanding the Project Hierarchy
  8. Modifying this Template
  9. Further Reading
  10. NI Training and Certification
  11. Important Information

This template includes three actors (Application, Alpha, and Beta) and shows how they communicate with each other.

Note   This template makes extensive use of LabVIEW classes. Designing an application with the Actor Framework requires familiarity with principles of object-oriented programming in LabVIEW. This document provides the information necessary to understand and modify the Actor Framework template. For more information about designing applications with the Actor Framework, refer to the Actor Framework Whitepaper in the Project Documentation folder of the Project Explorer window.

Example

Refer to the Feedback Evaporative Cooler sample project, available from the Create Project dialog box, for an example of adapting this template to an application.

Developer Walkthrough

See a developer walkthrough of the Actor Framework template.

System Requirements

LabVIEW Base, Full, or Professional Development System

Use Cases

The Actor Framework is suitable for applications where you find yourself duplicating large amounts of code but making small, specific tweaks to each copy. Developing medium-to-large applications in this way is difficult, especially if you intend to maintain and extend the application.

For example, consider an measurement application that needs to continuously take both strain and resistance measurements. A traditional approach would be to create a queued message handler that takes a strain measurement, copy this queued message handler, modify the copy to take a resistance measurement, and then combine both queued message handlers into a single application. This approach results in two queued message handlers that share a large amount of code but each have some specific differences. If you change one part of the program, you must track and duplicate these changes in the other one.

In using the Actor Framework approach, you would start by identifying functionality that both types of measurements share, such as the following steps:

  • Acquire a reference to the hardware device
  • Continuously take a measurement
  • Continuously process the measurement
  • Continuously display the processed measurement to the user, along with a history of previous measurements
  • Close the reference to the hardware device

Each of these steps is similar to a state, or message diagram, in a queued message handler. Although these steps are the same for both kinds of measurements, the specific commands involved are different for each type of measurement. The hardware device that is used is different, the VI that acquires the data is different, the processing applied to the measurement is different, and so on.

The object-oriented approach of the Actor Framework addresses the scalability and reuse issues while providing additional functionality. Using the Actor Framework, you can encapsulate the generic functionality described above in a Measurement actor. The Measurement actor, which is a LabVIEW class, would not be able to take a measurement itself; instead, its member VIs would define, in general terms, what kinds of steps are necessary. Each step would correlate to a member VI in the class.

Because the Measurement actor is a LabVIEW class, you would then create two child actors that inherit from Measurement for specific functionality: a Strain actor and a Resistance actor. These children would inherit the functionality of their parent but would add specific strain- or resistance-related operations, thus enabling these actors to actually take, process, and display continuous measurements. This approach maximizes code reuse by encapsulating generic functionality into a single point—the Measurement actor, leaving its children to define specific commands.

Additionally, because each actor is a separate entity, applications can load actors into memory dynamically. For example, you could have one application that, at the click of a button, is able to take a strain or resistance measurement. Implementing this kind of functionality without using the Actor Framework is difficult, time-consuming, and error-prone, especially if you plan to modify or extend the application in the future. The Actor Framework, meanwhile, is designed for these kinds of applications.

Running this Template

Complete the following steps to run this template:

  1. In the Project Explorer window, open and run Application Launcher.lvlib:Splash Screen.vi.
  2. Watch the Event Log for the messages that each nested actor (Alpha and Beta) sends to the top-level actor (Application).
  3. Click Send Alpha Message. The Application actor sends a message to the Alpha actor. Watch the Event Log for a response.
  4. Click Send Beta Message. The Application actor sends a message to the Beta actor. Watch the Event Log for a response.
  5. Stop the application by clicking Stop All.

Understanding the Components of the Actor Framework

The Actor Framework consists of actors and messages. Messages are delivered in message queues. To minimize errors and maximize application reliability, the Actor Framework restricts which actors can send messages to one another.

Actors

An actor is a LabVIEW class that represents the state of some task. All actor classes descend from the Actor class, which is included with LabVIEW. This class has three main components:

  • The actor's core VI—The core VI is a specially-named method, Actor Core, that defines the continuous behavior of the actor. This method defines the message-handling behavior of all actors. Descendants of this class override the method to display a user interface for the actor, append parallel loops, and launch nested actors.
  • The actor's specific methods—These VIs are members of the LabVIEW class that defines the actor. Typically, each method corresponds to a task the actor can perform. The ancestor class, Actor, includes several methods that are specifically designed to be overridden by descendants.
  • The actor's messages—A message is a LabVIEW class that defines what instruction an actor can receive and how it responds to that instruction. Other actors send these messages to an actor to get the actor to invoke one of its methods. When creating an application based on the Actor Framework, you generally define a message for each method of the actor. All messages descend from the Message class, which is included with LabVIEW.

    Although messages are not part of actors themselves, you generally define an actor's messages while defining the actor itself. Because of this close relationship, this template groups actors and messages for that actor together in a single project library.

For example, the following screenshot shows a project library that contains one actor (Alpha, represented by the Alpha class) and one message (the Alpha Task Msg class).

The screenshots above shows the following files that are related to this actor:

  • The actor's core VI is Actor Core. This method overrides its ancestor Actor Core method, defining a continuous behavior that is specific to the Alpha actor.
  • The actor's methods are Stop Core and Task. These execute under the following conditions:
    • Stop Core executes when the Alpha actor receives the Stop message. This method overrides the Stop Core method in the Actor class to define behavior that is specific to the Alpha actor.
    • Task executes when the Alpha actor receives the Task message. This method is specific to the Alpha actor; that is, this method is not defined in the Actor class.
  • The actor's message is contained in the Messages for Alpha folder. This actor defines only one message, Alpha Task Msg, which is descended from the Message class and contains the following members:
    • The Alpha Task Msg control is data this message carries.
    • Send Alpha Task is the VI that other actors use to send the Task message to the Alpha actor. This VI creates an instance of the message and populates that message with some data.
    • Do defines what the Alpha actor does when it receives the Task message. In this template, the Do VI instructs Alpha to execute its Task method.
    Note  
    • The Alpha class has a Stop Core method that executes when it receives the Stop message; however, this template does not define a Stop message. This message (the Stop Msg class) is defined in the Actor Framework itself; all actors inherit the ability to handle this message from the Actor class. Descendant classes, such as Alpha, need only to override the Stop Core method.
    • The Alpha class does not need to define a process for receiving and responding to messages. This behavior is defined in the Actor Core method of the Actor class and is inherited by all actors.

Minimizing Communication Errors Between Actors

By default, a given actor X can send messages to only the following actors:

  • The caller—The VI, which can be an actor, that launched X
  • Nested actors—Any actors that X launches

This restricted order of communication is called a task tree. It means there is only one communication path to manage, making it easy to write code that ensures that other actors have a chance to hear and respond messages before shutting down.

For example, this template defines the following task tree:

where Project_Name is the name you give the project.

This diagram indicates that the Application actor launches both the Alpha and Beta actors. Therefore, the Application actor is referred to as the top-level actor. The top-level actor is the single actor from which all other actors are launched. The top-level actor itself is launched from a regular VI.

Note  The task tree hierarchy is different from the LabVIEW class inheritance hierarchy. Although Alpha and Beta are launched from Application, the Alpha and Beta classes do not inherit from the Project_Name class.

Given this task tree, the following communication rules are in effect:

  • Application can send messages to both Alpha and Beta
  • Alpha can send messages only to Application
  • Beta can send messages only to Application

The implication is that neither Alpha nor Beta can send messages to each other. Alpha must send a message to Application, which decides whether Beta needs to hear the message and takes the appropriate action. Again, restricting the communication path helps you write more manageable and error-free code.

The following block diagram shows the code, located in the Actor Core method of the Project_Name class, that defines the task tree by launching Alpha and Beta:

Message Queues

Messages are sent by using queues. To enforce the task tree, each actor initially has access to only the following two message queues:

  • The queue the actor uses to send messages to its caller
  • The queue the actor uses to send messages to itself

Access to a queue is different from the queue itself. To prevent other actors from releasing its message queue, an actor does not share the queue itself. Instead, the Actor Framework introduces the concept of an enqueuer. An enqueuer is a reference that enables an actor to send messages to a queue but not to do anything else with it.

For example, consider an actor X that already is running. When it launched, X obtained a queue that it uses to send messages to itself. From X's point of view, this is the to-self queue. If X launches Y, the following steps occur:

  1. X is the caller of Y, so X gives Y access to X's to-self queue. From the Y's point of view, this queue is the to-caller queue. The queue is the same, but there are two different viewpoints.
  2. Y obtains a queue for sending messages to itself. From the Y's point of view, this queue is the to-self queue.
  3. Y gives X access to the queue obtained in step 2.

Y now has access to two queues:

  • To-caller queue—The queue that X gave Y access to in step 1. Recall that this is the same queue that X uses to communicate with itself.
  • To-self queue—The queue that Y obtained for itself in step 3.

The following diagram shows how these two actors can communicate with each other:

X now can send messages to itself (1) and Y (2). Y can send messages to X (3) and to itself (4). Although there are four directions a message can go in, only two queues are involved. Additionally, neither actor can release the queue of the other. Instead, each actor releases its own queue as part of its shutdown procedure.

Understanding the Project Hierarchy

After you create a project based on this template, LabVIEW displays the following hierarchy:

  • Project Documentation—Contains documentation about this template. As you develop the project and distribute it, National Instruments recommends you update this documentation accordingly.
  • The Project_Name Launcher library—Files related to launching the top-level application.
    • Localization—Facilitates translation of strings by centralizing all user-facing strings in one VI.
    • Splash Screen—Displays a splash screen while executing the Load App VI.
  • The Project_Name library—Contains the Application actor and the message it can receive.
    • Messages for Project_Name—Contains the message that the Application actor can receive.
      • The Log Event Msg class—Defines a message that instructs the Application actor to update its event log with a string.
        • Send Log Event—Sends the Log Event message to the Application actor, along with a string as data. The Alpha and Beta actors both send this message to the Application actor; therefore, you can find this VI called from the Task method of the Alpha and Beta actors.
        • Do—Instructs the Application actor to invoke its Log Event.vi method, using data carried with the Send Log Event VI.
    • The Project_Name class—The Application actor.
      • Localization—Facilitates translation of strings by centralizing all user-facing strings in one VI.
      • Actor Core—The actor's core VI, which executes the following tasks:
        • Launches the Alpha and Beta actors.
        • Gives these actors access to the queue for sending messages to the Application actor.
        • Displays a UI.
        • Waits for front panel events.
        • Responds to those events by sending messages to the Alpha and Beta actors.
      • Read Config File—Reads an integer from a configuration file.
      • Stop Core—Sends a Stop message to both the Alpha and Beta actors.
      • Log Event—Scrolls the Event Log text box on the front panel of the Actor Core VI in the Project_Name class.
      • Load App—Launches the Project_Name actor, thus launching the application itself, and posts the loading status to the Splash Screen VI.
  • The Alpha Actor library—Contains the Alpha actor and the messages it can receive.
    • Messages for Alpha—Contains messages that the Alpha actor can receive.
      • The Alpha Task Msg class—Defines a message that instructs the Alpha actor to execute its Task.vi method.
        • Send Alpha Task—Sends the Task message to the Alpha actor with some data attached. You can find this VI called from Actor Core method of the Project_Name class.
        • Do—Instructs the Alpha actor to run its Task method, using the data carried with the Send Alpha Task VI.
        • Write Data—Bundles an integer into the Task message the Alpha actor sends itself from its Actor Core method.
    • The Alpha class—The Alpha actor.
      • Localization— Facilitates translation of strings by centralizing all user-facing strings in one VI.
      • Actor Core—Instructs the Alpha actor to execute its Task.vi method every n milliseconds with -1 as the data. Receiving the Task message instructs the Alpha actor to execute its Task method with different data instead of -1.
      • Stop Core—Stops the timed message (that is defined in the Actor Core method) from being delivered.
      • Task—Sends a Log Event message to the Application actor along with an integer.
  • The Beta Actor library— Contains the Beta actor and the message it can receive. The structure and functionality of these files are similar to the functionality of the files in Alpha Actor.lvlib, with two exceptions:
    • The Actor Core method in the Beta class behaves differently than the Actor Core method in the Alpha class.
    • The Beta Task Msg class does not contain a Write Data method.

Modifying this Template

Determining Your Needs

An actor is a LabVIEW class. Like any LabVIEW class, before you create it, you must understand what the actor is and what the actor does.

To determine what actors you need to create and what each one does, think about the independently-running tasks in your application and what actions each task can perform. For example, consider a task that acquires a continuous measurement from an analog device. This task needs to know how to connect to the hardware, acquire a measurement continuously, write safe values to the hardware, and disconnect from the hardware. An actor for this task might have one method for each of these actions. Create one actor for each task you identify.

After you determine what an actor needs to do, determine which actions happen continuously while the actor is running and which actions happen only after receiving a message from another actor. Actions that happen continuously should be added to the Actor Core method of the actor. Actions that happen in response to a message should be represented as a method of the actor's class. Use this information to define the behavior of each actor. Then, create the messages that will instruct the actor to invoke each of its methods.

 

Defining the Behavior of an Actor

The Actor Framework provides two ways of defining the behavior of an actor. You must decide which of the following ways is appropriate:

  • For behavior that should occur in response to a message, create methods for the actor and then create the message that will trigger that method.

    For example, acquiring a single measurement from a hardware device is a behavior that should occur in response to a message. This behavior has a distinct beginning and end and does not need to execute continuously. The duration of this behavior is shorter than the duration of the actor itself.
  • For behavior that should occur continuously while the actor is running, override the Actor Core method.

    For example, monitoring a user interface and responding to events is a behavior that should occur continuously. This behavior needs to happen during the entire time the actor is running; that is, the duration of the behavior is equal to the duration of the actor itself.

 

Creating Methods for Actors

  1. Create a member VI in the class. Remember that some methods of the ancestor Actor class are designed to be overridden.
  2. Create the message that instructs the actor to invoke that method.
  3. Ensure another part of the application sends messages to the actor.

 

Defining an Actor's Continuous Behavior

The Actor Core method of the Actor class contains the code that processes and reacts to messages sent to the actor. Each actor inherits this behavior. Actors can do other things continuously while processing messages. To define an actor's continuous behavior, override the Actor Core method in a descendant class.

The following screenshot shows that all three actors in this template override the Actor Core method:

 

Creating an Actor

  1. Create a LabVIEW class and set it to inherit from Actor Framework.lvlib:Actor.lvclass.
  2. Define the behavior of the actor.
  3. Create messages the actor can receive.
  4. Ensure another part of the application launches the actor.
  5. Ensure other parts of the application send messages to the actor.
  6. Create code that stops the actor.

 

Stopping an Actor

To stop an actor, send the actor a Stop message by using one of the following VIs:

  • Send Normal Stop
  • Send Emergency Stop
  • Send Normal or Emergency Stop

These methods are available on the Functions palette. Refer to the Stop Core method of the Project_Name class for an example of stopping an actor.

 

Launching an Actor

Launch an actor by using the Launch Actor method, which is available on the Functions palette. Refer to the following code in the Load App VI for an example of launching a top-level actor:

Refer to the following code in the Actor Core method of the Project_Name class for an example of launching a nested actor:

 

Creating Messages

A message is a LabVIEW class that instructs an actor to invoke one of its methods. Complete the following steps to create a message for an actor:

  1. Ensure you have opened a LabVIEW project that contains the actor.
  2. Launch the Actor Framework Message Maker dialog box:

  3. Select the method for which you want to create a message. For example:

  4. Click Build Selected. After you click this button, LabVIEW creates method Msg.lvclass, where method is the method you selected, and inserts it in the Project Explorer window. For example:



    LabVIEW also opens the VIs for the members of the class, where:
    • method Msg.lvclass:method Msg.ctl is private data the message can access.
    • method Msg.lvclass:Send method.vi is the VI you use to send the message to the actor.
    • method Msg.lvclass:Do.vi defines what the actor does when it receives this message. By default, Do.vi instructs the actor to invoke method.vi.
  5. Customize these VIs according to the needs of your application.
  6. Send the message.

 

Sending Messages

To send a message, use method Msg.lvclass:Send method.vi, where method is the method you want the receiving actor to execute. You created Send method.vi when you created the message.

Note   Refer to Stopping an Actor for information about sending a Stop or Emergency Stop message.

In this template, refer to the following VIs for examples of sending messages:

  • The Actor Core method of the Beta class—Sends the Log Event message to the Application actor.
  • The Task method of the Beta class—Sends the Log Event message to the Application actor.
  • The Task method of the Alpha class—Sends the Log Event message to the Application actor.
  • The Actor Core method of the Project_Name class—
    • Sends the Alpha Task message to the Alpha actor.
    • Sends the Beta Task message to the Beta actor.

Changing What Happens When the Application Actor Sends a Message to the Alpha Actor

The Message to Alpha event case of the Event structure in the Actor Core method of the Project_Name class defines what happens when the application actor sends a message to the Alpha actor. Modify this event case according to the needs of your application.

Changing What Happens When the Application Actor Sends a Message to the Beta Actor

The Message to Beta event case of the Event structure in the Actor Core method of the Project_Name class defines what happens when the Application actor sends a message to the Beta actor. Modify this event case according to the needs of your application.

Changing What Happens when the Application Actor Stops

The stop behavior for the Application actor is defined in the following places:

  • The "Stop"; Value Change; Panel Close event case of the Event structure in the Actor Core method of the Project_Name class—This event case sends the Stop message from the Application actor to itself:



    After the Application actor receives this message, the Do VI of the Stop Msg class generates generate error code 43, indicating the actor stopped without an error, the Stop Core method of the Project_Name class will execute. This behavior is defined in the Actor Core method of the Actor class.
  • The Application Instance Close event case of this same Event structure—Code in this case is guaranteed to run to completion no matter how the application shuts down. Add any required cleanup code, such as resetting hardware to safe states, in this case.
  • The Stop Core method of the Project_Name class—By default, this method sends the Stop message to the Alpha and Beta actors.

    If you create nested actors at the same level as Alpha and Beta, modify this VI to tell those nested actors to stop also. These actors have their own stop behaviors that you can change.

 

Changing What Happens when Alpha or Beta Stop

The stop behaviors for these actors are defined in the Stop Core methods of the class. By default, these methods shut down parallel tasks that were started in the actor's Actor Core method. Modify the code in these methods according to the needs of your application.

If you modify this template such that Alpha or Beta launches any nested actors, ensure the actor's Stop Core method sends a Stop or Emergency Stop message, as appropriate, to these nested actors.

Changing the User Interface

You generally define the user interface of an actor in its Actor Core method. In this template, only the Application actor defines a user interface in its Actor Core method. The front panel of this VI is the user interface of the application. Change this user interface according to the needs of your application.

Further Reading

NI Training and Certification


Name Used in this Document Qualified Filename
Application Launcher library Application Launcher.lvlib
Localization VI Application Launcher.lvlib:Localization.vi
Splash Screen VI Application Launcher.lvlib:Splash Screen.vi
Project_Name Actor library Project_Name Actor.lvlib
Log Event Msg Project_Name Actor.lvlib:Log Event Msg.lvclass
Log Event Msg:Do VI Project_Name Actor.lvlib:Log Event Msg.lvclass:Do.vi
Log Event Msg:Send Log Event VI Project_Name Actor.lvlib:Log Event Msg.lvclass:Send Log Event.vi
Project_Name Project_Name Actor.lvlib:Project_Name.lvclass
Project_Name:Actor Core VI Project_Name Actor.lvlib:Project_Name.lvclass:Actor Core.vi
Project_Name:Load App VI Project_Name Actor.lvlib:Project_Name.lvclass:Load App.vi
Project_Name:Localization VI Project_Name Actor.lvlib:Project_Name.lvclass:Localization.vi
Project_Name:Log Event VI Project_Name Actor.lvlib:Project_Name.lvclass:Log Event.vi
Project_Name:Read Config File VI Project_Name Actor.lvlib:Project_Name.lvclass:Read Config File.vi
Project_Name:Stop Core VI Project_Name Actor.lvlib:Project_Name.lvclass:Stop Core.vi
Alpha Actor library Alpha Actor.lvlib
Alpha Task Msg Alpha Actor.lvlib:Alpha Task Msg.lvclass
Alpha Task Msg:Do VI Alpha Actor.lvlib:Alpha Task Msg.lvclass:Do.vi
Alpha Task Msg:Send Alpha Task VI Alpha Actor.lvlib:Alpha Task Msg.lvclass:Send Alpha Task.vi
Alpha Task Msg:Write Data VI Alpha Actor.lvlib:Alpha Task Msg.lvclass:Write Data.vi
Alpha Alpha Actor.lvlib:Alpha.lvclass
Alpha:Actor Core VI Alpha Actor.lvlib:Alpha.lvclass:Actor Core.vi
Alpha:Localization VI Alpha Actor.lvlib:Alpha.lvclass:Localization.vi
Alpha:Stop Core VI Alpha Actor.lvlib:Alpha.lvclass:Stop Core.vi
Alpha:Task VI Alpha Actor.lvlib:Alpha.lvclass:Task.vi
Beta Actor library Beta Actor.lvlib
Beta Task Msg Beta Actor.lvlib:Beta Task Msg.lvclass
Beta Task Msg:Do VI Beta Actor.lvlib:Beta Task Msg.lvclass:Do.vi
Beta Task Msg:Send Beta Task VI Beta Actor.lvlib:Beta Task Msg.lvclass:Send Beta Task.vi
Beta Beta Actor.lvlib:Beta.lvclass
Beta:Actor Core VI Beta Actor.lvlib:Beta.lvclass:Actor Core.vi
Beta:Localization VI Beta Actor.lvlib:Beta.lvclass:Localization.vi
Beta:Stop Core VI Beta Actor.lvlib:Beta.lvclass:Stop Core.vi
Beta:Task VI Beta Actor.lvlib:Beta.lvclass:Task.vi

Important Information

Copyright

© 2012 National Instruments. All rights reserved.

Under the copyright laws, this publication may not be reproduced or transmitted in any form, electronic or mechanical, including photocopying, recording, storing in an information retrieval system, or translating, in whole or in part, without the prior written consent of National Instruments Corporation.

National Instruments respects the intellectual property of others, and we ask our users to do the same. NI software is protected by copyright and other intellectual property laws. Where NI software may be used to reproduce software or other materials belonging to others, you may use NI software only to reproduce materials that you may reproduce in accordance with the terms of any applicable license or other legal restriction.

End-User License Agreements and Third-Party Legal Notices

You can find end-user license agreements (EULAs) and third-party legal notices in the following locations:

  • Notices are located in the <National Instruments>\_Legal Information and <National Instruments> directories.
  • EULAs are located in the <National Instruments>\Shared\MDF\Legal\license directory.
  • Review <National Instruments>\_Legal Information.txt for information on including legal information in installers built with NI products.

Trademarks

LabVIEW, National Instruments, NI, ni.com, the National Instruments corporate logo, and the Eagle logo are trademarks of National Instruments Corporation. Refer to the Trademark Information at ni.com/trademarks for other National Instruments trademarks.

Other product and company names mentioned herein are trademarks or trade names of their respective companies.

Patents

For patents covering the National Instruments products/technology, refer to the appropriate location: Help»Patents in your software, the patents.txt file on your media, or the National Instruments Patent Notice at ni.com/patents.

0 Ratings | 0.00 out of 5
Read in  |  Print |  PDF

Reader Comments | Submit a comment »

 

Legal
This tutorial (this "tutorial") was developed by National Instruments ("NI"). Although technical support of this tutorial may be made available by National Instruments, the content in this tutorial may not be completely tested and verified, and NI does not guarantee its quality in any way or that NI will continue to support this content with each new revision of related products and drivers. THIS TUTORIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND AND SUBJECT TO CERTAIN RESTRICTIONS AS MORE SPECIFICALLY SET FORTH IN NI.COM'S TERMS OF USE (http://ni.com/legal/termsofuse/unitedstates/us/).