TweetFollow Us on Twitter

Newton Toolkit
Volume Number:9
Issue Number:11
Column Tag:Newton

Newton Toolkit

You’ve seen Newt and what it can do - now take a look at the tools developers will work with.

By Don Bresee and Neil Ticktin, MacTech Magazine Editorial Staff
Tony Espinoza, Newton Software Tools, Apple Computer, Inc.

By now, you’ve taken a look at Newton. (If not, you should go and read the editorial starting on page 4 of this issue.) But as developers, you want to know about the tools for Newton - specifically the development environment. The Newton Toolkit (NTK for short) is how you develop apps for Newton. Below is a description of Newton’s built in tools, NTK and NewtonScript.

The Newton Toolkit

First, you need to know some basics about Newton programming and about NTK itself.

Newton Basics

The Newton system is an extremely versatile object oriented environment designed around the concept of the view. A view is any graphic component of the Newton user interface. Views also serve as the basic building blocks of Newton applications. You design and build these views with the Newton Toolkit for the Mac, which we will talk about later. First, it is necessary to get aquainted with the NewtonScript programming language.

NewtonScript

NewtonScript is a full featured, object oriented programming language. It has all the programming constructs and data structures needed to produce sophisticated applications. Some highlights:

• All statements are expressions (they return a value),

• Statements are grouped with Begin End,

• Loop constructs For, While, and Repeat Until are provided,

• A Foreach statement allows looping through the elements of a data structure,

• Break statement for terminating loops,

• Functions and Methods with parameters and local variables,

• Return statement for functions and methods,

• Arithmetic and string operators,

• Class and parent / child inheritance.

The most basic data reference in the Newton system the long word (32 bits). A reference is either a pointer or an immediate reference. Immediate references can be integer, character, or boolean and use 30 bits for data and 2 bits for flags. Booleans have two possible values, TRUE or NIL. Characters are represented in Unicode (in two bytes) to facilitate international conversions. Pointers reference objects in the heap. These objects include:

• Symbols (variable names, field names, script names),

• Strings,

• Reals (64 bit floating point numbers),

• Arrays (numbered elements, starting with 0),

• Frames (named elements).

Symbols are useful in writing general code. For instance, you could write a function that takes a symbol parameter that is the name of another function to call in a certain situation. The same idea can be used for field names in data structures. A routine could take a field name as a parameter, and perform some operation on that field, allowing you to write more general code.

The array data structure is extremely useful. The elements can be of different types in the same array. Elements can be added, deleted, and sorted. This type is ideal for lists of objects. Arrays can be given a class type. This seems to be for readability reasons since the class does not give an array any special properties, just a name. This is different than frames, which we will talk about now.

The frame is the most important type in the Newton system. A frame consists of a collection of slots. Each slot has a name and a value. A slot value can be a function, making the frame type capable of class definitions. Frames have special slots for class names and links to other classes that are needed for the inheritance mechanisms.

There are two types of inheritance in NewtonScript. The normal class inheritance that we are used to is called prototype inheritance in NewtonScript. When a frame is defined, the superclass name should be put in the “_proto” slot. Then the new frame will have access to (“inherit”) all the slots of that class, this includes data and methods.

The second type of inheritance is called parent inheritance. This mechanism is similar to the “chain of command” used in the THINK Class Library (TCL). This type of inheritance is used to set up hierarchies (views that contain and manage subviews). When a frame is defined, the class name of the parent (or supervisor) should be put in the “_parent” slot.

These two inheritance mechanisms interact in much the same way as they do in TCL. When a message is sent to an object, that object is checked first. If it can handle the message, it does. If not, the prototype (superclass) is checked, and then its prototype. If this process bottoms out (no prototype of the initial object can handle the message), the message is passed along to the parent (supervisor). Then the same process is used for the parent object (if the parent object can’t handle the message, the prototypes are checked and then that objects parent, and so on). For example, in a TCL application, when a quit message is sent to the gopher (assume it is a view), the gopher and its superclasses attempt to handle the message and cannot. The message is passed up the chain of command to the window, then to the document, and then to the application which completes the handling of the message (probably by a superclass of your application object).

The Newton System

The view is the most important object in Newton applications. Views are created from templates. A template is a frame containing the data description of an object (a view). The relationship between views and templates is similar to that of objects and classes.

