zookeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From an...@apache.org
Subject [5/6] zookeeper git commit: ZOOKEEPER-3153: Create MarkDown files and build process for them for …
Date Fri, 05 Oct 2018 13:04:31 GMT
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/javaExample.md
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/javaExample.md b/zookeeper-docs/src/main/resources/markdown/javaExample.md
new file mode 100644
index 0000000..b33963c
--- /dev/null
+++ b/zookeeper-docs/src/main/resources/markdown/javaExample.md
@@ -0,0 +1,627 @@
+<!--
+Copyright 2002-2004 The Apache Software Foundation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+//-->
+
+# ZooKeeper Java Example
+
+* [A Simple Watch Client](#ch_Introduction)
+    * [Requirements](#sc_requirements)
+    * [Program Design](#sc_design)
+* [The Executor Class](#sc_executor)
+* [The DataMonitor Class](#sc_DataMonitor)
+* [Complete Source Listings](#sc_completeSourceCode)
+
+<a name="ch_Introduction"></a>
+
+## A Simple Watch Client
+
+To introduce you to the ZooKeeper Java API, we develop here a very simple
+watch client. This ZooKeeper client watches a ZooKeeper node for changes
+and responds to by starting or stopping a program.
+
+<a name="sc_requirements"></a>
+
+### Requirements
+
+The client has four requirements:
+
+* It takes as parameters:
+  * the address of the ZooKeeper service
+  * the name of a znode - the one to be watched
+  * the name of a file to write the output to
+  * an executable with arguments.
+* It fetches the data associated with the znode and starts the executable.
+* If the znode changes, the client refetches the contents and restarts the executable.
+* If the znode disappears, the client kills the executable.
+
+<a name="sc_design"></a>
+
+### Program Design
+
+Conventionally, ZooKeeper applications are broken into two units, one which maintains the connection,
+and the other which monitors data.  In this application, the class called the **Executor**
+maintains the ZooKeeper connection, and the class called the  **DataMonitor** monitors the data
+in the ZooKeeper tree. Also, Executor contains the main thread and contains the execution logic.
+It is responsible for what little user interaction there is, as well as interaction with the exectuable program you
+pass in as an argument and which the sample (per the requirements) shuts down and restarts, according to the
+state of the znode.
+
+<a name="sc_executor"></a>
+
+## The Executor Class
+
+The Executor object is the primary container of the sample application. It contains
+both the **ZooKeeper** object, **DataMonitor**, as described above in
+[Program Design](#sc_design).
+
+
+    // from the Executor class...
+
+    public static void main(String[] args) {
+        if (args.length < 4) {
+            System.err
+                    .println("USAGE: Executor hostPort znode filename program [args ...]");
+            System.exit(2);
+        }
+        String hostPort = args[0];
+        String znode = args[1];
+        String filename = args[2];
+        String exec[] = new String[args.length - 3];
+        System.arraycopy(args, 3, exec, 0, exec.length);
+        try {
+            new Executor(hostPort, znode, filename, exec).run();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public Executor(String hostPort, String znode, String filename,
+            String exec[]) throws KeeperException, IOException {
+        this.filename = filename;
+        this.exec = exec;
+        zk = new ZooKeeper(hostPort, 3000, this);
+        dm = new DataMonitor(zk, znode, null, this);
+    }
+
+    public void run() {
+        try {
+            synchronized (this) {
+                while (!dm.dead) {
+                    wait();
+                }
+            }
+        } catch (InterruptedException e) {
+        }
+    }
+
+
+Recall that the Executor's job is to start and stop the executable whose name you pass in on the command line.
+It does this in response to events fired by the ZooKeeper object. As you can see in the code above, the Executor passes
+a reference to itself as the Watcher argument in the ZooKeeper constructor. It also passes a reference to itself
+as DataMonitorListener argument to the DataMonitor constructor. Per the Executor's definition, it implements both these
+interfaces:
+
+    public class Executor implements Watcher, Runnable, DataMonitor.DataMonitorListener {
+    ...
+
+
+The **Watcher** interface is defined by the ZooKeeper Java API.
+ZooKeeper uses it to communicate back to its container. It supports only one method, `process()`, and ZooKeeper uses
+it to communciates generic events that the main thread would be intersted in, such as the state of the ZooKeeper connection or the ZooKeeper session.The Executor
+in this example simply forwards those events down to the DataMonitor to decide what to do with them. It does this simply to illustrate
+the point that, by convention, the Executor or some Executor-like object "owns" the ZooKeeper connection, but it is free to delegate the events to other
+events to other objects. It also uses this as the default channel on which to fire watch events. (More on this later.)
+
+
+    public void process(WatchedEvent event) {
+        dm.process(event);
+    }
+
+
+The **DataMonitorListener**
+interface, on the other hand, is not part of the the ZooKeeper API. It is a completely custom interface,
+designed for this sample application. The DataMonitor object uses it to communicate back to its container, which
+is also the the Executor object.The DataMonitorListener interface looks like this:
+
+
+    public interface DataMonitorListener {
+        /**
+        * The existence status of the node has changed.
+        */
+        void exists(byte data[]);
+
+        /**
+        * The ZooKeeper session is no longer valid.
+        *
+        * @param rc
+        * the ZooKeeper reason code
+        */
+        void closing(int rc);
+    }
+
+
+This interface is defined in the DataMonitor class and implemented in the Executor class.
+When `Executor.exists()` is invoked,
+the Executor decides whether to start up or shut down per the requirements. Recall that the requires say to kill the executable when the
+znode ceases to _exist_.
+
+When `Executor.closing()`
+is invoked, the Executor decides whether or not to shut itself down in response to the ZooKeeper connection permanently disappearing.
+
+As you might have guessed, DataMonitor is the object that invokes
+these methods, in response to changes in ZooKeeper's state.
+
+Here are Executor's implementation of
+`DataMonitorListener.exists()` and `DataMonitorListener.closing`:
+
+
+    public void exists( byte[] data ) {
+        if (data == null) {
+            if (child != null) {
+                System.out.println("Killing process");
+                child.destroy();
+                try {
+                    child.waitFor();
+                } catch (InterruptedException e) {
+               }
+            }
+            child = null;
+        } else {
+            if (child != null) {
+                System.out.println("Stopping child");
+                child.destroy();
+                try {
+                   child.waitFor();
+                } catch (InterruptedException e) {
+                e.printStackTrace();
+                }
+            }
+            try {
+                FileOutputStream fos = new FileOutputStream(filename);
+                fos.write(data);
+                fos.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            try {
+                System.out.println("Starting child");
+                child = Runtime.getRuntime().exec(exec);
+                new StreamWriter(child.getInputStream(), System.out);
+                new StreamWriter(child.getErrorStream(), System.err);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void closing(int rc) {
+        synchronized (this) {
+            notifyAll();
+        }
+    }
+
+
+<a name="sc_DataMonitor"></a>
+
+## The DataMonitor Class
+
+The DataMonitor class has the meat of the ZooKeeper logic. It is mostly
+asynchronous and event driven. DataMonitor kicks things off in the constructor with:
+
+
+    public DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,
+            DataMonitorListener listener) {
+        this.zk = zk;
+        this.znode = znode;
+        this.chainedWatcher = chainedWatcher;
+        this.listener = listener;
+
+        // Get things started by checking if the node exists. We are going
+        // to be completely event driven
+
+
+The call to `ZooKeeper.exists()` checks for the existence of the znode,
+sets a watch, and passes a reference to itself (`this`)
+as the completion callback object. In this sense, it kicks things off, since the
+real processing happens when the watch is triggered.
+
+######Note
+
+>Don't confuse the completion callback with the watch callback. The `ZooKeeper.exists()`
+completion callback, which happens to be the method `StatCallback.processResult()` implemented
+in the DataMonitor object, is invoked when the asynchronous _setting of the watch_ operation
+(by `ZooKeeper.exists()`) completes on the server.
+
+>The triggering of the watch, on the other hand, sends an event to the _Executor_ object, since
+the Executor registered as the Watcher of the ZooKeeper object.
+
+>As an aside, you might note that the DataMonitor could also register itself as the Watcher
+for this particular watch event. This is new to ZooKeeper 3.0.0 (the support of multiple Watchers). In this
+example, however, DataMonitor does not register as the Watcher.
+
+When the `ZooKeeper.exists()` operation completes on the server, the ZooKeeper API invokes this completion callback on
+the client:
+
+
+    public void processResult(int rc, String path, Object ctx, Stat stat) {
+        boolean exists;
+        switch (rc) {
+        case Code.Ok:
+            exists = true;
+            break;
+        case Code.NoNode:
+            exists = false;
+            break;
+        case Code.SessionExpired:
+        case Code.NoAuth:
+            dead = true;
+            listener.closing(rc);
+            return;
+        default:
+            // Retry errors
+            zk.exists(znode, true, this, null);
+            return;
+        }
+
+        byte b[] = null;
+        if (exists) {
+            try {
+                b = zk.getData(znode, false, null);
+            } catch (KeeperException e) {
+                // We don't need to worry about recovering now. The watch
+                // callbacks will kick off any exception handling
+                e.printStackTrace();
+            } catch (InterruptedException e) {
+                return;
+            }
+        }     
+        if ((b == null &amp;&amp; b != prevData)
+            || (b != null &amp;&amp; !Arrays.equals(prevData, b))) {
+            listener.exists(b);</emphasis>
+            prevData = b;
+        }
+    }
+
+
+The code first checks the error codes for znode existence, fatal errors, and
+recoverable errors. If the file (or znode) exists, it gets the data from the znode, and
+then invoke the exists() callback of Executor if the state has changed. Note,
+it doesn't have to do any Exception processing for the getData call because it
+has watches pending for anything that could cause an error: if the node is deleted
+before it calls `ZooKeeper.getData()`, the watch event set by
+the `ZooKeeper.exists()` triggers a callback;
+if there is a communication error, a connection watch event fires when
+the connection comes back up.
+
+Finally, notice how DataMonitor processes watch events:
+
+
+    public void process(WatchedEvent event) {
+        String path = event.getPath();
+        if (event.getType() == Event.EventType.None) {
+            // We are are being told that the state of the
+            // connection has changed
+            switch (event.getState()) {
+            case SyncConnected:
+                // In this particular example we don't need to do anything
+                // here - watches are automatically re-registered with
+                // server and any watches triggered while the client was
+                // disconnected will be delivered (in order of course)
+                break;
+            case Expired:
+                // It's all over
+                dead = true;
+                listener.closing(KeeperException.Code.SessionExpired);
+                break;
+            }
+        } else {
+            if (path != null && path.equals(znode)) {
+                // Something has changed on the node, let's find out
+                zk.exists(znode, true, this, null);
+            }
+        }
+        if (chainedWatcher != null) {
+            chainedWatcher.process(event);
+        }
+    }
+
+
+If the client-side ZooKeeper libraries can re-establish the
+communication channel (SyncConnected event) to ZooKeeper before
+session expiration (Expired event) all of the session's watches will
+automatically be re-established with the server (auto-reset of watches
+is new in ZooKeeper 3.0.0). See [ZooKeeper Watches](zookeeperProgrammers.html#ch_zkWatches)
+in the programmer guide for more on this. A bit lower down in this
+function, when DataMonitor gets an event for a znode, it calls`ZooKeeper.exists()` to find out what has changed.
+
+<a name="sc_completeSourceCode"></a>
+
+## Complete Source Listings
+
+### Executor.java
+
+
+    /**
+     * A simple example program to use DataMonitor to start and
+     * stop executables based on a znode. The program watches the
+     * specified znode and saves the data that corresponds to the
+     * znode in the filesystem. It also starts the specified program
+     * with the specified arguments when the znode exists and kills
+     * the program if the znode goes away.
+     */
+    import java.io.FileOutputStream;
+    import java.io.IOException;
+    import java.io.InputStream;
+    import java.io.OutputStream;
+
+    import org.apache.zookeeper.KeeperException;
+    import org.apache.zookeeper.WatchedEvent;
+    import org.apache.zookeeper.Watcher;
+    import org.apache.zookeeper.ZooKeeper;
+
+    public class Executor
+        implements Watcher, Runnable, DataMonitor.DataMonitorListener
+    {
+        String znode;
+        DataMonitor dm;
+        ZooKeeper zk;
+        String filename;
+        String exec[];
+        Process child;
+
+        public Executor(String hostPort, String znode, String filename,
+                String exec[]) throws KeeperException, IOException {
+            this.filename = filename;
+            this.exec = exec;
+            zk = new ZooKeeper(hostPort, 3000, this);
+            dm = new DataMonitor(zk, znode, null, this);
+        }
+
+        /**
+         * @param args
+         */
+        public static void main(String[] args) {
+            if (args.length < 4) {
+                System.err
+                        .println("USAGE: Executor hostPort znode filename program [args ...]");
+                System.exit(2);
+            }
+            String hostPort = args[0];
+            String znode = args[1];
+            String filename = args[2];
+            String exec[] = new String[args.length - 3];
+            System.arraycopy(args, 3, exec, 0, exec.length);
+            try {
+                new Executor(hostPort, znode, filename, exec).run();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        /***************************************************************************
+         * We do process any events ourselves, we just need to forward them on.
+         *
+         * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.proto.WatcherEvent)
+         */
+        public void process(WatchedEvent event) {
+            dm.process(event);
+        }
+
+        public void run() {
+            try {
+                synchronized (this) {
+                    while (!dm.dead) {
+                        wait();
+                    }
+                }
+            } catch (InterruptedException e) {
+            }
+        }
+
+        public void closing(int rc) {
+            synchronized (this) {
+                notifyAll();
+            }
+        }
+
+        static class StreamWriter extends Thread {
+            OutputStream os;
+
+            InputStream is;
+
+            StreamWriter(InputStream is, OutputStream os) {
+                this.is = is;
+                this.os = os;
+                start();
+            }
+
+            public void run() {
+                byte b[] = new byte[80];
+                int rc;
+                try {
+                    while ((rc = is.read(b)) > 0) {
+                        os.write(b, 0, rc);
+                    }
+                } catch (IOException e) {
+                }
+
+            }
+        }
+
+        public void exists(byte[] data) {
+            if (data == null) {
+                if (child != null) {
+                    System.out.println("Killing process");
+                    child.destroy();
+                    try {
+                        child.waitFor();
+                    } catch (InterruptedException e) {
+                    }
+                }
+                child = null;
+            } else {
+                if (child != null) {
+                    System.out.println("Stopping child");
+                    child.destroy();
+                    try {
+                        child.waitFor();
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                }
+                try {
+                    FileOutputStream fos = new FileOutputStream(filename);
+                    fos.write(data);
+                    fos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                try {
+                    System.out.println("Starting child");
+                    child = Runtime.getRuntime().exec(exec);
+                    new StreamWriter(child.getInputStream(), System.out);
+                    new StreamWriter(child.getErrorStream(), System.err);
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+
+### DataMonitor.java
+
+
+    /**
+     * A simple class that monitors the data and existence of a ZooKeeper
+     * node. It uses asynchronous ZooKeeper APIs.
+     */
+    import java.util.Arrays;
+
+    import org.apache.zookeeper.KeeperException;
+    import org.apache.zookeeper.WatchedEvent;
+    import org.apache.zookeeper.Watcher;
+    import org.apache.zookeeper.ZooKeeper;
+    import org.apache.zookeeper.AsyncCallback.StatCallback;
+    import org.apache.zookeeper.KeeperException.Code;
+    import org.apache.zookeeper.data.Stat;
+
+    public class DataMonitor implements Watcher, StatCallback {
+
+        ZooKeeper zk;
+        String znode;
+        Watcher chainedWatcher;
+        boolean dead;
+        DataMonitorListener listener;
+        byte prevData[];
+
+        public DataMonitor(ZooKeeper zk, String znode, Watcher chainedWatcher,
+                DataMonitorListener listener) {
+            this.zk = zk;
+            this.znode = znode;
+            this.chainedWatcher = chainedWatcher;
+            this.listener = listener;
+            // Get things started by checking if the node exists. We are going
+            // to be completely event driven
+            zk.exists(znode, true, this, null);
+        }
+
+        /**
+         * Other classes use the DataMonitor by implementing this method
+         */
+        public interface DataMonitorListener {
+            /**
+             * The existence status of the node has changed.
+             */
+            void exists(byte data[]);
+
+            /**
+             * The ZooKeeper session is no longer valid.
+             *
+             * @param rc
+             *                the ZooKeeper reason code
+             */
+            void closing(int rc);
+        }
+
+        public void process(WatchedEvent event) {
+            String path = event.getPath();
+            if (event.getType() == Event.EventType.None) {
+                // We are are being told that the state of the
+                // connection has changed
+                switch (event.getState()) {
+                case SyncConnected:
+                    // In this particular example we don't need to do anything
+                    // here - watches are automatically re-registered with
+                    // server and any watches triggered while the client was
+                    // disconnected will be delivered (in order of course)
+                    break;
+                case Expired:
+                    // It's all over
+                    dead = true;
+                    listener.closing(KeeperException.Code.SessionExpired);
+                    break;
+                }
+            } else {
+                if (path != null && path.equals(znode)) {
+                    // Something has changed on the node, let's find out
+                    zk.exists(znode, true, this, null);
+                }
+            }
+            if (chainedWatcher != null) {
+                chainedWatcher.process(event);
+            }
+        }
+
+        public void processResult(int rc, String path, Object ctx, Stat stat) {
+            boolean exists;
+            switch (rc) {
+            case Code.Ok:
+                exists = true;
+                break;
+            case Code.NoNode:
+                exists = false;
+                break;
+            case Code.SessionExpired:
+            case Code.NoAuth:
+                dead = true;
+                listener.closing(rc);
+                return;
+            default:
+                // Retry errors
+                zk.exists(znode, true, this, null);
+                return;
+            }
+
+            byte b[] = null;
+            if (exists) {
+                try {
+                    b = zk.getData(znode, false, null);
+                } catch (KeeperException e) {
+                    // We don't need to worry about recovering now. The watch
+                    // callbacks will kick off any exception handling
+                    e.printStackTrace();
+                } catch (InterruptedException e) {
+                    return;
+                }
+            }
+            if ((b == null && b != prevData)
+                    || (b != null && !Arrays.equals(prevData, b))) {
+                listener.exists(b);
+                prevData = b;
+            }
+        }
+    }
+

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/recipes.md
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/recipes.md b/zookeeper-docs/src/main/resources/markdown/recipes.md
new file mode 100644
index 0000000..7d160e2
--- /dev/null
+++ b/zookeeper-docs/src/main/resources/markdown/recipes.md
@@ -0,0 +1,387 @@
+<!--
+Copyright 2002-2004 The Apache Software Foundation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+//-->
+
+# ZooKeeper Recipes and Solutions
+
+* [A Guide to Creating Higher-level Constructs with ZooKeeper](#ch_recipes)
+    * [Important Note About Error Handling](#sc_recipes_errorHandlingNote)
+    * [Out of the Box Applications: Name Service, Configuration, Group Membership](#sc_outOfTheBox)
+    * [Barriers](#sc_recipes_eventHandles)
+        * [Double Barriers](#sc_doubleBarriers)
+    * [Queues](#sc_recipes_Queues)
+        * [Priority Queues](#sc_recipes_priorityQueues)
+    * [Locks](#sc_recipes_Locks)
+        * [Recoverable Errors and the GUID](#sc_recipes_GuidNote)
+        * [Shared Locks](#Shared+Locks)
+        * [Revocable Shared Locks](#sc_revocableSharedLocks)
+    * [Two-phased Commit](#sc_recipes_twoPhasedCommit)
+    * [Leader Election](#sc_leaderElection)
+
+<a name="ch_recipes"></a>
+
+## A Guide to Creating Higher-level Constructs with ZooKeeper
+
+In this article, you'll find guidelines for using
+ZooKeeper to implement higher order functions. All of them are conventions
+implemented at the client and do not require special support from
+ZooKeeper. Hopfully the community will capture these conventions in client-side libraries
+to ease their use and to encourage standardization.
+
+One of the most interesting things about ZooKeeper is that even
+though ZooKeeper uses _asynchronous_ notifications, you
+can use it to build _synchronous_ consistency
+primitives, such as queues and locks. As you will see, this is possible
+because ZooKeeper imposes an overall order on updates, and has mechanisms
+to expose this ordering.
+
+Note that the recipes below attempt to employ best practices. In
+particular, they avoid polling, timers or anything else that would result
+in a "herd effect", causing bursts of traffic and limiting
+scalability.
+
+There are many useful functions that can be imagined that aren't
+included here - revocable read-write priority locks, as just one example.
+And some of the constructs mentioned here - locks, in particular -
+illustrate certain points, even though you may find other constructs, such
+as event handles or queues, a more practical means of performing the same
+function. In general, the examples in this section are designed to
+stimulate thought.
+
+<a name="sc_outOfTheBox"></a>
+
+### Out of the Box Applications: Name Service, Configuration, Group Membership
+
+Name service and configuration are two of the primary applications
+of ZooKeeper. These two functions are provided directly by the ZooKeeper
+API.
+
+Another function directly provided by ZooKeeper is _group
+membership_. The group is represented by a node. Members of the
+group create ephemeral nodes under the group node. Nodes of the members
+that fail abnormally will be removed automatically when ZooKeeper detects
+the failure.
+
+<a name="sc_recipes_eventHandles"></a>
+
+### Barriers
+
+Distributed systems use _barriers_
+to block processing of a set of nodes until a condition is met
+at which time all the nodes are allowed to proceed. Barriers are
+implemented in ZooKeeper by designating a barrier node. The
+barrier is in place if the barrier node exists. Here's the
+pseudo code:
+
+1. Client calls the ZooKeeper API's **exists()** function on the barrier node, with
+  _watch_ set to true.
+1. If **exists()** returns false, the
+  barrier is gone and the client proceeds
+1. Else, if **exists()** returns true,
+  the clients wait for a watch event from ZooKeeper for the barrier
+  node.
+1. When the watch event is triggered, the client reissues the
+  **exists( )** call, again waiting until
+  the barrier node is removed.
+
+<a name="sc_doubleBarriers"></a>
+
+#### Double Barriers
+
+Double barriers enable clients to synchronize the beginning and
+the end of a computation. When enough processes have joined the barrier,
+processes start their computation and leave the barrier once they have
+finished. This recipe shows how to use a ZooKeeper node as a
+barrier.
+
+The pseudo code in this recipe represents the barrier node as
+_b_. Every client process _p_
+registers with the barrier node on entry and unregisters when it is
+ready to leave. A node registers with the barrier node via the **Enter** procedure below, it waits until
+_x_ client process register before proceeding with
+the computation. (The _x_ here is up to you to
+determine for your system.)
+
+| **Enter**                         | **Leave**                     |
+|-----------------------------------|-------------------------------|
+| 1. Create a name __n_ = _b_+“/”+_p__ | 1. **L = getChildren(b, false)** |
+| 2. Set watch: **exists(_b_ + ‘‘/ready’’, true)** | 2. if no children, exit |
+| 3. Create child: **create(_n_, EPHEMERAL)**  | 3. if _p_ is only process node in L, delete(n) and exit |
+| 4. **L = getChildren(b, false)**  | 4. if _p_ is the lowest process node in L, wait on highest process node in L |
+| 5. if fewer children in L than_x_, wait for watch event  | 5. else **delete(_n_)**if still exists and wait on lowest process node in L |
+| 6. else **create(b + ‘‘/ready’’, REGULAR)** | 6. goto 1 |
+
+On entering, all processes watch on a ready node and
+create an ephemeral node as a child of the barrier node. Each process
+but the last enters the barrier and waits for the ready node to appear
+at line 5. The process that creates the xth node, the last process, will
+see x nodes in the list of children and create the ready node, waking up
+the other processes. Note that waiting processes wake up only when it is
+time to exit, so waiting is efficient.
+
+On exit, you can't use a flag such as _ready_
+because you are watching for process nodes to go away. By using
+ephemeral nodes, processes that fail after the barrier has been entered
+do not prevent correct processes from finishing. When processes are
+ready to leave, they need to delete their process nodes and wait for all
+other processes to do the same.
+
+Processes exit when there are no process nodes left as children of
+_b_. However, as an efficiency, you can use the
+lowest process node as the ready flag. All other processes that are
+ready to exit watch for the lowest existing process node to go away, and
+the owner of the lowest process watches for any other process node
+(picking the highest for simplicity) to go away. This means that only a
+single process wakes up on each node deletion except for the last node,
+which wakes up everyone when it is removed.
+
+<a name="sc_recipes_Queues"></a>
+
+### Queues
+
+Distributed queues are a common data structure. To implement a
+distributed queue in ZooKeeper, first designate a znode to hold the queue,
+the queue node. The distributed clients put something into the queue by
+calling create() with a pathname ending in "queue-", with the
+_sequence_ and _ephemeral_ flags in
+the create() call set to true. Because the _sequence_
+flag is set, the new pathnames will have the form
+_path-to-queue-node_/queue-X, where X is a monotonic increasing number. A
+client that wants to be removed from the queue calls ZooKeeper's **getChildren( )** function, with
+_watch_ set to true on the queue node, and begins
+processing nodes with the lowest number. The client does not need to issue
+another **getChildren( )** until it exhausts
+the list obtained from the first **getChildren(
+)** call. If there are are no children in the queue node, the
+reader waits for a watch notification to check the queue again.
+
+######Note
+>There now exists a Queue implementation in ZooKeeper
+recipes directory. This is distributed with the release --
+zookeeper-recipes/zookeeper-recipes-queue directory of the release artifact.
+
+<a name="sc_recipes_priorityQueues"></a>
+
+#### Priority Queues
+
+To implement a priority queue, you need only make two simple
+changes to the generic [queue
+recipe](#sc_recipes_Queues) . First, to add to a queue, the pathname ends with
+"queue-YY" where YY is the priority of the element with lower numbers
+representing higher priority (just like UNIX). Second, when removing
+from the queue, a client uses an up-to-date children list meaning that
+the client will invalidate previously obtained children lists if a watch
+notification triggers for the queue node.
+
+<a name="sc_recipes_Locks"></a>
+
+### Locks
+
+Fully distributed locks that are globally synchronous, meaning at
+any snapshot in time no two clients think they hold the same lock. These
+can be implemented using ZooKeeeper. As with priority queues, first define
+a lock node.
+
+######Note
+>There now exists a Lock implementation in ZooKeeper
+recipes directory. This is distributed with the release --
+zookeeper-recipes/zookeeper-recipes-lock directory of the release artifact.
+
+Clients wishing to obtain a lock do the following:
+
+1. Call **create( )** with a pathname
+  of "_locknode_/guid-lock-" and the _sequence_ and
+  _ephemeral_ flags set. The _guid_
+  is needed in case the create() result is missed. See the note below.
+1. Call **getChildren( )** on the lock
+  node _without_ setting the watch flag (this is
+  important to avoid the herd effect).
+1. If the pathname created in step **1** has the lowest sequence number suffix, the
+  client has the lock and the client exits the protocol.
+1. The client calls **exists( )** with
+  the watch flag set on the path in the lock directory with the next
+  lowest sequence number.
+1. if **exists( )** returns false, go
+  to step **2**. Otherwise, wait for a
+  notification for the pathname from the previous step before going to
+  step **2**.
+
+The unlock protocol is very simple: clients wishing to release a
+lock simply delete the node they created in step 1.
+
+Here are a few things to notice:
+
+* The removal of a node will only cause one client to wake up
+  since each node is watched by exactly one client. In this way, you
+  avoid the herd effect.
+
+* There is no polling or timeouts.
+
+* Because of the way you implement locking, it is easy to see the
+  amount of lock contention, break locks, debug locking problems,
+  etc.
+
+<a name="Shared+Locks"></a>
+
+#### Shared Locks
+
+You can implement shared locks by with a few changes to the lock
+protocol:
+
+| **Obtaining a read lock:** | **Obtaining a write lock:** |
+|----------------------------|-----------------------------|
+| 1. Call **create( )** to create a node with pathname "*guid-/read-*". This is the lock node use later in the protocol. Make sure to set both the _sequence_ and _ephemeral_ flags. | 1. Call **create( )** to create a node with pathname "*guid-/write-*". This is the lock node spoken of later in the protocol. Make sure to set both _sequence_ and _ephemeral_ flags. |
+| 2. Call **getChildren( )** on the lock node _without_ setting the _watch_ flag - this is important, as it avoids the herd effect. | 2. Call **getChildren( )** on the lock node _without_ setting the _watch_ flag - this is important, as it avoids the herd effect. |
+| 3. If there are no children with a pathname starting with "*write-*" and having a lower sequence number than the node created in step **1**, the client has the lock and can exit the protocol. | 3. If there are no children with a lower sequence number than the node created in step **1**, the client has the lock and the client exits the protocol. |
+| 4. Otherwise, call **exists( )**, with _watch_ flag, set on the node in lock directory with pathname staring with "*write-*" having the next lowest sequence number. | 4. Call **exists( ),** with _watch_ flag set, on the node with the pathname that has the next lowest sequence number. |
+| 5. If **exists( )** returns _false_, goto step **2**. | 5. If **exists( )** returns _false_, goto step **2**. Otherwise, wait for a notification for the pathname from the previous step before going to step **2**. |
+| 6. Otherwise, wait for a notification for the pathname from the previous step before going to step **2** |  |
+
+Notes:
+
+* It might appear that this recipe creates a herd effect:
+  when there is a large group of clients waiting for a read
+  lock, and all getting notified more or less simultaneously
+  when the "*write-*" node with the lowest
+  sequence number is deleted. In fact. that's valid behavior:
+  as all those waiting reader clients should be released since
+  they have the lock. The herd effect refers to releasing a
+  "herd" when in fact only a single or a small number of
+  machines can proceed.
+
+* See the [note for Locks](#sc_recipes_GuidNote) on how to use the guid in the node.
+
+<a name="sc_revocableSharedLocks"></a>
+
+#### Revocable Shared Locks
+
+With minor modifications to the Shared Lock protocol, you make
+shared locks revocable by modifying the shared lock protocol:
+
+In step **1**, of both obtain reader
+and writer lock protocols, call **getData(
+)** with _watch_ set, immediately after the
+call to **create( )**. If the client
+subsequently receives notification for the node it created in step
+**1**, it does another **getData( )** on that node, with
+_watch_ set and looks for the string "unlock", which
+signals to the client that it must release the lock. This is because,
+according to this shared lock protocol, you can request the client with
+the lock give up the lock by calling **setData()** on the lock node, writing "unlock" to that node.
+
+Note that this protocol requires the lock holder to consent to
+releasing the lock. Such consent is important, especially if the lock
+holder needs to do some processing before releasing the lock. Of course
+you can always implement _Revocable Shared Locks with Freaking
+Laser Beams_ by stipulating in your protocol that the revoker
+is allowed to delete the lock node if after some length of time the lock
+isn't deleted by the lock holder.
+
+<a name="sc_recipes_twoPhasedCommit"></a>
+
+### Two-phased Commit
+
+A two-phase commit protocol is an algorithm that lets all clients in
+a distributed system agree either to commit a transaction or abort.
+
+In ZooKeeper, you can implement a two-phased commit by having a
+coordinator create a transaction node, say "/app/Tx", and one child node
+per participating site, say "/app/Tx/s_i". When coordinator creates the
+child node, it leaves the content undefined. Once each site involved in
+the transaction receives the transaction from the coordinator, the site
+reads each child node and sets a watch. Each site then processes the query
+and votes "commit" or "abort" by writing to its respective node. Once the
+write completes, the other sites are notified, and as soon as all sites
+have all votes, they can decide either "abort" or "commit". Note that a
+node can decide "abort" earlier if some site votes for "abort".
+
+An interesting aspect of this implementation is that the only role
+of the coordinator is to decide upon the group of sites, to create the
+ZooKeeper nodes, and to propagate the transaction to the corresponding
+sites. In fact, even propagating the transaction can be done through
+ZooKeeper by writing it in the transaction node.
+
+There are two important drawbacks of the approach described above.
+One is the message complexity, which is O(n²). The second is the
+impossibility of detecting failures of sites through ephemeral nodes. To
+detect the failure of a site using ephemeral nodes, it is necessary that
+the site create the node.
+
+To solve the first problem, you can have only the coordinator
+notified of changes to the transaction nodes, and then notify the sites
+once coordinator reaches a decision. Note that this approach is scalable,
+but it's is slower too, as it requires all communication to go through the
+coordinator.
+
+To address the second problem, you can have the coordinator
+propagate the transaction to the sites, and have each site creating its
+own ephemeral node.
+
+<a name="sc_leaderElection"></a>
+
+### Leader Election
+
+A simple way of doing leader election with ZooKeeper is to use the
+**SEQUENCE|EPHEMERAL** flags when creating
+znodes that represent "proposals" of clients. The idea is to have a znode,
+say "/election", such that each znode creates a child znode "/election/guid-n_"
+with both flags SEQUENCE|EPHEMERAL. With the sequence flag, ZooKeeper
+automatically appends a sequence number that is greater than any one
+previously appended to a child of "/election". The process that created
+the znode with the smallest appended sequence number is the leader.
+
+That's not all, though. It is important to watch for failures of the
+leader, so that a new client arises as the new leader in the case the
+current leader fails. A trivial solution is to have all application
+processes watching upon the current smallest znode, and checking if they
+are the new leader when the smallest znode goes away (note that the
+smallest znode will go away if the leader fails because the node is
+ephemeral). But this causes a herd effect: upon a failure of the current
+leader, all other processes receive a notification, and execute
+getChildren on "/election" to obtain the current list of children of
+"/election". If the number of clients is large, it causes a spike on the
+number of operations that ZooKeeper servers have to process. To avoid the
+herd effect, it is sufficient to watch for the next znode down on the
+sequence of znodes. If a client receives a notification that the znode it
+is watching is gone, then it becomes the new leader in the case that there
+is no smaller znode. Note that this avoids the herd effect by not having
+all clients watching the same znode.
+
+Here's the pseudo code:
+
+Let ELECTION be a path of choice of the application. To volunteer to
+be a leader:
+
+1. Create znode z with path "ELECTION/guid-n_" with both SEQUENCE and
+  EPHEMERAL flags;
+1. Let C be the children of "ELECTION", and i be the sequence
+  number of z;
+1. Watch for changes on "ELECTION/guid-n_j", where j is the largest
+  sequence number such that j < i and n_j is a znode in C;
+
+Upon receiving a notification of znode deletion:
+
+1. Let C be the new set of children of ELECTION;
+1. If z is the smallest node in C, then execute leader
+  procedure;
+1. Otherwise, watch for changes on "ELECTION/guid-n_j", where j is the
+  largest sequence number such that j < i and n_j is a znode in C;
+
+Notes:
+
+* Note that the znode having no preceding znode on the list of
+  children does not imply that the creator of this znode is aware that it is
+  the current leader. Applications may consider creating a separate znode
+  to acknowledge that the leader has executed the leader procedure.

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/basic.css
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/basic.css b/zookeeper-docs/src/main/resources/markdown/skin/basic.css
new file mode 100644
index 0000000..01c383d
--- /dev/null
+++ b/zookeeper-docs/src/main/resources/markdown/skin/basic.css
@@ -0,0 +1,167 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/**
+ * General
+ */
+
+img { border: 0; }
+
+#content table {
+  border: 0;
+  width: 100%;
+}
+/*Hack to get IE to render the table at 100%*/
+* html #content table { margin-left: -3px; }
+
+#content th,
+#content td {
+  margin: 0;
+  padding: 0;
+  vertical-align: top;
+}
+
+.clearboth {
+  clear: both;
+}
+
+.note, .warning, .fixme {
+  clear:right;
+  border: solid black 1px;
+  margin: 1em 3em;
+}
+
+.note .label {
+  background: #369;
+  color: white;
+  font-weight: bold;
+  padding: 5px 10px;
+}
+.note .content {
+  background: #F0F0FF;
+  color: black;
+  line-height: 120%;
+  font-size: 90%;
+  padding: 5px 10px;
+}
+.warning .label {
+  background: #C00;
+  color: white;
+  font-weight: bold;
+  padding: 5px 10px;
+}
+.warning .content {
+  background: #FFF0F0;
+  color: black;
+  line-height: 120%;
+  font-size: 90%;
+  padding: 5px 10px;
+}
+.fixme .label {
+  background: #C6C600;
+  color: black;
+  font-weight: bold;
+  padding: 5px 10px;
+}
+.fixme .content {
+  padding: 5px 10px;
+}
+
+/**
+ * Typography
+ */
+
+body {
+  font-family: verdana, "Trebuchet MS", arial, helvetica, sans-serif;
+  font-size: 100%;
+}
+
+#content {
+  font-family: Georgia, Palatino, Times, serif;
+  font-size: 95%;
+}
+#tabs {
+  font-size: 70%;
+}
+#menu {
+  font-size: 80%;
+}
+#footer {
+  font-size: 70%;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  font-family: "Trebuchet MS", verdana, arial, helvetica, sans-serif;
+  font-weight: bold;
+  margin-top: 1em;
+  margin-bottom: .5em;
+}
+
+h1 {
+    margin-top: 0;
+    margin-bottom: 1em;
+  font-size: 1.4em;
+}
+#content h1 {
+  font-size: 160%;
+  margin-bottom: .5em;
+}
+#menu h1 {
+  margin: 0;
+  padding: 10px;
+  background: #336699;
+  color: white;
+}
+h2 { font-size: 120%; }
+h3 { font-size: 100%; }
+h4 { font-size: 90%; }
+h5 { font-size: 80%; }
+h6 { font-size: 75%; }
+
+p {
+  line-height: 120%;
+  text-align: left;
+  margin-top: .5em;
+  margin-bottom: 1em;
+}
+
+#content li,
+#content th,
+#content td,
+#content li ul,
+#content li ol{
+  margin-top: .5em;
+  margin-bottom: .5em;
+}
+
+
+#content li li,
+#minitoc-area li{
+  margin-top: 0em;
+  margin-bottom: 0em;
+}
+
+#content .attribution {
+  text-align: right;
+  font-style: italic;
+  font-size: 85%;
+  margin-top: 1em;
+}
+
+.codefrag {
+  font-family: "Courier New", Courier, monospace;
+  font-size: 110%;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/chapter.gif
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/chapter.gif b/zookeeper-docs/src/main/resources/markdown/skin/chapter.gif
new file mode 100644
index 0000000..d3d8245
Binary files /dev/null and b/zookeeper-docs/src/main/resources/markdown/skin/chapter.gif differ

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/chapter_open.gif
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/chapter_open.gif b/zookeeper-docs/src/main/resources/markdown/skin/chapter_open.gif
new file mode 100644
index 0000000..eecce18
Binary files /dev/null and b/zookeeper-docs/src/main/resources/markdown/skin/chapter_open.gif differ

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/current.gif
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/current.gif b/zookeeper-docs/src/main/resources/markdown/skin/current.gif
new file mode 100644
index 0000000..fd82c08
Binary files /dev/null and b/zookeeper-docs/src/main/resources/markdown/skin/current.gif differ

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/getBlank.js
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/getBlank.js b/zookeeper-docs/src/main/resources/markdown/skin/getBlank.js
new file mode 100644
index 0000000..d9978c0
--- /dev/null
+++ b/zookeeper-docs/src/main/resources/markdown/skin/getBlank.js
@@ -0,0 +1,40 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/**
+ * getBlank script - when included in a html file and called from a form text field, will set the value of this field to ""
+ * if the text value is still the standard value.
+ * getPrompt script - when included in a html file and called from a form text field, will set the value of this field to the prompt
+ * if the text value is empty.
+ *
+ * Typical usage:
+ * <script type="text/javascript" language="JavaScript" src="getBlank.js"></script>
+ * <input type="text" id="query" value="Search the site:" onFocus="getBlank (this, 'Search the site:');" onBlur="getBlank (this, 'Search the site:');"/>
+ */
+<!--
+function getBlank (form, stdValue){
+if (form.value == stdValue){
+	form.value = '';
+	}
+return true;
+}
+function getPrompt (form, stdValue){
+if (form.value == ''){
+	form.value = stdValue;
+	}
+return true;
+}
+//-->

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/getMenu.js
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/getMenu.js b/zookeeper-docs/src/main/resources/markdown/skin/getMenu.js
new file mode 100644
index 0000000..6878b26
--- /dev/null
+++ b/zookeeper-docs/src/main/resources/markdown/skin/getMenu.js
@@ -0,0 +1,45 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/**
+ * This script, when included in a html file, can be used to make collapsible menus
+ *
+ * Typical usage:
+ * <script type="text/javascript" language="JavaScript" src="menu.js"></script>
+ */
+
+if (document.getElementById){ 
+  document.write('<style type="text/css">.menuitemgroup{display: none;}</style>')
+}
+
+
+function SwitchMenu(obj, thePath)
+{
+var open = 'url("'+thePath + 'chapter_open.gif")';
+var close = 'url("'+thePath + 'chapter.gif")';
+  if(document.getElementById)  {
+    var el = document.getElementById(obj);
+    var title = document.getElementById(obj+'Title');
+
+    if(el.style.display != "block"){ 
+      title.style.backgroundImage = open;
+      el.style.display = "block";
+    }else{
+      title.style.backgroundImage = close;
+      el.style.display = "none";
+    }
+  }// end -  if(document.getElementById) 
+}//end - function SwitchMenu(obj)

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/header_white_line.gif
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/header_white_line.gif b/zookeeper-docs/src/main/resources/markdown/skin/header_white_line.gif
new file mode 100644
index 0000000..369cae8
Binary files /dev/null and b/zookeeper-docs/src/main/resources/markdown/skin/header_white_line.gif differ

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/init.js
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/init.js b/zookeeper-docs/src/main/resources/markdown/skin/init.js
new file mode 100644
index 0000000..f94eda1
--- /dev/null
+++ b/zookeeper-docs/src/main/resources/markdown/skin/init.js
@@ -0,0 +1,57 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/**
+ * This script, when included in a html file, can be used to make collapsible menus
+ *
+ * Typical usage:
+ * <script type="text/javascript" language="JavaScript" src="menu.js"></script>
+ */
+
+function getFileName(url){
+    var fileName = url.substring(url.lastIndexOf('/')+1);
+    return fileName;
+}
+
+function init(){
+    var url = window .location.pathname;
+    var fileName = getFileName(url);
+
+    var menuItemGroup = document.getElementById("menu").children;
+
+    for (i = 0; i < menuItemGroup.length; i++) {
+        if("menutitle" === menuItemGroup[i].className){
+            continue;
+        }
+        var menuItem = menuItemGroup[i].children;
+        if(menuItem.length>0){
+            for (j = 0; j < menuItem.length; j++) {
+                if(menuItem[j].firstElementChild != null){
+                    var linkItem = menuItem[j].firstElementChild;
+                    if('a' === linkItem.localName){
+                        var linkFile = getFileName(linkItem.href);
+                        if(fileName === linkFile && linkItem.href.lastIndexOf("api/index.html")<0){
+                            linkItem.className = "selected";
+                            linkItem.parentNode.parentNode.className = "selectedmenuitemgroup";
+                            var title = document.getElementById(linkItem.parentNode.parentNode.id+"Title");
+                            title.className="menutitle selected";
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/instruction_arrow.png
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/instruction_arrow.png b/zookeeper-docs/src/main/resources/markdown/skin/instruction_arrow.png
new file mode 100644
index 0000000..0fbc724
Binary files /dev/null and b/zookeeper-docs/src/main/resources/markdown/skin/instruction_arrow.png differ

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/menu.js
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/menu.js b/zookeeper-docs/src/main/resources/markdown/skin/menu.js
new file mode 100644
index 0000000..06ea471
--- /dev/null
+++ b/zookeeper-docs/src/main/resources/markdown/skin/menu.js
@@ -0,0 +1,48 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/**
+ * This script, when included in a html file, can be used to make collapsible menus
+ *
+ * Typical usage:
+ * <script type="text/javascript" language="JavaScript" src="menu.js"></script>
+ */
+
+if (document.getElementById){ 
+  document.write('<style type="text/css">.menuitemgroup{display: none;}</style>')
+}
+
+function SwitchMenu(obj)
+{
+  if(document.getElementById)  {
+    var el = document.getElementById(obj);
+    var title = document.getElementById(obj+'Title');
+
+    if(obj.indexOf("_selected_")==0&&el.style.display == ""){
+      el.style.display = "block";
+      title.className = "pagegroupselected";
+    }
+
+    if(el.style.display != "block"){
+      el.style.display = "block";
+      title.className = "pagegroupopen";
+    }
+    else{
+      el.style.display = "none";
+      title.className = "pagegroup";
+    }
+  }// end -  if(document.getElementById) 
+}//end - function SwitchMenu(obj)

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/page.gif
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/page.gif b/zookeeper-docs/src/main/resources/markdown/skin/page.gif
new file mode 100644
index 0000000..a144d32
Binary files /dev/null and b/zookeeper-docs/src/main/resources/markdown/skin/page.gif differ

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/print.css
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/print.css b/zookeeper-docs/src/main/resources/markdown/skin/print.css
new file mode 100644
index 0000000..aaa9931
--- /dev/null
+++ b/zookeeper-docs/src/main/resources/markdown/skin/print.css
@@ -0,0 +1,54 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+body {
+  font-family: Georgia, Palatino, serif;
+  font-size: 12pt;
+  background: white;
+}
+
+#tabs,
+#menu,
+#content .toc {
+  display: none;
+}
+
+#content {
+  width: auto;
+  padding: 0;
+  float: none !important;
+  color: black;
+  background: inherit;
+}
+
+a:link, a:visited {
+  color: #336699;
+  background: inherit;
+  text-decoration: underline;
+}
+
+#top .logo {
+  padding: 0;
+  margin: 0 0 2em 0;
+}
+
+#footer {
+  margin-top: 4em;
+}
+
+acronym {
+  border: 0;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/printer.gif
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/printer.gif b/zookeeper-docs/src/main/resources/markdown/skin/printer.gif
new file mode 100644
index 0000000..a8d0d41
Binary files /dev/null and b/zookeeper-docs/src/main/resources/markdown/skin/printer.gif differ

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/74c245b4/zookeeper-docs/src/main/resources/markdown/skin/profile.css
----------------------------------------------------------------------
diff --git a/zookeeper-docs/src/main/resources/markdown/skin/profile.css b/zookeeper-docs/src/main/resources/markdown/skin/profile.css
new file mode 100644
index 0000000..190e74f
--- /dev/null
+++ b/zookeeper-docs/src/main/resources/markdown/skin/profile.css
@@ -0,0 +1,159 @@
+
+
+/* ==================== aural ============================ */
+
+@media aural {
+  h1, h2, h3, h4, h5, h6 { voice-family: paul, male; stress: 20; richness: 90 }
+  h1 { pitch: x-low; pitch-range: 90 }
+  h2 { pitch: x-low; pitch-range: 80 }
+  h3 { pitch: low; pitch-range: 70 }
+  h4 { pitch: medium; pitch-range: 60 }
+  h5 { pitch: medium; pitch-range: 50 }
+  h6 { pitch: medium; pitch-range: 40 }
+  li, dt, dd { pitch: medium; richness: 60 }
+  dt { stress: 80 }
+  pre, code, tt { pitch: medium; pitch-range: 0; stress: 0; richness: 80 }
+  em { pitch: medium; pitch-range: 60; stress: 60; richness: 50 }
+  strong { pitch: medium; pitch-range: 60; stress: 90; richness: 90 }
+  dfn { pitch: high; pitch-range: 60; stress: 60 }
+  s, strike { richness: 0 }
+  i { pitch: medium; pitch-range: 60; stress: 60; richness: 50 }
+  b { pitch: medium; pitch-range: 60; stress: 90; richness: 90 }
+  u { richness: 0 }
+  
+  :link { voice-family: harry, male }
+  :visited { voice-family: betty, female }
+  :active { voice-family: betty, female; pitch-range: 80; pitch: x-high }
+}
+  
+#top          { background-color: #FFFFFF;}  
+ 
+#top .header .current { background-color: #4C6C8F;} 
+#top .header .current a:link {  color: #ffffff;  }
+#top .header .current a:visited { color: #ffffff; }
+#top .header .current a:hover { color: #ffffff; }
+ 
+#tabs li      { background-color: #E5E4D9 ;} 
+#tabs li a:link {  color: #000000;  }
+#tabs li a:visited { color: #000000; }
+#tabs li a:hover { color: #000000; }
+
+#level2tabs a.selected      { background-color: #4C6C8F ;} 
+#level2tabs a:link {  color: #ffffff;  }
+#level2tabs a:visited { color: #ffffff; }
+#level2tabs a:hover { color: #ffffff; }
+
+#level2tabs { background-color: #E5E4D9;}
+#level2tabs a.unselected:link {  color: #000000;  }
+#level2tabs a.unselected:visited { color: #000000; }
+#level2tabs a.unselected:hover { color: #000000; }
+
+.heading { background-color: #E5E4D9;} 
+
+.boxed { background-color: #E5E4D9;} 
+.underlined_5 	{border-bottom: solid 5px #E5E4D9;}
+.underlined_10 	{border-bottom: solid 10px #E5E4D9;}
+table caption { 
+background-color: #E5E4D9; 
+color: #000000;
+}
+    
+#feedback {
+color: #FFFFFF;
+background: #4C6C8F;
+text-align: center;
+}
+#feedback #feedbackto {
+color: #FFFFFF;
+}   
+
+#publishedStrip { 
+color: #FFFFFF;
+background: #4C6C8F; 
+}
+
+#publishedStrip { 
+color: #000000;
+background: #E5E4D9; 
+}
+
+#menu a.selected  { background-color: #CFDCED;
+  border-color: #999999;
+  color: #000000;}
+#menu a.selected:visited {  color: #000000;}
+
+#menu           { border-color: #999999;}
+#menu .menupageitemgroup  { border-color: #999999;}
+
+#menu      { background-color: #4C6C8F;} 
+#menu  {  color: #ffffff;} 
+#menu a:link {  color: #ffffff;} 
+#menu a:visited {  color: #ffffff;} 
+#menu a:hover {  
+background-color: #4C6C8F;
+color: #ffffff;} 
+
+#menu h1 {
+color: #000000;
+background-color: #cfdced;
+}   
+ 
+#top .searchbox { 
+background-color: #E5E4D9 ;
+color: #000000; 
+} 
+ 
+#menu .menupageitemgroup     { 
+background-color: #E5E4D9;
+}
+#menu .menupageitem {
+color: #000000;
+} 
+#menu .menupageitem a:link {  color: #000000;} 
+#menu .menupageitem a:visited {  color: #000000;} 
+#menu .menupageitem a:hover {  
+background-color: #E5E4D9;
+color: #000000;
+}
+
+body{ 
+background-color: #ffffff;
+color: #000000;
+} 
+a:link { color:#0000ff} 
+a:visited { color:#009999} 
+a:hover { color:#6587ff} 
+
+ 
+.ForrestTable      { background-color: #ccc;} 
+ 
+.ForrestTable td   { background-color: #ffffff;} 
+ 
+.highlight        { background-color: #ffff00;} 
+ 
+.fixme        { border-color: #c60;} 
+ 
+.note         { border-color: #069;} 
+ 
+.warning         { border-color: #900;}
+ 
+#footer       { background-color: #E5E4D9;} 
+/* extra-css */
+    
+    p.quote {
+      margin-left: 2em;
+      padding: .5em;
+      background-color: #f0f0f0;
+      font-family: monospace;
+    }
+
+    pre {
+      margin-left: 0em;
+      padding: 0.5em;
+      background-color: #f0f0f0;
+      font-family: monospace;
+    }
+
+
+
+  
\ No newline at end of file


Mime
View raw message