Edit in JSFiddle

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Orbiter Save Application State</title>

<!--CSS-->
<style type="text/css">
#outPane {
  border: inset 2px; 
  height: 200px; 
  width: 500px; 
  overflow: auto; 
  padding: 5px; 
  margin-bottom: 5px
}
</style>

<!--Load the Orbiter JavaScript library (non-minified version). Use during development.-->
<script type="text/javascript" src="http://unionplatform.com/cdn/Orbiter_latest.js"></script>
<!--Load the Orbiter JavaScript library (minified version). Use for production.-->
<!--<script type="text/javascript" src="http://unionplatform.com/cdn/Orbiter_latest_min.js"></script>-->

<!--Application code-->
<script type="text/javascript">
//==============================================================================
// VARIABLES
//==============================================================================
var orbiter;
var appRoom;

//==============================================================================
// INITIALIZATION
//==============================================================================
function init () {
  // Create the Orbiter instance, used to connect to and communicate with Union,
  // then enable automatic reconnection (one attempt every 15 seconds)
  orbiter = new net.user1.orbiter.Orbiter();
  orbiter.getConnectionMonitor().setAutoReconnectFrequency(15000);
  orbiter.getLog().setLevel(net.user1.logger.Logger.DEBUG);
  
  // If required JavaScript capabilities are missing, abort
  if (!orbiter.getSystem().isJavaScriptCompatible()) {
    displayMessage("Your browser is not supported.");
    return;
  }
  
  // Register for Orbiter's connection events
  orbiter.addEventListener(net.user1.orbiter.OrbiterEvent.READY, readyListener, this);
  orbiter.addEventListener(net.user1.orbiter.OrbiterEvent.CLOSE, closeListener, this);
  
  displayMessage("Connecting to Union...");
  
  // Connect to Union Server
  orbiter.connect("user1.net", 10100);
}

//==============================================================================
// ORBITER EVENT LISTENERS
//==============================================================================
// Triggered when the connection is ready
function readyListener (e) {
  displayMessage("Connected.");
  displayMessage("Joining room...");
  
  // Create the application room on the server. The room will be automatically
  // removed any time it becomes empty (has no occupants).
  appRoom = orbiter.getRoomManager().createRoom("examples.saveAppStateRoom");
  appRoom.addEventListener(net.user1.orbiter.RoomEvent.JOIN, joinRoomListener);
  appRoom.addEventListener(net.user1.orbiter.AttributeEvent.UPDATE, roomAttributeUpdateListener);
  
  // Join the application room
  appRoom.join();
}

// Triggered when the connection is closed
function closeListener (e) {
  displayMessage("Orbiter connection closed.");
}

//==============================================================================
// ROOM EVENT LISTENERS
//==============================================================================
// Triggered when the room is joined
function joinRoomListener (e) {
  displayMessage("Application room joined.");
  
  // Display the saved application state
  if (appRoom.getAttribute("currentSlide") == null) {
    // First client to join the room...
    displayMessage("No current presentation slide.");
    // ...so set the currentSlide to 1. Setting setAttribute()'s fourth argument
    // to true makes the attribute persistent (i.e., saved to the data source,
    // and retrievable even if the room or Union Server shuts down).
    displayMessage("Changing current slide to: 1");
    appRoom.setAttribute("currentSlide", "1", true, true);
  } else {
    displayMessage("The current slide is: " + appRoom.getAttribute("currentSlide"));
    // Save a new random current slide. The currentSlide attribute is 
    // persistent, so it will be saved to the data source for later retrieval.
    var newCurrentSlide = Math.floor(Math.random()*20);
    displayMessage("Changing current slide to: " + newCurrentSlide);
    appRoom.setAttribute("currentSlide", newCurrentSlide, true, true);
  }
}

function roomAttributeUpdateListener (e) {
  // If the room's attributes change after it has been synchronized...
  if (appRoom.getSyncState() == net.user1.orbiter.SynchronizationState.SYNCHRONIZED) {
    // ...and the client that changed the attribute was *not* the current client
    if (e.getChangedAttr().byClient != orbiter.self()) {
      // ...then display a message for the changed attribute
      if (e.getChangedAttr().name == "currentSlide") {
        displayMessage("UPDATE! New current slide: " + e.getChangedAttr().value);
      }
    }
  }
}

//==============================================================================
// UI
//==============================================================================
// Displays a single message on screen
function displayMessage (message) {
  // Make the new message element
  var msg = document.createElement("span");
  msg.appendChild(document.createTextNode(message));
  msg.appendChild(document.createElement("br"));

  // Append the new message to the output pane
  var outPane = document.getElementById("outPane");
  outPane.appendChild(msg);
  
  // Trim the chat to 500 messages
  if (outPane.childNodes.length > 500) {
    outPane.removeChild(outPane.firstChild);
  }
  outPane.scrollTop = outPane.scrollHeight;
}
</script>
</head>

<body onload="init()">
<!--Contains the output pane-->
<div id="outPane"></div>

</body>
</html>