Dozens of “proto templates” are provided in the Newton ROM. These templates offer most of the user interface functionality you will need when creating applications. It is quite complete. It includes buttons, pictures, text (static and editable), geometric shapes, pick-lists, and plenty of others. In addition to a view classes specific messages it handles, there are several system messages that can be sent to any view. These messages will allow you to customize your views behavior by supplementing the normal system behavior when certain events occur. For instance, you may want a certain view class to do something every time it is drawn. You simply define a “viewDrawScript” method for your view class and it will be called each time the system draws a view of that type.

Newton’s data storage and retrieval model is very interesting. It uses a unified data model, all data is stored in a common format. Therefore, no translation is required to read another application’s data. The model is built around soups. A soup holds a collection of related data objects called entries. Each entry is a frame. There is no restriction on the format of the entries. Different entries in the same soup can have different slots. Of course, this can get out of hand very quickly and it is a good idea to keep the structure of the entries uniform within each soup. Optional slots are useful for minimizing the number of bytes needed for an entry. This is an important point because a soup is a persistent storage object and memory is precious. In fact, when entries are saved to or retrieved from a soup, they are compressed or decompressed behind the scenes. This is done to make best use of memory. You can also define an index for each slot in a soup that will be searched frequently.

Each soup has a name and is contained in a store, which is also named. A store can be thought of as a disk volume. The Newton contains one internal store. Additional stores can be present on PCMCIA cards and other devices. To retrieve entries from a soup, you call the “Query” function. This function returns a cursor object. A cursor accesses the set of entries that satisfy the query, and gives the ability to step through those entries in indexed order. The system provides functions to do whatever you might want with stores, soups, entries, and cursors.

Another important concept on the Newton is Routing, which simplifies communications. Print, Fax, and Mail are all handled through one API. You define a format (a view) for the data and specify that format in the routing frame. You also design a routing slip that will get any additional information needed from the user before the operation is commenced (such as a name and fax number to send a fax). The system takes care of the other details for you.

Newton Toolkit

The Newton Toolkit (NTK) is the environment provided for the development of Newton applications. The main part of NTK is a Mac application that allows you to define views and write scripts. It also allows you to combine layout (templates), resource, data, and driver files into a project. NTK does this with a project document in much the same way THINK C does. The project window lists all the files in the project. Double clicking on a file in the list opens it for modification. “Building” your project results in what is called a package.

Apple recommends that this application be run on a Quadra with 8 MB of RAM and System 7.1. I played with it on a IIci and it took one minute fifteen seconds to launch from the Finder, and one minute ten seconds to open the checkbook sample. Once a project is open, it runs plenty fast enough. Expect installation of NTK to use about 2.5 MB of disk space. [We are reviewing 1.0b4 version. 1.0b6 is reportedly five times faster and will therefore easily run on a 68030 machine or better. Expect the release version to have better performance. - Ed.]

NTK also provides a Newton application called Toolkit which allows you to download your package to the Newton and test it (accessible on the Newton through the Extras drawer). You can test it and see the results immediately. This allows you to develop your application incrementally. You work on a view, build a package, download the package to the Newton, and then test it. You do this routine until that view is working right and then you build the next view.

Views and templates are created using the Template Editor. This editor has a layout window for drawing views (which is done by dragging out rectangles like in you would any drawing application), and a palette for selecting the view class. This palette has all the predefined Newton interface elements (templates), as well as any templates you have defined in the current project. Items are added by selecting an item from the palette and then placing the view where you want it in the layout window. A preview menu item allows you to view the screen as it would look on the Newton.

Fig. 1 Template Editor, palette, and Project Window.

The Browser window allows you to modify those templates created in the Template Editor. This is where you write the views specific methods. It also provides you with the ability to edit the initial values of all slots in the template. When you open a Browser, the view selected in the Template Editor and all of its subviews will be available in the new window. You can easily jump from method to method with pull down menus or with a pick list.

Fig. 2 Browser Window

