The Squirrel Browsing Tool CEDAR 5.0 The Squirrel Browsing Tool Database browsing in Cedar By Rick Cattell, Jim Donahue Last edit by Donahue.pa on December 14, 1983 9:32 am Release as [Indigo]Documentation>SquirrelDoc.Tioga XEROX Xerox Corporation Palo Alto Research Center 3333 Coyote Hill Road Palo Alto, California 94304 For Internal Xerox Use Only Introduction This document describes the general-purpose database management tools available for use in conjunction with the Cypress DBMS in the Cedar programming environment. The database management tools are packaged in a system called Squirrel. We describe only Squirrel here; the documentation for Cypress and Cedar can be found under separate cover. Some knowledge of Cypress is useful in understanding this document, and some knowledge of Cedar is essential. Our exposition is organized into two parts, aimed at two different audiences. In Part I, we describe the Squirrel system from a user's the point of view. Such a user might want database management tools to examine or create personal or public databases for which no specific application programs have been written: phone and address lists, bibliographies, documentation, or wine lists, for example. Squirrel provides simple tools for such users without requiring a deep understanding of Cypress or Cedar programming. In Part II of this document, we describe the Squirrel system from the point of view of a database application builder. Squirrel exports convenience procedures for use by application programs, and provides a central registry to give some degree of integration between applications. Our goal is to make it reasonably easy for a Cedar programmer to build a new database application in a relatively short period of time, and to make it possible to build simple databases with no programming at all. Part I. User Documentation for Database Tools 1. Introduction There are two levels of Squirrel users: those that simply intend to read databases, e.g. to examine the Cedar documentation whiteboards, and those that intend to create new databases, either personal databases or public ones. The former class of user may skip directly to the section of interest at this point. Skip to Section 4 if you are interested in whiteboards. For those that intend to use Squirrel more extensively, we summarize the entire system, beginning with a brief review of Cypress concepts. Cypress stores three kinds of basic data elements: relationships, entities, and datum values. Datum values may be ROPEs, INTs, BOOLs, or GreenwichMeanTimes. An entity is like a Cedar ATOM, it is a unique identifier for some object. A relationship is a tuple whose fields are entities and/or datum values. In this sense, a relationship is like a Cedar RECORD; Cypress provides more powerful query operations on relationships than are available on RECORDs, however. Entities are used in a database to represent physical or conceptual objects, such as people, documents, or electronic messages. Every entity in a database has a type, assigned according to the type of object it represents. We call entity types domains, e.g. the person domain. Every entity in a domain is given a name that uniquely identifies it within its domain. For people, we might use their social security number or their proper name. For the document domain, we might use the title of the document. Cypress permits a hierarchy of types of entities (domains). For example, there may be a variety of subtypes of document: journal papers, books, and reports. Datum values also have types, just as in Cedar. The data types are built-in (ROPE, INT, etc.). Relationships are the main information-carrying medium in a database. Relationships represent atomic facts about entities and datum values. For example, we might have a binary author relationship connecting a person with a document that he wrote. Relationships have types; we call these types relations. When a relation is defined to Cypress, we must say how many fields (attributes) it has, and what their types are. The attribute types may be domains (Person, Document, Message) or data types (ROPE, INT, BOOL). Each relation represents some kind of fact. For example a member relation might have three attributes, of type person, organization, and INT. A relationship in this member relation indicates that a given person has been a member of a given organization since a given year (the latter represented by the INT). The type specifications for a database (the domains and relations) are called the data schema. The data schema may generally be changed even when there are existing data in a database defined under an older schema. Cypress provides a mechanism for segmenting databases into independent physical files so that applications do not step on each other's toes. Segments allows the schema and data for applications to be separate, therefore you may define your schema in any way you find convenient for your application without regard for other applications. We discuss the definition of a data schema in the Section 7, and a default schema you might start with for a personal database in Section 3. Again, the above review of Cypress is too brief for a thorough understanding; the reader should consult the Cypress documentation for more explanation and examples. 2. Squirrel tool The Squirrel tools can be found in the Cedar release, as [Indigo]Top>Squirrel.df. Squirrel provides a number of database facilities: windows for examining and modifying data, windows for examining and modifying the data schema, windows to query databases, and a variety of other functions provided by a Squirrel "control" window. In Section 3 we describe the control window, which appears in iconic form when the user types "Squirrel" to the Cedar executive. In subsequent sections we describe the other facilities Squirrel provides. User interface Conventions A few words about the general Squirrel envrionment would he helpful before examining its components. Squirrel and application programs use three primary types of application viewers: displayers, editors, and queryers. We describe the user interface conventions for these three kinds of viewers here. A displayer presents information in the database about a database entity and provides a command menu to perform appropriate operations on the entity. For example, for an electronic message displayer, the message's header and body would be displayed, along with commands such as Answer, Forward, and Delete. An editor looks much like a displayer, but provides the user a form with which to modify the information about the entity. It usually has a different set of commands. For example, a message editor is created in response to a NewForm or Answer command in the Walnut system. A queryer looks like an editor, but the user may fill in the fields with values, boolean expressions of values, or other application-interpreted information; the queryer represents all the entities in a domain which satisfy the constraints. When the user invokes the query, the entities satisfying it are displayed and may be browsed or printed. The Squirrel tool provides basic database functions: commiting or aborting a transaction, dumping or loading a database segment, or erasing portions of a database. The Squirrel tool also allows invocation of a displayer, editor, or queryer, by filling in a domain and/or entity in the correspondingly labelled fields, and pushing the Display, Edit, or Query button. The Display and Edit buttons require that the Segment, Domain, and Entity name fields by entered; the Query button requires only the Segment and Domain fields. If no application has registered itself for the given domain when one of these three buttons is used, Squirrel invokes its default displayer, editor, or queryer. These default displayers, editors, and queryers may be used for various special purposes without the need for developing a database application. They will be described further in Sections 5 through 7, respectively. Squirrel, and database applications which adhere to its conventions, use a common set of interpretations for mouse buttons, menu names, window layout, etc., in the displayer and editor viewers. Below, we discuss the current choices; note that they are more in the spirit of suggestions than hard and fast rules. Button Interpretation Middle Open a new displayer window viewing entity at current cursor position Shift-Middle Give more information about entity in place (rather than new window) Left Select the entity or datum value at the current cursor position Control-Left Delete the entity or relationship at the cursor position Shift-Left Paste entity or datum value at cursor into the current input focus Right Extend a selection made by left to the current position Others Currently application-defined The middle button was dedicated to the "show me" interpretation (i.e., opening up a displayer on a selected entity) because this was deemed a very common operation, for browsing through data. Note that frequent use of the middle button can lead to many viewers on the screen, however. To this proliferation, the Squirrel windows follow the following convention for opening new windows when a user selects an entity with the middle button: 1. If the user has selected an entity (with the middle button) in the window before, and the displayer window thus created is still on the screen, re-use the previous displayer window. Note that the existing applications all have a "Freeze" menu item so that a user may prevent a viewer from being reused in this way. 2. Otherwise, create a new entity displayer on the screen for the selected entity, in non-iconic form on the left-hand side. The interpretation of the mouse buttons was chosen to be as compatible as possible with existing interpretations in the Cedar Viewers environment. There is in fact some overlap. For example, one can select an entity by selecting the entire window (or icon, if in iconic form) for its displayer. It can then be used as an implicit argument to a command, e.g. to add it to a set of entities in another window. Also, middle-button has the same meaning ("open") on Viewer icons as for Squirrel entities. 3. Squirrel Commands The first line of the Squirrel window provides a set of commands on segments and transactions. Most of these commands make use of the Segment field of the control window, which contains a string of the form [Server]SegmentName.segment (currently, the only legal server name is Luther.Alpine). Cypress allows only one segment with a given SegmentName to be open at a time. To reduce the confusion, Squirrel assumes that SegmentName is the print name of the atom Cypress uses to identify the segment; it may not differ from the file name. Since the segment name is a Cedar ATOM, capitalization is significant: only the first letter is capitalized. This is the only place in Squirrel where capitalization is significant. At present, the readOnly and number parameters to the Cypress DeclareSegment must be defaulted when using Squirrel. The first line of commands are: Save/Reset: You can abort or commit the transaction on the given segment by bugging "Reset" or "Save". (A full file name may be given in the Segment field, but only the SegmentName portion is necessary for these commands). Open/Close: Open calls DB.DeclareSegment and opens a transaction on the given segment. Close closes the transaction again. If a transaction is already open on the given segment, a warning is issued and the transaction remains open. Load/Dump: The Load button causes the file "SegmentName.dump" (where SegmentName is as defined above) to be read and its contents added to the segment. See Section 3 of Part II for the format of these files. The Dump button causes the file "SegmentName.dump" to be written, including the schema and data in the segment. List: This button causes the list of currently defined segments (opened by the user or by some program) to be listed in the Squirrel typescript. An indication is given whether they are open or closed. Squirrel currently opens a Squirrel segment (for default databases) and Icons segment (for icon information) when it starts up. EraseSegment: This button can be used to make an entire segment go away, e.g. to reload it from a previous dump. The second line of commands pertain to entities. Most of them make use of all three of the fields in the Squirrel control window (Segment, Domain, and Name): Display: This command creates a displayer on the named entity in the given domain in the given segment. (I.e., given in the Segment, Domain, and Name fields). If no application has registered itself to display entities in that domain, the default displayer is invoked. Edit: This command is the same as Display, but creates an editor (from an application, or the default editor). Query: This command creates a queryer window on the named domain. Erase: This command deletes the entity with the given name, domain, and segment. The Erase command may be used to erase entire domains or relations, by specifying "Domain" or "Relation" in the Domain field. The Name field may be a list in this case, separated by spaces. All the entities in the named domains (and all relationships which refer to them), or all of the relationships in the named relations will be deleted. Stop: This command can be used to abort a long operation (e.g. a Dump). Debug: This command causes Squirrel to invoke the default displayer, editor, or queryer regardless of whether an application has registered itself for a given domain. It also gives more information about entities when they are displayed, e.g. it shows the segment name as well as domain and entity names at the top of displayer windows. This command is useful when applicaiton programs are broken and being debugged. The more common commands invoked through the Squirrel window are also available as registered commands in the Cedar executive, and allow a number of optional arguments using the command line. They are (with the optional arguments specified in brackets): DBDump segment [file _ ] [~] [[Domains: ] domain1 ... domainn] [Relations: relation1 relationm]: dumps the named domains and relations in the given segment to the specified file (or segment.dump if none is given). The "~" before the list of domains and relations means "dump all except those named"; this is particularly useful if you want to dump all of the database that does not belong to one particular application. Note that the Dump button in the Squirrel window always dumps an entire segment, so the DBDump command is more specific. DBLoad [file] [segment]: loads the given segment from the given file (uses Squirrel.dump by default), The DBLoad command is a convenient way to load up a schema or build a segment for a new database application. For personal databases, a default schema you may find convenient can be found on [Indigo]Dump>PDB.dump. DBDisplay [segment:] [domain:] entityname: displays the named database entity. The segment defaults to Squirrel, and the domain may be defaulted as well if the entityname is unique across all domains. You should try starting up Squirrel at this point. Suggested exercises will be shown in a special font in this document, as in the following: Type the following command in a CommandTool: Squirrel This will also load Cypress and AlpineUserImpls. A Squirrel icon will appear on your screen, with the buttons as described above. Try closing and re-opening the Squirrel segment. 4. Whiteboards In this section we describe "Tree Squirrel", implementing Whiteboard entities for spatially displaying databases. Commands for examining whiteboards A Whiteboard may be displayed using the Squirrel Display button, or the Whiteboard command registered with the UserExec: Whiteboard name (displays the named whiteboard in the Squirrel segment). A whiteboard displays icons representing entities, organized spatially in a whiteboard Viewer as specified by the creator of the whiteboard. Both the entities and the spatial layout information are stored in the database. Try examining Jim Donahue's Cedar Documentation whiteboards. To do this type "Whiteboard Cedar" to the Cedar executive. Whiteboards may be manipulated using the menu at the top of a whiteboard window, or by using mouse buttons with special meanings within the whiteboard itself. For the purposes of browsing, only middle-button selection within the window itself will be needed. Middle-button selection means "open": whenever the user points at an icon on a whiteboard and presses the middle button, a new window is opened on the screen displaying the entity represented by that icon. Use middle-button selection to examine items on the Cedar whiteboard. Note that documents and programs open Tioga windows or start programs, respectively. Documents appear as the familiar Cedar icons for ducments, and programs as their normal icons as well. Whiteboards may be nested inside whiteboards: they appear as icons resembling phyusical whiteboards. Try browsing through some of these. Each time you select an icon, a new window will be created on the screen. You will require only the middle mouse button for this browsing. Commands for editing whiteboards If you plan to create or edit your own whiteboards, you will need to know about more than just browsing with middle-button selection. The meaning of the menu buttons on a Whiteboard are as follows: Reset: Restores a whiteboard to its state before any edits were made. Freeze: Retains this whiteboard on the screen, rather than replacing it with another whiteboard, when middle-button selection would normally display something else in it. NewBox: Creates a new text box on a whiteboard, near the upper left hand corner. A text box can be used for notes on the whiteboard, and may typed into as any Tioga document. It may be moved to wherever is convenient (using left button, described below). NewWB: Creates a new whiteboard within this whiteboard, near the upper left hand corner. It may be moved to wherever is convenient. AddSelected: You select an icon somewhere at the bottom of the Cedar Viewers screen for this command (there should be a way to select Viewers when they are not iconic, but not yet). The selected entity is added to the whiteboard. It may already be a database entity (e.g. another whiteboard entity), or it may be a Tioga document or Cedar program (in which case a database entity may be created to represent it). ShowLines: This command will draw lines showing relations between entities displayed on this whiteboard. Only the first two attributes of a relation (currently must be named "of" and "is") are used, as only binary relationships can be shown by a line. The lines are labelled with the name of the relation, and a small circle is shown at the end which represents the second attribute. The relations themselves must be created with the "Ground Squirrel" facilities described in Section 6. Grid: You may want the icons and text boxes on the whiteboard to line up either vertically or horizontally. The Grid menu item lets you set the size of a grid (in pixels) on which to place viewers on a whiteboard. The default grid size is 1; it can be doubled (up to a maximum of 32) by left-clicking the menu item and halved by right-clicking the menu item. Each time the grid is changed, the whiteboard will be redisplayed. Moreover, new items added to the whiteboard will only be allowed to settle on points on the grid (for icons, this means that the top left corner will be on a grid point, for text boxes that all of the corners will be on grid points). The second line of commands appears when the last menu item on the first line, the Store command, is invoked. The meanings of the second line menu items are as follows. Save: Stores any edits to the whiteboard in the database; removes "[New Version]" at top of window. Erase: Erases the entire whiteboard. Careful! Rename: Changes the name of this whiteboard to be the currently selected text. In addition to the commands at the top of a Whiteboard window, mouse button presses within the window area itself have specific effects on the entity the mouse is pointing at. Because mouse selections have their Tioga meanings when the cursor is inside text boxes, you must select just outside to get these effects on text boxes. The mouse buttons and their effects are: Left: Selects and moves the icon for the entity (or a text box) around on the whiteboard. Control Left: Deletes the entity from this whiteboard. Middle : Opens a displayer on the entity. Shift Middle : Opens a full-sized displayer on the entity. Control Middle : Places entities directly related to this one somewhere on the whiteboard, using some heuristics for their placement. I.e., it places all the entities to which lines would be drawn by the ShowLines command on the whiteboard. If there are more than half a dozen entities connected by the same relation, they will not be shown. If all of the entities related to entity X are on the whiteboard, then entity X has an outline around it to indicate this. Right: Grows (or shrinks) a text box. 5. Default displayer We now describe "Ground Squirrel", providing basic facilities for displaying, editing, and querying databases. You may want to try looking at a sample segment, so that you can experiment with the facilities described in subsequent sections: Close the remote Squirrel segment, if any, and open [Luther.Alpine]Squirrel.segment. Push the Display button to see the Domain domain. The default Squirrel displayer shows the domain and name of the entity displayed in the title of the window it allocates; all relationships in the segment that reference the entity are shown in the main body of the window. The relationships are diplayed in the form relation attribute1: value1 attribute2: value2 ... attributeN: valueN The attribute of the relation that references the displayer's entity is not shown, as this would be redundant. String, integer, and boolean valued attributes are displayed in the obvious way. For entity values, the entity name is displayed and may be selected with the middle mouse button to invoke a displayer for the entity. The default displayer also has two optional subwindows following the tuples that reference the entity. The first subwindow is labelled "Related Entities", and shows one or more icons for entities that are connected to the displayed entity by a special binary connection relation. The second subwindow is labelled "Notes", and appears if an optional piece of text has been associated with the entity. Display the Organization entity "Xerox PARC" in the [Luther.Alpine]Squirrel.segment opened earlier. Note the tuples in the top subwindow, from the sub-organization, address, and phone relations. Select the "Palo Alto, CA" entity in the address tuple with the middle button to put up a new displayer. If you try to do the same with a datum-valued field, e.g. "494-4000", the operation is rejected. If you select another entity in the same window, e.g. Xerox PARC CSL, the Palo Alto displayer will be replaced with it (unless you use the Freeze command to keep it). Note that [New Version] appears in the title of a displayer until Squirrel finishes painting the window, to give you some feedback as to its state. Below the tuples subwindow in the Xerox PARC window is a related-entities subwindow containing just one icon (for the Place Coyote Hill), and a notes subwindow containing a short comment on Xerox PARC. There are only two commands on the default displayer: Freeze, and Edit. Freeze has the usual meaning, described in Section 2. Edit causes the displayer to be replaced with an editor on the same entity. The contents of a displayer are not currently updated when a database transaction is aborted or if edits are made to the database through a program or editor window; this is a relatively simple change, however, and will probably appear in a future version. 6. Default editor The default editor displays the domain and name of the entity being edited at the top of the window, just as a displayer does. It differs from the default displayer in that a form is provided in the body of the window for the entity, showing not only those relationships which already reference the entity, but "blank" relationships for relations that could reference an entity of its domain. The blank fields of such a relationship can be filled in by the user. (If the editor window is on a new entity, then all the relationships shown will be blank, of course.) The tuple subwindow lines are of the form: relation attribute1: X value1 attribute2: X value2 ... attributeN: X valueN Where X is present only for entity-valued attributes, and consists of a box with an O, an N, or nothing in it. Unlike displayers, the values of the attributes are editable Tioga text, and the client may edit the entity's tuples by modifying these fields. If you desire the effect of a displayer, i.e. want to create a displayer for the entity, you should select the attribute name with the middle button, rather than the value. If a relationship in a displayer has more than three attributes (i.e. two plus the one referencing this entity), the relationship is split over multiple lines. If you need more space to type into one of the attribute values, select the relation name with the rightmost moust button and that tuple will be expanded. Multiple-buttoning give more space. For entity-valued fields, the X field indicates whether the user is entering a new or existing entity in the field. The default (a box with an O in it) is "OldOnly" mode, i.e. the string the user enters must be the name of an existing entity in the domain of the modified attribute. By selecting the box, the user may change the mode to N for "NewOnly" (creating a new entity with the given name), or an empty box, for "NewOrOld". As mentioned earlier, the editor provides blank tuples for a relation that could reference an entity of the given type, if there are not already tuples in the relation that reference it. The user may create new blank tuples by using the left button on the relation name in one of the tuples. Selecting the relation name in a tuple with the middle button will show more information about its fields: the types of its attributes, and whether any of them are keys of the relation. The editor window provides the following menu items: Reset: aborts all edits made by modifying fields in the tuple subwindow. Save: make all edits in the tuple subwindow appear in the database (but doesn't commit transaction). Rename: make the entity have the selected text as name. Merge: moves all the tuples associated with this entity to the entity whose name is selected, and deletes the entity associated with this window. That is, this command merges the two entities into one entity whose name is the selected text. EraseAll: deletes this entity and all the relationships associated with it. AddSelected: adds the entity whose icon is selected on the screen to the related-entities subwindow. You may edit the Notes at the bottom of the window to associate some comments with an entity. The comments will not be stored in the database until you invoke the Save command. Similarly, edits to the RelatedEntities subwindow do not appear in the database until edits are saved. Currently, the Save button on the default editor does NOT commit the database transaction that is opened. You must push the Save button on the Squirrel window to achieve that. You therefore have two levels of transaction in effect, and can back out of a number of edits by using the Abort button on the Squirrel window. The default editor is still somewhat experimental, and suggestions would be appreciated. The display package it uses appears to be slower than we anticipated, so we may switch to a simpler display scheme. Try pushing the Edit button on the Xerox PARC displayer; it will be transformed into an editor. Add a new sub-organization by using the left button on one of the relation name to create a new blank tuple. Remove a tuple by replacing all its fields with null strings. Edit the notes. Add a related entity by opening a displayer with the Squirrel window, making it iconic, selecting it, and using the AddSelected button on the default editor. Try some of the other features of the editor. Then Abort your transaction with the Squirrel window command (rather than updating the remote shared segment). 7. Default queryer The default queryer provides a form much like the default editor, with blank tuples for the relations an entity of the given domain may participate in. Unlike an editor, the form represent a generic set of entities of the given domain which satisfy the constraints filled in by the user. When the special Query button is pressed, a Viewer appears on the screen listing the entities which satisfy the query. These entities may then be examined by the ordinary browsing capabilities of Squirrel. The default queryer was only recently completed, try it at your own risk. 8. Schema displayers In addition to displayers and editors on ordinary data items, Squirrel implements special displayers and editors for domains and relations. The domain displayer shows the attributes in the data schema that can reference an entity from the domain, the sub-types and super-types of that domain, and all of the entities of the domain sorted by name. The displayer for a relation shows a table whose columns are labelled with the names, types, and uniqueness constraints of the relation's attributes; the rows of the table show the relationships in the relation. 9. Schema editors There are also editors for schema items, allowing you to create new domains and relations or modify existing ones. These facilities are not yet documented; see a wizard to show you, for now. The editor for a domain shows its sub-types and super-types. The editor automatically copies entities and renames domains if necessary to achieve the effect of a requested change (Cypress does not allow defining sub-types of a domain that already contains entities). The editor for a relation shows only the attribute names, types, and uniquenesses. The user may also delete attributes of the relation or create new ones; the relation editor will automatically copy all the relationships into a new relation with the same name, since the underlying database system does not allow changing attributes of a relation after relationships exist. 10. Appendix The mouse buttons and their function in the various pieces of software are as follows: Left: In general, selects the item. For whiteboard icons: can be used to move an item around, as long as the button is held down. For editors: on an attribute name or the Notes button selects the associated text in pending delete mode; left-selecting a relation name gives a new tuple from that relation. Middle: In general, opens the item as a window for whiteboard icons, entity-valued fields in displayers, and related entities in displayers. For editors: on the attribute name, opens the associated entity (can't be used on the value, since that give Tioga word-select); on a relation name, gives more information about the attributes expected. Right: On whiteboards: expands or contracts size of text boxes (use just outside box), while held down. For editors: on relation name and Notes button, increase space for text. [The above list is not complete; would someone like to contribute?] If you have ideas on how to make the interpretation of mouse buttons simpler and more consistent, please let us know. 11. User profile options There are two user profile options that you can change when running the Squirrel Tool. Squirrel.Segment: The name of the default Squirrel segment; the default is "[Luther.Alpine]Squirrel.segment" (so that browsers of the Cedar documentation don't have to specify anything) Icons.Segment: The name of the default icon database to be used when displaying whiteboards; the default is "[Luther.Alpine]Icons.segment" (if you want to build a private icon database for your own application, see Jim Donahue) Part II. Programmer's Documentation for Database Tools In this part of the Squirrel documentation, we describe the construction of database applications making use of the Squirrel facilities. An understanding of the Cypress package is necessary to building such an application. Cypress is described in [Indigo]Database> CypressDoc.press. We also include a few helpful hints on common snares in building applications. The user facilities described in Part I are useful in debugging application programs. Squirrel provides two other kinds of facilities to the application programmer: (1) a central registry for notification of database-related events, and (2) convenience procedures for common operations. The central registration is provided by the Nut interface, described in Section 2. The convenience procedures are provided by interfaces described in the subsequent sections. In writing a new application, you need to do two things: 1. Design a database schema for your application. Some hints at how to do this are given in the Cypress documentation; you should also seek out other people who have done applications, for hints on ways to do cleanly the things you have in mind. 2. Learn how to use the DB operations. These are described in the Cypress documentation -- the Cedar interface is found in DB.mesa in the latest Cypress.df (on [Indigo]Top>). There are certain idioms that are helpful; talk to Rick Cattell, Jim Donahue, Willie-Sue Haugeland or John Maxwell if you have questions about the best way to do something. The Cypress documentation includes a simple example of a database application, although that example does not use Squirrel. 1. Introduction Your application will interact with the database through "DB" and associated interfaces, implemented by Cypress. It will interact with other applications through "Nut" and associated interfaces, which are implemented by Squirrel. A basic tenet of Squirrel is that each database application is responsible for certain domains of entities. For example, when an entity is to be displayed or edited or when a database query is to be performed on a particular domain, Squirrel passes on the request to the application that has registered itself for the domain. Applications register their displayer, etc. and call other such procedures through operations in the Nut interface. A fundamental philosophy of the Squirrel system is that it should be possible to form a loose confederation of database applications which appear integrated to the user. To make this possible, it must be necessary for the database to be self-describing, so that applications need not build in all of the knowledge of the structure of the database. Cypress allows this self-description. In addition, there must be a natural means of invoking other applications, even though the number and structure of such applications is not known in advance and may change over time. There must be a means of broadcasting the occurrence of database events that require applications to update critical data structures, for instance when the a relationship has been deleted. The Nut interface of Squirrel provide these functions. In the remaining sections we discuss Nut and associated interfaces. In this section we discuss the tools provided by Squirrel to make it easier to build and debug new applications, the rights and responsibilities of each application in a communicating confederation, and the user-interface decisions made by the developers of the first applications to present a consistent interface. The facilities described in Part I can be invaluable in debugging database applications: 1. Windows for simple browsing, editing and querying of the database. The developer of new applications may browse and change a database without having to depend on his (possibly failing) application code. 2. The dump and load commands. The dump format is human-readable text, and contains the database schema as well as the data. 3. Examination and modification of the database schema, automatically re-organizing existing data for simple schema changes. Two caveats are necessary in using Squirrel to debug applications, however: 1. Squirrel's default displayers and editors cannot be used once your application has registered its own procedures for these operations -- bugging display through the Squirrel window uses the normal Nut.Display procedure. However, the Squirrel window also provides a "Debug" menu item; when Debug is invoked, all currently registered procedures are saved and the default procedures used until Debug is invoked again, when all of the application procedures are restored. So, when debugging your application, you can still rummage around in the database when your code fails. 2. If a Mesa monitor is locked, in particular the monitor on the implementation of the DB interface, it will not be possible to invoke other operations using that monitor. A common case of this is an uncaught signal from Cypress: you must abort the signal before examining the database with Squirrel. Segments The Cypress system provides a mechanism for segmenting databases into independent physical files to provide a "firewall" between applications. This independence is a great advantage, although it is not without cost. The main disadvantage is that cross-application data references are now a little trickier than they were in the old Cedar database system; we discuss a component of Squirrel that simplifies cross-segment references in Section 3. Another side-effect of our segment scheme is that applications must be assigned a segment name and number by a CSL "database administrator", as the name space for segments is global. The current database administrator is Rick Cattell. An application may be assigned more than one segment (we can currently have up to 1024 segments), and the segment files may be local or remote. Sometimes more than one application may want to share a segment, in which case they must both know the segment and schema item names. When more than one application shares a segment, it is wise for them to do so by sharing a common interface and implementation through which access to the common data is performed. In fact, even in the case of a simple application it is wise to package up the portion of your code which does database access in a single interface; this makes your program more independent of changes in the logical representation of data. The current segment scheme in Cypress is known to be a temporary crock. Something better will happen next year. Conventions We have adopted some conventions in our applications to make our code more understandable. Generally, the data schema is defined in an interface, with an Initialize procedure which does the DeclareRelations, DeclareDomains, etc. to define them. For domain and relation names, we use the same names for the Cedar Mesa variables as for the database items they represent. We capitalize domain names, and use lower case for relations and attributes. Attribute names, whose names in the database system are unique only in the context of their relation (just as Mesa record field names are unique only in the context of their record type), are given names that are the concatentation of the relation and attribute names. Examples: Person: Domain_ DeclareDomain["Person", $MySeg]; Document: Domain_ DeclareDomain["Document", $MySeg]; author: Relation_ DeclareRelation["Friend", $MySeg]; authorOf: Attribute_ DeclareAttribute[author, "of", Person]; authorIs: Attribute_ DeclareAttribute[author, "of", Document]; Unfortunately one may not generally provide the Cedar Mesa declaration and the database declarations of schema items on the same line as we have above, because it may be necessary to re-initialize the schema, e.g. when a transaction is closed and re-opened. We discuss this problem later. Squirrel Interfaces Squirrel exports the interfaces Nut, NutOps, NutViewer, and NutDump. The Nut interface contains the registration procedures. The NutOps interface contains convenience procedures for common database operations. The NutViewer interface contains convenience procedures for common Cedar Viewers operations. The NutDump interface contains procedures for dumping and reloading databases in Ascii format. 2. Nut Interface Each database application program, such as Walnut or Hickory, registers itself with Squirrel by passing procedures to be called when an event of interest to the application occurs. The application may register a displayer, editor, or queryer procedure to be called when the user requests one for a particular domain. Walnut registers such for the message domain, for example. An application may also register itself to be called when a database segment is opened or closed, or when database relations are updated. Registering, displaying, editing and querying is all done through the Nut interface (Nut.mesa in the Squirrel.df file). Additionally procedures are provided to broadcast to all registered applications that relationships have been added to or deleted from the database. Displaying, Editing and Querying There are three procedures in the interface that invoke displayers, editors and queryers when called: Display: PROC[ e: DB.Entity, seg: DB.Segment _ NIL, parent: Viewer_ NIL, method: Method _ oneOnly] RETURNS [v: Viewer]; Edit: PROC[ d: DB.Domain, eName: ROPE, seg: DB.Segment _ NIL, parent: Viewer_ NIL, method: Method _ oneOnly] RETURNS [v: Viewer]; Query: PROC[d: DB.Domain, init: REF ANY_ NIL] RETURNS [v: Viewer]; The Display procedure displays a database entity in a viewer chosen by the following rules: 1. If the method is replace, then replace the parent with a new viewer. If a new viewer is to be created, the Create procedure that is registered for the domain is called to produce one (see below). 2. If the method#replace and the parent#NIL, then use the last viewer spawned for this entity. To give the user some control over whether viewers are to be replaced, most applications provide a "Freeze" menu item that "hides" a viewer that was spawned. 3. If the method is oneOnly, look to see if there is already a viewer for this entity. The Edit procedure doesn't take an entity as an argument because the entity may not currently exist. Instead, it takes the entity name. The Query procedure simply is given the domain upon which a query is to be performed. Broadcasting Updates The Nut interface also provides a procedure Nut.Update to broadcast to other interested applications that important changes have been made to the database: Update: PROC[updateType: UpdateType, tuple: Relship] UpdateType: TYPE = {create, destroy} When Update is called, the update procedures that have been registered for each domain will be called (of course, not all applications will find it necessary to register an update procedure for each domain). The Update procedure may be used to communicate between applications, or between different windows of the same application. Registering An application calls Nut.Register to become the displayer, editor or queryer for a particular domain and to register update and notify procedures for domains: Register: PROC[ domain: ROPE, -- the domain in which this application is interested display: DisplayProc_ NIL, -- to make displayer for entity in domain edit: EditProc_ NIL, -- to make editor for new or old entity in domain query: QueryProc_ NIL, -- to make queryer on domain create: CreateProc_ NIL, -- to create viewer for above 3 (defaults to container) update: UpdateProc_ NIL, -- to call when relation ref'ing domain is updated transaction: TransactionProc_ NIL -- to call when segment is closed or opened ]; DisplayProc: TYPE = PROC[ e: DB.Entity, newV: Viewer, init: REF ANY_NIL] EditProc: TYPE = PROC[ d: DB.Domain, eName: ROPE_ NIL, newV: Viewer, init: REF ANY_NIL] QueryProc: TYPE = PROC[ d: DB.Domain, newV: Viewer, init: REF ANY_NIL] CreateProc: TYPE = PROC[ nutType: NutType, dName, eName, defaultLabel: ROPE, init: REF ANY ] RETURNS [v: Viewer] UpdateProc: TYPE = PROC[ updateType: UpdateType, tuple: Relship] TransactionProc: TYPE = PROC[ segment: DB.Segment, fileName: ROPE, type: TransactionType] If no application has registered a procedure for a particular action on some domain, a default procedure is provided by the Squirrel implementation; furthermore, new registrations will supercede previous ones unless the new procedures are NIL. To completely deregister an application, call the deregistration procedure: DeRegister: PROC[domain: ROPE] which deregisters all procedures for the domain. The function of the Create procedure was mentioned above -- if a new viewer is needed to display or edit an entity, the Create procedure registered for the domain is called (if none is registered, then a default one is called that creates a container with a default name). If you want to provide your own Create proc, you must observe the following rules: 1. The viewer should not be filled in or painted yet -- this will be done by the Display or Edit procedure that will be called after your Create proc returns. (Of course, you may set the name of the viewer, whether it is to be iconic or not and its iconic form, or the viewer's property list.) 2. If your Create proc decides not to create a viewer, then it should return NIL. Update and transaction procedures Even within a single application, it is convenient to have a mechanism to communicate between windows about updates to the database. For example, if a message is deleted, we would like it to disappear from any message set windows in which it appears. If any relationship is deleted, we would like it to disappear from any whiteboards in which it appears. For the purposes of applications so far, it seems simple enough to note the creation and deletion of database relationships. We will add a facility to note creation and deletion of entities or updates to relationship attributes if we find it necessary in the future. When you create or destroy a relationship and wish to notify other registered code of the change, call the update procedure: If you destroy an entity, you probably want to explicitly destroy all relationships which refer to it, and call this procedure for each one. The default editor does not currently do this. You may notify others of a segment/transaction open, close, or abort using the Notify procedure: Update: PROC[updateType: UpdateType, tuple: Relship]; UpdateType: TYPE = { create, destroy }; Segments and transactions are in one-to-one correspondence in all of our current applications. (This is mainly a result of the way transactions and segments are currently implemented, this may change in next year's Cypress). As with the Update procedure, we find it useful for multiple application sharing a segment, or multiple parts of the same application, to communicate through a central notification facility. Thus any components which must re-initialize their schema, for example, may register a procedure invoked on transaction open. Notify: PROC[segment: DB.Segment, fileName: ROPE, type: TransactionType] TransactionType: TYPE = { open, close, abort }; You should take down any windows viewing database objects when a transaction is closed or aborted, or be prepared to catch errors from Cypress and do something reasonable. 3. NutDump interfaces The operations that perform dumping and loading can be found in the NutDump interface; they include DumpToFile: PROC[fileName: ROPE _ NIL, dl: LIST OF Domain _ NIL, rl: LIST OF Relation _ NIL, complement: BOOLEAN _ FALSE]; -- Dumps only the domains and relations given; -- if complement = TRUE, dumps everything but the domains and relations given DumpAll: PROC[fileName: ROPE _ NIL] = INLINE {DumpToFile[fileName, NIL, NIL, TRUE]}; LoadFromFile: PROC[fileName: ROPE _ NIL]; -- Loads whatever is in the given file; uses same dump format as DumpToFile. Additionally, the NutDump interface provides operations to perform selective dumping; these are WriteSchema: PROC[s: STREAM, dl: LIST OF Domain, rl: LIST OF Relation]; WriteSystemEntity: PROC[s: STREAM, e: Entity];-- use for Domains, Relations, and Attributes WriteSystemRelship: PROC[s: STREAM, r: Relship]; -- schema for a SubType relship WriteDomain: PROC[s: STREAM, d: Domain]; -- writes all the entities of the domain WriteEntity: PROC[s: STREAM, e: Entity]; -- writes a particular entity WriteRelation: PROC[s: STREAM, r: Relation]; -- writes all the relships of the relation WriteRelship: PROC[s: STREAM, r: Relship]; -- writes a particular relship The Load button causes a file to be read into a database segment. The format of these files is given below: /Domain\name\nametype\ ...for each domain /Relation\name\ ...for each relation /Attribute\name\relation\type\cardinality\length\link\ ...for each attribute /domain\name-elt1\name-elt2\...\ ...for each entity /relation\attr1:val1\attr2:val2\...\ ...for each relship 4. NutViewer interface The NutViewer interface provides convenience procedures for dealing with Viewers, synchronizing database operations, and dealing with unanticipated error conditions. It is handy to have one central place to print error messages: Message: PUBLIC PROC[v: Viewer, msg1, msg2, msg3, msg4: ROPE_ NIL]; -- If the top level viewer in which v is nested has a $Typescript property, then -- prints the concatenated values msg1 through msg4 on the stream that is the value -- of that property. Otherwise, if the Squirrel window is on the screen, prints the -- messages in the Squirrel window (if it is in iconic form, it is blinked). -- Otherwise, print messages in message area. Error: PUBLIC PROC[v: Viewer, msg1, msg2, msg3, msg4: ROPE_ NIL]; -- Same as Message proc above, but blinks the screen first. MessageRope: PUBLIC PROC[v: Viewer, msg: ROPE_ NIL]; -- Prints the given msg as with Message proc above, but without CR. NutViewer also contains handy procedures for creating buttons, labels, and menus in application windows. To do this, you must first call an initialization procedure on your top level Viewer: Initialize: PROC[parent: Viewer] RETURNS [nV: Viewer]; -- The argument nV returned is passed along through each call to keep track of sibling -- pos'n, e.g.: nV_ MakeLabel["Foo", nV]. You may then call any of the following procedures to create labels, buttons, etc., on successive lines of your viewer: MakeLabel: PROC[ name: ROPE, sib: Viewer, newLine: BOOL_ FALSE] RETURNS [nV: Viewer]; -- The sib is a viewer to the left or above the label to be made, according to newLine. MakeTextViewer: PROC[ sib: Viewer, w: INTEGER_ 0, fullLine: BOOL_ FALSE] RETURNS [nV: Viewer]; -- Creates a text viewer, next right on the same line as v, or full width of next line -- if fullLine=TRUE MakeButton: PROC[ q: Queue, name: ROPE, proc: Buttons.ButtonProc, sib: Viewer, data: REF ANY_ NIL, border: BOOL_ FALSE, width: INTEGER_ 0, guarded: BOOL_ FALSE, font: VFonts.Font _ VFonts.defaultFont, newLine: BOOL_ FALSE] RETURNS [nV: Viewer]; -- Creates a new button, to the right or below sib, according to newLine. MakeMenuEntry: PROC[q: Queue, name: ROPE, proc: Menus.MenuProc, clientData: REF ANY_ NIL, documentation: REF ANY_ NIL, fork: BOOL_ TRUE, guarded: BOOL_ FALSE] RETURNS[Menus.MenuEntry]; -- Creates a menu entry, suitable to use as follows: -- Menus.AppendMenuEntry[myMenu, MakeMenuEntry[...]]. -- Main purpose of this procedure is to allow menu items to be queued. MakeTypescript: PROC[sib: Viewer] RETURNS [ts: Viewer]; -- The sib is sibling to create TS after, this must be last child of non-NIL sib.parent. MakeRuler: PROC[sib: Viewer, h: INTEGER_ 1] RETURNS [r: Viewer]; -- Put a h-bit wide line after sib. We assume sib.parent#NIL. MakeBigTextBox: PUBLIC PROC[sib: Viewer, contents: ROPE] RETURNS [nV: Viewer]; -- Makes editable text viewer taking rest of sib.parent's viewer, suitable for msg body or -- whatever. The sib is a sibling to create text box after, this must be last child of sib.parent. -- Again, we assume sib.parent#NIL. The buttons and menu entries created with the above procedures are automatically synchronized, so that only one application button will be processed at a time. In addition, catch phrases are automatically inserted to catch Nullified and Abort signals from Cypress, printing out appropriate messages with the Message procedure. See the NutViewer interface for more details, and how to use your own queue instead of the default one for synchronization. The NutViewer interface includes procedures to map a Viewer onto the entity it views, and vice versa. It also includes procedures for retrieving and assigning the icon for your Viewer. FindViewerForEntity: PROCEDURE[ e: DB.Entity, segment: DB.Segment _ NIL] RETURNS[viewer: ViewerClasses.Viewer]; ConvertViewerToEntity: PROCEDURE[ v: ViewerClasses.Viewer] RETURNS[e: DB.Entity]; SetIcon: PROC[e: Entity, iconFile: ROPE, fileIndex: CARDINAL]; NewIcon: PROC[file: ROPE, index: CARDINAL] RETURNS[Icons.IconFlavor]; GetIcon: PROC[e: Entity, seg: DB.Segment _ NIL] RETURNS[Icons.IconFlavor]; See the interface for more details on these procedures. 5. NutOps interface The NutOps interface provides convenience procedures for performing common database operations. These include various procedures for dealing with entities, attributes, and relations: IsSystemDomain:PROC[d: Domain] RETURNS[BOOLEAN]; IsSystemRelation: PROC[r: Relation] RETURNS[BOOLEAN]; GetRelation: PROC[a: Attribute] RETURNS[r: Relation]; AttributesOf: PROC[r: Relation] RETURNS[AttributeList]; FirstAttributeOf: PROC[r: Relation] RETURNS[Attribute]; EntityValued: PROC [a: Attribute] RETURNS[BOOL]; RSetSize: PROC[rs: RelshipSet] RETURNS[INT]; -- Returns the length of rs, and does a ReleaseRelshipSet GetRefAttributes: PROC[d: Domain] RETURNS[al: LIST OF Attribute]; -- Returns all the attributes that can reference an entity from domain d RemoveAttribute: PROC[a: Attribute, al: AttributeList] RETURNS[AttributeList]; -- Destructively removes a from al AppendAttributes: PROC [al1, al2: AttributeList] RETURNS [al: AttributeList]; -- Destructively appends al1 and al2 and returns the result The NutOps interface also provides various procedures for dealing with segments and transactions: AtomFromSegment: PROC[ segR: ROPE ] RETURNS[ ATOM ]; IsLocalName: PROC[ segR: ROPE ] RETURNS[ BOOL ]; SetUpSegment: PROC[ segmentFile: ROPE, seg: Segment, readOnly: BOOL _ TRUE, number: NAT _ 0]; TryRestart: PROC[trans: DB.Transaction]; -- Attempts to re-open an aborted transaction if user confirms. Do: PROC[ proc: PROC[ REF ANY ], clientData: REF ANY _ NIL, reTry: BOOL _ FALSE, msgViewer: Viewer _ NIL ] RETURNS[ succeeded: BOOL ]; -- Evaluates the procedure applied to the clientData after first enabling all of the -- necessary catch phrases to recover gracefully from problems communicating with -- Alpine; will attempt to retry the operation after a recovery (first calls -- TryRestart) if reTry is TRUE. All messages go to the msgViewer -- and succeeded is TRUE if it got through Again, see the interface for more details. 6. Initialization One tricky aspect of writing a database application is getting the initialization of your global data structures correct. When an application starts up, it should register itself and inititialize its schema and other global variables. To enable use of the same segment by Squirrel (for debugging), or by other applications (to share data), the application should register a TransactionProc that behaves as follows. After a transaction open, all application variables and windows must be refreshed; this means for example, reestablishing any properties that a window has that refers to database entities (this means that it may be better to refer to entities by saving the name of the entity in such instances). Before a transaction close, applications should either take down their windows or somehow disable operations on them. The easiest thing to do is just to take down the windows: otherwise, your application must be prepared to catch signals that happen when a DB operation is attempted with the database closed. Note that your schema (and any other database entities or relationships your application maintains) must be re-initialized in the event of re-opening a transaction. It therefore behooves one to put this initialization in one place, and call it whenever a transaction is re-opened. Note that you do not in general know whether this is the first time a user is running your program. The NewOrOld option the DB interface provides in the definition of schema items is useful in this regard, and you should probably use it: if a relation or domain does not exist, it is created, otherwise the existing one is used. The NewOrOld option may also be used in defining the segment in which your application's data resides. The NewOrOld option is not a panacea, however. If you change your schema, for example, you must be very careful. The current Cypress implementation does not always check that your schema is consistent (it cannot in the general case, at least in the sense of checking that you are aware the semantics of schema items you have not declared). You must therefore be prepared in a new release of you database application to: (1) write a program which updates your database from the old schema to the new, or (2) reload the database from a schema-independent log. We discuss the latter alternative in the next subsection. We have made some progress towards simplifying both of these alternatives, though there is much work to do. 7. Other helpful hints You may find it useful to keep a log of all database updates made by your application to its segment. We may build a common package to simplify the maintenance of this log for an application, providing facilities for rebuilding your application's segment from its log, and also for keeping pointers into the log from the database, e.g. so that your application need not store large pieces of text as database strings. The Cypress package contains a useful procedure you may call from the executive, DBShow.Show[x], where x may be an entity, relationship, domain, relation, or attribute. It will return a string describing x, in approximately the same format used by DBDump, described earlier. DBShow may be used even when you have a pending uncaught signal from Cypress, i.e. it does not go through the database MONITOR. Appendix: Internal Squirrel Documentation Because some database application writers may find examples of the use of Cypress helpful in the design of their own systems, we include here a roadmap of the internal implementation of Squirrel. This map is only a brief one, however, and we have found better ways to do things with experience. Please consult someone if in doubt. 1. Default entity displayers NutDefaultImpl implements the default displayer and queryer, and contains the top level of the default editor. 2. Default entity editor TuplesEditor is implemented by TuplesEditorImpl. It implements the top-most subwindow of the default entity editor. It may be used elsewhere, as well; currently it is not. EntityEditor is implemented by EntityEditorImpl. It is an implementation of the mini-whiteboard sub windows one sees in the default entity editor windows. This package may be used with any database application desiring such a handy subwindow. NoteEditor is implemented by NoteEditorImpl. It is the implementaiton of the Notes sub windows one sees in the default entity editor windows. This package may be used with any database application desiring this subwindow. 3. Whiteboards Whiteboard is implemented by WhiteboardImpl and WhiteboardToolImpl. WhiteboardImpl implements the functions on a whiteboard, e.g. adding an icon to a whiteboard. WhiteboardToolImpl implements functions having to do with tools and text on whiteboards WhiteboardNut is implemented by WhiteboardNutImpl. I don't know why it's separate from the rest or what it does. 4. Schema displayers and editors Schema is implemented by SchemaImpl and SchemaCopyImpl. The interface contains internal procedures used by the schema editors. They might also be of use to application programs wanting to modify database schemas. For example, they allow a relation to be copied so that a new subtype may be added. SystemNuts is implemented by DomainNutImpl and RelationNutImpl. DomainNutImpl contains the domain displayer and editor. RelationNutImpl contains the relation displayer and editor. 5. Nut interfaces Nut is implemented by NutImpl and NutDefaultImpl. NutImpl contains the central registration functions used by everyone for displayers, editors, and queryers. NutDefaultImpl implements the default displayer, editor, and queryer. NutOps is implemented by NutOpsImpl. It includes the handy database operations. NutViewer is implemented by NutViewerImpl and NutViewerMiscImpl. NutViewerImpl includes operations on the icons for nuts, and a mapping function from viewers to entities and back. NutViewerMiscImpl contains handy Viewers procedures for putting up buttons that reference entities. The nut viewers are given properties (by NutImpl.CreateNut), that can accessed by Squirrel or application programs to extract information about them: $EntityName: For displayers or editors, the name of the entity. $DomainName, $Segment: For displayers, editors, and queryers: the name of the relevant domain, and its segment (an atom). $NutType: A REF NutType, i.e. NARROW[...]^ will give displayer, editor, or queryer. $EntityHandle: Not currently universally used. For some displayers: the DB.Entity it corresponds to. $Entity: For displayers and editors, the concatenated segment name, domain name, and entity name, separated by "!"s (see DBNames). Also attached to icon viewers nested inside whiteboards. Warning, this may go away or change since it is subsumed by the above. $Implementor: Set only for displayers, editors, and queryers implemented by Squirrel (has the value $Squirrel, set by the corresponding implementation). Used to identify which viewers to take down when a segment is closed. Client is currently responsible to take down client viewers on the segment, by registering a TransactionProc. $RelationInfo, $DomainInfo: Used for relation and domain editors (set by these implementations), to reference records giving more information about them. In order to synchronize the creation of nuts (e.g. to avoid doing operations before the nut has completed displaying), a NutViewerState property is attached to nuts, with the values: $beingDisplayed: Set when the viewer is created, until the client's DisplayProc, EditProc, or QueryProc returns. $quiescent: Normal status. $beingDestroyed: Set when the viewer is in the process of being destroyed. 6. Top level functions SquirrelTool is implemented by SquirrelToolImpl. It implements the Squirrel control window. NutDump is implemented by NutDumpImpl and NutLoadImpl. They implement the dump and load functions, and may be called directly by application programs as desired. 7. Miscellaneous DBNames is a temporary interface, implemented by DBNamesImpl, to deal with cross-segment references, which will be phased out now that this functionality has been added to Cypress, as Remote-link attributes. NutPrivate, implemented by NutPrivateImpl, contains just a few procedures having to do with who spawned which windows. It should probably be merged with Nut, as others may want this information. Ê – "cedar" style˜Iblock•Mark centerHeaderšœÏsœ˜K– centerFooterš ˜ Ititlešœ˜Isubtitle˜Iabstractšœ œ* œ/˜K˜K˜K˜I boilerplateš ÏqœÏoœŸœŸœŸ Ñbox˜’Ihead˜ Ibody˜Å ˜-˜Q˜üQšœÓ˜ÓQšœöÏiœ ˜Qšœ_˜_Qš œ²¡œo¡ œG¡ œÁ¡œõ˜½QšœR¡ œz˜×Q˜àQ˜¤—˜QšœX˜XQšœÅ˜ÅP˜Q˜dQ˜ÇQ˜³Q˜’Q˜ÚQšœ¡œø˜Œ ˜¸ItablešÏbœ¢œê˜—Q˜¸Iindentšœ“¡œ¥˜¾Sšœ|˜|Q˜÷—˜Q˜ÏSšœ*˜*K˜9— šœ ˜ Q˜Sš¡ œÕ˜àSš¡ œÞ˜éSš¡ œ¸˜ÁSš¡œÆ˜ÊSš¡ œe˜qQ˜žSš¡œˆ˜Sš¡œk˜oSš¡œ=˜BSš¡œ¤˜©Sš¡œD˜HSš¡œž˜£Q˜þSš ¡œ+Ïdœ £œ£œ £œÂ˜¢Sš¡œÁ˜ÇSš¡ œÀ˜ÉQ˜Ž—Inotešœí˜íšœ˜Q˜qQš¡"˜"Q˜xSš¡ œ>˜HQ˜ÞTšœx˜xQ˜ÒTšœ›˜›Qš¡ ˜ Q˜…Q˜?Sš¡œ?˜ESš¡œ£˜ªSš¡œú˜€Sš¡œ˜„Sš¡ œ“˜žSš¡ œà˜éSš¡œ“˜—Q˜©Sš¡œ_˜cSš¡œ)˜.Sš¡œH˜NQšœ÷¡œ"¡œN˜ôSš¡œS˜YSš¡ œ*˜6Sš¡œ"˜)Sš¡ œ-˜:Sš¡œÄ˜ÓSš¡œ˜%—šœ˜Q˜ñTšœ‘˜‘Q˜‹S˜GQ˜ÈQšœ’˜’TšœÖ˜ÖT˜ÉQšœË˜ËQ˜€—˜Q˜· ˜*S˜N—Qšœð¡ œ4˜­Q˜àQ˜°Q˜¤Q˜¹Q˜4S˜IS˜eS˜8S˜òS˜LS˜eQ˜™Q˜ÁQ˜Í—T˜Ü˜Q˜ðT˜I—˜Q˜²—˜Q˜¿Q˜ƒ—˜ ˜VS˜²S˜ØS˜±S˜C—Q˜u—˜ ˜VKš¢œ´˜ÄKš¢ œà˜í———˜6Q˜øQ˜ÐQ˜8S˜÷S˜åQ˜{˜Q˜£Qšœ±˜±Qšœ€˜€QšœX˜XSšœÏ˜ÏS˜~S˜}QšœK˜KSšœÁ˜ÁS˜­˜Q˜¾Q˜¬Q˜p—˜ Q˜ÎK˜ S˜0Q˜4Q˜4Q˜K˜¡—˜Q˜‘——˜Q˜“˜ Q˜fIitemš ÏnœÏkœ"¥œ¥œ¥œ ˜xUš¤œ¥œ¥œ¥œ¥œ ¥œ¥œ¥œ ˜Uš ¤œ¥œ¥œ¥œ¥œ¥œ ˜B ˜\S˜ÇS˜þS˜W—Q˜ˆQ˜U—˜Q˜œUš¤œ¥œ(˜4Ušœ ¥œ˜$Q˜Ì—˜ Q˜ŸUš ¤œ¥œ ¥œÏc5œ¥œ¦*œ¥œ¦2œ¥œ¦œ¥œ¦8œ¥œ¦3œ¥œ¦,œ˜‚Uš ¤ œ¥œ¥œ$¥œ¥œ¥œ˜HUš¤œ¥œ¥œ¥œ¥œ¥œ¥œ¥œ˜WUš ¤ œ¥œ¥œ$¥œ¥œ¥œ˜FUš¤ œ¥œ¥œ0¥œ¥œ¥œ¥œ ˜pUš¤ œ¥œ¥œ)˜@Uš¤œ¥œ¥œ!¥œ˜YQ˜ÀUš¤ œ¥œ ¥œ˜I continuation˜0Q˜äS˜§S˜R—˜!Q˜äQ˜‰Q˜¾Q˜`Uš¤œ¥œ)˜5Ušœ ¥œ˜'Q˜ Uš¤œ¥œ ¥œ˜IUšœ¥œ˜0Q˜¬——˜ ˜cSšÐbn œ¥œ ¥œ¥œ ¥œ¥œ ¥œ ¥œ¥œ ¥œ¥œ¥œÐci/¡¨M˜Sš§œ¥œ ¥œ¥œ¥œ¥œ¥œ¥œ˜TSš § œ¥œ ¥œ¥œ¦¨I˜x—Qšœ_˜_Sš¤ œ¥œ¥œ¥œ¥œ ¥œ¥œ ˜GSš¤œ¥œ¥œ ¦-˜[Sš¤œ¥œ¥œ¦˜PSš¤ œ¥œ¥œ¦(˜QSš¤ œ¥œ¥œ¦˜FSš¤ œ¥œ¥œ¦*˜WSš¤ œ¥œ¥œ¦˜IQ˜lS˜*S˜%S˜MS˜4S˜9—˜Qšœ¥˜¥ šœ>˜>Sš¢œ¥ œ$¥ œ¦þœ¢œ¥ œ$¥ œ¦=œ¢ œ¥ œ¥ œ¦Eœ˜Ä— ˜¿Sš¤ ¥œ¥œ¦„˜¼— šœv˜vSšy¤ œ¥œ ¥œ¥œ¥œ¥œ¦Yœ¤œ¥œ¥ œ¥œ ¥œ¥œ¥œ¦mœ¤ œ¥œ¥œ1¥œ¥œ¥œ ¥œ¥œ ¥œ¥œ¥œ5¥œ¥œ¥œ¦Kœ¤ œ¥œ¥œ&¥œ¥œ¥œ¥œ¥œ¥œ¥œ¥œ ¥œ¥œ¥œ¦¹œ¤œ¥œ¥œ¦Yœ¤ œ¥œ¥œ¥œ¦?œ¤œ¥œ¥œ¥œ¥œ¦\œ¦‰˜˜ —Q˜Ä šœº˜ºSš¤œ¥ œ-¥œ˜qSš¤œ¥ œ¥œ˜SSš¤œ¥œ¥œ ¥œ˜>Sš ¤œ¥œ¥œ ¥œ¥œ˜ESš¤œ¥œ¥œ¥œ˜JSšœ7˜7——˜ šœ·˜·Sš¤œ¥œ ¥œ¥œ˜0Sš¤œ¥œ¥œ¥œ˜5Sš¤ œ¥œ¥œ˜5Sš¤ œ¥œ¥œ˜7Sš¤œ¥œ¥œ ˜7Sš¤ œ¥œ¥œ¥œ˜0Sš ¤œ¥œ¥œ¥œ¦9˜hSš ¤œ¥œ ¥œ¥œ¥œ¦H˜ŒSš¤œ¥œ"¥œ¦"˜sSš¤œ¥œ¥œ¦;˜‹— ˜aSš ¤œ¥œ¥œ¥œ¥œ˜4Sš ¤ œ¥œ¥œ¥œ¥œ˜0Sš ¤ œ¥œ¥œ¥œ¥œ ¥œ˜_Sš§ œ¥œ¥œ¦?˜jSš#¤œ¥œ¥œ¥œ¥œ¥œ¥œ¥œ ¥œ¥œ¥œ¥œ ¥œ¦Uœ¦Rœ¦Mœ¦Ðbc ¦b˜ð—Q˜*—˜Q˜yQ˜¤Qšœ¡œÁ˜ÞQšœœ˜œQ˜±Qšœ¬¡œ¦˜Ø—˜Q˜¢Qšœð¡œ!˜”——˜)Q˜Ì˜Qš¢œ`˜n—˜Qš¢ œ¡˜­Qš¢ œè˜ôQš¢ œÕ˜ß—˜Qš¢ œñ˜ûQš¢ œd˜q—˜ Qš¢œ¥˜«Qš¢ œ«˜µ—˜Qš¢œâ˜åQš¢œJ˜PQš¢ œ˜™—Q˜•S˜?S˜yS˜SS˜eS˜„S˜ÎS˜›Q˜¶Sšœp˜pSšœ˜SšœL˜L˜Qš¢ œP˜\Qš¢œ›˜¢—˜Qš¢œÈ˜ÏQš¢ œ¹˜Ã—P˜——…—úFO