The development process is slick considering the fact that you are developing applications for one computer on another. First you need to connect the Newton and the Mac. You can do this with a null modem cable (through the serial port) or with a LocalTalk connection (through the printer port). [With the pre-release version you want to stick to serial only. LocalTalk has not been tested in 1.0b4 and has problems. - Ed.] When the two are connected, you tell NTK to install the Toolkit application onto the Newton. Then you open the Newton’s Connection tool in the Extras drawer and tell it to connect to the Mac. After all this, the Toolkit tool will appear in the Extras drawer on the Newton. Now we are ready to download your project. Open your project and build a package in NTK. Then you tell NTK to download the package. Open the Toolkit tool on the Newton and hit the download button (you will need to choose a Mac if you are using a LocalTalk connection). Your application will appear in the Newton’s Extras drawer. Open it and test, test, test.

This sounds like a long process, but most of it will be done once per development session. When the Newton and the Mac are connected, and the Toolkit is installed on the Newton, only the build package and download steps are needed. The new copy of your application replaces the old one. So testing is quite easy after everything is installed and connected.

Some Examples of Newton Code

So now you’ve seen some of NTK, but what does NewtonScript really look like? To demonstrate this, we’ll look at some examples of programming using NTK, NewtonScript and Newton itself.

Adding to the Intelligent Assistant

You probably know a bit about Newton’s Intelligent Assistant. This built-in tool is designed to help the user use Newton in a “human fashion”. For example, if you are in the notetaking area, write in “Lunch with Neil Tue at 2pm”, Newton will take it from there - looking up Neil’s information in the name cards and scheduling the lunch in your calendar.

But what if you want to add verbs to the list that Newton knows how to handle. For example, if you were to ask it to add a verb called “page” that would have Newton page the person you asked it to. You will have the option of a paging service through which you would like to page.

To take advantage of this or check it out, first you need to have downloaded NTK Toolkit to Newton and connect/opened the Inspector window. Then, type in each of the “frames” below separately (the actual syntax, don’t bother with the comments which always start with “//”) into the Inspector window. Once you have it in, select the text, press “enter” to evaluate each one (remember to select the whole frame before hitting enter [similar to MPW]). You should get back a different response to each frame processed.

// 1
Inspector Window Code:
// the action template describes the "verb".
// requires a slot named "isa" that has 'dyna_user_action
// requires a value slot, which should be a string (never used)
// requires a lexicon slot, which should be a word array (synonyms)
actionTemplate := {
   value: "foo",
   isa: 'dyna_user_action,
   lexicon: ["page", "beep", "zap"],
}

// the target template describes "nouns" for the task.
// requires an isa slot, which has the value 'dyna_user_obj
// requires a value slot, which should be a string (never used)
// requires a lexicon slot, which should be a word array (synonyms)
targetTemplate := {
   isa: 'dyna_user_obj,
   value: "bar",
   lexicon: ["mobilecomm", "skytel", "pactel", "apple"],
}

// the post-parse function is called when IA matches the action.
// use compile function because it's a closure and it gets cloned,
// if just wrote a func() body, the clone would be huge in inspector.
// Don't need to use compile if it's written as part of an NTK app.
ppf := compile("print(\"Your Code Here!\")")

// the task template binds it all together.
// requires an isa slot, which should be 'task_template
// requires a primaryAct slot, which holds an actionTemplate.
// requires a signature slot, which is an array of actionTemplates,
// taskTemplates, and/or system task symbols.  (i.e. 'person)
// requires a preconditions slot, which matches signature array, but
//    contains symbols, one for each template.
// requires a postParse slot, which is the function to call
// requires a taskslip slot, which is a view template that can be
//    opened by the postParse method to provide more UI.  (not used)
taskTemplate := {
   isa: 'task_template,
   primary_act: actionTemplate,
   preconditions: ['pagingNet, 'pageAction, 'whoToPage],
   signature: [targetTemplate, actionTemplate, 'person],
   postparse: ppf,
   taskslip: nil,
}

// use global function RegTaskTemplate to give template to IA.
// keep the result, will need it later to unregister task (see below)
result := regtasktemplate(taskTemplate)

// use the parseUtter command to test.
p := parseutter("page Bob via MobileComm")

// once the above line is processed, the postParse method is called
// you will then see:
"Your Code Here!"

// here's the result frame which is also "self" within postParse func
// it's a clone of the taskTemplate passed with some additn’l slots.
// parse, input, and raw contain frames based on templates matched.
//    you can loop through them and use isa() to test for which of 
//    your templates were matched (see Checkbook example)
// phrases contains the matched words.
// noisewords contains unmatched words.
// origphrase contains the original phrase as written to IA.
// pagingNet, pageAction, and whoToPage are added because all the 
//   templates in the signature array were matched.  The slot 
//   contains the result of the match for the given template.

#4415C19  {isa: task_template,
           primary_act: {value: "foo",
                         isa: dyna_user_action,
                         Lexicon: [#4412121]},
           preconditions: [pagingNet, pageAction, whoToPage],
           signature: [{#4412241}, {#4412041}, person],
           postParse: <CodeBlock, 0 args #44124D1>,
           taskslip: NIL,
           parse: [[#4415C69], [#4415C79], [#4415CA1]],
           input: [{#4412041}, person, {#4412241}],
           raw: [[#44128B9], [#44151A1], [#44127E1]],
           phrases: ["page", "Bob", "MobileComm"],
           noisewords: ["via"],
           OrigPhrase: ["page", "Bob", "via", "MobileComm"],
           pagingNet: [[#44127E1]],
           pageAction: [[#44128B9]],
          whoToPage: [[#44151A1]]}

// Once you are done with this command, you need to unregister the 
// task to remove it.  Remember to do this before re-registering the 

// same task!
unregtasktemplate(result)

After you register the task (and until you remove it), you will notice that the “Page” verb is in the Assistant verb list just as all of the other verbs are.

Making your application screen-size independent

Just like the Macintosh, you will want to make your Newton applications screen size independent. The function call GetAppParams() returns a frame describing the current device view bounds and the location of the buttons. The return frame looks like this:


// 2

  {appAreaTop: 0,
  appAreaLeft: 0,
  appAreaWidth: 240,
  appAreaHeight: 320,
  buttonBarPosition: 'bottom} // one of 'top, 'bottom, 'left, 'right

You can use this call to set the viewbounds of your base application view during at viewSetupFormScript time. The simplest way is to create a function that will resize your view for you and call it from your viewSetupFormScript. Here is one that will take up the entire screen (leaving space for a frame around the base view):


// 3

sizeBaseToDisplay
func()
begin
    // assumes 1 pixel frame & top left parent relative justification
    local b := getAppParams();
    self.viewbounds.top := b.appAreaTop + 2 ;
    self.viewbounds.left := b.appAreaLeft + 2;
    self.viewBounds.bottom := self.viewbounds.top + b.appAreaHeight - 
4;
    self.viewBounds.right := self.viewbounds.left + b.appAreaWidth - 
4;
end

Once your base application view is sized correctly, you can use the viewJustify slot to make other parts of your application parent releative or sibling relative justified. Not all parts of your application need to be full or center justified, some parts will not be affected by a slightly smaller screen size.

Other parts of your application may need to be dynamically constructed (a view that has children representing soup entries, like the checkbook example included with NTK).

If you follow these simple design and develop guidelines, your application should work on future Newton products.

A Serial Connection Sample

This simple sample shows how to make a serial connection with a simple protocol implemented. In order to test this app you need to have the Newton connected to an outside source, such as a computer with a terminal emulator running (i.e., a Macintosh running MicroPhone), and you will control the protocol by typing commands in the terminal window and Newton will respond. Of course this is easier if the control is inside an appplication.

To take a look at this, read through the below user instructions to get an idea of what’s going on. Then build the below package in NTK using both the graphical tools and typing in scripts as indicated. Download this package on Newton. Then return to the User Instructions to run the example.

User Instructions:

1. Open up the terminal emulator (make sure local echo is on). The terminal emulator should be set for 9600bps, 8 bit no parity, XON/XOFF.

2. Start the Newton app

3. Hit Connect on the Newton side (now Newton will start waiting for an incoming ACK)

4. Type ACK? on the terminal, you should immediately get back ACK!

5. Type various other commands, and you should get input from the Newton.

(The following entries and responses are tied to entries in the Names card file on a specific Newton. Use names that you know are in your phone book.) Here’s an example of a simple session:

ACK?ACK!
CARD!Walthrop,Royce,Hillsdale
Thomas,Linda,Newton
Anderson,Bob,Fine

NAME!Jill UK  (You have to have something stored in the name preferences!)

The Protocol:

So what can you do with this? Newton will passively wait for a response from the other end. The other end should send a string with the four characters ACK? Newton responds with the string ACK! After this you could send the following strings to Newton and it will respond:

CARD! -> Newton will return parts of the card soup, strings separate 
by CR+LF

NAME! -> Newton will return the owner name as a string

SIZE! -> Newton will return available RAM size in bytes (string)

SEND! followed by a string terminated with a >, as in    “SEND!this is 
a string>”

BYE! -> Disconnect, and the Newton end will signal that the other end 
is no longer active (this is not fully support, you have to close the 
app in order to disconnect).

The Code:

Create a project called "Serial Protocol" and create the following views/frames in NTK.

This first frame is created by the template editor in NTK. Don’t type it in, just use the information below to create the view in the browser.


// 4

baseView :=
   {_proto: protoapp, 
   title: "Dump Names",
   viewBounds: {left: 0, top: 0, right: 240, bottom: 336},
   };

This second frame also isn’t code to type in, just the params you need to set up in NTK browser:


//5

info := 
   {_proto: protostatictext,
    text: "This simple application will dump all the Names Soup Information 
via the serial port",
    viewBounds: {left: 10, top: 18, right: 226, bottom: 66},
    viewJustify: 0,
   });

The DumpButton frame is partially created with graphical NTK tools, but much of the below scripting is to be typed in.


// 6

DumpButton := 
   {_proto: prototextbutton,
    text: "Connect",
    buttonClickScript:
      // Make the initial connection, start listening to incoming msg
      func()
      begin
      // do a connect
         anErr := ep:Connect(nil,nil);

         if anErr then
         begin
           Notify(kNotifyAlert, "DumpNames", 
  "Check your cables and terminal emulator, couldn't connect");
            return;
         end;

         // set the next input spec for listening mode
         ep:SetInputSpec(ep.waitforACK);
         SetValue(result,'text, "Connected, waiting for ACK?");
      end;,

    viewBounds: {left: 50, top: 218, right: 154, bottom: 250},

    viewSetupDoneScript:
      // Create the endpoint that we need later.
      func()
      begin
         local anErr := nil;

      // create an endpoint for our use
        ep := {_proto: protoSerialProtocol, _parent: self};
      // we assume 9600bps 8 bit no parity is fine

      // instantiate the endpoint
         anErr := ep:Instantiate(ep, nil);

       // configure (XON/XOFF support)
         ep:SetOptions([myInputOptions,myInputOptions]);

         if anErr then
         begin
            Notify(kNotifyAlert, "DumpNames",
 "Sorry, serial port already in use!");
           return;
         end;

      print("Created the endpoint");
         SetValue(result, 'text, "Ready for Connection");
      end,

    ep: nil,

    viewQuitScript:
      func()  // release the endpoint (connection, memory)
      begin
         ep:FlushInput ();
         ep:FlushOutput ();
         ep:SetInputSpec (nil);
         ep:Abort();
         AddDelayedAction(func() begin
               // let the endpoint clean up from the abort before
 //disconnecting and disposing
               ep:Disconnect();
               ep:Dispose();
               end,
               [], 1000);
      print("Disposed the endpoint");
      end,

    DumpResult: nil,

    ReleaseEndpoint:
      func()  // release the endpoint (connection, memory)
      begin
         ep:FlushInput ();
         ep:FlushOutput ();
         ep:SetInputSpec (nil);
         ep:Abort();
         ep:Release();
         ep:Dispose();
      print("Disposed the endpoint");
      end,

    myOutputOptions:
      {
      label: kCMOOutputFlowControlParms,
      type: 'option,
      data: {
         xonChar: unicodeDC1,
         xoffChar: unicodeDC3,
         useSoftFlowControl: true,
         useHardFlowControl: nil
         },
      },

    myInputOptions:
      {
      label: kCMOInputFlowControlParms,
      type: 'option,
      data: {
         xonChar: unicodeDC1,
         xoffChar: unicodeDC3,
         useSoftFlowControl: true,
         useHardFlowControl: nil
         },
      },

    protoSerialProtocol:
      // this is our special endpoint with the protocol built in. 
  // This works fine as long as you remember that this entity is 
      // created in Read-only space. Stay tuned for a solution where 

      // this is created in RAM (actually move this code so it 
      // executes during viewSetupDoneScript time and that's it)
      {
         _proto: protoSerialEndpoint,    // the basic serial endpoint
 
      // the rest here is just code for the state machine, all the
      // state frames are stored inside the the endpoint itself, it's 

      // just a handy place to put them, those could be stored 
      // anywhere.
 
      // We need to catch the last abort exception, later this should 

      // be more uniform, check out what the exception was and ignore
      // the abort one (the one causing the notify)
 
         exceptionHandler: func(exception)
         begin
               print("Got the exception from Abort, ignoring it!");
         end,

      // this is just the initial handshaking part to make sure that 

      // both ends are alive
         waitforACK:
         {
            InputForm: 'string,
            endCharacter: $?,         // ACK? expected

            InputScript: func(endpoint, s)
            begin
               if (StrPos(s, "ACK?", 0)) then
               begin
                  // tell status if needed
                  endpoint:Output("ACK!", nil);     // send response
                  endpoint:FlushOutput();

                  // the main dispatch loop
                  endpoint:SetInputSpec(endpoint.waitForFUNCTION); 
               end
            end,
            discardAfter: 200,
         },


      // This is the generic dispatcher state, send something ending 

      // with ! and the Newton will serve.
         waitForFUNCTION:
         {
            InputForm: 'string,
            endCharacter: $!,     // expects a '!' as part of command
            InputScript: func(endpoint, s)
            begin
               if(StrPos(s, "CARD!", 0)) then      // card function
               begin
                  //print("Card Function");
                  print(s);  // print the string itself as an example

                  // Call the name soup dumping function (LATER, send 

                  // the ep and let the function do the output!
                  endpoint:Output(endpoint:DumpNameSoup(), nil);
                  endpoint:Output(unicodeCR, nil);
                  endpoint:Output(unicodeLF, nil);
                  endpoint:FlushOutput();
               end;

               if(StrPos(s, "NAME!", 0)) then      // name function
               begin
                  print("Name function");
                  // Call the Name function (just a wrapper around
                  // userConfiguration.name)
                  endpoint:Output(endpoint:DumpName(), nil);
                  endpoint:Output(unicodeCR, nil);
                  endpoint:Output(unicodeLF, nil);
                  endpoint:FlushOutput();
               end;

               if(StrPos(s, "SIZE!", 0)) then      // size function
               begin
                  print("Size function");
                  endpoint:Output(endpoint:DumpSize(), nil);
                  endpoint:Output(unicodeCR, nil);
                  endpoint:Output(unicodeLF, nil);
                  endpoint:FlushOutput();
               end;

               if(StrPos(s, "SEND!", 0)) then
               begin
                print("String sending function, switch to receive string 
state");
                endpoint:SetInputSpec(endpoint.waitForSTRING);
               end;

               if(StrPos(s, "BYE!", 0)) then       // bye function
               begin
                  print("Bye function");
               end;
            end,
            discardAfter: 200,
         },

      // our special string handling state
         waitForSTRING:
         {
         InputForm: 'string,
         endCharacter: $>,

         InputScript: func(endpoint, s)
         begin
       // blast the string up to someone up there
                  endpoint:SendOverInfo(s);   
                  endpoint:Output("OK!", nil);      // send response
                  endpoint:FlushOutput();

                  // back to the main dispatch loop
                  endpoint:SetInputSpec(endpoint.waitForFUNCTION); 
          end,
         discardAfter: 200,
         }
      },

    DumpNameSoup:
      func()
      begin
        local theSoup, c, val, anErr;

         SetValue(result, 'text, "Sending over Card Soup Info");

      // get soup
         theSoup := GetStores()[0]:GetSoup("Names");

      // create a cursor
         local c := Query(theSoup, {type: 'index});

      //    while valid entries, dump the name information out
         repeat
         begin
            val := c:Entry();
            if(val.name.class = 'person) then
            begin
               DumpResult := DumpResult & val.name.last & $, 
 & val.name.first & $,  & val.city  & $\n & $\u000A;
            end;
         end
         until (c:Next() = nil);

      // return the big string
         return DumpResult;
      end,

    DumpName:
      func()
      begin
         SetValue(result, 'text, "Sending over Name information");
         return userConfiguration.name;
      end,

    DumpSize:

      // return size of internal storage
      func()
      begin
         local theStore := GetStores()[0];
         local used := theStore:UsedSize();
         local space := (theStore:TotalSize()  - used) div 1024;
         local Kused := used div 1024;

         return "K used =" &&  kUsed && ", K free =" && space;
      end,

    SendOverInfo:
      func(string)
      begin
         // have our own ref to it (string is changing beneath!)
         myString := Clone(string);

         // for the time being just draw it in the result view
         SetValue(result, 'text, myString);   
      end,
   });

This isn’t code to type in, just the params you need to set up the view in the NTK browser. Make sure to click "Allow Access From baseView" for this view named.

//7

result :=
   {_proto: protostatictext,
    text: "Status Information",
    viewBounds: {left: 10, top: 146, right: 226, bottom: 186},
    viewFormat: 336,
   });
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Dash 4.1.3 - Instant search and offline...
Dash is an API documentation browser and code snippet manager. Dash helps you store snippets of code, as well as instantly search and browse documentation for almost any API you might use (for a full... Read more
MacFamilyTree 8.2.7 - Create and explore...
MacFamilyTree gives genealogy a facelift: modern, interactive, convenient and fast. Explore your family tree and your family history in a way generations of chroniclers before you would have loved.... Read more
WhatsApp 0.2.8000 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
TotalFinder 1.10.7 - Adds tabs, hotkeys,...
TotalFinder is a universally acclaimed navigational companion for your Mac. Enhance your Mac's Finder with features so smart and convenient, you won't believe you ever lived without them. Features... Read more
Box Sync 4.0.7886 - Online synchronizati...
Box Sync gives you a hard-drive in the Cloud for online storage. Note: You must first sign up to use Box. What if the files you need are on your laptop -- but you're on the road with your iPhone? No... Read more
Espresso 5.1 - Powerful HTML, XML, CSS,...
Note from the developer: For the new Espresso, we changed our versioning and licensing approach with more consistent pricing and a simpler development timeline: "X+1". Each new update would increase... Read more
VueScan 9.6.04 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
Slack 3.0.5 - Collaborative communicatio...
Slack is a collaborative communication app that simplifies real-time messaging, archiving, and search for modern working teams. Version 3.0.5: Bug Fixes: An important security update. Security... Read more
VirtualBox 5.2.6 - x86 virtualization so...
VirtualBox is a family of powerful x86 virtualization products for enterprise as well as home use. Not only is VirtualBox an extremely feature rich, high performance product for enterprise customers... Read more
Vivaldi 1.13.1008.40 - An advanced brows...
Vivaldi is a browser for our friends. In 1994, two programmers started working on a web browser. Our idea was to make a really fast browser, capable of running on limited hardware, keeping in mind... Read more

Latest Forum Discussions

See All

The 7 best games that came out for iPhon...
Well, it's that time of the week. You know what I mean. You know exactly what I mean. It's the time of the week when we take a look at the best games that have landed on the App Store over the past seven days. And there are some real doozies here... | Read more »
Popular MMO Strategy game Lords Mobile i...
Delve into the crowded halls of the Play Store and you’ll find mobile fantasy strategy MMOs-a-plenty. One that’s kicking off the new year in style however is IGG’s Lords Mobile, which has beaten out the fierce competition to receive Google Play’s... | Read more »
Blocky Racing is a funky and fresh new k...
Blocky Racing has zoomed onto the App Store and Google Play this week, bringing with it plenty of classic kart racing shenanigans that will take you straight back to your childhood. If you’ve found yourself hooked on games like Mario Kart or Crash... | Read more »
Cytus II (Games)
Cytus II 1.0.1 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.1 (iTunes) Description: "Cytus II" is a music rhythm game created by Rayark Games. It's our fourth rhythm game title, following the footsteps of three... | Read more »
JYDGE (Games)
JYDGE 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: Build your JYDGE. Enter Edenbyrg. Get out alive. JYDGE is a lawful but awful roguehate top-down shooter where you get to build your... | Read more »
Tako Bubble guide - Tips and Tricks to S...
Tako Bubble is a pretty simple and fun puzzler, but the game can get downright devious with its puzzle design. If you insist on not paying for the game and want to manage your lives appropriately, check out these tips so you can avoid getting... | Read more »
Everything about Hero Academy 2 - The co...
It's fair to say we've spent a good deal of time on Hero Academy 2. So much so, that we think we're probably in a really good place to give you some advice about how to get the most out of the game. And in this guide, that's exactly what you're... | Read more »
Everything about Hero Academy 2: Part 3...
In the third part of our Hero Academy 2 guide we're going to take a look at the different modes you can play in the game. We'll explain what you need to do in each of them, and tell you why it's important that you do. [Read more] | Read more »
Everything about Hero Academy 2: Part 2...
In this second part of our guide to Hero Academy 2, we're going to have a look at the different card types that you're going to be using in the game. We'll split them up into different sections too, to make sure you're getting the most information... | Read more »
Everything about Hero Academy 2: Part 1...
So you've started playing Hero Academy 2, and you're feeling a little bit lost. Don't worry, we've got your back. So we've come up with a series of guides that are going to help you get to grips with everything that's going on in the game. [Read... | Read more »

Price Scanner via MacPrices.net

9.7-inch 2017 WiFi iPads on sale starting at...
B&H Photo has 9.7″ 2017 WiFi #Apple #iPads on sale for $30 off MSRP for a limited time. Shipping is free, and pay sales tax in NY & NJ only: – 32GB iPad WiFi: $299, $30 off – 128GB iPad WiFi... Read more
Wednesday deal: 13″ MacBook Pros for $100-$15...
B&H Photo has 13″ #Apple #MacBook Pros on sale for up to $100-$150 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13-inch 2.3GHz/128GB Space Gray... Read more
Apple now offering Certified Refurbished 2017...
Apple has Certified Refurbished 9.7″ WiFi iPads available for $50-$80 off the cost of new models. An Apple one-year warranty is included with each iPad, and shipping is free: – 9″ 32GB WiFi iPad: $... Read more
10″ iPad Pros on sale for $50-$75 off MSRP, n...
B&H Photo has 10″ and #Apple #iPad Pros on sale for up to $75 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only. Note that some sale prices are restricted to certain... Read more
Apple refurbished Mac minis available startin...
Apple has restocked Certified Refurbished Mac minis starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: – 1.4GHz Mac mini: $419 $80 off MSRP – 2.6GHz Mac... Read more
Amazon offers Silver 13″ Apple MacBook Pros f...
Amazon has new Silver 2017 13″ #Apple #MacBook Pros on sale today for up to $150 off MSRP, each including free shipping: – 13″ 2.3GHz/128GB Silver MacBook Pro (MPXR2LL/A): $1199.99 $100 off MSRP – 13... Read more
Sale: 12″ 1.3GHz MacBooks on sale for $1499,...
B&H Photo has Space Gray and Rose Gold 12″ 1.3GHz #Apple MacBooks on sale for $100 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 12″ 1.3GHz Space... Read more
Apple offers Certified Refurbished 2017 iMacs...
Apple has a full line of Certified Refurbished iMacs available for up to $350 off original MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: – 27... Read more
13″ MacBook Airs on sale for $120-$100 off MS...
B&H Photo has 2017 13″ 128GB MacBook Airs on sale for $120 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $... Read more
15″ Touch Bar MacBook Pros on sale for up to...
Adorama has Space Gray 15″ MacBook Pros on sale for $200 off MSRP. Shipping is free, and Adorama charges sales tax in NJ and NY only: – 15″ 2.8GHz MacBook Pro Space Gray (MPTR2LL/A): $2199, $200 off... Read more

Jobs Board

*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 113384559 Brandon, Florida, United States Posted: 10-Jan-2018 Weekly Hours: 40.00 **Job Summary** Are you passionate about Read more
Art Director, *Apple* Music + Beats1 Market...
# Art Director, Apple Music + Beats1 Marketing Design Job Number: 113258081 Santa Clara Valley, California, United States Posted: 05-Jan-2018 Weekly Hours: 40.00 Read more
*Apple* Pay & Wallet Engineering Manager...
# Apple Pay & Wallet Engineering Manager, Apple Watch Job Number: 83769531 Santa Clara Valley, California, United States Posted: 06-Nov-2017 Weekly Hours: 40.00 Read more
UI Tools and Automation Engineer, *Apple* M...
# UI Tools and Automation Engineer, Apple Media Products Job Number: 113136387 Santa Clara Valley, California, United States Posted: 11-Jan-2018 Weekly Hours: 40.00 Read more
Senior Product Architect, *Apple* Pay - App...
# Senior Product Architect, Apple Pay Job Number: 58046427 Santa Clara Valley, California, United States Posted: 04-Jan-2018 Weekly Hours: **Job Summary** Apple , Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.