diff --git a/akka-bbb-apps/src/main/java/name/fraser/neil/plaintext/diff_match_patch.java b/akka-bbb-apps/src/main/java/name/fraser/neil/plaintext/diff_match_patch.java
new file mode 100644
index 0000000000000000000000000000000000000000..24ffdacacaf03ec0f0c3036f6f6f5f4e826942c2
--- /dev/null
+++ b/akka-bbb-apps/src/main/java/name/fraser/neil/plaintext/diff_match_patch.java
@@ -0,0 +1,2420 @@
+/*
+ * Diff Match and Patch
+ *
+ * Copyright 2006 Google Inc.
+ * http://code.google.com/p/google-diff-match-patch/
+ *
+ * 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.
+ */
+
+package name.fraser.neil.plaintext;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/*
+ * Functions for diff, match and patch.
+ * Computes the difference between two texts to create a patch.
+ * Applies the patch onto another text, allowing for errors.
+ *
+ * @author fraser@google.com (Neil Fraser)
+ */
+
+/**
+ * Class containing the diff, match and patch methods.
+ * Also contains the behaviour settings.
+ */
+public class diff_match_patch {
+
+  // Defaults.
+  // Set these on your diff_match_patch instance to override the defaults.
+
+  /**
+   * Number of seconds to map a diff before giving up (0 for infinity).
+   */
+  public float Diff_Timeout = 1.0f;
+  /**
+   * Cost of an empty edit operation in terms of edit characters.
+   */
+  public short Diff_EditCost = 4;
+  /**
+   * The size beyond which the double-ended diff activates.
+   * Double-ending is twice as fast, but less accurate.
+   */
+  public short Diff_DualThreshold = 32;
+  /**
+   * At what point is no match declared (0.0 = perfection, 1.0 = very loose).
+   */
+  public float Match_Threshold = 0.5f;
+  /**
+   * How far to search for a match (0 = exact location, 1000+ = broad match).
+   * A match this many characters away from the expected location will add
+   * 1.0 to the score (0.0 is a perfect match).
+   */
+  public int Match_Distance = 1000;
+  /**
+   * When deleting a large block of text (over ~64 characters), how close does
+   * the contents have to match the expected contents. (0.0 = perfection,
+   * 1.0 = very loose).  Note that Match_Threshold controls how closely the
+   * end points of a delete need to match.
+   */
+  public float Patch_DeleteThreshold = 0.5f;
+  /**
+   * Chunk size for context length.
+   */
+  public short Patch_Margin = 4;
+
+  /**
+   * The number of bits in an int.
+   */
+  private int Match_MaxBits = 32;
+
+  /**
+   * Internal class for returning results from diff_linesToChars().
+   * Other less paranoid languages just use a three-element array.
+   */
+  protected static class LinesToCharsResult {
+    protected String chars1;
+    protected String chars2;
+    protected List<String> lineArray;
+
+    protected LinesToCharsResult(String chars1, String chars2,
+        List<String> lineArray) {
+      this.chars1 = chars1;
+      this.chars2 = chars2;
+      this.lineArray = lineArray;
+    }
+  }
+
+
+  //  DIFF FUNCTIONS
+
+
+  /**
+   * The data structure representing a diff is a Linked list of Diff objects:
+   * {Diff(Operation.DELETE, "Hello"), Diff(Operation.INSERT, "Goodbye"),
+   *  Diff(Operation.EQUAL, " world.")}
+   * which means: delete "Hello", add "Goodbye" and keep " world."
+   */
+  public enum Operation {
+    DELETE, INSERT, EQUAL
+  }
+
+
+  /**
+   * Find the differences between two texts.
+   * Run a faster slightly less optimal diff
+   * This method allows the 'checklines' of diff_main() to be optional.
+   * Most of the time checklines is wanted, so default to true.
+   * @param text1 Old string to be diffed.
+   * @param text2 New string to be diffed.
+   * @return Linked List of Diff objects.
+   */
+  public LinkedList<Diff> diff_main(String text1, String text2) {
+    return diff_main(text1, text2, true);
+  }
+
+  /**
+   * Find the differences between two texts.  Simplifies the problem by
+   * stripping any common prefix or suffix off the texts before diffing.
+   * @param text1 Old string to be diffed.
+   * @param text2 New string to be diffed.
+   * @param checklines Speedup flag.  If false, then don't run a
+   *     line-level diff first to identify the changed areas.
+   *     If true, then run a faster slightly less optimal diff
+   * @return Linked List of Diff objects.
+   */
+  public LinkedList<Diff> diff_main(String text1, String text2,
+                                    boolean checklines) {
+    // Check for equality (speedup)
+    LinkedList<Diff> diffs;
+    if (text1.equals(text2)) {
+      diffs = new LinkedList<Diff>();
+      diffs.add(new Diff(Operation.EQUAL, text1));
+      return diffs;
+    }
+
+    // Trim off common prefix (speedup)
+    int commonlength = diff_commonPrefix(text1, text2);
+    String commonprefix = text1.substring(0, commonlength);
+    text1 = text1.substring(commonlength);
+    text2 = text2.substring(commonlength);
+
+    // Trim off common suffix (speedup)
+    commonlength = diff_commonSuffix(text1, text2);
+    String commonsuffix = text1.substring(text1.length() - commonlength);
+    text1 = text1.substring(0, text1.length() - commonlength);
+    text2 = text2.substring(0, text2.length() - commonlength);
+
+    // Compute the diff on the middle block
+    diffs = diff_compute(text1, text2, checklines);
+
+    // Restore the prefix and suffix
+    if (commonprefix.length() != 0) {
+      diffs.addFirst(new Diff(Operation.EQUAL, commonprefix));
+    }
+    if (commonsuffix.length() != 0) {
+      diffs.addLast(new Diff(Operation.EQUAL, commonsuffix));
+    }
+
+    diff_cleanupMerge(diffs);
+    return diffs;
+  }
+
+
+  /**
+   * Find the differences between two texts.  Assumes that the texts do not
+   * have any common prefix or suffix.
+   * @param text1 Old string to be diffed.
+   * @param text2 New string to be diffed.
+   * @param checklines Speedup flag.  If false, then don't run a
+   *     line-level diff first to identify the changed areas.
+   *     If true, then run a faster slightly less optimal diff
+   * @return Linked List of Diff objects.
+   */
+  protected LinkedList<Diff> diff_compute(String text1, String text2,
+                                          boolean checklines) {
+    LinkedList<Diff> diffs = new LinkedList<Diff>();
+
+    if (text1.length() == 0) {
+      // Just add some text (speedup)
+      diffs.add(new Diff(Operation.INSERT, text2));
+      return diffs;
+    }
+
+    if (text2.length() == 0) {
+      // Just delete some text (speedup)
+      diffs.add(new Diff(Operation.DELETE, text1));
+      return diffs;
+    }
+
+    String longtext = text1.length() > text2.length() ? text1 : text2;
+    String shorttext = text1.length() > text2.length() ? text2 : text1;
+    int i = longtext.indexOf(shorttext);
+    if (i != -1) {
+      // Shorter text is inside the longer text (speedup)
+      Operation op = (text1.length() > text2.length()) ?
+                     Operation.DELETE : Operation.INSERT;
+      diffs.add(new Diff(op, longtext.substring(0, i)));
+      diffs.add(new Diff(Operation.EQUAL, shorttext));
+      diffs.add(new Diff(op, longtext.substring(i + shorttext.length())));
+      return diffs;
+    }
+    longtext = shorttext = null;  // Garbage collect.
+
+    // Check to see if the problem can be split in two.
+    String[] hm = diff_halfMatch(text1, text2);
+    if (hm != null) {
+      // A half-match was found, sort out the return data.
+      String text1_a = hm[0];
+      String text1_b = hm[1];
+      String text2_a = hm[2];
+      String text2_b = hm[3];
+      String mid_common = hm[4];
+      // Send both pairs off for separate processing.
+      LinkedList<Diff> diffs_a = diff_main(text1_a, text2_a, checklines);
+      LinkedList<Diff> diffs_b = diff_main(text1_b, text2_b, checklines);
+      // Merge the results.
+      diffs = diffs_a;
+      diffs.add(new Diff(Operation.EQUAL, mid_common));
+      diffs.addAll(diffs_b);
+      return diffs;
+    }
+
+    // Perform a real diff.
+    if (checklines && (text1.length() < 100 || text2.length() < 100)) {
+      checklines = false;  // Too trivial for the overhead.
+    }
+    List<String> linearray = null;
+    if (checklines) {
+      // Scan the text on a line-by-line basis first.
+      LinesToCharsResult b = diff_linesToChars(text1, text2);
+      text1 = b.chars1;
+      text2 = b.chars2;
+      linearray = b.lineArray;
+    }
+
+    diffs = diff_map(text1, text2);
+    if (diffs == null) {
+      // No acceptable result.
+      diffs = new LinkedList<Diff>();
+      diffs.add(new Diff(Operation.DELETE, text1));
+      diffs.add(new Diff(Operation.INSERT, text2));
+    }
+
+    if (checklines) {
+      // Convert the diff back to original text.
+      diff_charsToLines(diffs, linearray);
+      // Eliminate freak matches (e.g. blank lines)
+      diff_cleanupSemantic(diffs);
+
+      // Rediff any replacement blocks, this time character-by-character.
+      // Add a dummy entry at the end.
+      diffs.add(new Diff(Operation.EQUAL, ""));
+      int count_delete = 0;
+      int count_insert = 0;
+      String text_delete = "";
+      String text_insert = "";
+      ListIterator<Diff> pointer = diffs.listIterator();
+      Diff thisDiff = pointer.next();
+      while (thisDiff != null) {
+        switch (thisDiff.operation) {
+        case INSERT:
+          count_insert++;
+          text_insert += thisDiff.text;
+          break;
+        case DELETE:
+          count_delete++;
+          text_delete += thisDiff.text;
+          break;
+        case EQUAL:
+          // Upon reaching an equality, check for prior redundancies.
+          if (count_delete >= 1 && count_insert >= 1) {
+            // Delete the offending records and add the merged ones.
+            pointer.previous();
+            for (int j = 0; j < count_delete + count_insert; j++) {
+              pointer.previous();
+              pointer.remove();
+            }
+            for (Diff newDiff : diff_main(text_delete, text_insert, false)) {
+              pointer.add(newDiff);
+            }
+          }
+          count_insert = 0;
+          count_delete = 0;
+          text_delete = "";
+          text_insert = "";
+          break;
+        }
+        thisDiff = pointer.hasNext() ? pointer.next() : null;
+      }
+      diffs.removeLast();  // Remove the dummy entry at the end.
+    }
+    return diffs;
+  }
+
+
+  /**
+   * Split two texts into a list of strings.  Reduce the texts to a string of
+   * hashes where each Unicode character represents one line.
+   * @param text1 First string.
+   * @param text2 Second string.
+   * @return An object containing the encoded text1, the encoded text2 and
+   *     the List of unique strings.  The zeroth element of the List of
+   *     unique strings is intentionally blank.
+   */
+  protected LinesToCharsResult diff_linesToChars(String text1, String text2) {
+    List<String> lineArray = new ArrayList<String>();
+    Map<String, Integer> lineHash = new HashMap<String, Integer>();
+    // e.g. linearray[4] == "Hello\n"
+    // e.g. linehash.get("Hello\n") == 4
+
+    // "\x00" is a valid character, but various debuggers don't like it.
+    // So we'll insert a junk entry to avoid generating a null character.
+    lineArray.add("");
+
+    String chars1 = diff_linesToCharsMunge(text1, lineArray, lineHash);
+    String chars2 = diff_linesToCharsMunge(text2, lineArray, lineHash);
+    return new LinesToCharsResult(chars1, chars2, lineArray);
+  }
+
+
+  /**
+   * Split a text into a list of strings.  Reduce the texts to a string of
+   * hashes where each Unicode character represents one line.
+   * @param text String to encode.
+   * @param lineArray List of unique strings.
+   * @param lineHash Map of strings to indices.
+   * @return Encoded string.
+   */
+  private String diff_linesToCharsMunge(String text, List<String> lineArray,
+                                        Map<String, Integer> lineHash) {
+    int lineStart = 0;
+    int lineEnd = -1;
+    String line;
+    StringBuilder chars = new StringBuilder();
+    // Walk the text, pulling out a substring for each line.
+    // text.split('\n') would would temporarily double our memory footprint.
+    // Modifying text would create many large strings to garbage collect.
+    while (lineEnd < text.length() - 1) {
+      lineEnd = text.indexOf('\n', lineStart);
+      if (lineEnd == -1) {
+        lineEnd = text.length() - 1;
+      }
+      line = text.substring(lineStart, lineEnd + 1);
+      lineStart = lineEnd + 1;
+
+      if (lineHash.containsKey(line)) {
+        chars.append(String.valueOf((char) (int) lineHash.get(line)));
+      } else {
+        lineArray.add(line);
+        lineHash.put(line, lineArray.size() - 1);
+        chars.append(String.valueOf((char) (lineArray.size() - 1)));
+      }
+    }
+    return chars.toString();
+  }
+
+
+  /**
+   * Rehydrate the text in a diff from a string of line hashes to real lines of
+   * text.
+   * @param diffs LinkedList of Diff objects.
+   * @param lineArray List of unique strings.
+   */
+  protected void diff_charsToLines(LinkedList<Diff> diffs,
+                                  List<String> lineArray) {
+    StringBuilder text;
+    for (Diff diff : diffs) {
+      text = new StringBuilder();
+      for (int y = 0; y < diff.text.length(); y++) {
+        text.append(lineArray.get(diff.text.charAt(y)));
+      }
+      diff.text = text.toString();
+    }
+  }
+
+
+  /**
+   * Explore the intersection points between the two texts.
+   * @param text1 Old string to be diffed.
+   * @param text2 New string to be diffed.
+   * @return LinkedList of Diff objects or null if no diff available.
+   */
+  protected LinkedList<Diff> diff_map(String text1, String text2) {
+    long ms_end = System.currentTimeMillis() + (long) (Diff_Timeout * 1000);
+    // Cache the text lengths to prevent multiple calls.
+    int text1_length = text1.length();
+    int text2_length = text2.length();
+    int max_d = text1_length + text2_length - 1;
+    boolean doubleEnd = Diff_DualThreshold * 2 < max_d;
+    List<Set<Long>> v_map1 = new ArrayList<Set<Long>>();
+    List<Set<Long>> v_map2 = new ArrayList<Set<Long>>();
+    Map<Integer, Integer> v1 = new HashMap<Integer, Integer>();
+    Map<Integer, Integer> v2 = new HashMap<Integer, Integer>();
+    v1.put(1, 0);
+    v2.put(1, 0);
+    int x, y;
+    Long footstep = 0L;  // Used to track overlapping paths.
+    Map<Long, Integer> footsteps = new HashMap<Long, Integer>();
+    boolean done = false;
+    // If the total number of characters is odd, then the front path will
+    // collide with the reverse path.
+    boolean front = ((text1_length + text2_length) % 2 == 1);
+    for (int d = 0; d < max_d; d++) {
+      // Bail out if timeout reached.
+      if (Diff_Timeout > 0 && System.currentTimeMillis() > ms_end) {
+        return null;
+      }
+
+      // Walk the front path one step.
+      v_map1.add(new HashSet<Long>());  // Adds at index 'd'.
+      for (int k = -d; k <= d; k += 2) {
+        if (k == -d || k != d && v1.get(k - 1) < v1.get(k + 1)) {
+          x = v1.get(k + 1);
+        } else {
+          x = v1.get(k - 1) + 1;
+        }
+        y = x - k;
+        if (doubleEnd) {
+          footstep = diff_footprint(x, y);
+          if (front && (footsteps.containsKey(footstep))) {
+            done = true;
+          }
+          if (!front) {
+            footsteps.put(footstep, d);
+          }
+        }
+        while (!done && x < text1_length && y < text2_length
+               && text1.charAt(x) == text2.charAt(y)) {
+          x++;
+          y++;
+          if (doubleEnd) {
+            footstep = diff_footprint(x, y);
+            if (front && (footsteps.containsKey(footstep))) {
+              done = true;
+            }
+            if (!front) {
+              footsteps.put(footstep, d);
+            }
+          }
+        }
+        v1.put(k, x);
+        v_map1.get(d).add(diff_footprint(x, y));
+        if (x == text1_length && y == text2_length) {
+          // Reached the end in single-path mode.
+          return diff_path1(v_map1, text1, text2);
+        } else if (done) {
+          // Front path ran over reverse path.
+          v_map2 = v_map2.subList(0, footsteps.get(footstep) + 1);
+          LinkedList<Diff> a = diff_path1(v_map1, text1.substring(0, x),
+                                          text2.substring(0, y));
+          a.addAll(diff_path2(v_map2, text1.substring(x), text2.substring(y)));
+          return a;
+        }
+      }
+
+      if (doubleEnd) {
+        // Walk the reverse path one step.
+        v_map2.add(new HashSet<Long>());  // Adds at index 'd'.
+        for (int k = -d; k <= d; k += 2) {
+          if (k == -d || k != d && v2.get(k - 1) < v2.get(k + 1)) {
+            x = v2.get(k + 1);
+          } else {
+            x = v2.get(k - 1) + 1;
+          }
+          y = x - k;
+          footstep = diff_footprint(text1_length - x, text2_length - y);
+          if (!front && (footsteps.containsKey(footstep))) {
+            done = true;
+          }
+          if (front) {
+            footsteps.put(footstep, d);
+          }
+          while (!done && x < text1_length && y < text2_length
+                 && text1.charAt(text1_length - x - 1)
+                 == text2.charAt(text2_length - y - 1)) {
+            x++;
+            y++;
+            footstep = diff_footprint(text1_length - x, text2_length - y);
+            if (!front && (footsteps.containsKey(footstep))) {
+              done = true;
+            }
+            if (front) {
+              footsteps.put(footstep, d);
+            }
+          }
+          v2.put(k, x);
+          v_map2.get(d).add(diff_footprint(x, y));
+          if (done) {
+            // Reverse path ran over front path.
+            v_map1 = v_map1.subList(0, footsteps.get(footstep) + 1);
+            LinkedList<Diff> a
+                = diff_path1(v_map1, text1.substring(0, text1_length - x),
+                             text2.substring(0, text2_length - y));
+            a.addAll(diff_path2(v_map2, text1.substring(text1_length - x),
+                                text2.substring(text2_length - y)));
+            return a;
+          }
+        }
+      }
+    }
+    // Number of diffs equals number of characters, no commonality at all.
+    return null;
+  }
+
+
+  /**
+   * Work from the middle back to the start to determine the path.
+   * @param v_map List of path sets.
+   * @param text1 Old string fragment to be diffed.
+   * @param text2 New string fragment to be diffed.
+   * @return LinkedList of Diff objects.
+   */
+  protected LinkedList<Diff> diff_path1(List<Set<Long>> v_map,
+                                        String text1, String text2) {
+    LinkedList<Diff> path = new LinkedList<Diff>();
+    int x = text1.length();
+    int y = text2.length();
+    Operation last_op = null;
+    for (int d = v_map.size() - 2; d >= 0; d--) {
+      while (true) {
+        if (v_map.get(d).contains(diff_footprint(x - 1, y))) {
+          x--;
+          if (last_op == Operation.DELETE) {
+            path.getFirst().text = text1.charAt(x) + path.getFirst().text;
+          } else {
+            path.addFirst(new Diff(Operation.DELETE,
+                                   text1.substring(x, x + 1)));
+          }
+          last_op = Operation.DELETE;
+          break;
+        } else if (v_map.get(d).contains(diff_footprint(x, y - 1))) {
+          y--;
+          if (last_op == Operation.INSERT) {
+            path.getFirst().text = text2.charAt(y) + path.getFirst().text;
+          } else {
+            path.addFirst(new Diff(Operation.INSERT,
+                                   text2.substring(y, y + 1)));
+          }
+          last_op = Operation.INSERT;
+          break;
+        } else {
+          x--;
+          y--;
+          assert (text1.charAt(x) == text2.charAt(y))
+                 : "No diagonal.  Can't happen. (diff_path1)";
+          if (last_op == Operation.EQUAL) {
+            path.getFirst().text = text1.charAt(x) + path.getFirst().text;
+          } else {
+            path.addFirst(new Diff(Operation.EQUAL, text1.substring(x, x + 1)));
+          }
+          last_op = Operation.EQUAL;
+        }
+      }
+    }
+    return path;
+  }
+
+
+  /**
+   * Work from the middle back to the end to determine the path.
+   * @param v_map List of path sets.
+   * @param text1 Old string fragment to be diffed.
+   * @param text2 New string fragment to be diffed.
+   * @return LinkedList of Diff objects.
+   */
+  protected LinkedList<Diff> diff_path2(List<Set<Long>> v_map,
+                                        String text1, String text2) {
+    LinkedList<Diff> path = new LinkedList<Diff>();
+    int x = text1.length();
+    int y = text2.length();
+    Operation last_op = null;
+    for (int d = v_map.size() - 2; d >= 0; d--) {
+      while (true) {
+        if (v_map.get(d).contains(diff_footprint(x - 1, y))) {
+          x--;
+          if (last_op == Operation.DELETE) {
+            path.getLast().text += text1.charAt(text1.length() - x - 1);
+          } else {
+            path.addLast(new Diff(Operation.DELETE,
+                text1.substring(text1.length() - x - 1, text1.length() - x)));
+          }
+          last_op = Operation.DELETE;
+          break;
+        } else if (v_map.get(d).contains(diff_footprint(x, y - 1))) {
+          y--;
+          if (last_op == Operation.INSERT) {
+            path.getLast().text += text2.charAt(text2.length() - y - 1);
+          } else {
+            path.addLast(new Diff(Operation.INSERT,
+                text2.substring(text2.length() - y - 1, text2.length() - y)));
+          }
+          last_op = Operation.INSERT;
+          break;
+        } else {
+          x--;
+          y--;
+          assert (text1.charAt(text1.length() - x - 1)
+                  == text2.charAt(text2.length() - y - 1))
+                 : "No diagonal.  Can't happen. (diff_path2)";
+          if (last_op == Operation.EQUAL) {
+            path.getLast().text += text1.charAt(text1.length() - x - 1);
+          } else {
+            path.addLast(new Diff(Operation.EQUAL,
+                text1.substring(text1.length() - x - 1, text1.length() - x)));
+          }
+          last_op = Operation.EQUAL;
+        }
+      }
+    }
+    return path;
+  }
+
+
+  /**
+   * Compute a good hash of two integers.
+   * @param x First int.
+   * @param y Second int.
+   * @return A long made up of both ints.
+   */
+  protected long diff_footprint(int x, int y) {
+    // The maximum size for a long is 9,223,372,036,854,775,807
+    // The maximum size for an int is 2,147,483,647
+    // Two ints fit nicely in one long.
+    long result = x;
+    result = result << 32;
+    result += y;
+    return result;
+  }
+
+
+  /**
+   * Determine the common prefix of two strings
+   * @param text1 First string.
+   * @param text2 Second string.
+   * @return The number of characters common to the start of each string.
+   */
+  public int diff_commonPrefix(String text1, String text2) {
+    // Performance analysis: http://neil.fraser.name/news/2007/10/09/
+    int n = Math.min(text1.length(), text2.length());
+    for (int i = 0; i < n; i++) {
+      if (text1.charAt(i) != text2.charAt(i)) {
+        return i;
+      }
+    }
+    return n;
+  }
+
+
+  /**
+   * Determine the common suffix of two strings
+   * @param text1 First string.
+   * @param text2 Second string.
+   * @return The number of characters common to the end of each string.
+   */
+  public int diff_commonSuffix(String text1, String text2) {
+    // Performance analysis: http://neil.fraser.name/news/2007/10/09/
+    int text1_length = text1.length();
+    int text2_length = text2.length();
+    int n = Math.min(text1_length, text2_length);
+    for (int i = 1; i <= n; i++) {
+      if (text1.charAt(text1_length - i) != text2.charAt(text2_length - i)) {
+        return i - 1;
+      }
+    }
+    return n;
+  }
+
+
+  /**
+   * Do the two texts share a substring which is at least half the length of
+   * the longer text?
+   * @param text1 First string.
+   * @param text2 Second string.
+   * @return Five element String array, containing the prefix of text1, the
+   *     suffix of text1, the prefix of text2, the suffix of text2 and the
+   *     common middle.  Or null if there was no match.
+   */
+  protected String[] diff_halfMatch(String text1, String text2) {
+    String longtext = text1.length() > text2.length() ? text1 : text2;
+    String shorttext = text1.length() > text2.length() ? text2 : text1;
+    if (longtext.length() < 10 || shorttext.length() < 1) {
+      return null;  // Pointless.
+    }
+
+    // First check if the second quarter is the seed for a half-match.
+    String[] hm1 = diff_halfMatchI(longtext, shorttext,
+                                   (longtext.length() + 3) / 4);
+    // Check again based on the third quarter.
+    String[] hm2 = diff_halfMatchI(longtext, shorttext,
+                                   (longtext.length() + 1) / 2);
+    String[] hm;
+    if (hm1 == null && hm2 == null) {
+      return null;
+    } else if (hm2 == null) {
+      hm = hm1;
+    } else if (hm1 == null) {
+      hm = hm2;
+    } else {
+      // Both matched.  Select the longest.
+      hm = hm1[4].length() > hm2[4].length() ? hm1 : hm2;
+    }
+
+    // A half-match was found, sort out the return data.
+    if (text1.length() > text2.length()) {
+      return hm;
+      //return new String[]{hm[0], hm[1], hm[2], hm[3], hm[4]};
+    } else {
+      return new String[]{hm[2], hm[3], hm[0], hm[1], hm[4]};
+    }
+  }
+
+
+  /**
+   * Does a substring of shorttext exist within longtext such that the
+   * substring is at least half the length of longtext?
+   * @param longtext Longer string.
+   * @param shorttext Shorter string.
+   * @param i Start index of quarter length substring within longtext.
+   * @return Five element String array, containing the prefix of longtext, the
+   *     suffix of longtext, the prefix of shorttext, the suffix of shorttext
+   *     and the common middle.  Or null if there was no match.
+   */
+  private String[] diff_halfMatchI(String longtext, String shorttext, int i) {
+    // Start with a 1/4 length substring at position i as a seed.
+    String seed = longtext.substring(i, i + longtext.length() / 4);
+    int j = -1;
+    String best_common = "";
+    String best_longtext_a = "", best_longtext_b = "";
+    String best_shorttext_a = "", best_shorttext_b = "";
+    while ((j = shorttext.indexOf(seed, j + 1)) != -1) {
+      int prefixLength = diff_commonPrefix(longtext.substring(i),
+                                           shorttext.substring(j));
+      int suffixLength = diff_commonSuffix(longtext.substring(0, i),
+                                           shorttext.substring(0, j));
+      if (best_common.length() < suffixLength + prefixLength) {
+        best_common = shorttext.substring(j - suffixLength, j)
+            + shorttext.substring(j, j + prefixLength);
+        best_longtext_a = longtext.substring(0, i - suffixLength);
+        best_longtext_b = longtext.substring(i + prefixLength);
+        best_shorttext_a = shorttext.substring(0, j - suffixLength);
+        best_shorttext_b = shorttext.substring(j + prefixLength);
+      }
+    }
+    if (best_common.length() >= longtext.length() / 2) {
+      return new String[]{best_longtext_a, best_longtext_b,
+                          best_shorttext_a, best_shorttext_b, best_common};
+    } else {
+      return null;
+    }
+  }
+
+
+  /**
+   * Reduce the number of edits by eliminating semantically trivial equalities.
+   * @param diffs LinkedList of Diff objects.
+   */
+  public void diff_cleanupSemantic(LinkedList<Diff> diffs) {
+    if (diffs.isEmpty()) {
+      return;
+    }
+    boolean changes = false;
+    Stack<Diff> equalities = new Stack<Diff>();  // Stack of qualities.
+    String lastequality = null; // Always equal to equalities.lastElement().text
+    ListIterator<Diff> pointer = diffs.listIterator();
+    // Number of characters that changed prior to the equality.
+    int length_changes1 = 0;
+    // Number of characters that changed after the equality.
+    int length_changes2 = 0;
+    Diff thisDiff = pointer.next();
+    while (thisDiff != null) {
+      if (thisDiff.operation == Operation.EQUAL) {
+        // equality found
+        equalities.push(thisDiff);
+        length_changes1 = length_changes2;
+        length_changes2 = 0;
+        lastequality = thisDiff.text;
+      } else {
+        // an insertion or deletion
+        length_changes2 += thisDiff.text.length();
+        if (lastequality != null && (lastequality.length() <= length_changes1)
+            && (lastequality.length() <= length_changes2)) {
+          //System.out.println("Splitting: '" + lastequality + "'");
+          // Walk back to offending equality.
+          while (thisDiff != equalities.lastElement()) {
+            thisDiff = pointer.previous();
+          }
+          pointer.next();
+
+          // Replace equality with a delete.
+          pointer.set(new Diff(Operation.DELETE, lastequality));
+          // Insert a corresponding an insert.
+          pointer.add(new Diff(Operation.INSERT, lastequality));
+
+          equalities.pop();  // Throw away the equality we just deleted.
+          if (!equalities.empty()) {
+            // Throw away the previous equality (it needs to be reevaluated).
+            equalities.pop();
+          }
+          if (equalities.empty()) {
+            // There are no previous equalities, walk back to the start.
+            while (pointer.hasPrevious()) {
+              pointer.previous();
+            }
+          } else {
+            // There is a safe equality we can fall back to.
+            thisDiff = equalities.lastElement();
+            while (thisDiff != pointer.previous()) {
+              // Intentionally empty loop.
+            }
+          }
+
+          length_changes1 = 0;  // Reset the counters.
+          length_changes2 = 0;
+          lastequality = null;
+          changes = true;
+        }
+      }
+      thisDiff = pointer.hasNext() ? pointer.next() : null;
+    }
+
+    if (changes) {
+      diff_cleanupMerge(diffs);
+    }
+    diff_cleanupSemanticLossless(diffs);
+  }
+
+
+  /**
+   * Look for single edits surrounded on both sides by equalities
+   * which can be shifted sideways to align the edit to a word boundary.
+   * e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
+   * @param diffs LinkedList of Diff objects.
+   */
+  public void diff_cleanupSemanticLossless(LinkedList<Diff> diffs) {
+    String equality1, edit, equality2;
+    String commonString;
+    int commonOffset;
+    int score, bestScore;
+    String bestEquality1, bestEdit, bestEquality2;
+    // Create a new iterator at the start.
+    ListIterator<Diff> pointer = diffs.listIterator();
+    Diff prevDiff = pointer.hasNext() ? pointer.next() : null;
+    Diff thisDiff = pointer.hasNext() ? pointer.next() : null;
+    Diff nextDiff = pointer.hasNext() ? pointer.next() : null;
+    // Intentionally ignore the first and last element (don't need checking).
+    while (nextDiff != null) {
+      if (prevDiff.operation == Operation.EQUAL &&
+          nextDiff.operation == Operation.EQUAL) {
+        // This is a single edit surrounded by equalities.
+        equality1 = prevDiff.text;
+        edit = thisDiff.text;
+        equality2 = nextDiff.text;
+
+        // First, shift the edit as far left as possible.
+        commonOffset = diff_commonSuffix(equality1, edit);
+        if (commonOffset != 0) {
+          commonString = edit.substring(edit.length() - commonOffset);
+          equality1 = equality1.substring(0, equality1.length() - commonOffset);
+          edit = commonString + edit.substring(0, edit.length() - commonOffset);
+          equality2 = commonString + equality2;
+        }
+
+        // Second, step character by character right, looking for the best fit.
+        bestEquality1 = equality1;
+        bestEdit = edit;
+        bestEquality2 = equality2;
+        bestScore = diff_cleanupSemanticScore(equality1, edit)
+            + diff_cleanupSemanticScore(edit, equality2);
+        while (edit.length() != 0 && equality2.length() != 0
+            && edit.charAt(0) == equality2.charAt(0)) {
+          equality1 += edit.charAt(0);
+          edit = edit.substring(1) + equality2.charAt(0);
+          equality2 = equality2.substring(1);
+          score = diff_cleanupSemanticScore(equality1, edit)
+              + diff_cleanupSemanticScore(edit, equality2);
+          // The >= encourages trailing rather than leading whitespace on edits.
+          if (score >= bestScore) {
+            bestScore = score;
+            bestEquality1 = equality1;
+            bestEdit = edit;
+            bestEquality2 = equality2;
+          }
+        }
+
+        if (!prevDiff.text.equals(bestEquality1)) {
+          // We have an improvement, save it back to the diff.
+          if (bestEquality1.length() != 0) {
+            prevDiff.text = bestEquality1;
+          } else {
+            pointer.previous(); // Walk past nextDiff.
+            pointer.previous(); // Walk past thisDiff.
+            pointer.previous(); // Walk past prevDiff.
+            pointer.remove(); // Delete prevDiff.
+            pointer.next(); // Walk past thisDiff.
+            pointer.next(); // Walk past nextDiff.
+          }
+          thisDiff.text = bestEdit;
+          if (bestEquality2.length() != 0) {
+            nextDiff.text = bestEquality2;
+          } else {
+            pointer.remove(); // Delete nextDiff.
+            nextDiff = thisDiff;
+            thisDiff = prevDiff;
+          }
+        }
+      }
+      prevDiff = thisDiff;
+      thisDiff = nextDiff;
+      nextDiff = pointer.hasNext() ? pointer.next() : null;
+    }
+  }
+
+
+  /**
+   * Given two strings, compute a score representing whether the internal
+   * boundary falls on logical boundaries.
+   * Scores range from 5 (best) to 0 (worst).
+   * @param one First string.
+   * @param two Second string.
+   * @return The score.
+   */
+  private int diff_cleanupSemanticScore(String one, String two) {
+    if (one.length() == 0 || two.length() == 0) {
+      // Edges are the best.
+      return 5;
+    }
+
+    // Each port of this function behaves slightly differently due to
+    // subtle differences in each language's definition of things like
+    // 'whitespace'.  Since this function's purpose is largely cosmetic,
+    // the choice has been made to use each language's native features
+    // rather than force total conformity.
+    int score = 0;
+    // One point for non-alphanumeric.
+    if (!Character.isLetterOrDigit(one.charAt(one.length() - 1))
+        || !Character.isLetterOrDigit(two.charAt(0))) {
+      score++;
+      // Two points for whitespace.
+      if (Character.isWhitespace(one.charAt(one.length() - 1))
+          || Character.isWhitespace(two.charAt(0))) {
+        score++;
+        // Three points for line breaks.
+        if (Character.getType(one.charAt(one.length() - 1)) == Character.CONTROL
+            || Character.getType(two.charAt(0)) == Character.CONTROL) {
+          score++;
+          // Four points for blank lines.
+          if (BLANKLINEEND.matcher(one).find()
+              || BLANKLINESTART.matcher(two).find()) {
+            score++;
+          }
+        }
+      }
+    }
+    return score;
+  }
+
+
+  private Pattern BLANKLINEEND
+      = Pattern.compile("\\n\\r?\\n\\Z", Pattern.DOTALL);
+  private Pattern BLANKLINESTART
+      = Pattern.compile("\\A\\r?\\n\\r?\\n", Pattern.DOTALL);
+
+
+  /**
+   * Reduce the number of edits by eliminating operationally trivial equalities.
+   * @param diffs LinkedList of Diff objects.
+   */
+  public void diff_cleanupEfficiency(LinkedList<Diff> diffs) {
+    if (diffs.isEmpty()) {
+      return;
+    }
+    boolean changes = false;
+    Stack<Diff> equalities = new Stack<Diff>();  // Stack of equalities.
+    String lastequality = null; // Always equal to equalities.lastElement().text
+    ListIterator<Diff> pointer = diffs.listIterator();
+    // Is there an insertion operation before the last equality.
+    boolean pre_ins = false;
+    // Is there a deletion operation before the last equality.
+    boolean pre_del = false;
+    // Is there an insertion operation after the last equality.
+    boolean post_ins = false;
+    // Is there a deletion operation after the last equality.
+    boolean post_del = false;
+    Diff thisDiff = pointer.next();
+    Diff safeDiff = thisDiff;  // The last Diff that is known to be unsplitable.
+    while (thisDiff != null) {
+      if (thisDiff.operation == Operation.EQUAL) {
+        // equality found
+        if (thisDiff.text.length() < Diff_EditCost && (post_ins || post_del)) {
+          // Candidate found.
+          equalities.push(thisDiff);
+          pre_ins = post_ins;
+          pre_del = post_del;
+          lastequality = thisDiff.text;
+        } else {
+          // Not a candidate, and can never become one.
+          equalities.clear();
+          lastequality = null;
+          safeDiff = thisDiff;
+        }
+        post_ins = post_del = false;
+      } else {
+        // an insertion or deletion
+        if (thisDiff.operation == Operation.DELETE) {
+          post_del = true;
+        } else {
+          post_ins = true;
+        }
+        /*
+         * Five types to be split:
+         * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
+         * <ins>A</ins>X<ins>C</ins><del>D</del>
+         * <ins>A</ins><del>B</del>X<ins>C</ins>
+         * <ins>A</del>X<ins>C</ins><del>D</del>
+         * <ins>A</ins><del>B</del>X<del>C</del>
+         */
+        if (lastequality != null
+            && ((pre_ins && pre_del && post_ins && post_del)
+                || ((lastequality.length() < Diff_EditCost / 2)
+                    && ((pre_ins ? 1 : 0) + (pre_del ? 1 : 0)
+                        + (post_ins ? 1 : 0) + (post_del ? 1 : 0)) == 3))) {
+          //System.out.println("Splitting: '" + lastequality + "'");
+          // Walk back to offending equality.
+          while (thisDiff != equalities.lastElement()) {
+            thisDiff = pointer.previous();
+          }
+          pointer.next();
+
+          // Replace equality with a delete.
+          pointer.set(new Diff(Operation.DELETE, lastequality));
+          // Insert a corresponding an insert.
+          pointer.add(thisDiff = new Diff(Operation.INSERT, lastequality));
+
+          equalities.pop();  // Throw away the equality we just deleted.
+          lastequality = null;
+          if (pre_ins && pre_del) {
+            // No changes made which could affect previous entry, keep going.
+            post_ins = post_del = true;
+            equalities.clear();
+            safeDiff = thisDiff;
+          } else {
+            if (!equalities.empty()) {
+              // Throw away the previous equality (it needs to be reevaluated).
+              equalities.pop();
+            }
+            if (equalities.empty()) {
+              // There are no previous questionable equalities,
+              // walk back to the last known safe diff.
+              thisDiff = safeDiff;
+            } else {
+              // There is an equality we can fall back to.
+              thisDiff = equalities.lastElement();
+            }
+            while (thisDiff != pointer.previous()) {
+              // Intentionally empty loop.
+            }
+            post_ins = post_del = false;
+          }
+
+          changes = true;
+        }
+      }
+      thisDiff = pointer.hasNext() ? pointer.next() : null;
+    }
+
+    if (changes) {
+      diff_cleanupMerge(diffs);
+    }
+  }
+
+
+  /**
+   * Reorder and merge like edit sections.  Merge equalities.
+   * Any edit section can move as long as it doesn't cross an equality.
+   * @param diffs LinkedList of Diff objects.
+   */
+  public void diff_cleanupMerge(LinkedList<Diff> diffs) {
+    diffs.add(new Diff(Operation.EQUAL, ""));  // Add a dummy entry at the end.
+    ListIterator<Diff> pointer = diffs.listIterator();
+    int count_delete = 0;
+    int count_insert = 0;
+    String text_delete = "";
+    String text_insert = "";
+    Diff thisDiff = pointer.next();
+    Diff prevEqual = null;
+    int commonlength;
+    while (thisDiff != null) {
+      switch (thisDiff.operation) {
+      case INSERT:
+        count_insert++;
+        text_insert += thisDiff.text;
+        prevEqual = null;
+        break;
+      case DELETE:
+        count_delete++;
+        text_delete += thisDiff.text;
+        prevEqual = null;
+        break;
+      case EQUAL:
+        if (count_delete != 0 || count_insert != 0) {
+          // Delete the offending records.
+          pointer.previous();  // Reverse direction.
+          while (count_delete-- > 0) {
+            pointer.previous();
+            pointer.remove();
+          }
+          while (count_insert-- > 0) {
+            pointer.previous();
+            pointer.remove();
+          }
+          if (count_delete != 0 && count_insert != 0) {
+            // Factor out any common prefixies.
+            commonlength = diff_commonPrefix(text_insert, text_delete);
+            if (commonlength != 0) {
+              if (pointer.hasPrevious()) {
+                thisDiff = pointer.previous();
+                assert thisDiff.operation == Operation.EQUAL
+                       : "Previous diff should have been an equality.";
+                thisDiff.text += text_insert.substring(0, commonlength);
+                pointer.next();
+              } else {
+                pointer.add(new Diff(Operation.EQUAL,
+                    text_insert.substring(0, commonlength)));
+              }
+              text_insert = text_insert.substring(commonlength);
+              text_delete = text_delete.substring(commonlength);
+            }
+            // Factor out any common suffixies.
+            commonlength = diff_commonSuffix(text_insert, text_delete);
+            if (commonlength != 0) {
+              thisDiff = pointer.next();
+              thisDiff.text = text_insert.substring(text_insert.length()
+                  - commonlength) + thisDiff.text;
+              text_insert = text_insert.substring(0, text_insert.length()
+                  - commonlength);
+              text_delete = text_delete.substring(0, text_delete.length()
+                  - commonlength);
+              pointer.previous();
+            }
+          }
+          // Insert the merged records.
+          if (text_delete.length() != 0) {
+            pointer.add(new Diff(Operation.DELETE, text_delete));
+          }
+          if (text_insert.length() != 0) {
+            pointer.add(new Diff(Operation.INSERT, text_insert));
+          }
+          // Step forward to the equality.
+          thisDiff = pointer.hasNext() ? pointer.next() : null;
+        } else if (prevEqual != null) {
+          // Merge this equality with the previous one.
+          prevEqual.text += thisDiff.text;
+          pointer.remove();
+          thisDiff = pointer.previous();
+          pointer.next();  // Forward direction
+        }
+        count_insert = 0;
+        count_delete = 0;
+        text_delete = "";
+        text_insert = "";
+        prevEqual = thisDiff;
+        break;
+      }
+      thisDiff = pointer.hasNext() ? pointer.next() : null;
+    }
+    // System.out.println(diff);
+    if (diffs.getLast().text.length() == 0) {
+      diffs.removeLast();  // Remove the dummy entry at the end.
+    }
+
+    /*
+     * Second pass: look for single edits surrounded on both sides by equalities
+     * which can be shifted sideways to eliminate an equality.
+     * e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
+     */
+    boolean changes = false;
+    // Create a new iterator at the start.
+    // (As opposed to walking the current one back.)
+    pointer = diffs.listIterator();
+    Diff prevDiff = pointer.hasNext() ? pointer.next() : null;
+    thisDiff = pointer.hasNext() ? pointer.next() : null;
+    Diff nextDiff = pointer.hasNext() ? pointer.next() : null;
+    // Intentionally ignore the first and last element (don't need checking).
+    while (nextDiff != null) {
+      if (prevDiff.operation == Operation.EQUAL &&
+          nextDiff.operation == Operation.EQUAL) {
+        // This is a single edit surrounded by equalities.
+        if (thisDiff.text.endsWith(prevDiff.text)) {
+          // Shift the edit over the previous equality.
+          thisDiff.text = prevDiff.text
+              + thisDiff.text.substring(0, thisDiff.text.length()
+                                           - prevDiff.text.length());
+          nextDiff.text = prevDiff.text + nextDiff.text;
+          pointer.previous(); // Walk past nextDiff.
+          pointer.previous(); // Walk past thisDiff.
+          pointer.previous(); // Walk past prevDiff.
+          pointer.remove(); // Delete prevDiff.
+          pointer.next(); // Walk past thisDiff.
+          thisDiff = pointer.next(); // Walk past nextDiff.
+          nextDiff = pointer.hasNext() ? pointer.next() : null;
+          changes = true;
+        } else if (thisDiff.text.startsWith(nextDiff.text)) {
+          // Shift the edit over the next equality.
+          prevDiff.text += nextDiff.text;
+          thisDiff.text = thisDiff.text.substring(nextDiff.text.length())
+              + nextDiff.text;
+          pointer.remove(); // Delete nextDiff.
+          nextDiff = pointer.hasNext() ? pointer.next() : null;
+          changes = true;
+        }
+      }
+      prevDiff = thisDiff;
+      thisDiff = nextDiff;
+      nextDiff = pointer.hasNext() ? pointer.next() : null;
+    }
+    // If shifts were made, the diff needs reordering and another shift sweep.
+    if (changes) {
+      diff_cleanupMerge(diffs);
+    }
+  }
+
+
+  /**
+   * loc is a location in text1, compute and return the equivalent location in
+   * text2.
+   * e.g. "The cat" vs "The big cat", 1->1, 5->8
+   * @param diffs LinkedList of Diff objects.
+   * @param loc Location within text1.
+   * @return Location within text2.
+   */
+  public int diff_xIndex(LinkedList<Diff> diffs, int loc) {
+    int chars1 = 0;
+    int chars2 = 0;
+    int last_chars1 = 0;
+    int last_chars2 = 0;
+    Diff lastDiff = null;
+    for (Diff aDiff : diffs) {
+      if (aDiff.operation != Operation.INSERT) {
+        // Equality or deletion.
+        chars1 += aDiff.text.length();
+      }
+      if (aDiff.operation != Operation.DELETE) {
+        // Equality or insertion.
+        chars2 += aDiff.text.length();
+      }
+      if (chars1 > loc) {
+        // Overshot the location.
+        lastDiff = aDiff;
+        break;
+      }
+      last_chars1 = chars1;
+      last_chars2 = chars2;
+    }
+    if (lastDiff != null && lastDiff.operation == Operation.DELETE) {
+      // The location was deleted.
+      return last_chars2;
+    }
+    // Add the remaining character length.
+    return last_chars2 + (loc - last_chars1);
+  }
+
+
+  /**
+   * Convert a Diff list into a pretty HTML report.
+   * @param diffs LinkedList of Diff objects.
+   * @return HTML representation.
+   */
+  public String diff_prettyHtml(LinkedList<Diff> diffs) {
+    StringBuilder html = new StringBuilder();
+    int i = 0;
+    for (Diff aDiff : diffs) {
+      String text = aDiff.text.replace("&", "&amp;").replace("<", "&lt;")
+          .replace(">", "&gt;").replace("\n", "&para;<BR>");
+      switch (aDiff.operation) {
+      case INSERT:
+        html.append("<INS STYLE=\"background:#E6FFE6;\" TITLE=\"i=").append(i)
+            .append("\">").append(text).append("</INS>");
+        break;
+      case DELETE:
+        html.append("<DEL STYLE=\"background:#FFE6E6;\" TITLE=\"i=").append(i)
+            .append("\">").append(text).append("</DEL>");
+        break;
+      case EQUAL:
+        html.append("<SPAN TITLE=\"i=").append(i).append("\">").append(text)
+            .append("</SPAN>");
+        break;
+      }
+      if (aDiff.operation != Operation.DELETE) {
+        i += aDiff.text.length();
+      }
+    }
+    return html.toString();
+  }
+
+
+  /**
+   * Compute and return the source text (all equalities and deletions).
+   * @param diffs LinkedList of Diff objects.
+   * @return Source text.
+   */
+  public String diff_text1(LinkedList<Diff> diffs) {
+    StringBuilder text = new StringBuilder();
+    for (Diff aDiff : diffs) {
+      if (aDiff.operation != Operation.INSERT) {
+        text.append(aDiff.text);
+      }
+    }
+    return text.toString();
+  }
+
+
+  /**
+   * Compute and return the destination text (all equalities and insertions).
+   * @param diffs LinkedList of Diff objects.
+   * @return Destination text.
+   */
+  public String diff_text2(LinkedList<Diff> diffs) {
+    StringBuilder text = new StringBuilder();
+    for (Diff aDiff : diffs) {
+      if (aDiff.operation != Operation.DELETE) {
+        text.append(aDiff.text);
+      }
+    }
+    return text.toString();
+  }
+
+
+  /**
+   * Compute the Levenshtein distance; the number of inserted, deleted or
+   * substituted characters.
+   * @param diffs LinkedList of Diff objects.
+   * @return Number of changes.
+   */
+  public int diff_levenshtein(LinkedList<Diff> diffs) {
+    int levenshtein = 0;
+    int insertions = 0;
+    int deletions = 0;
+    for (Diff aDiff : diffs) {
+      switch (aDiff.operation) {
+      case INSERT:
+        insertions += aDiff.text.length();
+        break;
+      case DELETE:
+        deletions += aDiff.text.length();
+        break;
+      case EQUAL:
+        // A deletion and an insertion is one substitution.
+        levenshtein += Math.max(insertions, deletions);
+        insertions = 0;
+        deletions = 0;
+        break;
+      }
+    }
+    levenshtein += Math.max(insertions, deletions);
+    return levenshtein;
+  }
+
+
+  /**
+   * Crush the diff into an encoded string which describes the operations
+   * required to transform text1 into text2.
+   * E.g. =3\t-2\t+ing  -> Keep 3 chars, delete 2 chars, insert 'ing'.
+   * Operations are tab-separated.  Inserted text is escaped using %xx notation.
+   * @param diffs Array of diff tuples.
+   * @return Delta text.
+   */
+  public String diff_toDelta(LinkedList<Diff> diffs) {
+    StringBuilder text = new StringBuilder();
+    for (Diff aDiff : diffs) {
+      switch (aDiff.operation) {
+      case INSERT:
+        try {
+          text.append("+").append(URLEncoder.encode(aDiff.text, "UTF-8")
+                                            .replace('+', ' ')).append("\t");
+        } catch (UnsupportedEncodingException e) {
+          // Not likely on modern system.
+          throw new Error("This system does not support UTF-8.", e);
+        }
+        break;
+      case DELETE:
+        text.append("-").append(aDiff.text.length()).append("\t");
+        break;
+      case EQUAL:
+        text.append("=").append(aDiff.text.length()).append("\t");
+        break;
+      }
+    }
+    String delta = text.toString();
+    if (delta.length() != 0) {
+      // Strip off trailing tab character.
+      delta = delta.substring(0, delta.length() - 1);
+      delta = unescapeForEncodeUriCompatability(delta);
+    }
+    return delta;
+  }
+
+
+  /**
+   * Given the original text1, and an encoded string which describes the
+   * operations required to transform text1 into text2, compute the full diff.
+   * @param text1 Source string for the diff.
+   * @param delta Delta text.
+   * @return Array of diff tuples or null if invalid.
+   * @throws IllegalArgumentException If invalid input.
+   */
+  public LinkedList<Diff> diff_fromDelta(String text1, String delta)
+      throws IllegalArgumentException {
+    LinkedList<Diff> diffs = new LinkedList<Diff>();
+    int pointer = 0;  // Cursor in text1
+    String[] tokens = delta.split("\t");
+    for (String token : tokens) {
+      if (token.length() == 0) {
+        // Blank tokens are ok (from a trailing \t).
+        continue;
+      }
+      // Each token begins with a one character parameter which specifies the
+      // operation of this token (delete, insert, equality).
+      String param = token.substring(1);
+      switch (token.charAt(0)) {
+      case '+':
+        // decode would change all "+" to " "
+        param = param.replace("+", "%2B");
+        try {
+          param = URLDecoder.decode(param, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+          // Not likely on modern system.
+          throw new Error("This system does not support UTF-8.", e);
+        } catch (IllegalArgumentException e) {
+          // Malformed URI sequence.
+          throw new IllegalArgumentException(
+              "Illegal escape in diff_fromDelta: " + param, e);
+        }
+        diffs.add(new Diff(Operation.INSERT, param));
+        break;
+      case '-':
+        // Fall through.
+      case '=':
+        int n;
+        try {
+          n = Integer.parseInt(param);
+        } catch (NumberFormatException e) {
+          throw new IllegalArgumentException(
+              "Invalid number in diff_fromDelta: " + param, e);
+        }
+        if (n < 0) {
+          throw new IllegalArgumentException(
+              "Negative number in diff_fromDelta: " + param);
+        }
+        String text;
+        try {
+          text = text1.substring(pointer, pointer += n);
+        } catch (StringIndexOutOfBoundsException e) {
+          throw new IllegalArgumentException("Delta length (" + pointer
+              + ") larger than source text length (" + text1.length()
+              + ").", e);
+        }
+        if (token.charAt(0) == '=') {
+          diffs.add(new Diff(Operation.EQUAL, text));
+        } else {
+          diffs.add(new Diff(Operation.DELETE, text));
+        }
+        break;
+      default:
+        // Anything else is an error.
+        throw new IllegalArgumentException(
+            "Invalid diff operation in diff_fromDelta: " + token.charAt(0));
+      }
+    }
+    if (pointer != text1.length()) {
+      throw new IllegalArgumentException("Delta length (" + pointer
+          + ") smaller than source text length (" + text1.length() + ").");
+    }
+    return diffs;
+  }
+
+
+  //  MATCH FUNCTIONS
+
+
+  /**
+   * Locate the best instance of 'pattern' in 'text' near 'loc'.
+   * Returns -1 if no match found.
+   * @param text The text to search.
+   * @param pattern The pattern to search for.
+   * @param loc The location to search around.
+   * @return Best match index or -1.
+   */
+  public int match_main(String text, String pattern, int loc) {
+    loc = Math.max(0, Math.min(loc, text.length()));
+    if (text.equals(pattern)) {
+      // Shortcut (potentially not guaranteed by the algorithm)
+      return 0;
+    } else if (text.length() == 0) {
+      // Nothing to match.
+      return -1;
+    } else if (loc + pattern.length() <= text.length()
+        && text.substring(loc, loc + pattern.length()).equals(pattern)) {
+      // Perfect match at the perfect spot!  (Includes case of null pattern)
+      return loc;
+    } else {
+      // Do a fuzzy compare.
+      return match_bitap(text, pattern, loc);
+    }
+  }
+
+
+  /**
+   * Locate the best instance of 'pattern' in 'text' near 'loc' using the
+   * Bitap algorithm.  Returns -1 if no match found.
+   * @param text The text to search.
+   * @param pattern The pattern to search for.
+   * @param loc The location to search around.
+   * @return Best match index or -1.
+   */
+  protected int match_bitap(String text, String pattern, int loc) {
+    assert (Match_MaxBits == 0 || pattern.length() <= Match_MaxBits)
+        : "Pattern too long for this application.";
+
+    // Initialise the alphabet.
+    Map<Character, Integer> s = match_alphabet(pattern);
+
+    // Highest score beyond which we give up.
+    double score_threshold = Match_Threshold;
+    // Is there a nearby exact match? (speedup)
+    int best_loc = text.indexOf(pattern, loc);
+    if (best_loc != -1) {
+      score_threshold = Math.min(match_bitapScore(0, best_loc, loc, pattern),
+          score_threshold);
+      // What about in the other direction? (speedup)
+      best_loc = text.lastIndexOf(pattern, loc + pattern.length());
+      if (best_loc != -1) {
+        score_threshold = Math.min(match_bitapScore(0, best_loc, loc, pattern),
+            score_threshold);
+      }
+    }
+
+    // Initialise the bit arrays.
+    int matchmask = 1 << (pattern.length() - 1);
+    best_loc = -1;
+
+    int bin_min, bin_mid;
+    int bin_max = pattern.length() + text.length();
+    // Empty initialization added to appease Java compiler.
+    int[] last_rd = new int[0];
+    for (int d = 0; d < pattern.length(); d++) {
+      // Scan for the best match; each iteration allows for one more error.
+      // Run a binary search to determine how far from 'loc' we can stray at
+      // this error level.
+      bin_min = 0;
+      bin_mid = bin_max;
+      while (bin_min < bin_mid) {
+        if (match_bitapScore(d, loc + bin_mid, loc, pattern)
+            <= score_threshold) {
+          bin_min = bin_mid;
+        } else {
+          bin_max = bin_mid;
+        }
+        bin_mid = (bin_max - bin_min) / 2 + bin_min;
+      }
+      // Use the result from this iteration as the maximum for the next.
+      bin_max = bin_mid;
+      int start = Math.max(1, loc - bin_mid + 1);
+      int finish = Math.min(loc + bin_mid, text.length()) + pattern.length();
+
+      int[] rd = new int[finish + 2];
+      rd[finish + 1] = (1 << d) - 1;
+      for (int j = finish; j >= start; j--) {
+        int charMatch;
+        if (text.length() <= j - 1 || !s.containsKey(text.charAt(j - 1))) {
+          // Out of range.
+          charMatch = 0;
+        } else {
+          charMatch = s.get(text.charAt(j - 1));
+        }
+        if (d == 0) {
+          // First pass: exact match.
+          rd[j] = ((rd[j + 1] << 1) | 1) & charMatch;
+        } else {
+          // Subsequent passes: fuzzy match.
+          rd[j] = ((rd[j + 1] << 1) | 1) & charMatch
+              | (((last_rd[j + 1] | last_rd[j]) << 1) | 1) | last_rd[j + 1];
+        }
+        if ((rd[j] & matchmask) != 0) {
+          double score = match_bitapScore(d, j - 1, loc, pattern);
+          // This match will almost certainly be better than any existing
+          // match.  But check anyway.
+          if (score <= score_threshold) {
+            // Told you so.
+            score_threshold = score;
+            best_loc = j - 1;
+            if (best_loc > loc) {
+              // When passing loc, don't exceed our current distance from loc.
+              start = Math.max(1, 2 * loc - best_loc);
+            } else {
+              // Already passed loc, downhill from here on in.
+              break;
+            }
+          }
+        }
+      }
+      if (match_bitapScore(d + 1, loc, loc, pattern) > score_threshold) {
+        // No hope for a (better) match at greater error levels.
+        break;
+      }
+      last_rd = rd;
+    }
+    return best_loc;
+  }
+
+
+  /**
+   * Compute and return the score for a match with e errors and x location.
+   * @param e Number of errors in match.
+   * @param x Location of match.
+   * @param loc Expected location of match.
+   * @param pattern Pattern being sought.
+   * @return Overall score for match (0.0 = good, 1.0 = bad).
+   */
+  private double match_bitapScore(int e, int x, int loc, String pattern) {
+    float accuracy = (float) e / pattern.length();
+    int proximity = Math.abs(loc - x);
+    if (Match_Distance == 0) {
+      // Dodge divide by zero error.
+      return proximity == 0 ? accuracy : 1.0;
+    }
+    return accuracy + (proximity / (float) Match_Distance);
+  }
+
+
+  /**
+   * Initialise the alphabet for the Bitap algorithm.
+   * @param pattern The text to encode.
+   * @return Hash of character locations.
+   */
+  protected Map<Character, Integer> match_alphabet(String pattern) {
+    Map<Character, Integer> s = new HashMap<Character, Integer>();
+    char[] char_pattern = pattern.toCharArray();
+    for (char c : char_pattern) {
+      s.put(c, 0);
+    }
+    int i = 0;
+    for (char c : char_pattern) {
+      s.put(c, s.get(c) | (1 << (pattern.length() - i - 1)));
+      i++;
+    }
+    return s;
+  }
+
+
+  //  PATCH FUNCTIONS
+
+
+  /**
+   * Increase the context until it is unique,
+   * but don't let the pattern expand beyond Match_MaxBits.
+   * @param patch The patch to grow.
+   * @param text Source text.
+   */
+  protected void patch_addContext(Patch patch, String text) {
+    if (text.length() == 0) {
+      return;
+    }
+    String pattern = text.substring(patch.start2, patch.start2 + patch.length1);
+    int padding = 0;
+
+    // Look for the first and last matches of pattern in text.  If two different
+    // matches are found, increase the pattern length.
+    while (text.indexOf(pattern) != text.lastIndexOf(pattern)
+        && pattern.length() < Match_MaxBits - Patch_Margin - Patch_Margin) {
+      padding += Patch_Margin;
+      pattern = text.substring(Math.max(0, patch.start2 - padding),
+          Math.min(text.length(), patch.start2 + patch.length1 + padding));
+    }
+    // Add one chunk for good luck.
+    padding += Patch_Margin;
+
+    // Add the prefix.
+    String prefix = text.substring(Math.max(0, patch.start2 - padding),
+        patch.start2);
+    if (prefix.length() != 0) {
+      patch.diffs.addFirst(new Diff(Operation.EQUAL, prefix));
+    }
+    // Add the suffix.
+    String suffix = text.substring(patch.start2 + patch.length1,
+        Math.min(text.length(), patch.start2 + patch.length1 + padding));
+    if (suffix.length() != 0) {
+      patch.diffs.addLast(new Diff(Operation.EQUAL, suffix));
+    }
+
+    // Roll back the start points.
+    patch.start1 -= prefix.length();
+    patch.start2 -= prefix.length();
+    // Extend the lengths.
+    patch.length1 += prefix.length() + suffix.length();
+    patch.length2 += prefix.length() + suffix.length();
+  }
+
+
+  /**
+   * Compute a list of patches to turn text1 into text2.
+   * A set of diffs will be computed.
+   * @param text1 Old text.
+   * @param text2 New text.
+   * @return LinkedList of Patch objects.
+   */
+  public LinkedList<Patch> patch_make(String text1, String text2) {
+    // No diffs provided, compute our own.
+    LinkedList<Diff> diffs = diff_main(text1, text2, true);
+    if (diffs.size() > 2) {
+      diff_cleanupSemantic(diffs);
+      diff_cleanupEfficiency(diffs);
+    }
+    return patch_make(text1, diffs);
+  }
+
+
+  /**
+   * Compute a list of patches to turn text1 into text2.
+   * text1 will be derived from the provided diffs.
+   * @param diffs Array of diff tuples for text1 to text2.
+   * @return LinkedList of Patch objects.
+   */
+  public LinkedList<Patch> patch_make(LinkedList<Diff> diffs) {
+    // No origin string provided, compute our own.
+    String text1 = diff_text1(diffs);
+    return patch_make(text1, diffs);
+  }
+
+
+  /**
+   * Compute a list of patches to turn text1 into text2.
+   * text2 is ignored, diffs are the delta between text1 and text2.
+   * @param text1 Old text
+   * @param text2 Ignored.
+   * @param diffs Array of diff tuples for text1 to text2.
+   * @return LinkedList of Patch objects.
+   * @deprecated Prefer patch_make(String text1, LinkedList<Diff> diffs).
+   */
+  public LinkedList<Patch> patch_make(String text1, String text2,
+      LinkedList<Diff> diffs) {
+    return patch_make(text1, diffs);
+  }
+
+
+  /**
+   * Compute a list of patches to turn text1 into text2.
+   * A set of diffs will be computed.
+   * @param text1 Old text.
+   * @param text2 New text.
+   * @return String representation of a LinkedList of Patch objects.
+   */
+  public String custom_patch_make(String text1, String text2) {
+    return patch_toText(patch_make(text1, text2));
+  }
+
+
+  /**
+   * Compute a list of patches to turn text1 into text2.
+   * text2 is not provided, diffs are the delta between text1 and text2.
+   * @param text1 Old text.
+   * @param diffs Array of diff tuples for text1 to text2.
+   * @return LinkedList of Patch objects.
+   */
+  public LinkedList<Patch> patch_make(String text1, LinkedList<Diff> diffs) {
+    LinkedList<Patch> patches = new LinkedList<Patch>();
+    if (diffs.isEmpty()) {
+      return patches;  // Get rid of the null case.
+    }
+    Patch patch = new Patch();
+    int char_count1 = 0;  // Number of characters into the text1 string.
+    int char_count2 = 0;  // Number of characters into the text2 string.
+    // Start with text1 (prepatch_text) and apply the diffs until we arrive at
+    // text2 (postpatch_text). We recreate the patches one by one to determine
+    // context info.
+    String prepatch_text = text1;
+    String postpatch_text = text1;
+    for (Diff aDiff : diffs) {
+      if (patch.diffs.isEmpty() && aDiff.operation != Operation.EQUAL) {
+        // A new patch starts here.
+        patch.start1 = char_count1;
+        patch.start2 = char_count2;
+      }
+
+      switch (aDiff.operation) {
+      case INSERT:
+        patch.diffs.add(aDiff);
+        patch.length2 += aDiff.text.length();
+        postpatch_text = postpatch_text.substring(0, char_count2)
+            + aDiff.text + postpatch_text.substring(char_count2);
+        break;
+      case DELETE:
+        patch.length1 += aDiff.text.length();
+        patch.diffs.add(aDiff);
+        postpatch_text = postpatch_text.substring(0, char_count2)
+            + postpatch_text.substring(char_count2 + aDiff.text.length());
+        break;
+      case EQUAL:
+        if (aDiff.text.length() <= 2 * Patch_Margin
+            && !patch.diffs.isEmpty() && aDiff != diffs.getLast()) {
+          // Small equality inside a patch.
+          patch.diffs.add(aDiff);
+          patch.length1 += aDiff.text.length();
+          patch.length2 += aDiff.text.length();
+        }
+
+        if (aDiff.text.length() >= 2 * Patch_Margin) {
+          // Time for a new patch.
+          if (!patch.diffs.isEmpty()) {
+            patch_addContext(patch, prepatch_text);
+            patches.add(patch);
+            patch = new Patch();
+            // Unlike Unidiff, our patch lists have a rolling context.
+            // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff
+            // Update prepatch text & pos to reflect the application of the
+            // just completed patch.
+            prepatch_text = postpatch_text;
+            char_count1 = char_count2;
+          }
+        }
+        break;
+      }
+
+      // Update the current character count.
+      if (aDiff.operation != Operation.INSERT) {
+        char_count1 += aDiff.text.length();
+      }
+      if (aDiff.operation != Operation.DELETE) {
+        char_count2 += aDiff.text.length();
+      }
+    }
+    // Pick up the leftover patch if not empty.
+    if (!patch.diffs.isEmpty()) {
+      patch_addContext(patch, prepatch_text);
+      patches.add(patch);
+    }
+
+    return patches;
+  }
+
+
+  /**
+   * Given an array of patches, return another array that is identical.
+   * @param patches Array of patch objects.
+   * @return Array of patch objects.
+   */
+  public LinkedList<Patch> patch_deepCopy(LinkedList<Patch> patches) {
+    LinkedList<Patch> patchesCopy = new LinkedList<Patch>();
+    for (Patch aPatch : patches) {
+      Patch patchCopy = new Patch();
+      for (Diff aDiff : aPatch.diffs) {
+        Diff diffCopy = new Diff(aDiff.operation, aDiff.text);
+        patchCopy.diffs.add(diffCopy);
+      }
+      patchCopy.start1 = aPatch.start1;
+      patchCopy.start2 = aPatch.start2;
+      patchCopy.length1 = aPatch.length1;
+      patchCopy.length2 = aPatch.length2;
+      patchesCopy.add(patchCopy);
+    }
+    return patchesCopy;
+  }
+
+
+  /**
+   * Merge a set of patches onto the text.  Return a patched text, as well
+   * as an array of true/false values indicating which patches were applied.
+   * @param patches Array of patch objects
+   * @param text Old text.
+   * @return Two element Object array, containing the new text and an array of
+   *      boolean values.
+   */
+  public Object[] patch_apply(LinkedList<Patch> patches, String text) {
+    if (patches.isEmpty()) {
+      return new Object[]{text, new boolean[0]};
+    }
+
+    // Deep copy the patches so that no changes are made to originals.
+    patches = patch_deepCopy(patches);
+
+    String nullPadding = patch_addPadding(patches);
+    text = nullPadding + text + nullPadding;
+    patch_splitMax(patches);
+
+    int x = 0;
+    // delta keeps track of the offset between the expected and actual location
+    // of the previous patch.  If there are patches expected at positions 10 and
+    // 20, but the first patch was found at 12, delta is 2 and the second patch
+    // has an effective expected position of 22.
+    int delta = 0;
+    boolean[] results = new boolean[patches.size()];
+    for (Patch aPatch : patches) {
+      int expected_loc = aPatch.start2 + delta;
+      String text1 = diff_text1(aPatch.diffs);
+      int start_loc;
+      int end_loc = -1;
+      if (text1.length() > this.Match_MaxBits) {
+        // patch_splitMax will only provide an oversized pattern in the case of
+        // a monster delete.
+        start_loc = match_main(text,
+            text1.substring(0, this.Match_MaxBits), expected_loc);
+        if (start_loc != -1) {
+          end_loc = match_main(text,
+              text1.substring(text1.length() - this.Match_MaxBits),
+              expected_loc + text1.length() - this.Match_MaxBits);
+          if (end_loc == -1 || start_loc >= end_loc) {
+            // Can't find valid trailing context.  Drop this patch.
+            start_loc = -1;
+          }
+        }
+      } else {
+        start_loc = match_main(text, text1, expected_loc);
+      }
+      if (start_loc == -1) {
+        // No match found.  :(
+        results[x] = false;
+        // Subtract the delta for this failed patch from subsequent patches.
+        delta -= aPatch.length2 - aPatch.length1;
+      } else {
+        // Found a match.  :)
+        results[x] = true;
+        delta = start_loc - expected_loc;
+        String text2;
+        if (end_loc == -1) {
+          text2 = text.substring(start_loc,
+              Math.min(start_loc + text1.length(), text.length()));
+        } else {
+          text2 = text.substring(start_loc,
+              Math.min(end_loc + this.Match_MaxBits, text.length()));
+        }
+        if (text1.equals(text2)) {
+          // Perfect match, just shove the replacement text in.
+          text = text.substring(0, start_loc) + diff_text2(aPatch.diffs)
+              + text.substring(start_loc + text1.length());
+        } else {
+          // Imperfect match.  Run a diff to get a framework of equivalent
+          // indices.
+          LinkedList<Diff> diffs = diff_main(text1, text2, false);
+          if (text1.length() > this.Match_MaxBits
+              && diff_levenshtein(diffs) / (float) text1.length()
+              > this.Patch_DeleteThreshold) {
+            // The end points match, but the content is unacceptably bad.
+            results[x] = false;
+          } else {
+            diff_cleanupSemanticLossless(diffs);
+            int index1 = 0;
+            for (Diff aDiff : aPatch.diffs) {
+              if (aDiff.operation != Operation.EQUAL) {
+                int index2 = diff_xIndex(diffs, index1);
+                if (aDiff.operation == Operation.INSERT) {
+                  // Insertion
+                  text = text.substring(0, start_loc + index2) + aDiff.text
+                      + text.substring(start_loc + index2);
+                } else if (aDiff.operation == Operation.DELETE) {
+                  // Deletion
+                  text = text.substring(0, start_loc + index2)
+                      + text.substring(start_loc + diff_xIndex(diffs,
+                      index1 + aDiff.text.length()));
+                }
+              }
+              if (aDiff.operation != Operation.DELETE) {
+                index1 += aDiff.text.length();
+              }
+            }
+          }
+        }
+      }
+      x++;
+    }
+    // Strip the padding off.
+    text = text.substring(nullPadding.length(), text.length()
+        - nullPadding.length());
+    return new Object[]{text, results};
+  }
+
+
+  /**
+   * Add some padding on text start and end so that edges can match something.
+   * Intended to be called only from within patch_apply.
+   * @param patches Array of patch objects.
+   * @return The padding string added to each side.
+   */
+  public String patch_addPadding(LinkedList<Patch> patches) {
+    int paddingLength = this.Patch_Margin;
+    String nullPadding = "";
+    for (int x = 1; x <= paddingLength; x++) {
+      nullPadding += String.valueOf((char) x);
+    }
+
+    // Bump all the patches forward.
+    for (Patch aPatch : patches) {
+      aPatch.start1 += paddingLength;
+      aPatch.start2 += paddingLength;
+    }
+
+    // Add some padding on start of first diff.
+    Patch patch = patches.getFirst();
+    LinkedList<Diff> diffs = patch.diffs;
+    if (diffs.isEmpty() || diffs.getFirst().operation != Operation.EQUAL) {
+      // Add nullPadding equality.
+      diffs.addFirst(new Diff(Operation.EQUAL, nullPadding));
+      patch.start1 -= paddingLength;  // Should be 0.
+      patch.start2 -= paddingLength;  // Should be 0.
+      patch.length1 += paddingLength;
+      patch.length2 += paddingLength;
+    } else if (paddingLength > diffs.getFirst().text.length()) {
+      // Grow first equality.
+      Diff firstDiff = diffs.getFirst();
+      int extraLength = paddingLength - firstDiff.text.length();
+      firstDiff.text = nullPadding.substring(firstDiff.text.length())
+          + firstDiff.text;
+      patch.start1 -= extraLength;
+      patch.start2 -= extraLength;
+      patch.length1 += extraLength;
+      patch.length2 += extraLength;
+    }
+
+    // Add some padding on end of last diff.
+    patch = patches.getLast();
+    diffs = patch.diffs;
+    if (diffs.isEmpty() || diffs.getLast().operation != Operation.EQUAL) {
+      // Add nullPadding equality.
+      diffs.addLast(new Diff(Operation.EQUAL, nullPadding));
+      patch.length1 += paddingLength;
+      patch.length2 += paddingLength;
+    } else if (paddingLength > diffs.getLast().text.length()) {
+      // Grow last equality.
+      Diff lastDiff = diffs.getLast();
+      int extraLength = paddingLength - lastDiff.text.length();
+      lastDiff.text += nullPadding.substring(0, extraLength);
+      patch.length1 += extraLength;
+      patch.length2 += extraLength;
+    }
+
+    return nullPadding;
+  }
+
+
+  /**
+   * Look through the patches and break up any which are longer than the
+   * maximum limit of the match algorithm.
+   * @param patches LinkedList of Patch objects.
+   */
+  public void patch_splitMax(LinkedList<Patch> patches) {
+    int patch_size;
+    String precontext, postcontext;
+    Patch patch;
+    int start1, start2;
+    boolean empty;
+    Operation diff_type;
+    String diff_text;
+    ListIterator<Patch> pointer = patches.listIterator();
+    Patch bigpatch = pointer.hasNext() ? pointer.next() : null;
+    while (bigpatch != null) {
+      if (bigpatch.length1 <= Match_MaxBits) {
+        bigpatch = pointer.hasNext() ? pointer.next() : null;
+        continue;
+      }
+      // Remove the big old patch.
+      pointer.remove();
+      patch_size = Match_MaxBits;
+      start1 = bigpatch.start1;
+      start2 = bigpatch.start2;
+      precontext = "";
+      while (!bigpatch.diffs.isEmpty()) {
+        // Create one of several smaller patches.
+        patch = new Patch();
+        empty = true;
+        patch.start1 = start1 - precontext.length();
+        patch.start2 = start2 - precontext.length();
+        if (precontext.length() != 0) {
+          patch.length1 = patch.length2 = precontext.length();
+          patch.diffs.add(new Diff(Operation.EQUAL, precontext));
+        }
+        while (!bigpatch.diffs.isEmpty()
+            && patch.length1 < patch_size - Patch_Margin) {
+          diff_type = bigpatch.diffs.getFirst().operation;
+          diff_text = bigpatch.diffs.getFirst().text;
+          if (diff_type == Operation.INSERT) {
+            // Insertions are harmless.
+            patch.length2 += diff_text.length();
+            start2 += diff_text.length();
+            patch.diffs.addLast(bigpatch.diffs.removeFirst());
+            empty = false;
+          } else if (diff_type == Operation.DELETE && patch.diffs.size() == 1
+              && patch.diffs.getFirst().operation == Operation.EQUAL
+              && diff_text.length() > 2 * patch_size) {
+            // This is a large deletion.  Let it pass in one chunk.
+            patch.length1 += diff_text.length();
+            start1 += diff_text.length();
+            empty = false;
+            patch.diffs.add(new Diff(diff_type, diff_text));
+            bigpatch.diffs.removeFirst();
+          } else {
+            // Deletion or equality.  Only take as much as we can stomach.
+            diff_text = diff_text.substring(0, Math.min(diff_text.length(),
+                patch_size - patch.length1 - Patch_Margin));
+            patch.length1 += diff_text.length();
+            start1 += diff_text.length();
+            if (diff_type == Operation.EQUAL) {
+              patch.length2 += diff_text.length();
+              start2 += diff_text.length();
+            } else {
+              empty = false;
+            }
+            patch.diffs.add(new Diff(diff_type, diff_text));
+            if (diff_text.equals(bigpatch.diffs.getFirst().text)) {
+              bigpatch.diffs.removeFirst();
+            } else {
+              bigpatch.diffs.getFirst().text = bigpatch.diffs.getFirst().text
+                  .substring(diff_text.length());
+            }
+          }
+        }
+        // Compute the head context for the next patch.
+        precontext = diff_text2(patch.diffs);
+        precontext = precontext.substring(Math.max(0, precontext.length()
+            - Patch_Margin));
+        // Append the end context for this patch.
+        if (diff_text1(bigpatch.diffs).length() > Patch_Margin) {
+          postcontext = diff_text1(bigpatch.diffs).substring(0, Patch_Margin);
+        } else {
+          postcontext = diff_text1(bigpatch.diffs);
+        }
+        if (postcontext.length() != 0) {
+          patch.length1 += postcontext.length();
+          patch.length2 += postcontext.length();
+          if (!patch.diffs.isEmpty()
+              && patch.diffs.getLast().operation == Operation.EQUAL) {
+            patch.diffs.getLast().text += postcontext;
+          } else {
+            patch.diffs.add(new Diff(Operation.EQUAL, postcontext));
+          }
+        }
+        if (!empty) {
+          pointer.add(patch);
+        }
+      }
+      bigpatch = pointer.hasNext() ? pointer.next() : null;
+    }
+  }
+
+
+  /**
+   * Take a list of patches and return a textual representation.
+   * @param patches List of Patch objects.
+   * @return Text representation of patches.
+   */
+  public String patch_toText(List<Patch> patches) {
+    StringBuilder text = new StringBuilder();
+    for (Patch aPatch : patches) {
+      text.append(aPatch);
+    }
+    return text.toString();
+  }
+
+
+  /**
+   * Parse a textual representation of patches and return a List of Patch
+   * objects.
+   * @param textline Text representation of patches.
+   * @return List of Patch objects.
+   * @throws IllegalArgumentException If invalid input.
+   */
+  public LinkedList<Patch> patch_fromText(String textline)
+      throws IllegalArgumentException {
+    LinkedList<Patch> patches = new LinkedList<Patch>();
+    if (textline.length() == 0) {
+      return patches;
+    }
+    List<String> textList = Arrays.asList(textline.split("\n"));
+    LinkedList<String> text = new LinkedList<String>(textList);
+    Patch patch;
+    Pattern patchHeader
+        = Pattern.compile("^@@ -(\\d+),?(\\d*) \\+(\\d+),?(\\d*) @@$");
+    Matcher m;
+    char sign;
+    String line;
+    while (!text.isEmpty()) {
+      m = patchHeader.matcher(text.getFirst());
+      if (!m.matches()) {
+        throw new IllegalArgumentException(
+            "Invalid patch string: " + text.getFirst());
+      }
+      patch = new Patch();
+      patches.add(patch);
+      patch.start1 = Integer.parseInt(m.group(1));
+      if (m.group(2).length() == 0) {
+        patch.start1--;
+        patch.length1 = 1;
+      } else if (m.group(2).equals("0")) {
+        patch.length1 = 0;
+      } else {
+        patch.start1--;
+        patch.length1 = Integer.parseInt(m.group(2));
+      }
+
+      patch.start2 = Integer.parseInt(m.group(3));
+      if (m.group(4).length() == 0) {
+        patch.start2--;
+        patch.length2 = 1;
+      } else if (m.group(4).equals("0")) {
+        patch.length2 = 0;
+      } else {
+        patch.start2--;
+        patch.length2 = Integer.parseInt(m.group(4));
+      }
+      text.removeFirst();
+
+      while (!text.isEmpty()) {
+        try {
+          sign = text.getFirst().charAt(0);
+        } catch (IndexOutOfBoundsException e) {
+          // Blank line?  Whatever.
+          text.removeFirst();
+          continue;
+        }
+        line = text.getFirst().substring(1);
+        line = line.replace("+", "%2B");  // decode would change all "+" to " "
+        try {
+          line = URLDecoder.decode(line, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+          // Not likely on modern system.
+          throw new Error("This system does not support UTF-8.", e);
+        } catch (IllegalArgumentException e) {
+          // Malformed URI sequence.
+          throw new IllegalArgumentException(
+              "Illegal escape in patch_fromText: " + line, e);
+        }
+        if (sign == '-') {
+          // Deletion.
+          patch.diffs.add(new Diff(Operation.DELETE, line));
+        } else if (sign == '+') {
+          // Insertion.
+          patch.diffs.add(new Diff(Operation.INSERT, line));
+        } else if (sign == ' ') {
+          // Minor equality.
+          patch.diffs.add(new Diff(Operation.EQUAL, line));
+        } else if (sign == '@') {
+          // Start of next patch.
+          break;
+        } else {
+          // WTF?
+          throw new IllegalArgumentException(
+              "Invalid patch mode '" + sign + "' in: " + line);
+        }
+        text.removeFirst();
+      }
+    }
+    return patches;
+  }
+
+
+  /**
+   * Class representing one diff operation.
+   */
+  public static class Diff {
+    /**
+     * One of: INSERT, DELETE or EQUAL.
+     */
+    public Operation operation;
+    /**
+     * The text associated with this diff operation.
+     */
+    public String text;
+
+    /**
+     * Constructor.  Initializes the diff with the provided values.
+     * @param operation One of INSERT, DELETE or EQUAL.
+     * @param text The text being applied.
+     */
+    public Diff(Operation operation, String text) {
+      // Construct a diff with the specified operation and text.
+      this.operation = operation;
+      this.text = text;
+    }
+
+
+    /**
+     * Display a human-readable version of this Diff.
+     * @return text version.
+     */
+    public String toString() {
+      String prettyText = this.text.replace('\n', '\u00b6');
+      return "Diff(" + this.operation + ",\"" + prettyText + "\")";
+    }
+
+
+    /**
+     * Is this Diff equivalent to another Diff?
+     * @param d Another Diff to compare against.
+     * @return true or false.
+     */
+    public boolean equals(Object d) {
+      try {
+        return (((Diff) d).operation == this.operation)
+               && (((Diff) d).text.equals(this.text));
+      } catch (ClassCastException e) {
+        return false;
+      }
+    }
+  }
+
+
+  /**
+   * Class representing one patch operation.
+   */
+  public static class Patch {
+    public LinkedList<Diff> diffs;
+    public int start1;
+    public int start2;
+    public int length1;
+    public int length2;
+
+
+    /**
+     * Constructor.  Initializes with an empty list of diffs.
+     */
+    public Patch() {
+      this.diffs = new LinkedList<Diff>();
+    }
+
+
+    /**
+     * Emmulate GNU diff's format.
+     * Header: @@ -382,8 +481,9 @@
+     * Indicies are printed as 1-based, not 0-based.
+     * @return The GNU diff string.
+     */
+    public String toString() {
+      String coords1, coords2;
+      if (this.length1 == 0) {
+        coords1 = this.start1 + ",0";
+      } else if (this.length1 == 1) {
+        coords1 = Integer.toString(this.start1 + 1);
+      } else {
+        coords1 = (this.start1 + 1) + "," + this.length1;
+      }
+      if (this.length2 == 0) {
+        coords2 = this.start2 + ",0";
+      } else if (this.length2 == 1) {
+        coords2 = Integer.toString(this.start2 + 1);
+      } else {
+        coords2 = (this.start2 + 1) + "," + this.length2;
+      }
+      StringBuilder text = new StringBuilder();
+      text.append("@@ -").append(coords1).append(" +").append(coords2)
+          .append(" @@\n");
+      // Escape the body of the patch with %xx notation.
+      for (Diff aDiff : this.diffs) {
+        switch (aDiff.operation) {
+        case INSERT:
+          text.append('+');
+          break;
+        case DELETE:
+          text.append('-');
+          break;
+        case EQUAL:
+          text.append(' ');
+          break;
+        }
+        try {
+          text.append(URLEncoder.encode(aDiff.text, "UTF-8").replace('+', ' '))
+              .append("\n");
+        } catch (UnsupportedEncodingException e) {
+          // Not likely on modern system.
+          throw new Error("This system does not support UTF-8.", e);
+        }
+      }
+      return unescapeForEncodeUriCompatability(text.toString());
+    }
+  }
+
+
+  /**
+   * Unescape selected chars for compatability with JavaScript's encodeURI.
+   * In speed critical applications this could be dropped since the
+   * receiving application will certainly decode these fine.
+   * Note that this function is case-sensitive.  Thus "%3f" would not be
+   * unescaped.  But this is ok because it is only called with the output of
+   * URLEncoder.encode which returns uppercase hex.
+   *
+   * Example: "%3F" -> "?", "%24" -> "$", etc.
+   *
+   * @param str The string to escape.
+   * @return The escaped string.
+   */
+  private static String unescapeForEncodeUriCompatability(String str) {
+    return str.replace("%21", "!").replace("%7E", "~")
+        .replace("%27", "'").replace("%28", "(").replace("%29", ")")
+        .replace("%3B", ";").replace("%2F", "/").replace("%3F", "?")
+        .replace("%3A", ":").replace("%40", "@").replace("%26", "&")
+        .replace("%3D", "=").replace("%2B", "+").replace("%24", "$")
+        .replace("%2C", ",").replace("%23", "#");
+  }
+}
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/api/IBigBlueButtonInGW.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/api/IBigBlueButtonInGW.java
index 0f08f1d2232806abf11ea9b7cddbdc4e0befc2c9..77099b7de5e97cb2b26c5b37e12ce49df959b60e 100755
--- a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/api/IBigBlueButtonInGW.java
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/api/IBigBlueButtonInGW.java
@@ -16,6 +16,7 @@ public interface IBigBlueButtonInGW {
 	void destroyMeeting(String meetingID);
 	void getAllMeetings(String meetingID);
 	void lockSettings(String meetingID, Boolean locked, Map<String, Boolean> lockSettigs);
+	void activityResponse(String meetingID);
 
 	// Polling
 	void votePoll(String meetingId, String userId, String pollId, Integer questionId, Integer answerId);
@@ -31,11 +32,12 @@ public interface IBigBlueButtonInGW {
 
 	// Users
 	void validateAuthToken(String meetingId, String userId, String token, String correlationId, String sessionId);
-	void registerUser(String roomName, String userid, String username, String role, String externUserID, String authToken, String avatarURL);
+	void registerUser(String roomName, String userid, String username, String role, String externUserID, String authToken, String avatarURL, Boolean guest);
 	void userEmojiStatus(String meetingId, String userId, String emojiStatus);	
 	void shareWebcam(String meetingId, String userId, String stream);
 	void unshareWebcam(String meetingId, String userId, String stream);
 	void setUserStatus(String meetingID, String userID, String status, Object value);
+	void setUserRole(String meetingID, String userID, String role);
 	void getUsers(String meetingID, String requesterID);
 	void userLeft(String meetingID, String userID, String sessionId);
 	void userJoin(String meetingID, String userID, String authToken);
@@ -46,6 +48,10 @@ public interface IBigBlueButtonInGW {
 	void getRecordingStatus(String meetingId, String userId);
 	void userConnectedToGlobalAudio(String voiceConf, String userid, String name);
 	void userDisconnectedFromGlobalAudio(String voiceConf, String userid, String name);
+	void getGuestPolicy(String meetingID, String userID);
+	void setGuestPolicy(String meetingID, String guestPolicy, String setBy);
+	void responseToGuest(String meetingID, String userID, Boolean response, String requesterID);
+	void logoutEndMeeting(String meetingID, String userID);
 
 	// Voice
 	void initAudioSettings(String meetingID, String requesterID, Boolean muted);
@@ -87,7 +93,7 @@ public interface IBigBlueButtonInGW {
             int pagesCompleted, String presName);
 
 	void sendConversionCompleted(String messageKey, String meetingId, 
-            String code, String presId, int numPages, String presName, String presBaseUrl);
+            String code, String presId, int numPages, String presName, String presBaseUrl, boolean downloadable);
 
 	// Layout
 	void getCurrentLayout(String meetingID, String requesterID);
@@ -100,6 +106,7 @@ public interface IBigBlueButtonInGW {
 	void getChatHistory(String meetingID, String requesterID, String replyTo);
 	void sendPublicMessage(String meetingID, String requesterID, Map<String, String> message);
 	void sendPrivateMessage(String meetingID, String requesterID, Map<String, String> message);
+	void clearPublicChatHistory(String meetingID, String requesterID);
 
 	// Whiteboard
 	void sendWhiteboardAnnotation(String meetingID, String requesterID, java.util.Map<String, Object> annotation);	
@@ -120,4 +127,12 @@ public interface IBigBlueButtonInGW {
 	void deskShareRTMPBroadcastStarted(String conferenceName, String streamname, int videoWidth, int videoHeight, String timestamp);
 	void deskShareRTMPBroadcastStopped(String conferenceName, String streamname, int videoWidth, int videoHeight, String timestamp);
 	void deskShareGetInfoRequest(String meetingId, String requesterId, String replyTo);
+
+	// Shared notes
+	void patchDocument(String meetingID, String requesterID, String noteID, String patch, String operation);
+	void getCurrentDocument(String meetingID, String requesterID);
+	void createAdditionalNotes(String meetingID, String requesterID, String noteName);
+	void destroyAdditionalNotes(String meetingID, String requesterID, String noteID);
+	void requestAdditionalNotesSet(String meetingID, String requesterID, int additionalNotesSetSize);
+	void sharedNotesSyncNoteRequest(String meetingID, String requesterID, String noteID);
 }
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/ChatMessageReceiver.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/ChatMessageReceiver.java
index 8a2d83e45032891dbf7818d715b53c4b743a9777..06c747304fdd00c19e84ba6c30f5e622a15ecc30 100755
--- a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/ChatMessageReceiver.java
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/ChatMessageReceiver.java
@@ -4,6 +4,7 @@ import org.bigbluebutton.common.messages.GetChatHistoryRequestMessage;
 import org.bigbluebutton.common.messages.MessagingConstants;
 import org.bigbluebutton.common.messages.SendPrivateChatMessage;
 import org.bigbluebutton.common.messages.SendPublicChatMessage;
+import org.bigbluebutton.common.messages.ClearPublicChatHistoryRequestMessage;
 
 import com.google.gson.JsonParser;
 import com.google.gson.JsonObject;
@@ -36,6 +37,9 @@ public class ChatMessageReceiver implements MessageHandler{
 					} else if (SendPrivateChatMessage.SEND_PRIVATE_CHAT_MESSAGE.equals(messageName)){
 						SendPrivateChatMessage msg = SendPrivateChatMessage.fromJson(message);
 						bbbGW.sendPrivateMessage(msg.meetingId, msg.requesterId, msg.messageInfo);
+					} else if (ClearPublicChatHistoryRequestMessage.CLEAR_PUBLIC_CHAT_HISTORY_REQUEST.equals(messageName)){
+						ClearPublicChatHistoryRequestMessage msg = ClearPublicChatHistoryRequestMessage.fromJson(message);
+						bbbGW.clearPublicChatHistory(msg.meetingId, msg.requesterId);
 					}
 				}
 			}
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/ConversionUpdatesProcessor.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/ConversionUpdatesProcessor.java
index 18915d896ddfd460555502cd38177df6be081e65..8726df9da017f391410cdfeb0c5452cf758d059c 100755
--- a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/ConversionUpdatesProcessor.java
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/ConversionUpdatesProcessor.java
@@ -50,9 +50,9 @@ public class ConversionUpdatesProcessor {
 	
 	public void sendConversionCompleted(String messageKey, String conference, 
             String code, String presId, Integer numberOfPages, String presName,
-            String presBaseUrl) {
+            String presBaseUrl, Boolean downloadable) {
 		bbbInGW.sendConversionCompleted(messageKey, conference, 
-	            code, presId, numberOfPages, presName, presBaseUrl);
+	            code, presId, numberOfPages, presName, presBaseUrl, downloadable);
 	}
 	
     public void setBigBlueButtonInGW(IBigBlueButtonInGW inGW) {
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/MeetingMessageReceiver.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/MeetingMessageReceiver.java
index cf1100af5bd4f1133033b3df8adfe11fcf800e0c..14cfd9e9e1d48ecadc5b22380f76771d8340d347 100755
--- a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/MeetingMessageReceiver.java
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/MeetingMessageReceiver.java
@@ -3,6 +3,7 @@ package org.bigbluebutton.core.pubsub.receivers;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.bigbluebutton.common.messages.ActivityResponseMessage;
 import org.bigbluebutton.common.messages.DestroyMeetingMessage;
 import org.bigbluebutton.common.messages.EndMeetingMessage;
 import org.bigbluebutton.common.messages.GetAllMeetingsRequest;
@@ -60,7 +61,7 @@ public class MeetingMessageReceiver implements MessageHandler {
 					bbbGW.endMeeting(emm.meetingId);
 				} else if (msg instanceof RegisterUserMessage) {
 					RegisterUserMessage rum = (RegisterUserMessage) msg;
-					bbbGW.registerUser(rum.meetingID, rum.internalUserId, rum.fullname, rum.role, rum.externUserID, rum.authToken, rum.avatarURL);
+					bbbGW.registerUser(rum.meetingID, rum.internalUserId, rum.fullname, rum.role, rum.externUserID, rum.authToken, rum.avatarURL, rum.guest);
 				} else if (msg instanceof DestroyMeetingMessage) {
 					DestroyMeetingMessage dmm = (DestroyMeetingMessage) msg;
 					bbbGW.destroyMeeting(dmm.meetingId);
@@ -104,6 +105,9 @@ public class MeetingMessageReceiver implements MessageHandler {
 				else if (msg instanceof GetAllMeetingsRequest) {
 					GetAllMeetingsRequest gamr = (GetAllMeetingsRequest) msg;
 					bbbGW.getAllMeetings("no_need_of_a_meeting_id");
+				} else if (msg instanceof ActivityResponseMessage) {
+					ActivityResponseMessage arm = (ActivityResponseMessage) msg;
+					bbbGW.activityResponse(arm.meetingId);
 				} else {
 					System.out.println("Unknown message: [" + message + "]");
 				}
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/PresentationMessageListener.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/PresentationMessageListener.java
index d91e5f38ded2a98c00aff0903d89c8865ac62305..7486fde9e95fa9145aa654252ad2688bb5e09e1d 100755
--- a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/PresentationMessageListener.java
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/PresentationMessageListener.java
@@ -72,10 +72,10 @@ public class PresentationMessageListener implements MessageHandler {
         
         private void sendConversionCompleted(String messageKey, String conference,
                 String code, String presId, Integer numberOfPages,
-                String filename, String presBaseUrl) {
+                String filename, String presBaseUrl, Boolean downloadable) {
                 
                 conversionUpdatesProcessor.sendConversionCompleted(messageKey, conference,
-                        code, presId, numberOfPages, filename, presBaseUrl);
+                        code, presId, numberOfPages, filename, presBaseUrl, downloadable);
         }
 
         @Override
@@ -107,7 +107,7 @@ public class PresentationMessageListener implements MessageHandler {
 //    						sendConversionCompleted(msg.messageKey, msg.meetingId, msg.code,
 //    								msg.presId, msg.numPages, msg.presName, msg.presBaseUrl);
     						bbbInGW.sendConversionCompleted(msg.messageKey, msg.meetingId, msg.code,
-    								msg.presId, msg.numPages, msg.presName, msg.presBaseUrl);
+    								msg.presId, msg.numPages, msg.presName, msg.presBaseUrl, msg.downloadable);
     					} else if (SendPageCountErrorMessage.SEND_PAGE_COUNT_ERROR.equals(messageName)) {
     						SendPageCountErrorMessage msg = SendPageCountErrorMessage.fromJson(message);
 //    						sendPageCountError(msg.messageKey, msg.meetingId, msg.code,
@@ -171,9 +171,10 @@ public class PresentationMessageListener implements MessageHandler {
     				} else if(messageKey.equalsIgnoreCase(CONVERSION_COMPLETED_KEY)){
     					Integer numberOfPages = new Integer((String) map.get("numberOfPages"));
     					String presBaseUrl = (String) map.get("presentationBaseUrl");
+    					Boolean downloadable = new Boolean((String) map.get("downloadable"));
 
     					sendConversionCompleted(messageKey, conference, code,
-    							presId, numberOfPages, filename, presBaseUrl);
+    							presId, numberOfPages, filename, presBaseUrl, downloadable);
     				}
     			}
     		}
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/RedisMessageReceiver.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/RedisMessageReceiver.java
index 827fe403df3694d740ff83cabd1c471b3dec7a2b..baf56e41c94b17d8ffd3b2bd267d38a7679424c9 100755
--- a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/RedisMessageReceiver.java
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/RedisMessageReceiver.java
@@ -57,6 +57,9 @@ public class RedisMessageReceiver {
 		
 		CaptionMessageReceiver captionRx = new CaptionMessageReceiver(bbbGW);
 		receivers.add(captionRx);
+
+		SharedNotesMessageReceiver notesRx = new SharedNotesMessageReceiver(bbbGW);
+		receivers.add(notesRx);
 	}
 	
 	public void handleMessage(String pattern, String channel, String message) {
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/SharedNotesMessageReceiver.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/SharedNotesMessageReceiver.java
new file mode 100644
index 0000000000000000000000000000000000000000..48eaae191f7032fda975a5b45e661e5f07df385f
--- /dev/null
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/SharedNotesMessageReceiver.java
@@ -0,0 +1,101 @@
+
+package org.bigbluebutton.core.pubsub.receivers;
+
+import org.bigbluebutton.common.messages.CreateAdditionalNotesRequestMessage;
+import org.bigbluebutton.common.messages.DestroyAdditionalNotesRequestMessage;
+import org.bigbluebutton.common.messages.GetCurrentDocumentRequestMessage;
+import org.bigbluebutton.common.messages.MessagingConstants;
+import org.bigbluebutton.common.messages.PatchDocumentRequestMessage;
+import org.bigbluebutton.common.messages.RequestAdditionalNotesSetRequestMessage;
+import org.bigbluebutton.common.messages.SharedNotesSyncNoteRequestMessage;
+
+import org.bigbluebutton.core.api.IBigBlueButtonInGW;
+
+import com.google.gson.JsonParser;
+import com.google.gson.JsonObject;
+
+public class SharedNotesMessageReceiver implements MessageHandler {
+
+	private IBigBlueButtonInGW bbbInGW;
+
+	public SharedNotesMessageReceiver(IBigBlueButtonInGW bbbInGW) {
+		this.bbbInGW = bbbInGW;
+	}
+
+	@Override
+	public void handleMessage(String pattern, String channel, String message) {
+		if (channel.equalsIgnoreCase(MessagingConstants.TO_SHAREDNOTES_CHANNEL)) {
+			JsonParser parser = new JsonParser();
+			JsonObject obj = (JsonObject) parser.parse(message);
+			if (obj.has("header") && obj.has("payload")) {
+				JsonObject header = (JsonObject) obj.get("header");
+
+				if (header.has("name")) {
+					String messageName = header.get("name").getAsString();
+					switch (messageName) {
+						case PatchDocumentRequestMessage.PATCH_DOCUMENT_REQUEST:
+							processPatchDocumentRequestMessage(message);
+							break;
+						case GetCurrentDocumentRequestMessage.GET_CURRENT_DOCUMENT_REQUEST:
+							processGetCurrentDocumentRequestMessage(message);
+							break;
+						case CreateAdditionalNotesRequestMessage.CREATE_ADDITIONAL_NOTES_REQUEST:
+							processCreateAdditionalNotesRequestMessage(message);
+							break;
+						case DestroyAdditionalNotesRequestMessage.DESTROY_ADDITIONAL_NOTES_REQUEST:
+							processDestroyAdditionalNotesRequestMessage(message);
+							break;
+						case RequestAdditionalNotesSetRequestMessage.REQUEST_ADDITIONAL_NOTES_SET_REQUEST:
+							processRequestAdditionalNotesSetRequestMessage(message);
+							break;
+						case SharedNotesSyncNoteRequestMessage.SHAREDNOTES_SYNC_NOTE_REQUEST:
+							processSharedNotesSyncNoteRequestMessage(message);
+							break;
+					}
+				}
+			}
+		}
+	}
+
+	private void processPatchDocumentRequestMessage(String json) {
+		PatchDocumentRequestMessage msg = PatchDocumentRequestMessage.fromJson(json);
+		if (msg != null) {
+			bbbInGW.patchDocument(msg.meetingID, msg.requesterID, msg.noteID, msg.patch, msg.operation);
+		}
+	}
+
+	private void processGetCurrentDocumentRequestMessage(String json) {
+		GetCurrentDocumentRequestMessage msg = GetCurrentDocumentRequestMessage.fromJson(json);
+		if (msg != null) {
+			bbbInGW.getCurrentDocument(msg.meetingID, msg.requesterID);
+		}
+	}
+
+	private void processCreateAdditionalNotesRequestMessage(String json) {
+		CreateAdditionalNotesRequestMessage msg = CreateAdditionalNotesRequestMessage.fromJson(json);
+		if (msg != null) {
+			bbbInGW.createAdditionalNotes(msg.meetingID, msg.requesterID, msg.noteName);
+		}
+	}
+
+	private void processDestroyAdditionalNotesRequestMessage(String json) {
+		DestroyAdditionalNotesRequestMessage msg = DestroyAdditionalNotesRequestMessage.fromJson(json);
+		if (msg != null) {
+			bbbInGW.destroyAdditionalNotes(msg.meetingID, msg.requesterID, msg.noteID);
+		}
+	}
+
+	private void processRequestAdditionalNotesSetRequestMessage(String json) {
+		RequestAdditionalNotesSetRequestMessage msg = RequestAdditionalNotesSetRequestMessage.fromJson(json);
+		if (msg != null) {
+			bbbInGW.requestAdditionalNotesSet(msg.meetingID, msg.requesterID, msg.additionalNotesSetSize);
+		}
+	}
+
+	private void processSharedNotesSyncNoteRequestMessage(String json) {
+		SharedNotesSyncNoteRequestMessage msg = SharedNotesSyncNoteRequestMessage.fromJson(json);
+		if (msg != null) {
+			bbbInGW.sharedNotesSyncNoteRequest(msg.meetingID, msg.requesterID, msg.noteID);
+		}
+	}
+}
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/UsersMessageReceiver.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/UsersMessageReceiver.java
index a43ec10c7e3bbd69db0a21cce621b4318ca56a01..c33b6de9fb6849ee59b7919a00771a41c610c6e5 100755
--- a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/UsersMessageReceiver.java
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/pubsub/receivers/UsersMessageReceiver.java
@@ -111,6 +111,21 @@ public class UsersMessageReceiver implements MessageHandler{
 					  case EndAllBreakoutRoomsRequest.NAME:
 						  bbbInGW.handleJsonMessage(message);
 						  break;
+					  case ChangeUserRoleMessage.CHANGE_USER_ROLE:
+						  processChangeUserRoleMessage(message);
+						  break;
+					  case GetGuestPolicyMessage.GET_GUEST_POLICY:
+						  processGetGuestPolicyMessage(message);
+						  break;
+					  case SetGuestPolicyMessage.SET_GUEST_POLICY:
+						  processSetGuestPolicyMessage(message);
+						  break;
+					  case RespondToGuestMessage.RESPOND_TO_GUEST:
+						  processRespondToGuestMessage(message);
+						  break;
+					  case LogoutEndMeetingRequestMessage.LOGOUT_END_MEETING_REQUEST_MESSAGE:
+						  processLogoutEndMeetingRequestMessage(message);
+						  break;
 					}
 				}
 			}
@@ -343,4 +358,39 @@ public class UsersMessageReceiver implements MessageHandler{
 			bbbInGW.ejectUserFromVoice(msg.meetingId, msg.userId, msg.requesterId);
 		}
 	}
+
+	private void processChangeUserRoleMessage(String message) {
+		ChangeUserRoleMessage msg = ChangeUserRoleMessage.fromJson(message);
+		if (msg != null) {
+			bbbInGW.setUserRole(msg.meetingId, msg.userId, msg.role);
+		}
+	}
+
+	private void processGetGuestPolicyMessage(String message) {
+		GetGuestPolicyMessage msg = GetGuestPolicyMessage.fromJson(message);
+		if (msg != null) {
+			bbbInGW.getGuestPolicy(msg.meetingId, msg.requesterId);
+		}
+	}
+
+	private void processSetGuestPolicyMessage(String message) {
+		SetGuestPolicyMessage msg = SetGuestPolicyMessage.fromJson(message);
+		if (msg != null) {
+			bbbInGW.setGuestPolicy(msg.meetingId, msg.guestPolicy, msg.setBy);
+		}
+	}
+
+	private void processRespondToGuestMessage(String message) {
+		RespondToGuestMessage msg = RespondToGuestMessage.fromJson(message);
+		if (msg != null) {
+			bbbInGW.responseToGuest(msg.meetingId, msg.userId, msg.response, msg.requesterId);
+		}
+	}
+
+	private void processLogoutEndMeetingRequestMessage(String message) {
+		LogoutEndMeetingRequestMessage lemm = LogoutEndMeetingRequestMessage.fromJson(message);
+		if (lemm != null) {
+			bbbInGW.logoutEndMeeting(lemm.meetingId, lemm.userId);
+		}
+	}
 }
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/ClearPublicChatRecordEvent.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/ClearPublicChatRecordEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5f23ec784b173c6381aee25e7f2043531e5e8f6
--- /dev/null
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/ClearPublicChatRecordEvent.java
@@ -0,0 +1,27 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.core.recorders.events;
+
+public class ClearPublicChatRecordEvent extends AbstractChatRecordEvent {
+
+	public ClearPublicChatRecordEvent() {
+		super();
+		setEvent("ClearPublicChatEvent");
+	}
+}
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/GuestAskToEnterRecordEvent.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/GuestAskToEnterRecordEvent.java
new file mode 100755
index 0000000000000000000000000000000000000000..ae0911b9c9a338772325f01cb2d8cb3068f0e35b
--- /dev/null
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/GuestAskToEnterRecordEvent.java
@@ -0,0 +1,35 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.core.recorders.events;
+
+public class GuestAskToEnterRecordEvent extends AbstractParticipantRecordEvent {
+
+	public GuestAskToEnterRecordEvent() {
+		super();
+		setEvent("GuestAskToEnterEvent");
+	}
+
+	public void setUserId(String userId) {
+		eventMap.put("userId", userId);
+	}
+
+	public void setName(String name) {
+		eventMap.put("name", name);
+	}
+}
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/GuestPolicyEvent.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/GuestPolicyEvent.java
new file mode 100755
index 0000000000000000000000000000000000000000..649acc7db3d674eb38444a1098601eed6a0576ad
--- /dev/null
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/GuestPolicyEvent.java
@@ -0,0 +1,31 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.core.recorders.events;
+
+public class GuestPolicyEvent extends AbstractParticipantRecordEvent {
+
+	public GuestPolicyEvent() {
+		super();
+		setEvent("GuestPolicyEvent");
+	}
+
+	public void setPolicy(String guestPolicy) {
+		eventMap.put("guestPolicy", guestPolicy);
+	}
+}
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/ModeratorResponseEvent.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/ModeratorResponseEvent.java
new file mode 100755
index 0000000000000000000000000000000000000000..ddd82cd1bbcf28ac497829370aaa6e9a2dc850f6
--- /dev/null
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/ModeratorResponseEvent.java
@@ -0,0 +1,35 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.core.recorders.events;
+
+public class ModeratorResponseEvent extends AbstractParticipantRecordEvent {
+
+	public ModeratorResponseEvent() {
+		super();
+		setEvent("ModeratorResponseEvent");
+	}
+
+	public void setUserId(String userId) {
+		eventMap.put("userId", userId);
+	}
+
+	public void setResp(Boolean resp) {
+		eventMap.put("resp", resp.toString());
+	}
+}
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/ParticipantRoleChangeRecordEvent.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/ParticipantRoleChangeRecordEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a7ac21ea9d0180cd7904e178eac5b0cdbd19b65
--- /dev/null
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/ParticipantRoleChangeRecordEvent.java
@@ -0,0 +1,35 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.core.recorders.events;
+
+public class ParticipantRoleChangeRecordEvent extends AbstractParticipantRecordEvent {
+
+	public ParticipantRoleChangeRecordEvent() {
+		super();
+		setEvent("ParticipantRoleChangeEvent");
+	}
+
+	public void setUserId(String userId) {
+		eventMap.put("userId", userId);
+	}
+
+	public void setRole(String role) {
+		eventMap.put("role", role);
+	}
+}
diff --git a/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/WaitingForModeratorEvent.java b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/WaitingForModeratorEvent.java
new file mode 100755
index 0000000000000000000000000000000000000000..d195e8ecf0148955d80539950c78b9027361b037
--- /dev/null
+++ b/akka-bbb-apps/src/main/java/org/bigbluebutton/core/recorders/events/WaitingForModeratorEvent.java
@@ -0,0 +1,35 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.core.recorders.events;
+
+public class WaitingForModeratorEvent extends AbstractParticipantRecordEvent {
+
+	public WaitingForModeratorEvent() {
+		super();
+		setEvent("WaitingForModeratorEvent");
+	}
+
+	public void setUserId(String userId) {
+		eventMap.put("userId", userId);
+	}
+
+	public void setArg(String arg) {
+		eventMap.put("userId_userName", arg);
+	}
+}
diff --git a/akka-bbb-apps/src/main/resources/application.conf b/akka-bbb-apps/src/main/resources/application.conf
index 2d7ca78d6068ae4cde42d5404b2f41141f17064f..7f042e21e13c44fb5d89393a6e180e7ec81e771c 100755
--- a/akka-bbb-apps/src/main/resources/application.conf
+++ b/akka-bbb-apps/src/main/resources/application.conf
@@ -40,6 +40,13 @@ http {
   port = 9000
 }
 
+inactivity {
+    # time in seconds
+    deadline=7200
+    # inactivity warning message
+    timeLeft=300
+}
+
 services {
   bbbWebAPI = "http://192.168.23.33/bigbluebutton/api"
   sharedSecret = "changeme"
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala
index 83d3b7cceebc5f0566a84fab8c9c7e52b41cbcf8..4ceeaadec064bdd9ae98088f886504e97fa9a688 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/SystemConfiguration.scala
@@ -21,4 +21,7 @@ trait SystemConfiguration {
   lazy val keysExpiresInSec = Try(config.getInt("redis.keyExpiry")).getOrElse(14 * 86400) // 14 days
   lazy val red5DeskShareIP = Try(config.getString("red5.deskshareip")).getOrElse("127.0.0.1")
   lazy val red5DeskShareApp = Try(config.getString("red5.deskshareapp")).getOrElse("")
+
+  lazy val inactivityDeadline = Try(config.getInt("inactivity.deadline")).getOrElse(2 * 3600) // 2 hours
+  lazy val inactivityTimeLeft = Try(config.getInt("inactivity.timeLeft")).getOrElse(5 * 60) // 5 minutes
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala
index f7412ebe32f966fba68c2cb83e0b806ec7ecdff4..00978a4048ec9db44af14b16f688fa53d64e2490 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonActor.scala
@@ -2,8 +2,10 @@ package org.bigbluebutton.core
 
 import akka.actor._
 import akka.actor.ActorLogging
+import akka.actor.SupervisorStrategy.Resume
 import akka.pattern.{ ask, pipe }
 import akka.util.Timeout
+import java.io.{ PrintWriter, StringWriter }
 import scala.concurrent.duration._
 import org.bigbluebutton.core.bus._
 import org.bigbluebutton.core.api._
@@ -26,6 +28,16 @@ class BigBlueButtonActor(val system: ActorSystem,
 
   private var meetings = new collection.immutable.HashMap[String, RunningMeeting]
 
+  override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
+    case e: Exception => {
+      val sw: StringWriter = new StringWriter()
+      sw.write("An exception has been thrown on BigBlueButtonActor, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+      e.printStackTrace(new PrintWriter(sw))
+      log.error(sw.toString())
+      Resume
+    }
+  }
+
   def receive = {
     case msg: CreateMeeting => handleCreateMeeting(msg)
     case msg: DestroyMeeting => handleDestroyMeeting(msg)
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala
index 7989bf5c84dc8ddb22197f6d6cc0852fade7ce81..0df8cb779169d822896259304e031a5be312bfdf 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/BigBlueButtonInGW.scala
@@ -71,7 +71,8 @@ class BigBlueButtonInGW(
           msg.payload.createDate,
           red5DeskShareIP, red5DeskShareApp,
           msg.payload.isBreakout,
-          msg.payload.sequence)
+          msg.payload.sequence,
+          msg.payload.metadata)
 
         eventBus.publish(BigBlueButtonEvent("meeting-manager", new CreateMeeting(msg.payload.id, mProps)))
       }
@@ -129,6 +130,10 @@ class BigBlueButtonInGW(
 
   }
 
+  def activityResponse(meetingId: String) {
+    eventBus.publish(BigBlueButtonEvent(meetingId, new ActivityResponse(meetingId)))
+  }
+
   /**
    * ***********************************************************
    * Message Interface for Users
@@ -138,9 +143,9 @@ class BigBlueButtonInGW(
     eventBus.publish(BigBlueButtonEvent(meetingId, new ValidateAuthToken(meetingId, userId, token, correlationId, sessionId)))
   }
 
-  def registerUser(meetingID: String, userID: String, name: String, role: String, extUserID: String, authToken: String, avatarURL: String): Unit = {
+  def registerUser(meetingID: String, userID: String, name: String, role: String, extUserID: String, authToken: String, avatarURL: String, guest: java.lang.Boolean): Unit = {
     val userRole = if (role == "MODERATOR") Role.MODERATOR else Role.VIEWER
-    eventBus.publish(BigBlueButtonEvent(meetingID, new RegisterUser(meetingID, userID, name, userRole, extUserID, authToken, avatarURL)))
+    eventBus.publish(BigBlueButtonEvent(meetingID, new RegisterUser(meetingID, userID, name, userRole, extUserID, authToken, avatarURL, guest)))
   }
 
   def sendLockSettings(meetingID: String, userId: String, settings: java.util.Map[String, java.lang.Boolean]) {
@@ -221,6 +226,10 @@ class BigBlueButtonInGW(
     eventBus.publish(BigBlueButtonEvent(meetingId, new EjectUserFromMeeting(meetingId, userId, ejectedBy)))
   }
 
+  def logoutEndMeeting(meetingId: String, userId: String) {
+    eventBus.publish(BigBlueButtonEvent(meetingId, new LogoutEndMeeting(meetingId, userId)))
+  }
+
   def shareWebcam(meetingId: String, userId: String, stream: String) {
     eventBus.publish(BigBlueButtonEvent(meetingId, new UserShareWebcam(meetingId, userId, stream)))
   }
@@ -233,6 +242,11 @@ class BigBlueButtonInGW(
     eventBus.publish(BigBlueButtonEvent(meetingID, new ChangeUserStatus(meetingID, userID, status, value)))
   }
 
+  def setUserRole(meetingID: String, userID: String, role: String) {
+    val userRole = if (role == "MODERATOR") Role.MODERATOR else Role.VIEWER
+    eventBus.publish(BigBlueButtonEvent(meetingID, new ChangeUserRole(meetingID, userID, userRole)))
+  }
+
   def getUsers(meetingID: String, requesterID: String) {
     eventBus.publish(BigBlueButtonEvent(meetingID, new GetUsers(meetingID, requesterID)))
   }
@@ -270,6 +284,31 @@ class BigBlueButtonInGW(
     eventBus.publish(BigBlueButtonEvent(voiceConf, new UserDisconnectedFromGlobalAudio(voiceConf, voiceConf, userid, name)))
   }
 
+  /**
+   * ***********************************************************************
+   * Message Interface for Guest
+   * *******************************************************************
+   */
+
+  def getGuestPolicy(meetingId: String, requesterId: String) {
+    eventBus.publish(BigBlueButtonEvent(meetingId, new GetGuestPolicy(meetingId, requesterId)))
+  }
+
+  def setGuestPolicy(meetingId: String, guestPolicy: String, requesterId: String) {
+    val policy = guestPolicy.toUpperCase() match {
+      case "ALWAYS_ACCEPT" => GuestPolicy.ALWAYS_ACCEPT
+      case "ALWAYS_DENY" => GuestPolicy.ALWAYS_DENY
+      case "ASK_MODERATOR" => GuestPolicy.ASK_MODERATOR
+      //default
+      case undef => GuestPolicy.ASK_MODERATOR
+    }
+    eventBus.publish(BigBlueButtonEvent(meetingId, new SetGuestPolicy(meetingId, policy, requesterId)))
+  }
+
+  def responseToGuest(meetingId: String, userId: String, response: java.lang.Boolean, requesterId: String) {
+    eventBus.publish(BigBlueButtonEvent(meetingId, new RespondToGuest(meetingId, userId, response, requesterId)))
+  }
+
   /**
    * ************************************************************************************
    * Message Interface for Presentation
@@ -314,10 +353,10 @@ class BigBlueButtonInGW(
     pages
   }
 
-  def sendConversionCompleted(messageKey: String, meetingId: String, code: String, presentationId: String, numPages: Int, presName: String, presBaseUrl: String) {
+  def sendConversionCompleted(messageKey: String, meetingId: String, code: String, presentationId: String, numPages: Int, presName: String, presBaseUrl: String, downloadable: Boolean) {
 
     val pages = generatePresentationPages(presentationId, numPages, presBaseUrl)
-    val presentation = new Presentation(id = presentationId, name = presName, pages = pages)
+    val presentation = new Presentation(id = presentationId, name = presName, pages = pages, downloadable = downloadable)
     eventBus.publish(BigBlueButtonEvent(meetingId, new PresentationConversionCompleted(meetingId, messageKey, code, presentation)))
 
   }
@@ -393,6 +432,10 @@ class BigBlueButtonInGW(
     eventBus.publish(BigBlueButtonEvent(meetingID, new SendPrivateMessageRequest(meetingID, requesterID, mapAsScalaMap(message).toMap)))
   }
 
+  def clearPublicChatHistory(meetingID: String, requesterID: String) {
+    eventBus.publish(BigBlueButtonEvent(meetingID, new ClearPublicChatHistoryRequest(meetingID, requesterID)))
+  }
+
   /**
    * *******************************************************************
    * Message Interface for Whiteboard
@@ -567,4 +610,40 @@ class BigBlueButtonInGW(
   def editCaptionHistory(meetingID: String, userID: String, startIndex: Integer, endIndex: Integer, locale: String, localeCode: String, text: String) {
     eventBus.publish(BigBlueButtonEvent(meetingID, new EditCaptionHistoryRequest(meetingID, userID, startIndex, endIndex, locale, localeCode, text)))
   }
+
+  /**
+   * *******************************************************************
+   * Message Interface for Shared Notes
+   * *****************************************************************
+   */
+
+  def patchDocument(meetingId: String, userId: String, noteId: String, patch: String, operation: String) {
+    val sharedNotesOperation = operation.toUpperCase() match {
+      case "PATCH" => SharedNotesOperation.PATCH
+      case "UNDO" => SharedNotesOperation.UNDO
+      case "REDO" => SharedNotesOperation.REDO
+      case _ => SharedNotesOperation.UNDEFINED
+    }
+    eventBus.publish(BigBlueButtonEvent(meetingId, new PatchDocumentRequest(meetingId, userId, noteId, patch, sharedNotesOperation)))
+  }
+
+  def getCurrentDocument(meetingId: String, userId: String) {
+    eventBus.publish(BigBlueButtonEvent(meetingId, new GetCurrentDocumentRequest(meetingId, userId)))
+  }
+
+  def createAdditionalNotes(meetingId: String, userId: String, noteName: String) {
+    eventBus.publish(BigBlueButtonEvent(meetingId, new CreateAdditionalNotesRequest(meetingId, userId, noteName)))
+  }
+
+  def destroyAdditionalNotes(meetingId: String, userId: String, noteId: String) {
+    eventBus.publish(BigBlueButtonEvent(meetingId, new DestroyAdditionalNotesRequest(meetingId, userId, noteId)))
+  }
+
+  def requestAdditionalNotesSet(meetingId: String, userId: String, additionalNotesSetSize: Int) {
+    eventBus.publish(BigBlueButtonEvent(meetingId, new RequestAdditionalNotesSetRequest(meetingId, userId, additionalNotesSetSize)))
+  }
+
+  def sharedNotesSyncNoteRequest(meetingId: String, userId: String, noteId: String) {
+    eventBus.publish(BigBlueButtonEvent(meetingId, new SharedNotesSyncNoteRequest(meetingId, userId, noteId)))
+  }
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/LiveMeeting.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/LiveMeeting.scala
index 419d910b160e63c188d1467fd4dcca162e22c7c1..c6a13c137c45ab2259e3d317be1592ba45486eaf 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/LiveMeeting.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/LiveMeeting.scala
@@ -22,10 +22,11 @@ class LiveMeeting(val mProps: MeetingProperties,
   val wbModel: WhiteboardModel,
   val presModel: PresentationModel,
   val breakoutModel: BreakoutRoomModel,
-  val captionModel: CaptionModel)(implicit val context: ActorContext)
+  val captionModel: CaptionModel,
+  val notesModel: SharedNotesModel)(implicit val context: ActorContext)
     extends UsersApp with PresentationApp
     with LayoutApp with ChatApp with WhiteboardApp with PollApp
-    with BreakoutRoomApp with CaptionApp {
+    with BreakoutRoomApp with CaptionApp with SharedNotesApp {
 
   val log = Logging(context.system, getClass)
 
@@ -246,4 +247,24 @@ class LiveMeeting(val mProps: MeetingProperties,
     }
   }
 
+  def handleGetGuestPolicy(msg: GetGuestPolicy) {
+    outGW.send(new GetGuestPolicyReply(msg.meetingID, mProps.recorded, msg.requesterID, meetingModel.getGuestPolicy().toString()))
+  }
+
+  def handleSetGuestPolicy(msg: SetGuestPolicy) {
+    meetingModel.setGuestPolicy(msg.policy)
+    meetingModel.setGuestPolicySetBy(msg.setBy)
+    outGW.send(new GuestPolicyChanged(msg.meetingID, mProps.recorded, meetingModel.getGuestPolicy().toString()))
+  }
+
+  def handleLogoutEndMeeting(msg: LogoutEndMeeting) {
+    if (usersModel.isModerator(msg.userID)) {
+      handleEndMeeting(EndMeeting(mProps.meetingID))
+    }
+  }
+
+  def handleActivityResponse(msg: ActivityResponse) {
+    log.info("User endorsed that meeting {} is active", mProps.meetingID)
+    outGW.send(new MeetingIsActive(mProps.meetingID))
+  }
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala
index 833feb3afe2ae7a518f7e7b217b5268a04e8be9c..e29ed0d3d8f5b1676b40d72c535ef8658676d40d 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingActor.scala
@@ -4,13 +4,17 @@ import akka.actor.Actor
 import akka.actor.ActorRef
 import akka.actor.ActorLogging
 import akka.actor.Props
+import akka.actor.OneForOneStrategy
+import akka.actor.SupervisorStrategy.Resume
+import java.io.{ PrintWriter, StringWriter }
+import org.bigbluebutton.SystemConfiguration
 import org.bigbluebutton.core.bus._
 import org.bigbluebutton.core.api._
 import java.util.concurrent.TimeUnit
 import org.bigbluebutton.core.util._
 import scala.concurrent.duration._
-import org.bigbluebutton.core.apps.{ PollApp, UsersApp, PresentationApp, LayoutApp, ChatApp, WhiteboardApp, CaptionApp }
-import org.bigbluebutton.core.apps.{ ChatModel, LayoutModel, UsersModel, PollModel, WhiteboardModel, CaptionModel }
+import org.bigbluebutton.core.apps.{ PollApp, UsersApp, PresentationApp, LayoutApp, ChatApp, WhiteboardApp, CaptionApp, SharedNotesApp }
+import org.bigbluebutton.core.apps.{ ChatModel, LayoutModel, UsersModel, PollModel, WhiteboardModel, CaptionModel, SharedNotesModel }
 import org.bigbluebutton.core.apps.PresentationModel
 import org.bigbluebutton.core.apps.BreakoutRoomApp
 import org.bigbluebutton.core.apps.BreakoutRoomModel
@@ -26,10 +30,44 @@ object MeetingActorInternal {
 // periodically sends messages to the meeting actor
 class MeetingActorInternal(val mProps: MeetingProperties,
   val eventBus: IncomingEventBus, val outGW: OutMessageGateway)
-    extends Actor with ActorLogging {
+    extends Actor with ActorLogging with SystemConfiguration {
+
+  override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
+    case e: Exception => {
+      val sw: StringWriter = new StringWriter()
+      sw.write("An exception has been thrown on MeetingActorInternal, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+      e.printStackTrace(new PrintWriter(sw))
+      log.error(sw.toString())
+      Resume
+    }
+  }
+
+  private def getInactivityDeadline(): Int = {
+    val time = getMetadata(Metadata.INACTIVITY_DEADLINE, mProps.metadata) match {
+      case Some(result) => result.asInstanceOf[Int]
+      case None => inactivityDeadline
+    }
+    log.debug("InactivityDeadline: {} seconds", time)
+    time
+  }
+
+  private def getInactivityTimeLeft(): Int = {
+    val time = getMetadata(Metadata.INACTIVITY_TIMELEFT, mProps.metadata) match {
+      case Some(result) => result.asInstanceOf[Int]
+      case None => inactivityTimeLeft
+    }
+    log.debug("InactivityTimeLeft: {} seconds", time)
+    time
+  }
+
+  private val InactivityDeadline = FiniteDuration(getInactivityDeadline(), "seconds")
+  private val InactivityTimeLeft = FiniteDuration(getInactivityTimeLeft(), "seconds")
+  private val MonitorFrequency = 10 seconds
+  private var deadline = InactivityDeadline.fromNow
+  private var inactivityWarning: Deadline = null
 
   import context.dispatcher
-  context.system.scheduler.schedule(5 seconds, 10 seconds, self, "MonitorNumberOfWebUsers")
+  context.system.scheduler.schedule(5 seconds, MonitorFrequency, self, "Monitor")
 
   // Query to get voice conference users
   outGW.send(new GetUsersInVoiceConference(mProps.meetingID, mProps.recorded, mProps.voiceBridge))
@@ -42,7 +80,19 @@ class MeetingActorInternal(val mProps: MeetingProperties,
   }
 
   def receive = {
-    case "MonitorNumberOfWebUsers" => handleMonitorNumberOfWebUsers()
+    case "Monitor" => handleMonitor()
+    case msg: Object => handleMessage(msg)
+  }
+
+  def handleMonitor() {
+    handleMonitorActivity()
+    handleMonitorNumberOfWebUsers()
+  }
+
+  def handleMessage(msg: Object) {
+    if (isMeetingActivity(msg)) {
+      notifyActivity()
+    }
   }
 
   def handleMonitorNumberOfWebUsers() {
@@ -57,6 +107,105 @@ class MeetingActorInternal(val mProps: MeetingProperties,
     }
 
   }
+
+  private def handleMonitorActivity() {
+    if (deadline.isOverdue() && inactivityWarning != null && inactivityWarning.isOverdue()) {
+      log.info("Closing meeting {} due to inactivity for {} seconds", mProps.meetingID, InactivityDeadline.toSeconds)
+      updateInactivityMonitors()
+      eventBus.publish(BigBlueButtonEvent(mProps.meetingID, EndMeeting(mProps.meetingID)))
+      // Or else make sure to send only one warning message
+    } else if (deadline.isOverdue() && inactivityWarning == null) {
+      log.info("Sending inactivity warning to meeting {}", mProps.meetingID)
+      outGW.send(new InactivityWarning(mProps.meetingID, InactivityTimeLeft.toSeconds))
+      // We add 5 seconds so clients will have enough time to process the message
+      inactivityWarning = (InactivityTimeLeft + (5 seconds)).fromNow
+    }
+  }
+
+  private def updateInactivityMonitors() {
+    deadline = InactivityDeadline.fromNow
+    inactivityWarning = null
+  }
+
+  private def notifyActivity() {
+    if (inactivityWarning != null) {
+      outGW.send(new MeetingIsActive(mProps.meetingID))
+    }
+
+    updateInactivityMonitors()
+  }
+
+  private def handleActivityResponse(msg: ActivityResponse) {
+    log.info("User endorsed that meeting {} is active", mProps.meetingID)
+    updateInactivityMonitors()
+    outGW.send(new MeetingIsActive(mProps.meetingID))
+  }
+
+  private def isMeetingActivity(msg: Object): Boolean = {
+    // We need to avoid all internal system's messages
+    msg match {
+      case msg: MonitorNumberOfUsers => false
+      case msg: SendTimeRemainingUpdate => false
+      case msg: SendBreakoutUsersUpdate => false
+      case msg: BreakoutRoomCreated => false
+      case _ => true
+    }
+  }
+
+  def getMetadata(key: String, metadata: java.util.Map[String, String]): Option[Object] = {
+    var value: Option[String] = None
+    if (metadata.containsKey(key)) {
+      value = Some(metadata.get(key))
+    }
+
+    value match {
+      case Some(v) => {
+        key match {
+          case Metadata.INACTIVITY_DEADLINE => {
+            // Can be defined between 1 minute to 6 hours
+            metadataIntegerValueOf(v, 60, 21600) match {
+              case Some(r) => Some(r.asInstanceOf[Object])
+              case None => None
+            }
+          }
+          case Metadata.INACTIVITY_TIMELEFT => {
+            // Can be defined between 30 seconds to 30 minutes
+            metadataIntegerValueOf(v, 30, 1800) match {
+              case Some(r) => Some(r.asInstanceOf[Object])
+              case None => None
+            }
+          }
+          case _ => None
+        }
+      }
+      case None => None
+    }
+  }
+
+  private def metadataIntegerValueOf(value: String, lowerBound: Int, upperBound: Int): Option[Int] = {
+    stringToInt(value) match {
+      case Some(r) => {
+        if (lowerBound <= r && r <= upperBound) {
+          Some(r)
+        } else {
+          None
+        }
+      }
+      case None => None
+    }
+  }
+
+  private def stringToInt(value: String): Option[Int] = {
+    var result: Option[Int] = None
+    try {
+      result = Some(Integer.parseInt(value))
+    } catch {
+      case e: Exception => {
+        result = None
+      }
+    }
+    result
+  }
 }
 
 object MeetingActor {
@@ -71,6 +220,16 @@ class MeetingActor(val mProps: MeetingProperties,
   val outGW: OutMessageGateway)
     extends Actor with ActorLogging {
 
+  override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
+    case e: Exception => {
+      val sw: StringWriter = new StringWriter()
+      sw.write("An exception has been thrown on MeetingActor, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+      e.printStackTrace(new PrintWriter(sw))
+      log.error(sw.toString())
+      Resume
+    }
+  }
+
   val chatModel = new ChatModel()
   val layoutModel = new LayoutModel()
   val meetingModel = new MeetingModel()
@@ -80,20 +239,27 @@ class MeetingActor(val mProps: MeetingProperties,
   val presModel = new PresentationModel()
   val breakoutModel = new BreakoutRoomModel()
   val captionModel = new CaptionModel()
+  val notesModel = new SharedNotesModel()
 
   // We extract the meeting handlers into this class so it is
   // easy to test.
   val liveMeeting = new LiveMeeting(mProps, eventBus, outGW,
     chatModel, layoutModel, meetingModel, usersModel, pollModel,
-    wbModel, presModel, breakoutModel, captionModel)
+    wbModel, presModel, breakoutModel, captionModel, notesModel)
 
   /**
    * Put the internal message injector into another actor so this
    * actor is easy to test.
    */
-  var actorMonitor = context.actorOf(MeetingActorInternal.props(mProps, eventBus, outGW))
+  var actorMonitor = context.actorOf(MeetingActorInternal.props(mProps, eventBus, outGW), "actorMonitor-" + mProps.meetingID)
+
+  /** Subscribe to meeting and voice events. **/
+  eventBus.subscribe(actorMonitor, mProps.meetingID)
+  eventBus.subscribe(actorMonitor, mProps.voiceBridge)
+  eventBus.subscribe(actorMonitor, mProps.deskshareBridge)
 
   def receive = {
+    case msg: ActivityResponse => liveMeeting.handleActivityResponse(msg)
     case msg: MonitorNumberOfUsers => liveMeeting.handleMonitorNumberOfWebUsers(msg)
     case msg: ValidateAuthToken => liveMeeting.handleValidateAuthToken(msg)
     case msg: RegisterUser => liveMeeting.handleRegisterUser(msg)
@@ -160,6 +326,10 @@ class MeetingActor(val mProps: MeetingProperties,
     case msg: RespondToPollRequest => liveMeeting.handleRespondToPollRequest(msg)
     case msg: GetPollRequest => liveMeeting.handleGetPollRequest(msg)
     case msg: GetCurrentPollRequest => liveMeeting.handleGetCurrentPollRequest(msg)
+    case msg: ChangeUserRole => liveMeeting.handleChangeUserRole(msg)
+    case msg: LogoutEndMeeting => liveMeeting.handleLogoutEndMeeting(msg)
+    case msg: ClearPublicChatHistoryRequest => liveMeeting.handleClearPublicChatHistoryRequest(msg)
+
     // Breakout rooms
     case msg: BreakoutRoomsListMessage => liveMeeting.handleBreakoutRoomsList(msg)
     case msg: CreateBreakoutRooms => liveMeeting.handleCreateBreakoutRooms(msg)
@@ -185,6 +355,19 @@ class MeetingActor(val mProps: MeetingProperties,
     case msg: DeskShareRTMPBroadcastStoppedRequest => liveMeeting.handleDeskShareRTMPBroadcastStoppedRequest(msg)
     case msg: DeskShareGetDeskShareInfoRequest => liveMeeting.handleDeskShareGetDeskShareInfoRequest(msg)
 
+    // Guest
+    case msg: GetGuestPolicy => liveMeeting.handleGetGuestPolicy(msg)
+    case msg: SetGuestPolicy => liveMeeting.handleSetGuestPolicy(msg)
+    case msg: RespondToGuest => liveMeeting.handleRespondToGuest(msg)
+
+    // Shared Notes
+    case msg: PatchDocumentRequest => liveMeeting.handlePatchDocumentRequest(msg)
+    case msg: GetCurrentDocumentRequest => liveMeeting.handleGetCurrentDocumentRequest(msg)
+    case msg: CreateAdditionalNotesRequest => liveMeeting.handleCreateAdditionalNotesRequest(msg)
+    case msg: DestroyAdditionalNotesRequest => liveMeeting.handleDestroyAdditionalNotesRequest(msg)
+    case msg: RequestAdditionalNotesSetRequest => liveMeeting.handleRequestAdditionalNotesSetRequest(msg)
+    case msg: SharedNotesSyncNoteRequest => liveMeeting.handleSharedNotesSyncNoteRequest(msg)
+
     case _ => // do nothing
   }
 
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingModel.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingModel.scala
index 6001330ab8dbeee650540af5ec5ac483a12dfdec..5afdc85a61d922c23c8b5212684cb4483031ac09 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingModel.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MeetingModel.scala
@@ -1,5 +1,7 @@
 package org.bigbluebutton.core
 
+import org.bigbluebutton.core.api.GuestPolicy
+import org.bigbluebutton.core.api.Metadata
 import org.bigbluebutton.core.api.Permissions
 import java.util.concurrent.TimeUnit
 
@@ -8,7 +10,7 @@ case class MeetingProperties(meetingID: String, externalMeetingID: String, paren
   recorded: Boolean, voiceBridge: String, deskshareBridge: String, duration: Int,
   autoStartRecording: Boolean, allowStartStopRecording: Boolean, moderatorPass: String,
   viewerPass: String, createTime: Long, createDate: String,
-  red5DeskShareIP: String, red5DeskShareApp: String, isBreakout: Boolean, sequence: Int)
+  red5DeskShareIP: String, red5DeskShareApp: String, isBreakout: Boolean, sequence: Int, metadata: java.util.Map[String, String])
 
 case class MeetingExtensionProp(maxExtensions: Int = 2, numExtensions: Int = 0, extendByMinutes: Int = 20,
   sendNotice: Boolean = true, sent15MinNotice: Boolean = false,
@@ -23,6 +25,8 @@ class MeetingModel {
   private var muted = false;
   private var meetingEnded = false
   private var meetingMuted = false
+  private var guestPolicy = GuestPolicy.ASK_MODERATOR
+  private var guestPolicySetBy: String = null
 
   private var hasLastWebUserLeft = false
   private var lastWebUserLeftOnTimestamp: Long = 0
@@ -130,4 +134,8 @@ class MeetingModel {
   def hasMeetingEnded(): Boolean = meetingEnded
   def timeNowInMinutes(): Long = TimeUnit.NANOSECONDS.toMinutes(System.nanoTime())
   def timeNowInSeconds(): Long = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime())
+  def getGuestPolicy(): GuestPolicy.GuestPolicy = guestPolicy
+  def setGuestPolicy(policy: GuestPolicy.GuestPolicy) = guestPolicy = policy
+  def getGuestPolicySetBy(): String = guestPolicySetBy
+  def setGuestPolicySetBy(user: String) = guestPolicySetBy = user
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MessageSenderActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MessageSenderActor.scala
index 6324ca571df3412e3366e56e75daa8d4e2c80988..03cd897d242afe14a0ecad6742b4705656bf7687 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MessageSenderActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/MessageSenderActor.scala
@@ -4,6 +4,9 @@ import akka.actor.Actor
 import akka.actor.ActorRef
 import akka.actor.ActorLogging
 import akka.actor.Props
+import akka.actor.OneForOneStrategy
+import akka.actor.SupervisorStrategy.Resume
+import java.io.{ PrintWriter, StringWriter }
 import org.bigbluebutton.core.api._
 import org.bigbluebutton.common.messages.MessagingConstants
 import org.bigbluebutton.core.pubsub.senders.ChatMessageToJsonConverter
@@ -20,8 +23,10 @@ import org.bigbluebutton.core.apps.Page
 
 import collection.JavaConverters._
 import scala.collection.JavaConversions._
+import scala.concurrent.duration._
 import org.bigbluebutton.core.apps.SimplePollResultOutVO
 import org.bigbluebutton.core.apps.SimplePollOutVO
+import org.bigbluebutton.core.pubsub.senders.SharedNotesMessageToJsonConverter
 import org.bigbluebutton.core.pubsub.senders.UsersMessageToJsonConverter
 import org.bigbluebutton.common.messages.GetUsersFromVoiceConfRequestMessage
 import org.bigbluebutton.common.messages.MuteUserInVoiceConfRequestMessage
@@ -43,12 +48,23 @@ object MessageSenderActor {
 class MessageSenderActor(val service: MessageSender)
     extends Actor with ActorLogging {
 
+  override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
+    case e: Exception => {
+      val sw: StringWriter = new StringWriter()
+      sw.write("An exception has been thrown on MessageSenderActor, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+      e.printStackTrace(new PrintWriter(sw))
+      log.error(sw.toString())
+      Resume
+    }
+  }
+
   val encoder = new ToJsonEncoder()
   def receive = {
     case msg: UserEjectedFromMeeting => handleUserEjectedFromMeeting(msg)
     case msg: GetChatHistoryReply => handleGetChatHistoryReply(msg)
     case msg: SendPublicMessageEvent => handleSendPublicMessageEvent(msg)
     case msg: SendPrivateMessageEvent => handleSendPrivateMessageEvent(msg)
+    case msg: ClearPublicChatHistoryReply => handleClearPublicChatHistoryReply(msg)
     case msg: MeetingCreated => handleMeetingCreated(msg)
     case msg: VoiceRecordingStarted => handleVoiceRecordingStarted(msg)
     case msg: VoiceRecordingStopped => handleVoiceRecordingStopped(msg)
@@ -60,6 +76,8 @@ class MessageSenderActor(val service: MessageSender)
     case msg: MeetingDestroyed => handleMeetingDestroyed(msg)
     case msg: KeepAliveMessageReply => handleKeepAliveMessageReply(msg)
     case msg: PubSubPong => handlePubSubPong(msg)
+    case msg: InactivityWarning => handleInactivityWarning(msg)
+    case msg: MeetingIsActive => handleMeetingIsActive(msg)
     case msg: StartRecording => handleStartRecording(msg)
     case msg: StopRecording => handleStopRecording(msg)
     case msg: GetAllMeetingsReply => handleGetAllMeetingsReply(msg)
@@ -103,6 +121,7 @@ class MessageSenderActor(val service: MessageSender)
     case msg: UserSharedWebcam => handleUserSharedWebcam(msg)
     case msg: UserUnsharedWebcam => handleUserUnsharedWebcam(msg)
     case msg: UserStatusChange => handleUserStatusChange(msg)
+    case msg: UserRoleChange => handleUserRoleChange(msg)
     case msg: UserVoiceMuted => handleUserVoiceMuted(msg)
     case msg: UserVoiceTalking => handleUserVoiceTalking(msg)
     case msg: MuteVoiceUser => handleMuteVoiceUser(msg)
@@ -139,6 +158,14 @@ class MessageSenderActor(val service: MessageSender)
     case msg: DeskShareNotifyViewersRTMP => handleDeskShareNotifyViewersRTMP(msg)
     case msg: DeskShareNotifyASingleViewer => handleDeskShareNotifyASingleViewer(msg)
     case msg: DeskShareHangUp => handleDeskShareHangUp(msg)
+    case msg: GetGuestPolicyReply => handleGetGuestPolicyReply(msg)
+    case msg: GuestPolicyChanged => handleGuestPolicyChanged(msg)
+    case msg: GuestAccessDenied => handleGuestAccessDenied(msg)
+    case msg: PatchDocumentReply => handlePatchDocumentReply(msg)
+    case msg: GetCurrentDocumentReply => handleGetCurrentDocumentReply(msg)
+    case msg: CreateAdditionalNotesReply => handleCreateAdditionalNotesReply(msg)
+    case msg: DestroyAdditionalNotesReply => handleDestroyAdditionalNotesReply(msg)
+    case msg: SharedNotesSyncNoteReply => handleSharedNotesSyncNoteReply(msg)
     case _ => // do nothing
   }
 
@@ -187,6 +214,11 @@ class MessageSenderActor(val service: MessageSender)
     service.send(MessagingConstants.FROM_CHAT_CHANNEL, json)
   }
 
+  private def handleClearPublicChatHistoryReply(msg: ClearPublicChatHistoryReply) {
+    val json = ChatMessageToJsonConverter.clearPublicChatHistoryReplyToJson(msg)
+    service.send(MessagingConstants.FROM_CHAT_CHANNEL, json)
+  }
+
   private def handleStartRecordingVoiceConf(msg: StartRecordingVoiceConf) {
     val m = new StartRecordingVoiceConfRequestMessage(msg.meetingID, msg.voiceConfId)
     service.send(MessagingConstants.TO_VOICE_CONF_SYSTEM_CHAN, m.toJson())
@@ -279,6 +311,16 @@ class MessageSenderActor(val service: MessageSender)
     service.send(MessagingConstants.FROM_MEETING_CHANNEL, json)
   }
 
+  private def handleInactivityWarning(msg: InactivityWarning) {
+    val json = MeetingMessageToJsonConverter.inactivityWarningToJson(msg)
+    service.send(MessagingConstants.FROM_MEETING_CHANNEL, json)
+  }
+
+  private def handleMeetingIsActive(msg: MeetingIsActive) {
+    val json = MeetingMessageToJsonConverter.meetingIsActiveToJson(msg)
+    service.send(MessagingConstants.FROM_MEETING_CHANNEL, json)
+  }
+
   private def pageToMap(page: Page): java.util.Map[String, Any] = {
     val res = new scala.collection.mutable.HashMap[String, Any]
     res += "id" -> page.id
@@ -582,6 +624,11 @@ class MessageSenderActor(val service: MessageSender)
     service.send(MessagingConstants.FROM_USERS_CHANNEL, json)
   }
 
+  private def handleUserRoleChange(msg: UserRoleChange) {
+    val json = UsersMessageToJsonConverter.userRoleChangeToJson(msg)
+    service.send(MessagingConstants.FROM_USERS_CHANNEL, json)
+  }
+
   private def handleChangedUserEmojiStatus(msg: UserChangedEmojiStatus) {
     val json = UsersMessageToJsonConverter.userChangedEmojiStatusToJson(msg)
     service.send(MessagingConstants.FROM_USERS_CHANNEL, json)
@@ -772,4 +819,44 @@ class MessageSenderActor(val service: MessageSender)
     val json = MeetingMessageToJsonConverter.breakoutRoomsTimeRemainingUpdateToJson(msg)
     service.send(MessagingConstants.FROM_USERS_CHANNEL, json)
   }
+
+  private def handleGetGuestPolicyReply(msg: GetGuestPolicyReply) {
+    val json = UsersMessageToJsonConverter.getGuestPolicyReplyToJson(msg)
+    service.send(MessagingConstants.FROM_USERS_CHANNEL, json)
+  }
+
+  private def handleGuestPolicyChanged(msg: GuestPolicyChanged) {
+    val json = UsersMessageToJsonConverter.guestPolicyChangedToJson(msg)
+    service.send(MessagingConstants.FROM_USERS_CHANNEL, json)
+  }
+
+  private def handleGuestAccessDenied(msg: GuestAccessDenied) {
+    val json = UsersMessageToJsonConverter.guestAccessDeniedToJson(msg)
+    service.send(MessagingConstants.FROM_USERS_CHANNEL, json)
+  }
+
+  private def handlePatchDocumentReply(msg: PatchDocumentReply) {
+    val json = SharedNotesMessageToJsonConverter.patchDocumentReplyToJson(msg)
+    service.send(MessagingConstants.FROM_SHAREDNOTES_CHANNEL, json)
+  }
+
+  private def handleGetCurrentDocumentReply(msg: GetCurrentDocumentReply) {
+    val json = SharedNotesMessageToJsonConverter.getCurrentDocumentReplyToJson(msg)
+    service.send(MessagingConstants.FROM_SHAREDNOTES_CHANNEL, json)
+  }
+
+  private def handleCreateAdditionalNotesReply(msg: CreateAdditionalNotesReply) {
+    val json = SharedNotesMessageToJsonConverter.createAdditionalNotesReplyToJson(msg)
+    service.send(MessagingConstants.FROM_SHAREDNOTES_CHANNEL, json)
+  }
+
+  private def handleDestroyAdditionalNotesReply(msg: DestroyAdditionalNotesReply) {
+    val json = SharedNotesMessageToJsonConverter.destroyAdditionalNotesReplyToJson(msg)
+    service.send(MessagingConstants.FROM_SHAREDNOTES_CHANNEL, json)
+  }
+
+  private def handleSharedNotesSyncNoteReply(msg: SharedNotesSyncNoteReply) {
+    val json = SharedNotesMessageToJsonConverter.sharedNotesSyncNoteReplyToJson(msg)
+    service.send(MessagingConstants.FROM_SHAREDNOTES_CHANNEL, json)
+  }
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/OutMessageGatewayActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/OutMessageGatewayActor.scala
index 4b154ad00e09f34d8b33e4477ee15512609171c7..c45a6c189e8c353db53ed4642526091706132382 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/OutMessageGatewayActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/OutMessageGatewayActor.scala
@@ -4,6 +4,9 @@ import akka.actor.Actor
 import akka.actor.ActorRef
 import akka.actor.ActorLogging
 import akka.actor.Props
+import akka.actor.OneForOneStrategy
+import akka.actor.SupervisorStrategy.Resume
+import java.io.{ PrintWriter, StringWriter }
 import org.bigbluebutton.core.api._
 import java.util.concurrent.TimeUnit
 import org.bigbluebutton.core.util._
@@ -24,6 +27,16 @@ class OutMessageGatewayActor(val meetingId: String, val recorder: RecorderApplic
   private val recorderActor = context.actorOf(RecorderActor.props(recorder), "recorderActor-" + meetingId)
   private val msgSenderActor = context.actorOf(MessageSenderActor.props(msgSender), "senderActor-" + meetingId)
 
+  override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
+    case e: Exception => {
+      val sw: StringWriter = new StringWriter()
+      sw.write("An exception has been thrown on OutMessageGatewayActor, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+      e.printStackTrace(new PrintWriter(sw))
+      log.error(sw.toString())
+      Resume
+    }
+  }
+
   def receive = {
     case msg: IOutMessage => {
       msgSenderActor forward msg
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/RecorderActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/RecorderActor.scala
index 3bb0c046da679dc51042806ddf59167413c271ba..b163c2becd3c0c82299531fbabaf6e668371382a 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/RecorderActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/RecorderActor.scala
@@ -4,11 +4,16 @@ import akka.actor.Actor
 import akka.actor.ActorRef
 import akka.actor.ActorLogging
 import akka.actor.Props
+import akka.actor.OneForOneStrategy
+import akka.actor.SupervisorStrategy.Resume
+import java.io.{ PrintWriter, StringWriter }
 import org.bigbluebutton.core.api._
 import org.bigbluebutton.core.api._
 import scala.collection.JavaConversions._
+import scala.concurrent.duration._
 import org.bigbluebutton.core.service.recorder.RecorderApplication
 import org.bigbluebutton.core.recorders.events.PublicChatRecordEvent
+import org.bigbluebutton.core.recorders.events.ClearPublicChatRecordEvent
 import org.bigbluebutton.core.recorders.events.ConversionCompletedPresentationRecordEvent
 import org.bigbluebutton.core.recorders.events.GotoSlidePresentationRecordEvent
 import org.bigbluebutton.core.recorders.events.ResizeAndMoveSlidePresentationRecordEvent
@@ -46,8 +51,19 @@ object RecorderActor {
 class RecorderActor(val recorder: RecorderApplication)
     extends Actor with ActorLogging {
 
+  override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
+    case e: Exception => {
+      val sw: StringWriter = new StringWriter()
+      sw.write("An exception has been thrown on RecorderActor, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+      e.printStackTrace(new PrintWriter(sw))
+      log.error(sw.toString())
+      Resume
+    }
+  }
+
   def receive = {
     case msg: SendPublicMessageEvent => handleSendPublicMessageEvent(msg)
+    case msg: ClearPublicChatHistoryReply => handleClearPublicChatHistoryReply(msg)
     case msg: ClearPresentationOutMsg => handleClearPresentationOutMsg(msg)
     case msg: RemovePresentationOutMsg => handleRemovePresentationOutMsg(msg)
     case msg: SendCursorUpdateOutMsg => handleSendCursorUpdateOutMsg(msg)
@@ -93,6 +109,15 @@ class RecorderActor(val recorder: RecorderApplication)
     }
   }
 
+  private def handleClearPublicChatHistoryReply(msg: ClearPublicChatHistoryReply) {
+    if (msg.recorded) {
+      val ev = new ClearPublicChatRecordEvent();
+      ev.setTimestamp(TimestampGenerator.generateTimestamp);
+      ev.setMeetingId(msg.meetingID);
+      recorder.record(msg.meetingID, ev);
+    }
+  }
+
   private def handleClearPresentationOutMsg(msg: ClearPresentationOutMsg) {
 
   }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/Constants.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/Constants.scala
index c55149c0dc41ca529eba0662c132ac189eb93905..ad51c681b6661a0d419c8ef44724330a87c4f2e5 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/Constants.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/Constants.scala
@@ -39,6 +39,7 @@ object Constants {
   val FORCE = "force"
   val RESPONSE = "response"
   val PRESENTATION_ID = "presentation_id"
+  val DOWNLOADABLE = "downloadable"
   val X_OFFSET = "x_offset"
   val Y_OFFSET = "y_offset"
   val WIDTH_RATIO = "width_ratio"
@@ -98,4 +99,17 @@ object Constants {
   val VIEWER_PASS = "viewer_pass"
   val CREATE_TIME = "create_time"
   val CREATE_DATE = "create_date"
+  val GUEST = "guest"
+  val WAITING_FOR_ACCEPTANCE = "waiting_for_acceptance"
+  val GUEST_POLICY = "guest_policy"
+  val GUESTS_WAITING = "guests_waiting"
+  val NOTE_ID = "note_id"
+  val NOTES = "notes"
+  val NOTE_NAME = "note_name"
+  val PATCH = "patch"
+  val PATCH_ID = "patch_id"
+  val UNDO = "undo"
+  val REDO = "redo"
+  val OPERATION = "operation"
+  val NOTE = "note"
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/InMessages.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/InMessages.scala
index d92663d98fff357341f11c562f915d36a06580c0..880dbd6330652cc49e0d93695b905fa2a56c9c4d 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/InMessages.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/InMessages.scala
@@ -1,6 +1,8 @@
 package org.bigbluebutton.core.api
 
 import org.bigbluebutton.core.api.Role._
+import org.bigbluebutton.core.api.GuestPolicy._
+import org.bigbluebutton.core.api.SharedNotesOperation._
 import org.bigbluebutton.core.apps.AnnotationVO
 import org.bigbluebutton.core.apps.Presentation
 import org.bigbluebutton.core.MeetingProperties
@@ -75,7 +77,7 @@ case class GetLockSettings(meetingID: String, userId: String) extends InMessage
 case class ValidateAuthToken(meetingID: String, userId: String, token: String,
   correlationId: String, sessionId: String) extends InMessage
 case class RegisterUser(meetingID: String, userID: String, name: String, role: Role,
-  extUserID: String, authToken: String, avatarURL: String) extends InMessage
+  extUserID: String, authToken: String, avatarURL: String, guest: Boolean) extends InMessage
 case class UserJoining(meetingID: String, userID: String, authToken: String) extends InMessage
 case class UserLeaving(meetingID: String, userID: String, sessionId: String) extends InMessage
 case class GetUsers(meetingID: String, requesterID: String) extends InMessage
@@ -84,10 +86,13 @@ case class EjectUserFromMeeting(meetingID: String, userId: String, ejectedBy: St
 case class UserShareWebcam(meetingID: String, userId: String, stream: String) extends InMessage
 case class UserUnshareWebcam(meetingID: String, userId: String, stream: String) extends InMessage
 case class ChangeUserStatus(meetingID: String, userID: String, status: String, value: Object) extends InMessage
+case class ChangeUserRole(meetingID: String, userID: String, role: Role) extends InMessage
 case class AssignPresenter(meetingID: String, newPresenterID: String, newPresenterName: String, assignedBy: String) extends InMessage
 case class SetRecordingStatus(meetingID: String, userId: String, recording: Boolean) extends InMessage
 case class GetRecordingStatus(meetingID: String, userId: String) extends InMessage
 case class AllowUserToShareDesktop(meetingID: String, userID: String) extends InMessage
+case class ActivityResponse(meetingID: String) extends InMessage
+case class LogoutEndMeeting(meetingID: String, userID: String) extends InMessage
 
 //////////////////////////////////////////////////////////////////////////////////
 // Chat
@@ -96,11 +101,20 @@ case class AllowUserToShareDesktop(meetingID: String, userID: String) extends In
 case class GetChatHistoryRequest(meetingID: String, requesterID: String, replyTo: String) extends InMessage
 case class SendPublicMessageRequest(meetingID: String, requesterID: String, message: Map[String, String]) extends InMessage
 case class SendPrivateMessageRequest(meetingID: String, requesterID: String, message: Map[String, String]) extends InMessage
+case class ClearPublicChatHistoryRequest(meetingID: String, requesterID: String) extends InMessage
 case class UserConnectedToGlobalAudio(meetingID: String, /** Not used. Just to satisfy trait **/ voiceConf: String,
   userid: String, name: String) extends InMessage
 case class UserDisconnectedFromGlobalAudio(meetingID: String, /** Not used. Just to satisfy trait **/ voiceConf: String,
   userid: String, name: String) extends InMessage
 
+///////////////////////////////////////////////////////////////////////////////////////
+// Guest support
+///////////////////////////////////////////////////////////////////////////////////////
+
+case class GetGuestPolicy(meetingID: String, requesterID: String) extends InMessage
+case class SetGuestPolicy(meetingID: String, policy: GuestPolicy, setBy: String) extends InMessage
+case class RespondToGuest(meetingID: String, userId: String, response: Boolean, requesterID: String) extends InMessage
+
 ///////////////////////////////////////////////////////////////////////////////////////
 // Layout
 //////////////////////////////////////////////////////////////////////////////////////
@@ -193,3 +207,13 @@ case class DeskShareRTMPBroadcastStartedRequest(conferenceName: String, streamna
 case class DeskShareRTMPBroadcastStoppedRequest(conferenceName: String, streamname: String, videoWidth: Int, videoHeight: Int, timestamp: String) extends InMessage
 case class DeskShareGetDeskShareInfoRequest(conferenceName: String, requesterID: String, replyTo: String) extends InMessage
 
+/////////////////////////////////////////////////////////////////////////////////////
+// Shared notes
+/////////////////////////////////////////////////////////////////////////////////////
+
+case class PatchDocumentRequest(meetingID: String, requesterID: String, noteID: String, patch: String, operation: SharedNotesOperation) extends InMessage
+case class GetCurrentDocumentRequest(meetingID: String, requesterID: String) extends InMessage
+case class CreateAdditionalNotesRequest(meetingID: String, requesterID: String, noteName: String) extends InMessage
+case class DestroyAdditionalNotesRequest(meetingID: String, requesterID: String, noteID: String) extends InMessage
+case class RequestAdditionalNotesSetRequest(meetingID: String, requesterID: String, additionalNotesSetSize: Int) extends InMessage
+case class SharedNotesSyncNoteRequest(meetingID: String, requesterID: String, noteID: String) extends InMessage
\ No newline at end of file
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/MessageNames.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/MessageNames.scala
index 0b803aed90806a3c7199dd559bfc998d486ce220..ec9a13ebdb3262a0304a601fd0971fd300b32d7e 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/MessageNames.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/MessageNames.scala
@@ -24,11 +24,13 @@ object MessageNames {
   val USER_SHARE_WEBCAM = "user_share_webcam_request"
   val USER_UNSHARE_WEBCAM = "user_unshare_webcam_request"
   val CHANGE_USER_STATUS = "change_user_status_request"
+  val CHANGE_USER_ROLE = "change_user_role"
   val ASSIGN_PRESENTER = "assign_presenter_request"
   val SET_RECORDING_STATUS = "set_recording_status_request"
   val GET_CHAT_HISTORY = "get_chat_history_request"
   val SEND_PUBLIC_MESSAGE = "send_public_chat_message_request"
   val SEND_PRIVATE_MESSAGE = "send_private_chat_message_request"
+  val CLEAR_PUBLIC_CHAT_HISTORY = "clear_public_chat_history_request"
   val GET_CURRENT_LAYOUT = "get_current_layout_request"
   val SET_LAYOUT = "set_layout_request"
   val BROADCAST_LAYOUT = "broadcast_layout_request"
@@ -79,6 +81,9 @@ object MessageNames {
   val UNDO_WHITEBOARD = "undo_whiteboard_request"
   val ENABLE_WHITEBOARD = "enable_whiteboard_request"
   val IS_WHITEBOARD_ENABLED = "is_whiteboard_enabled_request"
+  var GET_GUEST_POLICY = "get_guest_policy"
+  val SET_GUEST_POLICY = "set_guest_policy"
+  val RESPOND_TO_GUEST = "respond_to_guest"
   val GET_ALL_MEETINGS_REQUEST = "get_all_meetings_request"
 
   // OUT MESSAGES
@@ -112,6 +117,7 @@ object MessageNames {
   val USER_SHARED_WEBCAM = "user_shared_webcam_message"
   val USER_UNSHARED_WEBCAM = "user_unshared_webcam_message"
   val USER_STATUS_CHANGED = "user_status_changed_message"
+  val USER_ROLE_CHANGED = "user_role_change"
   val MUTE_VOICE_USER = "mute_voice_user_request"
   val USER_VOICE_MUTED = "user_voice_muted_message"
   val USER_VOICE_TALKING = "user_voice_talking_message"
@@ -124,6 +130,7 @@ object MessageNames {
   val GET_CHAT_HISTORY_REPLY = "get_chat_history_reply"
   val SEND_PUBLIC_CHAT_MESSAGE = "send_public_chat_message"
   val SEND_PRIVATE_CHAT_MESSAGE = "send_private_chat_message"
+  val CLEAR_PUBLIC_CHAT_HISTORY_REPLY = "clear_public_chat_history_reply"
   val GET_CURRENT_LAYOUT_REPLY = "get_current_layout_reply"
   val SET_LAYOUT_REPLY = "set_layout_reply"
   val BROADCAST_LAYOUT_REPLY = "broadcast_layout_reply"
@@ -170,4 +177,15 @@ object MessageNames {
 
   // breakout rooms
   val BREAKOUT_ROOM_STARTED = "BreakoutRoomStarted"
+
+  var GET_GUEST_POLICY_REPLY = "get_guest_policy_reply"
+  val GUEST_POLICY_CHANGED = "guest_policy_changed"
+  val GUEST_ACCESS_DENIED = "guest_access_denied"
+  val PATCH_DOCUMENT_REPLY = "patch_document_reply"
+  val GET_CURRENT_DOCUMENT_REPLY = "get_current_document_reply"
+  val CREATE_ADDITIONAL_NOTES_REPLY = "create_additional_notes_reply"
+  val DESTROY_ADDITIONAL_NOTES_REPLY = "destroy_additional_notes_reply"
+  val SHAREDNOTES_SYNC_NOTE_REPLY = "sharednotes_sync_note_reply"
+  val INACTIVITY_WARNING = "inactivity_warning_message"
+  val MEETING_IS_ACTIVE = "meeting_is_active_message"
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/OutMessages.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/OutMessages.scala
index 5e3138f7c2759aae9ce77551710b195f5ef49c94..0fd4dd52f60b93079f8cd503eded8a28bb465258 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/OutMessages.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/OutMessages.scala
@@ -23,6 +23,8 @@ case class MeetingState(meetingID: String, recorded: Boolean, userId: String, pe
 case class MeetingHasEnded(meetingID: String, userId: String) extends IOutMessage
 case class MeetingDestroyed(meetingID: String) extends IOutMessage
 case class DisconnectAllUsers(meetingID: String) extends IOutMessage
+case class InactivityWarning(meetingID: String, duration: Long) extends IOutMessage
+case class MeetingIsActive(meetingID: String) extends IOutMessage
 case class DisconnectUser(meetingID: String, userId: String) extends IOutMessage
 case class KeepAliveMessageReply(aliveID: String) extends IOutMessage
 case class PubSubPong(system: String, timestamp: Long) extends IOutMessage
@@ -65,6 +67,7 @@ case class UserListeningOnly(meetingID: String, recorded: Boolean, userID: Strin
 case class UserSharedWebcam(meetingID: String, recorded: Boolean, userID: String, stream: String) extends IOutMessage
 case class UserUnsharedWebcam(meetingID: String, recorded: Boolean, userID: String, stream: String) extends IOutMessage
 case class UserStatusChange(meetingID: String, recorded: Boolean, userID: String, status: String, value: Object) extends IOutMessage
+case class UserRoleChange(meetingID: String, recorded: Boolean, userID: String, role: String) extends IOutMessage
 case class GetUsersInVoiceConference(meetingID: String, recorded: Boolean, voiceConfId: String) extends IOutMessage
 case class MuteVoiceUser(meetingID: String, recorded: Boolean, requesterID: String,
   userId: String, voiceConfId: String, voiceUserId: String, mute: Boolean) extends IOutMessage
@@ -90,6 +93,7 @@ case class SendPublicMessageEvent(meetingID: String, recorded: Boolean, requeste
   message: Map[String, String]) extends IOutMessage
 case class SendPrivateMessageEvent(meetingID: String, recorded: Boolean, requesterID: String,
   message: Map[String, String]) extends IOutMessage
+case class ClearPublicChatHistoryReply(meetingID: String, recorded: Boolean, requesterID: String) extends IOutMessage
 
 // Layout
 case class GetCurrentLayoutReply(meetingID: String, recorded: Boolean, requesterID: String, layoutID: String,
@@ -158,6 +162,18 @@ case class DeskShareNotifyViewersRTMP(meetingID: String, streamPath: String, vid
 case class DeskShareNotifyASingleViewer(meetingID: String, userID: String, streamPath: String, videoWidth: Int, videoHeight: Int, broadcasting: Boolean) extends IOutMessage
 case class DeskShareHangUp(meetingID: String, fsConferenceName: String) extends IOutMessage
 
+// Guest
+case class GetGuestPolicyReply(meetingID: String, recorded: Boolean, requesterID: String, policy: String) extends IOutMessage
+case class GuestPolicyChanged(meetingID: String, recorded: Boolean, policy: String) extends IOutMessage
+case class GuestAccessDenied(meetingID: String, recorded: Boolean, userId: String) extends IOutMessage
+
+// Shared Notes
+case class PatchDocumentReply(meetingID: String, recorded: Boolean, requesterID: String, noteID: String, patch: String, patchID: Int, undo: Boolean, redo: Boolean) extends IOutMessage
+case class GetCurrentDocumentReply(meetingID: String, recorded: Boolean, requesterID: String, notes: Map[String, NoteReport]) extends IOutMessage
+case class CreateAdditionalNotesReply(meetingID: String, recorded: Boolean, requesterID: String, noteID: String, noteName: String) extends IOutMessage
+case class DestroyAdditionalNotesReply(meetingID: String, recorded: Boolean, requesterID: String, noteID: String) extends IOutMessage
+case class SharedNotesSyncNoteReply(meetingID: String, recorded: Boolean, requesterID: String, noteID: String, note: NoteReport) extends IOutMessage
+
 // Value Objects
 case class MeetingVO(id: String, recorded: Boolean)
 
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/ValueObjects.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/ValueObjects.scala
index d636b4a6d77db41afd43723ef7c5b824e381653c..e3f12208b8203d0c9909ff981f6fff2360a8189a 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/ValueObjects.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/api/ValueObjects.scala
@@ -2,12 +2,35 @@ package org.bigbluebutton.core.api
 
 import java.lang.Boolean
 
+import scala.collection.mutable.Stack
+
 object Role extends Enumeration {
   type Role = Value
   val MODERATOR = Value("MODERATOR")
   val VIEWER = Value("VIEWER")
 }
 
+object Metadata extends Enumeration {
+  type Metadata = String
+  val INACTIVITY_DEADLINE = "mconf-live-inactivity-deadline"
+  val INACTIVITY_TIMELEFT = "mconf-live-inactivity-timeleft"
+}
+
+object GuestPolicy extends Enumeration {
+  type GuestPolicy = Value
+  val ALWAYS_ACCEPT = Value("ALWAYS_ACCEPT")
+  val ALWAYS_DENY = Value("ALWAYS_DENY")
+  val ASK_MODERATOR = Value("ASK_MODERATOR")
+}
+
+object SharedNotesOperation extends Enumeration {
+  type SharedNotesOperation = Value
+  val PATCH = Value("PATCH")
+  val UNDO = Value("UNDO")
+  val REDO = Value("REDO")
+  val UNDEFINED = Value("UNDEFINED")
+}
+
 case class StatusCode(val code: Int, val text: String)
 object StatusCodes {
   // Borrowed from https://dev.twitter.com/overview/api/response-codes (ralam June 18, 2015)
@@ -70,7 +93,9 @@ case class RegisteredUser(
   name: String,
   role: Role.Role,
   authToken: String,
-  avatarURL: String)
+  avatarURL: String,
+  guest: Boolean,
+  waitingForAcceptance: Boolean)
 
 case class Voice(
   id: String,
@@ -87,6 +112,8 @@ case class UserVO(
   externUserID: String,
   name: String,
   role: Role.Role,
+  guest: Boolean,
+  waitingForAcceptance: Boolean,
   emojiStatus: String,
   presenter: Boolean,
   hasStream: Boolean,
@@ -119,7 +146,8 @@ case class MeetingConfig(name: String,
   record: Boolean = false,
   duration: MeetingDuration,
   defaultAvatarURL: String,
-  defaultConfigToken: String)
+  defaultConfigToken: String,
+  guestPolicy: GuestPolicy.GuestPolicy = GuestPolicy.ASK_MODERATOR)
 
 case class MeetingName(name: String)
 
@@ -138,3 +166,23 @@ case class MeetingInfo(
   recorded: Boolean,
   voiceBridge: String,
   duration: Long)
+
+trait BaseNote {
+  def name: String
+  def document: String
+  def patchCounter: Int
+}
+
+case class Note(
+  name: String,
+  document: String,
+  patchCounter: Int,
+  undoPatches: Stack[(String, String)],
+  redoPatches: Stack[(String, String)]) extends BaseNote
+
+case class NoteReport(
+  name: String,
+  document: String,
+  patchCounter: Int,
+  undo: Boolean,
+  redo: Boolean) extends BaseNote
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ChatApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ChatApp.scala
index 61b6cd84076cf15abb99876b5bf42ccadfa3151d..81203cd8f4950edc6fcb3cc7e1980cdb69644bc3 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ChatApp.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ChatApp.scala
@@ -26,4 +26,10 @@ trait ChatApp {
     val privMsg = msg.message.toMap
     outGW.send(new SendPrivateMessageEvent(mProps.meetingID, mProps.recorded, msg.requesterID, privMsg))
   }
+
+  def handleClearPublicChatHistoryRequest(msg: ClearPublicChatHistoryRequest) {
+    chatModel.clearPublicChatHistory()
+    outGW.send(new ClearPublicChatHistoryReply(mProps.meetingID, mProps.recorded, msg.requesterID))
+  }
+
 }
\ No newline at end of file
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ChatModel.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ChatModel.scala
index b6dd6b49e984033ac5fd1912fc7070b6396804b5..515dd2adabfd34c9409c3d90c324353f0d6b9266 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ChatModel.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/ChatModel.scala
@@ -16,4 +16,8 @@ class ChatModel {
   def addNewChatMessage(msg: Map[String, String]) {
     messages append msg
   }
+
+  def clearPublicChatHistory() {
+    messages.clear();
+  }
 }
\ No newline at end of file
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/LayoutModel.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/LayoutModel.scala
index d3a5ecf6309d1757de01ad594fdc9dd04395b4d0..b95c59ef33f1f22f090c2c470b7799c86d3177b4 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/LayoutModel.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/LayoutModel.scala
@@ -4,7 +4,8 @@ class LayoutModel {
   private var setByUser: String = "system";
   private var currentLayout = "";
   private var layoutLocked = false
-  private var affectViewersOnly = true
+  // this is not being set by the client, and we need to apply the layouts to all users, not just viewers, so will keep the default value of this as false
+  private var affectViewersOnly = false
 
   def setCurrentLayout(layout: String) {
     currentLayout = layout
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/PresentationModel.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/PresentationModel.scala
index eac0060212da6f3b85e84199e1b0184a1d3c8ca4..0bbbec87ccd12aa491c16d6c775a4378129d97c7 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/PresentationModel.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/PresentationModel.scala
@@ -4,7 +4,7 @@ case class CurrentPresenter(userId: String, name: String, assignedBy: String)
 case class CurrentPresentationInfo(presenter: CurrentPresenter, presentations: Seq[Presentation])
 case class CursorLocation(xPercent: Double = 0D, yPercent: Double = 0D)
 case class Presentation(id: String, name: String, current: Boolean = false,
-  pages: scala.collection.immutable.HashMap[String, Page])
+  pages: scala.collection.immutable.HashMap[String, Page], downloadable: Boolean)
 
 case class Page(id: String, num: Int,
   thumbUri: String = "",
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/SharedNotesApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/SharedNotesApp.scala
new file mode 100644
index 0000000000000000000000000000000000000000..3fc8e02de1a9d88fb07302f0a53e66a04f73ac2a
--- /dev/null
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/SharedNotesApp.scala
@@ -0,0 +1,63 @@
+package org.bigbluebutton.core.apps
+
+import org.bigbluebutton.core.api._
+import org.bigbluebutton.core.LiveMeeting
+import org.bigbluebutton.core.OutMessageGateway
+
+trait SharedNotesApp {
+  this: LiveMeeting =>
+
+  val outGW: OutMessageGateway
+
+  def handlePatchDocumentRequest(msg: PatchDocumentRequest) {
+    val requesterID = msg.operation match {
+      case SharedNotesOperation.PATCH => msg.requesterID
+      case SharedNotesOperation.UNDO => "SYSTEM"
+      case SharedNotesOperation.REDO => "SYSTEM"
+      case _ => return
+    }
+
+    val (patchID, patch, undo, redo) = notesModel.patchDocument(msg.noteID, msg.patch, msg.operation)
+
+    if (patch != "") outGW.send(new PatchDocumentReply(mProps.meetingID, mProps.recorded, requesterID, msg.noteID, patch, patchID, undo, redo))
+  }
+
+  def handleGetCurrentDocumentRequest(msg: GetCurrentDocumentRequest) {
+    val notesReport = notesModel.notesReport.toMap
+
+    outGW.send(new GetCurrentDocumentReply(mProps.meetingID, mProps.recorded, msg.requesterID, notesReport))
+  }
+
+  private def createAdditionalNotes(requesterID: String, noteName: String = "") {
+    notesModel.synchronized {
+      val noteID = notesModel.createNote(noteName)
+
+      outGW.send(new CreateAdditionalNotesReply(mProps.meetingID, mProps.recorded, requesterID, noteID, noteName))
+    }
+  }
+
+  def handleCreateAdditionalNotesRequest(msg: CreateAdditionalNotesRequest) {
+    createAdditionalNotes(msg.requesterID, msg.noteName)
+  }
+
+  def handleDestroyAdditionalNotesRequest(msg: DestroyAdditionalNotesRequest) {
+    notesModel.synchronized {
+      notesModel.destroyNote(msg.noteID)
+
+      outGW.send(new DestroyAdditionalNotesReply(mProps.meetingID, mProps.recorded, msg.requesterID, msg.noteID))
+    }
+  }
+
+  def handleRequestAdditionalNotesSetRequest(msg: RequestAdditionalNotesSetRequest) {
+    while (notesModel.notesSize < msg.additionalNotesSetSize) {
+      createAdditionalNotes(msg.requesterID)
+    }
+  }
+
+  def handleSharedNotesSyncNoteRequest(msg: SharedNotesSyncNoteRequest) {
+    notesModel.getNoteReport(msg.noteID) match {
+      case Some(note) => outGW.send(new SharedNotesSyncNoteReply(mProps.meetingID, mProps.recorded, msg.requesterID, msg.noteID, note))
+      case None =>
+    }
+  }
+}
\ No newline at end of file
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/SharedNotesModel.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/SharedNotesModel.scala
new file mode 100644
index 0000000000000000000000000000000000000000..23dcdc19df4e7f380caa9fa8db0209d9da243a16
--- /dev/null
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/SharedNotesModel.scala
@@ -0,0 +1,116 @@
+package org.bigbluebutton.core.apps
+
+import org.bigbluebutton.core.api._
+import org.bigbluebutton.core.api.SharedNotesOperation._
+import name.fraser.neil.plaintext.diff_match_patch
+import name.fraser.neil.plaintext.diff_match_patch._
+import scala.collection.mutable.Stack
+import scala.collection.mutable.HashMap
+import scala.collection._
+import java.util.Collections
+
+class SharedNotesModel {
+  val notes = new HashMap[String, Note]()
+  notes += ("MAIN_WINDOW" -> new Note("", "", 0, new Stack(), new Stack()))
+  private val patcher = new diff_match_patch()
+  private var notesCounter = 0;
+  private var removedNotes: Set[Int] = Set()
+  private val maxUndoStackSize = 30
+
+  def patchDocument(noteID: String, patch: String, operation: SharedNotesOperation): (Integer, String, Boolean, Boolean) = {
+    notes.synchronized {
+      val note = notes(noteID)
+      val document = note.document
+      var undoPatches = note.undoPatches
+      var redoPatches = note.redoPatches
+
+      var patchToApply = operation match {
+        case SharedNotesOperation.PATCH => {
+          patch
+        }
+        case SharedNotesOperation.UNDO => {
+          if (undoPatches.isEmpty) {
+            return (-1, "", false, false)
+          } else {
+            val (undo, redo) = undoPatches.pop()
+            redoPatches.push((undo, redo))
+            undo
+          }
+        }
+        case SharedNotesOperation.REDO => {
+          if (redoPatches.isEmpty) {
+            return (-1, "", false, false)
+          } else {
+            val (undo, redo) = redoPatches.pop()
+            undoPatches.push((undo, redo))
+            redo
+          }
+        }
+      }
+
+      val patchObjects = patcher.patch_fromText(patchToApply)
+      val result = patcher.patch_apply(patchObjects, document)
+
+      // If it is a patch operation, save an undo patch and clear redo stack
+      if (operation == SharedNotesOperation.PATCH) {
+        undoPatches.push((patcher.custom_patch_make(result(0).toString(), document), patchToApply))
+        redoPatches.clear
+
+        if (undoPatches.size > maxUndoStackSize) {
+          undoPatches = undoPatches.dropRight(1)
+        }
+      }
+
+      val patchCounter = note.patchCounter + 1
+      notes(noteID) = new Note(note.name, result(0).toString(), patchCounter, undoPatches, redoPatches)
+      (patchCounter, patchToApply, !undoPatches.isEmpty, !redoPatches.isEmpty)
+    }
+  }
+
+  def createNote(noteName: String = ""): String = {
+    var noteID = 0
+    if (removedNotes.isEmpty) {
+      notesCounter += 1
+      noteID = notesCounter
+    } else {
+      noteID = removedNotes.min
+      removedNotes -= noteID
+    }
+    notes += (noteID.toString -> new Note(noteName, "", 0, new Stack(), new Stack()))
+
+    noteID.toString
+  }
+
+  def destroyNote(noteID: String) {
+    removedNotes += noteID.toInt
+    notes -= noteID
+  }
+
+  def notesSize(): Int = {
+    notes.size
+  }
+
+  def notesReport: HashMap[String, NoteReport] = {
+    notes.synchronized {
+      var report = new HashMap[String, NoteReport]()
+      notes foreach {
+        case (id, note) =>
+          report += (id -> noteToReport(note))
+      }
+      report
+    }
+  }
+
+  def getNoteReport(noteID: String): Option[NoteReport] = {
+    notes.synchronized {
+      notes.get(noteID) match {
+        case Some(note) => Some(noteToReport(note))
+        case None => None
+      }
+    }
+  }
+
+  private def noteToReport(note: Note): NoteReport = {
+    new NoteReport(note.name, note.document, note.patchCounter, !note.undoPatches.isEmpty, !note.redoPatches.isEmpty)
+  }
+}
\ No newline at end of file
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/UsersApp.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/UsersApp.scala
index 3348e72775b6b70aecb81fdbbfe49429a447fc59..b2d385a3d5eb3d21eee8986291e9555b1cde4d9d 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/UsersApp.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/UsersApp.scala
@@ -7,6 +7,7 @@ import scala.collection.mutable.ArrayBuffer
 import scala.collection.immutable.ListSet
 import org.bigbluebutton.core.OutMessageGateway
 import org.bigbluebutton.core.LiveMeeting
+import org.bigbluebutton.core.api.GuestPolicy
 
 trait UsersApp {
   this: LiveMeeting =>
@@ -120,7 +121,7 @@ trait UsersApp {
       log.info("Register user failed. Mmeeting has ended. meetingId=" + mProps.meetingID + " userId=" + msg.userID)
       sendMeetingHasEnded(msg.userID)
     } else {
-      val regUser = new RegisteredUser(msg.userID, msg.extUserID, msg.name, msg.role, msg.authToken, msg.avatarURL)
+      val regUser = new RegisteredUser(msg.userID, msg.extUserID, msg.name, msg.role, msg.authToken, msg.avatarURL, msg.guest, msg.guest)
       usersModel.addRegisteredUser(msg.authToken, regUser)
 
       log.info("Register user success. meetingId=" + mProps.meetingID + " userId=" + msg.userID + " user=" + regUser)
@@ -234,6 +235,16 @@ trait UsersApp {
     }
   }
 
+  def handleChangeUserRole(msg: ChangeUserRole) {
+    usersModel.getUser(msg.userID) foreach { user =>
+      val uvo = user.copy(role = msg.role)
+      usersModel.addUser(uvo)
+      usersModel.updateRegUser(uvo)
+      val userRole = if (msg.role == Role.MODERATOR) "MODERATOR" else "VIEWER"
+      outGW.send(new UserRoleChange(mProps.meetingID, mProps.recorded, msg.userID, userRole))
+    }
+  }
+
   def makeSurePresenterIsAssigned(user: UserVO): Unit = {
     if (user.presenter) {
       /* The current presenter has left the meeting. Find a moderator and make
@@ -371,8 +382,9 @@ trait UsersApp {
        * Initialize the newly joined user copying voice status in case this
        * join is due to a reconnect.
        */
+      val waitingForAcceptance = ru.guest && meetingModel.getGuestPolicy() == GuestPolicy.ASK_MODERATOR && ru.waitingForAcceptance
       val uvo = new UserVO(msg.userID, ru.externId, ru.name,
-        ru.role, emojiStatus = "none", presenter = false,
+        ru.role, ru.guest, waitingForAcceptance = waitingForAcceptance, emojiStatus = "none", presenter = false,
         hasStream = false, locked = getInitialLockStatus(ru.role),
         webcamStreams = new ListSet[String](), phoneUser = false, vu,
         listenOnly = vu.listenOnly, avatarURL = vu.avatarURL, joinedWeb = true)
@@ -381,17 +393,22 @@ trait UsersApp {
 
       log.info("User joined meeting. metingId=" + mProps.meetingID + " userId=" + uvo.userID + " user=" + uvo)
 
-      outGW.send(new UserJoined(mProps.meetingID, mProps.recorded, uvo))
-      outGW.send(new MeetingState(mProps.meetingID, mProps.recorded, uvo.userID, meetingModel.getPermissions(), meetingModel.isMeetingMuted()))
-
-      // Become presenter if the only moderator		
-      if ((usersModel.numModerators == 1) || (usersModel.noPresenter())) {
-        if (ru.role == Role.MODERATOR) {
-          assignNewPresenter(msg.userID, ru.name, msg.userID)
+      if (uvo.guest && meetingModel.getGuestPolicy() == GuestPolicy.ALWAYS_DENY) {
+        outGW.send(new GuestAccessDenied(mProps.meetingID, mProps.recorded, uvo.userID))
+      } else {
+        outGW.send(new UserJoined(mProps.meetingID, mProps.recorded, uvo))
+        outGW.send(new MeetingState(mProps.meetingID, mProps.recorded, uvo.userID, meetingModel.getPermissions(), meetingModel.isMeetingMuted()))
+        if (!waitingForAcceptance) {
+          // Become presenter if the only moderator
+          if ((usersModel.numModerators == 1) || (usersModel.noPresenter())) {
+            if (ru.role == Role.MODERATOR) {
+              assignNewPresenter(msg.userID, ru.name, msg.userID)
+            }
+          }
         }
+        webUserJoined
+        startRecordingIfAutoStart()
       }
-      webUserJoined
-      startRecordingIfAutoStart()
     }
   }
 
@@ -457,7 +474,7 @@ trait UsersApp {
          * So we call him "phoneUser".
          */
         val uvo = new UserVO(webUserId, msg.externUserId, msg.callerIdName,
-          Role.VIEWER, emojiStatus = "none", presenter = false,
+          Role.VIEWER, guest = false, waitingForAcceptance = false, emojiStatus = "none", presenter = false,
           hasStream = false, locked = getInitialLockStatus(Role.VIEWER),
           webcamStreams = new ListSet[String](),
           phoneUser = !msg.listenOnly, vu, listenOnly = msg.listenOnly, avatarURL = msg.avatarURL, joinedWeb = false)
@@ -635,4 +652,26 @@ trait UsersApp {
 
     }
   }
+
+  def handleRespondToGuest(msg: RespondToGuest) {
+    if (usersModel.isModerator(msg.requesterID)) {
+      var usersToAnswer: Array[UserVO] = null;
+      if (msg.userId == null) {
+        usersToAnswer = usersModel.getUsers.filter(u => u.waitingForAcceptance == true)
+      } else {
+        usersToAnswer = usersModel.getUsers.filter(u => u.waitingForAcceptance == true && u.userID == msg.userId)
+      }
+      usersToAnswer foreach { user =>
+        println("UsersApp - handleGuestAccessDenied for user [" + user.userID + "]");
+        if (msg.response == true) {
+          val nu = user.copy(waitingForAcceptance = false)
+          usersModel.addUser(nu)
+          usersModel.updateRegUser(nu)
+          outGW.send(new UserJoined(mProps.meetingID, mProps.recorded, nu))
+        } else {
+          outGW.send(new GuestAccessDenied(mProps.meetingID, mProps.recorded, user.userID))
+        }
+      }
+    }
+  }
 }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/UsersModel.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/UsersModel.scala
index 13d911e920c5ea6e36081c107363b369d6282778..0ada7d31cdcdd29850c603ca6f6e9020391c4ae3 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/UsersModel.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/UsersModel.scala
@@ -139,6 +139,13 @@ class UsersModel {
     uservos.values filter (u => u.role == VIEWER) toArray
   }
 
+  def isModerator(userId: String): Boolean = {
+    uservos.get(userId) match {
+      case Some(user) => return user.role == MODERATOR && !user.waitingForAcceptance
+      case None => return false
+    }
+  }
+
   def getRegisteredUserWithUserID(userID: String): Option[RegisteredUser] = {
     regUsers.values find (ru => userID contains ru.id)
   }
@@ -152,6 +159,17 @@ class UsersModel {
     }
   }
 
+  def updateRegUser(uvo: UserVO) {
+    getRegisteredUserWithUserID(uvo.userID) match {
+      case Some(ru) => {
+        val regUser = new RegisteredUser(uvo.userID, uvo.externUserID, uvo.name, uvo.role, ru.authToken, uvo.avatarURL, uvo.guest, uvo.waitingForAcceptance)
+        regUsers -= ru.authToken
+        regUsers += ru.authToken -> regUser
+      }
+      case None =>
+    }
+  }
+
   def addGlobalAudioConnection(userID: String): Boolean = {
     globalAudioConnectionCounter.get(userID) match {
       case Some(vc) => {
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ChatMessageToJsonConverter.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ChatMessageToJsonConverter.scala
index 029f95017bc903209b94ab1311c6f1adf2cc7323..5eeef4de4e7c54dbb80d308d7ab76bdd10e432dd 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ChatMessageToJsonConverter.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ChatMessageToJsonConverter.scala
@@ -64,4 +64,13 @@ object ChatMessageToJsonConverter {
     val header = Util.buildHeader(MessageNames.SEND_PRIVATE_CHAT_MESSAGE, None)
     Util.buildJson(header, payload)
   }
+
+  def clearPublicChatHistoryReplyToJson(msg: ClearPublicChatHistoryReply): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.REQUESTER_ID, msg.requesterID)
+
+    val header = Util.buildHeader(MessageNames.CLEAR_PUBLIC_CHAT_HISTORY_REPLY, None)
+    Util.buildJson(header, payload)
+  }
 }
\ No newline at end of file
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/MeetingMessageToJsonConverter.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/MeetingMessageToJsonConverter.scala
index 244b97558afdad7d7630fad7c498d7d8cea39fb5..a8ed6e52ca3d88a54b1fa14b7a2f99b7aa08c429 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/MeetingMessageToJsonConverter.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/MeetingMessageToJsonConverter.scala
@@ -216,4 +216,21 @@ object MeetingMessageToJsonConverter {
     val header = Util.buildHeader(BreakoutRoomsTimeRemainingUpdate.NAME, None)
     Util.buildJson(header, payload)
   }
-}
+
+  def inactivityWarningToJson(msg: InactivityWarning): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.DURATION, msg.duration)
+
+    val header = Util.buildHeader(MessageNames.INACTIVITY_WARNING, None)
+    Util.buildJson(header, payload)
+  }
+
+  def meetingIsActiveToJson(msg: MeetingIsActive): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+
+    val header = Util.buildHeader(MessageNames.MEETING_IS_ACTIVE, None)
+    Util.buildJson(header, payload)
+  }
+}
\ No newline at end of file
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/PesentationMessageToJsonConverter.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/PesentationMessageToJsonConverter.scala
index ad67db4b1dbd12e9cd5d6371fdd06e40fd30c18e..a26548a2342e7ecf2c210ce17ecc39faac493b1f 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/PesentationMessageToJsonConverter.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/PesentationMessageToJsonConverter.scala
@@ -64,6 +64,7 @@ object PesentationMessageToJsonConverter {
       presentation.put(Constants.ID, pres.id)
       presentation.put(Constants.NAME, pres.name)
       presentation.put(Constants.CURRENT, pres.current: java.lang.Boolean)
+      presentation.put(Constants.DOWNLOADABLE, pres.downloadable: java.lang.Boolean)
 
       // Get the pages for a presentation
       val pages = new java.util.ArrayList[java.util.Map[String, Any]]()
@@ -120,6 +121,7 @@ object PesentationMessageToJsonConverter {
     presentation.put(Constants.ID, msg.presentation.id)
     presentation.put(Constants.NAME, msg.presentation.name)
     presentation.put(Constants.CURRENT, msg.presentation.current: java.lang.Boolean)
+    presentation.put(Constants.DOWNLOADABLE, msg.presentation.downloadable: java.lang.Boolean)
 
     // Get the pages for a presentation
     val pages = new java.util.ArrayList[java.util.Map[String, Any]]()
@@ -204,6 +206,7 @@ object PesentationMessageToJsonConverter {
     presentation.put(Constants.ID, msg.presentation.id)
     presentation.put(Constants.NAME, msg.presentation.name)
     presentation.put(Constants.CURRENT, msg.presentation.current: java.lang.Boolean)
+    presentation.put(Constants.DOWNLOADABLE, msg.presentation.downloadable: java.lang.Boolean)
 
     val pages = new java.util.ArrayList[java.util.Map[String, Any]]()
     msg.presentation.pages.values foreach { p =>
@@ -225,6 +228,7 @@ object PesentationMessageToJsonConverter {
     presentation.put(Constants.ID, msg.presentation.id)
     presentation.put(Constants.NAME, msg.presentation.name)
     presentation.put(Constants.CURRENT, msg.presentation.current: java.lang.Boolean)
+    presentation.put(Constants.DOWNLOADABLE, msg.presentation.downloadable: java.lang.Boolean)
 
     val pages = new java.util.ArrayList[java.util.Map[String, Any]]()
     msg.presentation.pages.values foreach { p =>
@@ -246,6 +250,7 @@ object PesentationMessageToJsonConverter {
     presentation.put(Constants.ID, msg.current.id)
     presentation.put(Constants.NAME, msg.current.name)
     presentation.put(Constants.CURRENT, msg.current.current: java.lang.Boolean)
+    presentation.put(Constants.DOWNLOADABLE, msg.current.downloadable: java.lang.Boolean)
 
     val pages = new java.util.ArrayList[java.util.Map[String, Any]]()
 
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/SharedNotesMessageToJsonConverter.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/SharedNotesMessageToJsonConverter.scala
new file mode 100644
index 0000000000000000000000000000000000000000..1e263d78aaded711a8d10b3caea968bdb8ae8e59
--- /dev/null
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/SharedNotesMessageToJsonConverter.scala
@@ -0,0 +1,69 @@
+package org.bigbluebutton.core.pubsub.senders
+
+import org.bigbluebutton.core.messaging.Util
+import org.bigbluebutton.core.api._
+import com.google.gson.Gson
+import scala.collection.JavaConverters._
+
+object SharedNotesMessageToJsonConverter {
+  def patchDocumentReplyToJson(msg: PatchDocumentReply): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.RECORDED, msg.recorded)
+    payload.put(Constants.REQUESTER_ID, msg.requesterID)
+    payload.put(Constants.NOTE_ID, msg.noteID)
+    payload.put(Constants.PATCH, msg.patch)
+    payload.put(Constants.PATCH_ID, msg.patchID)
+    payload.put(Constants.UNDO, msg.undo)
+    payload.put(Constants.REDO, msg.redo)
+
+    val header = Util.buildHeader(MessageNames.PATCH_DOCUMENT_REPLY, None)
+    Util.buildJson(header, payload)
+  }
+
+  def getCurrentDocumentReplyToJson(msg: GetCurrentDocumentReply): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.RECORDED, msg.recorded)
+    payload.put(Constants.REQUESTER_ID, msg.requesterID)
+    payload.put(Constants.NOTES, msg.notes.asJava)
+
+    val header = Util.buildHeader(MessageNames.GET_CURRENT_DOCUMENT_REPLY, None)
+    Util.buildJson(header, payload)
+  }
+
+  def createAdditionalNotesReplyToJson(msg: CreateAdditionalNotesReply): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.RECORDED, msg.recorded)
+    payload.put(Constants.REQUESTER_ID, msg.requesterID)
+    payload.put(Constants.NOTE_NAME, msg.noteName)
+    payload.put(Constants.NOTE_ID, msg.noteID)
+
+    val header = Util.buildHeader(MessageNames.CREATE_ADDITIONAL_NOTES_REPLY, None)
+    Util.buildJson(header, payload)
+  }
+
+  def destroyAdditionalNotesReplyToJson(msg: DestroyAdditionalNotesReply): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.RECORDED, msg.recorded)
+    payload.put(Constants.REQUESTER_ID, msg.requesterID)
+    payload.put(Constants.NOTE_ID, msg.noteID)
+
+    val header = Util.buildHeader(MessageNames.DESTROY_ADDITIONAL_NOTES_REPLY, None)
+    Util.buildJson(header, payload)
+  }
+
+  def sharedNotesSyncNoteReplyToJson(msg: SharedNotesSyncNoteReply): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.RECORDED, msg.recorded)
+    payload.put(Constants.REQUESTER_ID, msg.requesterID)
+    payload.put(Constants.NOTE_ID, msg.noteID)
+    payload.put(Constants.NOTE, msg.note)
+
+    val header = Util.buildHeader(MessageNames.SHAREDNOTES_SYNC_NOTE_REPLY, None)
+    Util.buildJson(header, payload)
+  }
+}
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/UsersMessageToJsonConverter.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/UsersMessageToJsonConverter.scala
index 1c003c65d18eadd762ccbafaa8144aa1864b1b41..4a775255d3d3b496df1a6a446ea4fabcfac50210 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/UsersMessageToJsonConverter.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/UsersMessageToJsonConverter.scala
@@ -16,6 +16,8 @@ object UsersMessageToJsonConverter {
     wuser += "extern_userid" -> user.externUserID
     wuser += "name" -> user.name
     wuser += "role" -> user.role.toString()
+    wuser += "guest" -> user.guest
+    wuser += "waiting_for_acceptance" -> user.waitingForAcceptance
     wuser += "emoji_status" -> user.emojiStatus
     wuser += "presenter" -> user.presenter
     wuser += "has_stream" -> user.hasStream
@@ -48,6 +50,8 @@ object UsersMessageToJsonConverter {
     wuser += "role" -> user.role.toString()
     wuser += "authToken" -> user.authToken
     wuser += "avatarURL" -> user.avatarURL
+    wuser += "guest" -> user.guest
+    wuser += "waiting_for_acceptance" -> user.waitingForAcceptance
 
     mapAsJavaMap(wuser)
   }
@@ -202,6 +206,16 @@ object UsersMessageToJsonConverter {
     Util.buildJson(header, payload)
   }
 
+  def userRoleChangeToJson(msg: UserRoleChange): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.USER_ID, msg.userID)
+    payload.put(Constants.ROLE, msg.role)
+
+    val header = Util.buildHeader(MessageNames.USER_ROLE_CHANGED, None)
+    Util.buildJson(header, payload)
+  }
+
   def userSharedWebcamToJson(msg: UserSharedWebcam): String = {
     val payload = new java.util.HashMap[String, Any]()
     payload.put(Constants.MEETING_ID, msg.meetingID)
@@ -431,4 +445,61 @@ object UsersMessageToJsonConverter {
     val header = Util.buildHeader(MessageNames.USER_LISTEN_ONLY, None)
     Util.buildJson(header, payload)
   }
-}
+
+  def getGuestPolicyToJson(msg: GetGuestPolicy): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.REQUESTER_ID, msg.requesterID)
+
+    val header = Util.buildHeader(MessageNames.GET_GUEST_POLICY, None)
+    Util.buildJson(header, payload)
+  }
+
+  def setGuestPolicyToJson(msg: SetGuestPolicy): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.GUEST_POLICY, msg.policy.toString())
+
+    val header = Util.buildHeader(MessageNames.SET_GUEST_POLICY, None)
+    Util.buildJson(header, payload)
+  }
+
+  def respondToGuestToJson(msg: RespondToGuest): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.USER_ID, msg.userId)
+    payload.put(Constants.RESPONSE, msg.response.toString())
+    payload.put(Constants.REQUESTER_ID, msg.requesterID)
+
+    val header = Util.buildHeader(MessageNames.RESPOND_TO_GUEST, None)
+    Util.buildJson(header, payload)
+  }
+
+  def getGuestPolicyReplyToJson(msg: GetGuestPolicyReply): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.REQUESTER_ID, msg.requesterID)
+    payload.put(Constants.GUEST_POLICY, msg.policy)
+
+    val header = Util.buildHeader(MessageNames.GET_GUEST_POLICY_REPLY, None)
+    Util.buildJson(header, payload)
+  }
+
+  def guestPolicyChangedToJson(msg: GuestPolicyChanged): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.GUEST_POLICY, msg.policy)
+
+    val header = Util.buildHeader(MessageNames.GUEST_POLICY_CHANGED, None)
+    Util.buildJson(header, payload)
+  }
+
+  def guestAccessDeniedToJson(msg: GuestAccessDenied): String = {
+    val payload = new java.util.HashMap[String, Any]()
+    payload.put(Constants.MEETING_ID, msg.meetingID)
+    payload.put(Constants.USER_ID, msg.userId)
+
+    val header = Util.buildHeader(MessageNames.GUEST_ACCESS_DENIED, None)
+    Util.buildJson(header, payload)
+  }
+}
\ No newline at end of file
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/AppsRedisSubscriberActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/AppsRedisSubscriberActor.scala
index 8c0544cbb4a68c2d83b4abba952289ae0243703c..6187fcd93cee5ace269878f0a352de05aff137fc 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/AppsRedisSubscriberActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/endpoint/redis/AppsRedisSubscriberActor.scala
@@ -1,6 +1,9 @@
 package org.bigbluebutton.endpoint.redis
 
 import akka.actor.Props
+import akka.actor.OneForOneStrategy
+import akka.actor.SupervisorStrategy.Resume
+import java.io.{ PrintWriter, StringWriter }
 import java.net.InetSocketAddress
 import redis.actors.RedisSubscriberActor
 import redis.api.pubsub.{ PMessage, Message }
@@ -29,6 +32,16 @@ class AppsRedisSubscriberActor(msgReceiver: RedisMessageReceiver, redisHost: Str
       new InetSocketAddress(redisHost, redisPort),
       channels, patterns) {
 
+  override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
+    case e: Exception => {
+      val sw: StringWriter = new StringWriter()
+      sw.write("An exception has been thrown on AppsRedisSubscriberActor, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+      e.printStackTrace(new PrintWriter(sw))
+      log.error(sw.toString())
+      Resume
+    }
+  }
+
   // Set the name of this client to be able to distinguish when doing
   // CLIENT LIST on redis-cli
   write(ClientSetname("BbbAppsAkkaSub").encodedRequest)
diff --git a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/endpoint/redis/AppsRedisSubscriberActor.scala b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/endpoint/redis/AppsRedisSubscriberActor.scala
index 780956206c1c1c95e92197dcb96f0a4b62295d52..2b8295b74f467e282ab588facd479b56a4575eb1 100755
--- a/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/endpoint/redis/AppsRedisSubscriberActor.scala
+++ b/akka-bbb-fsesl/src/main/scala/org/bigbluebutton/endpoint/redis/AppsRedisSubscriberActor.scala
@@ -1,6 +1,9 @@
 package org.bigbluebutton.endpoint.redis
 
 import akka.actor.Props
+import akka.actor.OneForOneStrategy
+import akka.actor.SupervisorStrategy.Resume
+import java.io.{ PrintWriter, StringWriter }
 import java.net.InetSocketAddress
 import redis.actors.RedisSubscriberActor
 import redis.api.pubsub.{ PMessage, Message }
@@ -32,6 +35,16 @@ class AppsRedisSubscriberActor(val system: ActorSystem, msgReceiver: RedisMessag
     extends RedisSubscriberActor(new InetSocketAddress(redisHost, redisPort),
       channels, patterns) {
 
+  override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
+    case e: Exception => {
+      val sw: StringWriter = new StringWriter()
+      sw.write("An exception has been thrown on AppsRedisSubscriberActor, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+      e.printStackTrace(new PrintWriter(sw))
+      log.error(sw.toString())
+      Resume
+    }
+  }
+
   val decoder = new FromJsonDecoder()
 
   var lastPongReceivedOn = 0L
diff --git a/bbb-api-demo/src/main/webapp/bbb_api.jsp b/bbb-api-demo/src/main/webapp/bbb_api.jsp
index 6609cc955f08557211f35dc0118848144358dea3..26b73a119ee5a27f89020c1a4393641a5e248be9 100755
--- a/bbb-api-demo/src/main/webapp/bbb_api.jsp
+++ b/bbb-api-demo/src/main/webapp/bbb_api.jsp
@@ -125,7 +125,15 @@ public String createMeeting(String meetingID, String welcome, String moderatorPa
 //
 // getJoinMeetingURL() -- get join meeting URL for both viewer and moderator
 //
+
 public String getJoinMeetingURL(String username, String meetingID, String password, String clientURL) {
+	return getJoinMeetingURL(username, meetingID, password, clientURL, false);
+}
+
+//
+// getJoinMeetingURL() -- get join meeting URL for both viewer and moderator
+//
+public String getJoinMeetingURL(String username, String meetingID, String password, String clientURL, Boolean guest) {
 	String base_url_join = BigBlueButtonURL + "api/join?";
         String clientURL_param = "";
 
@@ -136,7 +144,7 @@ public String getJoinMeetingURL(String username, String meetingID, String passwo
 
 	String join_parameters = "meetingID=" + urlEncode(meetingID)
 		+ "&fullName=" + urlEncode(username) + "&password="
-		+ urlEncode(password) +  clientURL_param;
+		+ urlEncode(password) + "&guest=" + urlEncode(guest.toString()) +  clientURL_param;
 
 	return base_url_join + join_parameters + "&checksum="
 		+ checksum("join" + join_parameters + salt);
diff --git a/bbb-api-demo/src/main/webapp/css/mconf-bootstrap.min.css b/bbb-api-demo/src/main/webapp/css/mconf-bootstrap.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..b6f2281784d44047cbcb84a1df94c4e3abeae4b5
--- /dev/null
+++ b/bbb-api-demo/src/main/webapp/css/mconf-bootstrap.min.css
@@ -0,0 +1,689 @@
+article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
+audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
+audio:not([controls]){display:none;}
+html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
+a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
+a:hover,a:active{outline:0;}
+sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
+sup{top:-0.5em;}
+sub{bottom:-0.25em;}
+img{height:auto;border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;}
+button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
+button,input{*overflow:visible;line-height:normal;}
+button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
+button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
+input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}
+input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
+textarea{overflow:auto;vertical-align:top;}
+.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";}
+.clearfix:after{clear:both;}
+.hide-text{overflow:hidden;text-indent:100%;white-space:nowrap;}
+.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}
+body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;}
+a{color:#367380;text-decoration:none;}
+a:hover{color:#1f434a;text-decoration:underline;}
+.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";}
+.row:after{clear:both;}
+[class*="span"]{float:left;margin-left:20px;}
+.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
+.span12{width:940px;}
+.span11{width:860px;}
+.span10{width:780px;}
+.span9{width:700px;}
+.span8{width:620px;}
+.span7{width:540px;}
+.span6{width:460px;}
+.span5{width:380px;}
+.span4{width:300px;}
+.span3{width:220px;}
+.span2{width:140px;}
+.span1{width:60px;}
+.offset12{margin-left:980px;}
+.offset11{margin-left:900px;}
+.offset10{margin-left:820px;}
+.offset9{margin-left:740px;}
+.offset8{margin-left:660px;}
+.offset7{margin-left:580px;}
+.offset6{margin-left:500px;}
+.offset5{margin-left:420px;}
+.offset4{margin-left:340px;}
+.offset3{margin-left:260px;}
+.offset2{margin-left:180px;}
+.offset1{margin-left:100px;}
+.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";}
+.row-fluid:after{clear:both;}
+.row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;}
+.row-fluid>[class*="span"]:first-child{margin-left:0;}
+.row-fluid > .span12{width:99.99999998999999%;}
+.row-fluid > .span11{width:91.489361693%;}
+.row-fluid > .span10{width:82.97872339599999%;}
+.row-fluid > .span9{width:74.468085099%;}
+.row-fluid > .span8{width:65.95744680199999%;}
+.row-fluid > .span7{width:57.446808505%;}
+.row-fluid > .span6{width:48.93617020799999%;}
+.row-fluid > .span5{width:40.425531911%;}
+.row-fluid > .span4{width:31.914893614%;}
+.row-fluid > .span3{width:23.404255317%;}
+.row-fluid > .span2{width:14.89361702%;}
+.row-fluid > .span1{width:6.382978723%;}
+.container{margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";}
+.container:after{clear:both;}
+.container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";}
+.container-fluid:after{clear:both;}
+p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;}
+.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;}
+h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;}
+h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;}
+h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;}
+h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;}
+h4,h5,h6{line-height:18px;}
+h4{font-size:14px;}h4 small{font-size:12px;}
+h5{font-size:12px;}
+h6{font-size:11px;color:#999999;text-transform:uppercase;}
+.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;}
+.page-header h1{line-height:1;}
+ul,ol{padding:0;margin:0 0 9px 25px;}
+ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
+ul{list-style:disc;}
+ol{list-style:decimal;}
+li{line-height:18px;}
+ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}
+dl{margin-bottom:18px;}
+dt,dd{line-height:18px;}
+dt{font-weight:bold;line-height:17px;}
+dd{margin-left:9px;}
+.dl-horizontal dt{float:left;clear:left;width:120px;text-align:right;}
+.dl-horizontal dd{margin-left:130px;}
+hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}
+strong{font-weight:bold;}
+em{font-style:italic;}
+.muted{color:#999999;}
+abbr[title]{border-bottom:1px dotted #ddd;cursor:help;}
+abbr.initialism{font-size:90%;text-transform:uppercase;}
+blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;}
+blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
+blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
+q:before,q:after,blockquote:before,blockquote:after{content:"";}
+address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;}
+small{font-size:100%;}
+cite{font-style:normal;}
+code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}
+pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;word-wrap:break-word;}pre.prettyprint{margin-bottom:18px;}
+pre code{padding:0;color:inherit;background-color:transparent;border:0;}
+.pre-scrollable{max-height:340px;overflow-y:scroll;}
+form{margin:0 0 18px;}
+fieldset{padding:0;margin:0;border:0;}
+legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;}legend small{font-size:13.5px;color:#999999;}
+label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px;}
+input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
+label{display:block;margin-bottom:5px;color:#333333;}
+input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #cccccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.uneditable-textarea{width:auto;height:auto;}
+label input,label textarea,label select{display:block;}
+input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border:0 \9;}
+input[type="image"]{border:0;}
+input[type="file"]{width:auto;padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;}
+select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;}
+input[type="file"]{line-height:18px \9;}
+select{width:220px;background-color:#ffffff;}
+select[multiple],select[size]{height:auto;}
+input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+textarea{height:auto;}
+input[type="hidden"]{display:none;}
+.radio,.checkbox{padding-left:18px;}
+.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;}
+.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
+.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}
+.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
+input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;}
+input:focus,textarea:focus{border-color:#367380;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px #367380;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px #367380;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px #367380;outline:0;outline:thin dotted \9;}
+input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
+.input-mini{width:60px;}
+.input-small{width:90px;}
+.input-medium{width:150px;}
+.input-large{width:210px;}
+.input-xlarge{width:270px;}
+.input-xxlarge{width:530px;}
+input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;}
+input,textarea,.uneditable-input{margin-left:0;}
+input.span12, textarea.span12, .uneditable-input.span12{width:930px;}
+input.span11, textarea.span11, .uneditable-input.span11{width:850px;}
+input.span10, textarea.span10, .uneditable-input.span10{width:770px;}
+input.span9, textarea.span9, .uneditable-input.span9{width:690px;}
+input.span8, textarea.span8, .uneditable-input.span8{width:610px;}
+input.span7, textarea.span7, .uneditable-input.span7{width:530px;}
+input.span6, textarea.span6, .uneditable-input.span6{width:450px;}
+input.span5, textarea.span5, .uneditable-input.span5{width:370px;}
+input.span4, textarea.span4, .uneditable-input.span4{width:290px;}
+input.span3, textarea.span3, .uneditable-input.span3{width:210px;}
+input.span2, textarea.span2, .uneditable-input.span2{width:130px;}
+input.span1, textarea.span1, .uneditable-input.span1{width:50px;}
+input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#eeeeee;border-color:#ddd;cursor:not-allowed;}
+.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
+.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;}
+.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
+.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
+.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;}
+.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
+.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
+.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;}
+.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}
+input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
+.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#eeeeee;border-top:1px solid #ddd;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";}
+.form-actions:after{clear:both;}
+.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
+:-moz-placeholder{color:#999999;}
+::-webkit-input-placeholder{color:#999999;}
+.help-block,.help-inline{color:#555555;}
+.help-block{display:block;margin-bottom:9px;}
+.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;}
+.input-prepend,.input-append{margin-bottom:5px;}.input-prepend input,.input-append input,.input-prepend select,.input-append select,.input-prepend .uneditable-input,.input-append .uneditable-input{*margin-left:0;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend select:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;}
+.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;}
+.input-prepend .add-on,.input-append .add-on{display:inline-block;width:auto;min-width:16px;height:18px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 #ffffff;vertical-align:middle;background-color:#eeeeee;border:1px solid #ccc;}
+.input-prepend .add-on,.input-append .add-on,.input-prepend .btn,.input-append .btn{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;}
+.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;}
+.input-append input,.input-append select .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.input-append .uneditable-input{border-left-color:#eee;border-right-color:#ccc;}
+.input-append .add-on,.input-append .btn{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
+.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
+.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;}
+.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;margin-bottom:0;}
+.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
+.form-search label,.form-inline label{display:inline-block;}
+.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;}
+.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;}
+.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-left:0;margin-right:3px;}
+.control-group{margin-bottom:9px;}
+legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;}
+.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";}
+.form-horizontal .control-group:after{clear:both;}
+.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right;}
+.form-horizontal .controls{margin-left:160px;*display:inline-block;*margin-left:0;*padding-left:20px;}
+.form-horizontal .help-block{margin-top:9px;margin-bottom:0;}
+.form-horizontal .form-actions{padding-left:160px;}
+table{max-width:100%;border-collapse:collapse;border-spacing:0;background-color:transparent;}
+.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;}
+.table th{font-weight:bold;}
+.table thead th{vertical-align:bottom;}
+.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;}
+.table tbody+tbody{border-top:2px solid #dddddd;}
+.table-condensed th,.table-condensed td{padding:4px 5px;}
+.table-bordered{border:1px solid #dddddd;border-left:0;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;}
+.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}
+.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
+.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
+.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
+.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
+.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
+.table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;}
+table .span1{float:none;width:44px;margin-left:0;}
+table .span2{float:none;width:124px;margin-left:0;}
+table .span3{float:none;width:204px;margin-left:0;}
+table .span4{float:none;width:284px;margin-left:0;}
+table .span5{float:none;width:364px;margin-left:0;}
+table .span6{float:none;width:444px;margin-left:0;}
+table .span7{float:none;width:524px;margin-left:0;}
+table .span8{float:none;width:604px;margin-left:0;}
+table .span9{float:none;width:684px;margin-left:0;}
+table .span10{float:none;width:764px;margin-left:0;}
+table .span11{float:none;width:844px;margin-left:0;}
+table .span12{float:none;width:924px;margin-left:0;}
+table .span13{float:none;width:1004px;margin-left:0;}
+table .span14{float:none;width:1084px;margin-left:0;}
+table .span15{float:none;width:1164px;margin-left:0;}
+table .span16{float:none;width:1244px;margin-left:0;}
+table .span17{float:none;width:1324px;margin-left:0;}
+table .span18{float:none;width:1404px;margin-left:0;}
+table .span19{float:none;width:1484px;margin-left:0;}
+table .span20{float:none;width:1564px;margin-left:0;}
+table .span21{float:none;width:1644px;margin-left:0;}
+table .span22{float:none;width:1724px;margin-left:0;}
+table .span23{float:none;width:1804px;margin-left:0;}
+table .span24{float:none;width:1884px;margin-left:0;}
+[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;*margin-right:.3em;}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0;}
+.icon-white{background-image:url("../img/glyphicons-halflings-white.png");}
+.icon-glass{background-position:0 0;}
+.icon-music{background-position:-24px 0;}
+.icon-search{background-position:-48px 0;}
+.icon-envelope{background-position:-72px 0;}
+.icon-heart{background-position:-96px 0;}
+.icon-star{background-position:-120px 0;}
+.icon-star-empty{background-position:-144px 0;}
+.icon-user{background-position:-168px 0;}
+.icon-film{background-position:-192px 0;}
+.icon-th-large{background-position:-216px 0;}
+.icon-th{background-position:-240px 0;}
+.icon-th-list{background-position:-264px 0;}
+.icon-ok{background-position:-288px 0;}
+.icon-remove{background-position:-312px 0;}
+.icon-zoom-in{background-position:-336px 0;}
+.icon-zoom-out{background-position:-360px 0;}
+.icon-off{background-position:-384px 0;}
+.icon-signal{background-position:-408px 0;}
+.icon-cog{background-position:-432px 0;}
+.icon-trash{background-position:-456px 0;}
+.icon-home{background-position:0 -24px;}
+.icon-file{background-position:-24px -24px;}
+.icon-time{background-position:-48px -24px;}
+.icon-road{background-position:-72px -24px;}
+.icon-download-alt{background-position:-96px -24px;}
+.icon-download{background-position:-120px -24px;}
+.icon-upload{background-position:-144px -24px;}
+.icon-inbox{background-position:-168px -24px;}
+.icon-play-circle{background-position:-192px -24px;}
+.icon-repeat{background-position:-216px -24px;}
+.icon-refresh{background-position:-240px -24px;}
+.icon-list-alt{background-position:-264px -24px;}
+.icon-lock{background-position:-287px -24px;}
+.icon-flag{background-position:-312px -24px;}
+.icon-headphones{background-position:-336px -24px;}
+.icon-volume-off{background-position:-360px -24px;}
+.icon-volume-down{background-position:-384px -24px;}
+.icon-volume-up{background-position:-408px -24px;}
+.icon-qrcode{background-position:-432px -24px;}
+.icon-barcode{background-position:-456px -24px;}
+.icon-tag{background-position:0 -48px;}
+.icon-tags{background-position:-25px -48px;}
+.icon-book{background-position:-48px -48px;}
+.icon-bookmark{background-position:-72px -48px;}
+.icon-print{background-position:-96px -48px;}
+.icon-camera{background-position:-120px -48px;}
+.icon-font{background-position:-144px -48px;}
+.icon-bold{background-position:-167px -48px;}
+.icon-italic{background-position:-192px -48px;}
+.icon-text-height{background-position:-216px -48px;}
+.icon-text-width{background-position:-240px -48px;}
+.icon-align-left{background-position:-264px -48px;}
+.icon-align-center{background-position:-288px -48px;}
+.icon-align-right{background-position:-312px -48px;}
+.icon-align-justify{background-position:-336px -48px;}
+.icon-list{background-position:-360px -48px;}
+.icon-indent-left{background-position:-384px -48px;}
+.icon-indent-right{background-position:-408px -48px;}
+.icon-facetime-video{background-position:-432px -48px;}
+.icon-picture{background-position:-456px -48px;}
+.icon-pencil{background-position:0 -72px;}
+.icon-map-marker{background-position:-24px -72px;}
+.icon-adjust{background-position:-48px -72px;}
+.icon-tint{background-position:-72px -72px;}
+.icon-edit{background-position:-96px -72px;}
+.icon-share{background-position:-120px -72px;}
+.icon-check{background-position:-144px -72px;}
+.icon-move{background-position:-168px -72px;}
+.icon-step-backward{background-position:-192px -72px;}
+.icon-fast-backward{background-position:-216px -72px;}
+.icon-backward{background-position:-240px -72px;}
+.icon-play{background-position:-264px -72px;}
+.icon-pause{background-position:-288px -72px;}
+.icon-stop{background-position:-312px -72px;}
+.icon-forward{background-position:-336px -72px;}
+.icon-fast-forward{background-position:-360px -72px;}
+.icon-step-forward{background-position:-384px -72px;}
+.icon-eject{background-position:-408px -72px;}
+.icon-chevron-left{background-position:-432px -72px;}
+.icon-chevron-right{background-position:-456px -72px;}
+.icon-plus-sign{background-position:0 -96px;}
+.icon-minus-sign{background-position:-24px -96px;}
+.icon-remove-sign{background-position:-48px -96px;}
+.icon-ok-sign{background-position:-72px -96px;}
+.icon-question-sign{background-position:-96px -96px;}
+.icon-info-sign{background-position:-120px -96px;}
+.icon-screenshot{background-position:-144px -96px;}
+.icon-remove-circle{background-position:-168px -96px;}
+.icon-ok-circle{background-position:-192px -96px;}
+.icon-ban-circle{background-position:-216px -96px;}
+.icon-arrow-left{background-position:-240px -96px;}
+.icon-arrow-right{background-position:-264px -96px;}
+.icon-arrow-up{background-position:-289px -96px;}
+.icon-arrow-down{background-position:-312px -96px;}
+.icon-share-alt{background-position:-336px -96px;}
+.icon-resize-full{background-position:-360px -96px;}
+.icon-resize-small{background-position:-384px -96px;}
+.icon-plus{background-position:-408px -96px;}
+.icon-minus{background-position:-433px -96px;}
+.icon-asterisk{background-position:-456px -96px;}
+.icon-exclamation-sign{background-position:0 -120px;}
+.icon-gift{background-position:-24px -120px;}
+.icon-leaf{background-position:-48px -120px;}
+.icon-fire{background-position:-72px -120px;}
+.icon-eye-open{background-position:-96px -120px;}
+.icon-eye-close{background-position:-120px -120px;}
+.icon-warning-sign{background-position:-144px -120px;}
+.icon-plane{background-position:-168px -120px;}
+.icon-calendar{background-position:-192px -120px;}
+.icon-random{background-position:-216px -120px;}
+.icon-comment{background-position:-240px -120px;}
+.icon-magnet{background-position:-264px -120px;}
+.icon-chevron-up{background-position:-288px -120px;}
+.icon-chevron-down{background-position:-313px -119px;}
+.icon-retweet{background-position:-336px -120px;}
+.icon-shopping-cart{background-position:-360px -120px;}
+.icon-folder-close{background-position:-384px -120px;}
+.icon-folder-open{background-position:-408px -120px;}
+.icon-resize-vertical{background-position:-432px -119px;}
+.icon-resize-horizontal{background-position:-456px -118px;}
+.dropdown{position:relative;}
+.dropdown-toggle{*margin-bottom:-3px;}
+.dropdown-toggle:active,.open .dropdown-toggle{outline:0;}
+.caret{display:inline-block;width:0;height:0;vertical-align:top;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000000;opacity:0.3;filter:alpha(opacity=30);content:"";}
+.dropdown .caret{margin-top:8px;margin-left:2px;}
+.dropdown:hover .caret,.open.dropdown .caret{opacity:1;filter:alpha(opacity=100);}
+.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;padding:4px 0;margin:0;list-style:none;background-color:#ffffff;border-color:#ccc;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:1px;-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;}.dropdown-menu.pull-right{right:0;left:auto;}
+.dropdown-menu .divider{height:1px;margin:8px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;}
+.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#333333;white-space:nowrap;}
+.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#367380;}
+.dropdown.open{*z-index:1000;}.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);}
+.dropdown.open .dropdown-menu{display:block;}
+.pull-right .dropdown-menu{left:auto;right:0;}
+.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"\2191";}
+.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;}
+.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}
+.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
+.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;}
+.collapse{-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;position:relative;overflow:hidden;height:0;}.collapse.in{height:auto;}
+.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;opacity:0.4;filter:alpha(opacity=40);cursor:pointer;}
+.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 10px 4px;margin-bottom:0;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);vertical-align:middle;background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-ms-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(top, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);border:1px solid #cccccc;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;}
+.btn:active,.btn.active{background-color:#cccccc \9;}
+.btn:first-child{*margin-left:0;}
+.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
+.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
+.btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;outline:0;}
+.btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
+.btn-large [class^="icon-"]{margin-top:1px;}
+.btn-small{padding:5px 9px;font-size:11px;line-height:16px;}
+.btn-small [class^="icon-"]{margin-top:-1px;}
+.btn-mini{padding:2px 6px;font-size:11px;line-height:14px;}
+.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;}
+.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);}
+.btn-primary{background-color:#366c80;background-image:-moz-linear-gradient(top, #367380, #366180);background-image:-ms-linear-gradient(top, #367380, #366180);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#367380), to(#366180));background-image:-webkit-linear-gradient(top, #367380, #366180);background-image:-o-linear-gradient(top, #367380, #366180);background-image:linear-gradient(top, #367380, #366180);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#367380', endColorstr='#366180', GradientType=0);border-color:#366180 #366180 #1f384a;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#366180;}
+.btn-primary:active,.btn-primary.active{background-color:#27455c \9;}
+.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;}
+.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
+.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;}
+.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
+.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;}
+.btn-success:active,.btn-success.active{background-color:#408140 \9;}
+.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;}
+.btn-info:active,.btn-info.active{background-color:#24748c \9;}
+.btn-inverse{background-color:#414141;background-image:-moz-linear-gradient(top, #555555, #222222);background-image:-ms-linear-gradient(top, #555555, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));background-image:-webkit-linear-gradient(top, #555555, #222222);background-image:-o-linear-gradient(top, #555555, #222222);background-image:linear-gradient(top, #555555, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#222222;}
+.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;}
+button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;}
+button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;}
+button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;}
+button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;}
+.btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";}
+.btn-group:after{clear:both;}
+.btn-group:first-child{*margin-left:0;}
+.btn-group+.btn-group{margin-left:5px;}
+.btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;}
+.btn-group .btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.btn-group .btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
+.btn-group .btn:last-child,.btn-group .dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
+.btn-group .btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}
+.btn-group .btn.large:last-child,.btn-group .large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}
+.btn-group .btn:hover,.btn-group .btn:focus,.btn-group .btn:active,.btn-group .btn.active{z-index:2;}
+.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
+.btn-group .dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:3px;*padding-bottom:3px;}
+.btn-group .btn-mini.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:1px;*padding-bottom:1px;}
+.btn-group .btn-small.dropdown-toggle{*padding-top:4px;*padding-bottom:4px;}
+.btn-group .btn-large.dropdown-toggle{padding-left:12px;padding-right:12px;}
+.btn-group.open{*z-index:1000;}.btn-group.open .dropdown-menu{display:block;margin-top:1px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
+.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);}
+.btn .caret{margin-top:7px;margin-left:0;}
+.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);}
+.btn-mini .caret{margin-top:5px;}
+.btn-small .caret{margin-top:6px;}
+.btn-large .caret{margin-top:6px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
+.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);}
+.alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#c09853;}
+.alert-heading{color:inherit;}
+.alert .close{position:relative;top:-2px;right:-21px;line-height:18px;}
+.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;}
+.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;}
+.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;}
+.alert-block{padding-top:14px;padding-bottom:14px;}
+.alert-block>p,.alert-block>ul{margin-bottom:0;}
+.alert-block p+p{margin-top:5px;}
+.nav{margin-left:0;margin-bottom:18px;list-style:none;}
+.nav>li>a{display:block;}
+.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;}
+.nav .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;}
+.nav li+.nav-header{margin-top:9px;}
+.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;}
+.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}
+.nav-list>li>a{padding:3px 15px;}
+.nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#367380;}
+.nav-list [class^="icon-"]{margin-right:2px;}
+.nav-list .divider{height:1px;margin:8px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;}
+.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";}
+.nav-tabs:after,.nav-pills:after{clear:both;}
+.nav-tabs>li,.nav-pills>li{float:left;}
+.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}
+.nav-tabs{border-bottom:1px solid #ddd;}
+.nav-tabs>li{margin-bottom:-1px;}
+.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;}
+.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
+.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
+.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#367380;}
+.nav-stacked>li{float:none;}
+.nav-stacked>li>a{margin-right:0;}
+.nav-tabs.nav-stacked{border-bottom:0;}
+.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
+.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
+.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;}
+.nav-pills.nav-stacked>li>a{margin-bottom:3px;}
+.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}
+.nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;}
+.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#367380;border-bottom-color:#367380;margin-top:6px;}
+.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#1f434a;border-bottom-color:#1f434a;}
+.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;border-bottom-color:#333333;}
+.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;}
+.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;}
+.nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);}
+.tabs-stacked .open>a:hover{border-color:#999999;}
+.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";}
+.tabbable:after{clear:both;}
+.tab-content{display:table;width:100%;}
+.tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;}
+.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
+.tab-content>.active,.pill-content>.active{display:block;}
+.tabs-below .nav-tabs{border-top:1px solid #ddd;}
+.tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;}
+.tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;}
+.tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;}
+.tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;}
+.tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}
+.tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}
+.tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
+.tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}
+.tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}
+.tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}
+.tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
+.tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}
+.tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}
+.navbar{*position:relative;*z-index:2;overflow:visible;margin-bottom:18px;}
+.navbar-inner{padding-left:20px;padding-right:20px;background-color:#1b454e;background-image:-moz-linear-gradient(top, #27535c, #0a3138);background-image:-ms-linear-gradient(top, #27535c, #0a3138);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#27535c), to(#0a3138));background-image:-webkit-linear-gradient(top, #27535c, #0a3138);background-image:-o-linear-gradient(top, #27535c, #0a3138);background-image:linear-gradient(top, #27535c, #0a3138);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#27535c', endColorstr='#0a3138', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);}
+.navbar .container{width:auto;}
+.btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#1b454e;background-image:-moz-linear-gradient(top, #27535c, #0a3138);background-image:-ms-linear-gradient(top, #27535c, #0a3138);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#27535c), to(#0a3138));background-image:-webkit-linear-gradient(top, #27535c, #0a3138);background-image:-o-linear-gradient(top, #27535c, #0a3138);background-image:linear-gradient(top, #27535c, #0a3138);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#27535c', endColorstr='#0a3138', GradientType=0);border-color:#0a3138 #0a3138 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#0a3138;}
+.btn-navbar:active,.btn-navbar.active{background-color:#020b0d \9;}
+.btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);}
+.btn-navbar .icon-bar+.icon-bar{margin-top:3px;}
+.nav-collapse.collapse{height:auto;}
+.navbar{color:#bbbbbb;}.navbar .brand:hover{text-decoration:none;}
+.navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;}
+.navbar .navbar-text{margin-bottom:0;line-height:40px;}
+.navbar .btn,.navbar .btn-group{margin-top:5px;}
+.navbar .btn-group .btn{margin-top:0;}
+.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";}
+.navbar-form:after{clear:both;}
+.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;}
+.navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0;}
+.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;}
+.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;}
+.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;background-color:#1d90a4;border:1px solid #061e22;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query:-moz-placeholder{color:#cccccc;}
+.navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;}
+.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;}
+.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;}
+.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
+.navbar-fixed-top{top:0;}
+.navbar-fixed-bottom{bottom:0;}
+.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;}
+.navbar .nav.pull-right{float:right;}
+.navbar .nav>li{display:block;float:left;}
+.navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#bbbbbb;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}
+.navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;}
+.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#0a3138;}
+.navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#0a3138;border-right:1px solid #27535c;}
+.navbar .nav.pull-right{margin-left:10px;margin-right:0;}
+.navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;}
+.navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;}
+.navbar-fixed-bottom .dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;}
+.navbar-fixed-bottom .dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;}
+.navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
+.navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);}
+.navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;}
+.navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;}
+.navbar .nav.pull-right .dropdown-menu,.navbar .nav .dropdown-menu.pull-right{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before,.navbar .nav .dropdown-menu.pull-right:before{left:auto;right:12px;}
+.navbar .nav.pull-right .dropdown-menu:after,.navbar .nav .dropdown-menu.pull-right:after{left:auto;right:13px;}
+.breadcrumb{padding:7px 14px;margin:0 0 18px;list-style:none;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;}
+.breadcrumb .divider{padding:0 5px;color:#999999;}
+.breadcrumb .active a{color:#333333;}
+.pagination{height:36px;margin:18px 0;}
+.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
+.pagination li{display:inline;}
+.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;}
+.pagination a:hover,.pagination .active a{background-color:#f5f5f5;}
+.pagination .active a{color:#999999;cursor:default;}
+.pagination .disabled span,.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;}
+.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
+.pagination-centered{text-align:center;}
+.pagination-right{text-align:right;}
+.pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";}
+.pager:after{clear:both;}
+.pager li{display:inline;}
+.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
+.pager a:hover{text-decoration:none;background-color:#f5f5f5;}
+.pager .next a{float:right;}
+.pager .previous a{float:left;}
+.pager .disabled a,.pager .disabled a:hover{color:#999999;background-color:#fff;cursor:default;}
+.modal-open .dropdown-menu{z-index:2050;}
+.modal-open .dropdown.open{*z-index:2050;}
+.modal-open .popover{z-index:2060;}
+.modal-open .tooltip{z-index:2070;}
+.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}
+.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}
+.modal{position:fixed;top:50%;left:50%;z-index:1050;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}
+.modal.fade.in{top:50%;}
+.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}
+.modal-body{overflow-y:auto;max-height:400px;padding:15px;}
+.modal-form{margin-bottom:0;}
+.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";}
+.modal-footer:after{clear:both;}
+.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;}
+.modal-footer .btn-group .btn+.btn{margin-left:-1px;}
+.tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);}
+.tooltip.top{margin-top:-2px;}
+.tooltip.right{margin-left:2px;}
+.tooltip.bottom{margin-top:2px;}
+.tooltip.left{margin-left:-2px;}
+.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
+.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
+.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
+.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
+.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.tooltip-arrow{position:absolute;width:0;height:0;}
+.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;}
+.popover.right{margin-left:5px;}
+.popover.bottom{margin-top:5px;}
+.popover.left{margin-left:-5px;}
+.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
+.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
+.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
+.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
+.popover .arrow{position:absolute;width:0;height:0;}
+.popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);}
+.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;}
+.popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;}
+.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";}
+.thumbnails:after{clear:both;}
+.thumbnails>li{float:left;margin:0 0 18px 20px;}
+.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);}
+a.thumbnail:hover{border-color:#367380;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);}
+.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;}
+.thumbnail .caption{padding:9px;}
+.label{padding:1px 4px 2px;font-size:10.998px;font-weight:bold;line-height:13px;color:#ffffff;vertical-align:middle;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.label:hover{color:#ffffff;text-decoration:none;}
+.label-important{background-color:#b94a48;}
+.label-important:hover{background-color:#953b39;}
+.label-warning{background-color:#f89406;}
+.label-warning:hover{background-color:#c67605;}
+.label-success{background-color:#468847;}
+.label-success:hover{background-color:#356635;}
+.label-info{background-color:#3a87ad;}
+.label-info:hover{background-color:#2d6987;}
+.label-inverse{background-color:#333333;}
+.label-inverse:hover{background-color:#1a1a1a;}
+.badge{padding:1px 9px 2px;font-size:12.025px;font-weight:bold;white-space:nowrap;color:#ffffff;background-color:#999999;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}
+.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}
+.badge-error{background-color:#b94a48;}
+.badge-error:hover{background-color:#953b39;}
+.badge-warning{background-color:#f89406;}
+.badge-warning:hover{background-color:#c67605;}
+.badge-success{background-color:#468847;}
+.badge-success:hover{background-color:#356635;}
+.badge-info{background-color:#3a87ad;}
+.badge-info:hover{background-color:#2d6987;}
+.badge-inverse{background-color:#333333;}
+.badge-inverse:hover{background-color:#1a1a1a;}
+@-webkit-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;}
+.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;}
+.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;}
+.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);}
+.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);}
+.progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);}
+.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.progress-warning .bar{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);}
+.progress-warning.progress-striped .bar{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.accordion{margin-bottom:18px;}
+.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.accordion-heading{border-bottom:0;}
+.accordion-heading .accordion-toggle{display:block;padding:8px 15px;}
+.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;}
+.carousel{position:relative;margin-bottom:18px;line-height:1;}
+.carousel-inner{overflow:hidden;width:100%;position:relative;}
+.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}
+.carousel .item>img{display:block;line-height:1;}
+.carousel .active,.carousel .next,.carousel .prev{display:block;}
+.carousel .active{left:0;}
+.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;}
+.carousel .next{left:100%;}
+.carousel .prev{left:-100%;}
+.carousel .next.left,.carousel .prev.right{left:0;}
+.carousel .active.left{left:-100%;}
+.carousel .active.right{left:100%;}
+.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;}
+.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);}
+.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);}
+.carousel-caption h4,.carousel-caption p{color:#ffffff;}
+.hero-unit{padding:60px;margin-bottom:30px;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;}
+.hero-unit p{font-size:18px;font-weight:200;line-height:27px;color:inherit;}
+.pull-right{float:right;}
+.pull-left{float:left;}
+.hide{display:none;}
+.show{display:block;}
+.invisible{visibility:hidden;}
diff --git a/bbb-api-demo/src/main/webapp/demo10_helper.jsp b/bbb-api-demo/src/main/webapp/demo10_helper.jsp
index 38905bc02698405842404d6ee7a53abc20cf14ba..62024f89611941fa102a1ff0859543cb5d655687 100755
--- a/bbb-api-demo/src/main/webapp/demo10_helper.jsp
+++ b/bbb-api-demo/src/main/webapp/demo10_helper.jsp
@@ -14,7 +14,7 @@ String locIP=request.getLocalAddr();
 	<running><%= isMeetingRunning(request.getParameter("meetingID")) %></running>
 </response>
 <% } else if(request.getParameter("command").equals("getRecords")){%>
-      <%= getRecordings("English 101,English 102,English 103,English 104,English 105,English 106,English 107,English 108,English 109,English 110")%>
+      <%= getRecordings(request.getParameter("meetingID"))%>
 <% } else if(request.getParameter("command").equals("publish")||request.getParameter("command").equals("unpublish")){%>
 	<%= setPublishRecordings( (request.getParameter("command").equals("publish")) ? true : false , request.getParameter("recordID"))%>
 <% } else if(request.getParameter("command").equals("delete")){%>
diff --git a/bbb-api-demo/src/main/webapp/demo3.jsp b/bbb-api-demo/src/main/webapp/demo3.jsp
index 02c3d7b22394ae80f4bfbe2fc31bcb4917c8f91c..48690e06897d449c64dd2b771b823c2bf4234c6a 100755
--- a/bbb-api-demo/src/main/webapp/demo3.jsp
+++ b/bbb-api-demo/src/main/webapp/demo3.jsp
@@ -197,6 +197,16 @@ if (request.getParameterMap().isEmpty()) {
 			<td>
 				<input type="password" required name="password" /></td>
 		</tr>
+		<tr>
+			<td>
+				&nbsp;</td>
+			<td style="text-align: right; ">
+				Guest:</td>
+			<td>
+				&nbsp;</td>
+			<td>
+				<input type="checkbox" name="guest" value="guest" /></td>
+		</tr>
 		<tr>
 			<td>
 				&nbsp;</td>
@@ -273,7 +283,7 @@ Error: createMeeting() failed
 		// We've got a valid meeting_ID and passoword -- let's join!
 		//
 		
-		String joinURL = getJoinMeetingURL(username, meeting_ID, password, null);
+		String joinURL = getJoinMeetingURL(username, meeting_ID, password, null, request.getParameter("guest") != null);
 %>
 
 <script language="javascript" type="text/javascript">
diff --git a/bbb-api-demo/src/main/webapp/demo_mconf.jsp b/bbb-api-demo/src/main/webapp/demo_mconf.jsp
new file mode 100644
index 0000000000000000000000000000000000000000..da156df4c13bda68874ca8a918672cfc2c35bf39
--- /dev/null
+++ b/bbb-api-demo/src/main/webapp/demo_mconf.jsp
@@ -0,0 +1,444 @@
+<!--
+
+BigBlueButton - http://www.bigbluebutton.org
+
+Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
+
+BigBlueButton is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, If not, see <http://www.gnu.org/licenses/>.
+
+Author: Fred Dixon <ffdixon@bigbluebutton.org>
+
+-->
+
+<%@ page language="java" contentType="text/html; charset=UTF-8"
+	pageEncoding="UTF-8"%>
+<%
+	request.setCharacterEncoding("UTF-8");
+	response.setCharacterEncoding("UTF-8");
+%>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<title>Mconf-Live Demo</title>
+	<link rel="stylesheet" href="css/mconf-bootstrap.min.css" type="text/css" />
+	<link rel="stylesheet" type="text/css" href="css/ui.jqgrid.css" />
+	<link rel="stylesheet" type="text/css" href="css/redmond/jquery-ui-redmond.css" />
+	<script type="text/javascript" src="js/jquery.min.js"></script>
+	<script type="text/javascript" src="js/jquery-ui.js"></script>
+	<script type="text/javascript" src="js/jquery.validate.min.js"></script>
+	<script src="js/grid.locale-en.js" type="text/javascript"></script>
+	<script src="js/jquery.jqGrid.min.js" type="text/javascript"></script>
+	<script src="js/jquery.xml2json.js" type="text/javascript"></script>
+	<style type="text/css">
+	 .ui-jqgrid{
+		font-size:0.7em;
+		margin-left: auto;
+		margin-right: auto;
+	}
+	label.error{
+		float: none;
+		color: red;
+		padding-left: .5em;
+		vertical-align: top;
+		width:200px;
+		text-align:left;
+	}
+	</style>
+</head>
+<body>
+
+<%@ include file="bbb_api.jsp"%>
+
+<%
+
+//
+// We're going to define some sample courses (meetings) below.  This API exampe shows how you can create a login page for a course.
+// The password below are not available to users as they are compiled on the server.
+//
+
+HashMap<String, HashMap> allMeetings = new HashMap<String, HashMap>();
+HashMap<String, String> meeting;
+
+// String welcome = "<br>Welcome to %%CONFNAME%%!<br><br>For help see our <a href=\"event:http://www.bigbluebutton.org/content/videos\"><u>tutorial videos</u></a>.<br><br>To join the voice bridge for this meeting:<br>  (1) click the headset icon in the upper-left, or<br>  (2) dial xxx-xxx-xxxx (toll free:1-xxx-xxx-xxxx) and enter conference ID: %%CONFNUM%%.<br><br>";
+
+String welcome = "<br>Welcome to <b>%%CONFNAME%%</b>!<br><br>In order to speak, click on the headset icon.";
+
+meeting = new HashMap<String, String>();
+allMeetings.put( "Test room 1", meeting );	// The title that will appear in the drop-down menu
+	meeting.put("welcomeMsg", 	welcome);			// The welcome mesage
+	meeting.put("moderatorPW", 	"prof123");			// The password for moderator
+	meeting.put("viewerPW", 	"student123");			// The password for viewer
+	meeting.put("voiceBridge", 	"72013");			// The extension number for the voice bridge (use if connected to phone system)
+	meeting.put("logoutURL", 	"/demo/demo_mconf.jsp");  // The logout URL (use if you want to return to your pages)
+
+meeting = new HashMap<String, String>();
+allMeetings.put( "Test room 2", meeting );	// The title that will appear in the drop-down menu
+	meeting.put("welcomeMsg", 	welcome);			// The welcome mesage
+	meeting.put("moderatorPW", 	"prof123");			// The password for moderator
+	meeting.put("viewerPW", 	"student123");			// The password for viewer
+	meeting.put("voiceBridge", 	"72014");			// The extension number for the voice bridge (use if connected to phone system)
+	meeting.put("logoutURL", 	"/demo/demo_mconf.jsp");  // The logout URL (use if you want to return to your pages)
+
+meeting = new HashMap<String, String>();
+allMeetings.put( "Test room 3", meeting );	// The title that will appear in the drop-down menu
+	meeting.put("welcomeMsg", 	welcome);			// The welcome mesage
+	meeting.put("moderatorPW", 	"prof123");			// The password for moderator
+	meeting.put("viewerPW", 	"student123");			// The password for viewer
+	meeting.put("voiceBridge", 	"72015");			// The extension number for the voice bridge (use if connected to phone system)
+	meeting.put("logoutURL", 	"/demo/demo_mconf.jsp");  // The logout URL (use if you want to return to your pages)
+
+meeting = new HashMap<String, String>();
+allMeetings.put( "Test room 4", meeting );	// The title that will appear in the drop-down menu
+	meeting.put("welcomeMsg", 	welcome);			// The welcome mesage
+	meeting.put("moderatorPW", 	"prof123");			// The password for moderator
+	meeting.put("viewerPW", 	"student123");			// The password for viewer
+	meeting.put("voiceBridge", 	"72016");			// The extension number for the voice bridge (use if connected to phone system)
+	meeting.put("logoutURL", 	"/demo/demo_mconf.jsp");  // The logout URL (use if you want to return to your pages)
+
+meeting = null;
+
+Iterator<String> meetingIterator = new TreeSet<String>(allMeetings.keySet()).iterator();
+
+if (request.getParameterMap().isEmpty()) {
+		//
+		// Assume we want to join a course
+		//
+	%>
+
+<div style="width: 400px; margin: auto auto; ">
+	<div style="text-align: center; ">
+		<img src="images/mconf.png" style="
+			width: 300px;
+			height: auto;
+			display: block; margin-left: auto; margin-right: auto;
+		">
+	</div>
+
+	<span style="text-align: center; ">
+		<h3>Join a test room</h3>
+	</span>
+
+	<FORM NAME="form1" METHOD="GET">
+	<table cellpadding="3" cellspacing="5">
+		<tbody>
+			<tr>
+				<td>
+					&nbsp;</td>
+				<td style="text-align: right; ">
+					Room:</td>
+				<td>
+					&nbsp;
+				</td>
+				<td style="text-align: left ">
+				<select name="meetingID" onchange="onChangeMeeting(this.value);">
+				<%
+					String key;
+					while (meetingIterator.hasNext()) {
+						key = meetingIterator.next();
+						out.println("<option value=\"" + key + "\">" + key + "</option>");
+					}
+				%>
+				</select><span id="label_meeting_running" hidden><i>&nbsp;Running!</i></span>
+
+				</td>
+			</tr>
+			<tr>
+				<td>
+					&nbsp;</td>
+				<td style="text-align: right; ">
+					Full&nbsp;Name:</td>
+				<td style="width: 5px; ">
+					&nbsp;</td>
+				<td style="text-align: left ">
+					<input type="text" autofocus required name="username" /></td>
+			</tr>
+			<tr>
+				<td>
+					&nbsp;</td>
+				<td style="text-align: right; ">
+					Role:</td>
+				<td>
+					&nbsp;</td>
+				<td>
+					<input type="radio" name="password" value="prof123" text="Moderator" checked>Moderator</input>
+					<input type="radio" name="password" value="student123">Viewer</input>
+				</td>
+			</tr>
+			<tr>
+				<td>
+					&nbsp;</td>
+				<td style="text-align: right; ">
+					Guest:</td>
+				<td>
+					&nbsp;</td>
+				<td>
+					<input id="check_guest" type="checkbox" name="guest" value="guest" />&nbsp;&nbsp;&nbsp;(authorization required)</td>
+			</tr>
+			<tr>
+				<td>
+					&nbsp;</td>
+				<td>
+					&nbsp;</td>
+				<td>
+					&nbsp;</td>
+				<td>
+					<input type="submit" value="Join" style="width: 220px; "></td>
+			</tr>
+		</tbody>
+	</table>
+	<INPUT TYPE=hidden NAME=action VALUE="create">
+	</FORM>
+</div>
+
+<div style="text-align: center; ">
+	<h3>Recorded Sessions</h3>
+
+	<select id="actionscmb" name="actions" onchange="recordedAction(this.value);">
+		<option value="novalue" selected>Actions...</option>
+		<option value="publish">Publish</option>
+		<option value="unpublish">Unpublish</option>
+		<option value="delete">Delete</option>
+	</select>
+	<table id="recordgrid"></table>
+	<div id="pager"></div>
+	<p>Note: New recordings will appear in the above list after processing.  Refresh your browser to update the list.</p>
+	<script>
+	function onChangeMeeting(meetingID){
+		isRunningMeeting(meetingID);
+	}
+	function recordedAction(action){
+		if(action=="novalue"){
+			return;
+		}
+
+		var s = jQuery("#recordgrid").jqGrid('getGridParam','selarrrow');
+		if(s.length==0){
+			alert("Select at least one row");
+			$("#actionscmb").val("novalue");
+			return;
+		}
+		var recordid="";
+		for(var i=0;i<s.length;i++){
+			var d = jQuery("#recordgrid").jqGrid('getRowData',s[i]);
+			recordid+=d.id;
+			if(i!=s.length-1)
+				recordid+=",";
+		}
+		if(action=="delete"){
+			var answer = confirm ("Are you sure to delete the selected recordings?");
+			if (answer)
+				sendRecordingAction(recordid,action);
+			else{
+				$("#actionscmb").val("novalue");
+				return;
+			}
+		}else{
+			sendRecordingAction(recordid,action);
+		}
+		$("#actionscmb").val("novalue");
+	}
+
+	function sendRecordingAction(recordID,action){
+		$.ajax({
+			type: "GET",
+			url: 'demo10_helper.jsp',
+			data: "command="+action+"&recordID="+recordID,
+			dataType: "xml",
+			cache: false,
+			success: function(xml) {
+				window.location.reload(true);
+				$("#recordgrid").trigger("reloadGrid");
+			},
+			error: function() {
+				alert("Failed to connect to API.");
+			}
+		});
+	}
+
+	function isRunningMeeting(meetingID) {
+		$.ajax({
+			type: "GET",
+			url: 'demo10_helper.jsp',
+			data: "command=isRunning&meetingID="+meetingID,
+			dataType: "xml",
+			cache: false,
+			success: function(xml) {
+				response = $.xml2json(xml);
+				if(response.running=="true"){
+					$("#check_record").attr("readonly","readonly");
+					$("#check_record").attr("disabled","disabled");
+					$("#label_meeting_running").removeAttr("hidden");
+					$("#meta_description").val("An active session exists for "+meetingID+". This session is being recorded.");
+					$("#meta_description").attr("readonly","readonly");
+					$("#meta_description").attr("disabled","disabled");
+				}else{
+					$("#check_record").removeAttr("readonly");
+					$("#check_record").removeAttr("disabled");
+					$("#label_meeting_running").attr("hidden","");
+					$("#meta_description").val("");
+					$("#meta_description").removeAttr("readonly");
+					$("#meta_description").removeAttr("disabled");
+				}
+
+			},
+			error: function() {
+				alert("Failed to connect to API.");
+			}
+		});
+	}
+	var meetingID="Test room 1,Test room 2,Test room 3,Test room 4";
+	$(document).ready(function(){
+		isRunningMeeting("Test room 1");
+		$("#formcreate").validate();
+		$("#meetingID option[value='Test room 1']").attr("selected","selected");
+		jQuery("#recordgrid").jqGrid({
+			url: "demo10_helper.jsp?command=getRecords&meetingID="+meetingID,
+			datatype: "xml",
+			height: 150,
+			loadonce: true,
+			sortable: true,
+			colNames:['Id','Room','Date Recorded', 'Published', 'Playback', 'Length'],
+			colModel:[
+				{name:'id',index:'id', width:50, hidden:true, xmlmap: "recordID"},
+				{name:'course',index:'course', width:150, xmlmap: "name", sortable:true},
+				{name:'daterecorded',index:'daterecorded', width:200, xmlmap: "startTime", sortable: true, sorttype: "datetime", datefmt: "d-m-y h:i:s"},
+				{name:'published',index:'published', width:80, xmlmap: "published", sortable:true },
+				{name:'playback',index:'playback', width:150, xmlmap:"playback", sortable:false},
+				{name:'length',index:'length', width:80, xmlmap:"length", sortable:true}
+			],
+			xmlReader: {
+				root : "recordings",
+				row: "recording",
+				repeatitems:false,
+				id: "recordID"
+			},
+			pager : '#pager',
+			emptyrecords: "Nothing to display",
+			multiselect: true,
+			caption: "Recorded Sessions",
+			loadComplete: function(){
+				$("#recordgrid").trigger("reloadGrid");
+			}
+		});
+	});
+	</script>
+</div>
+
+<%
+	} else if (request.getParameter("action").equals("create")) {
+		//
+		// Got an action=create
+		//
+
+		String username = request.getParameter("username");
+		String meetingID = request.getParameter("meetingID");
+		String password = request.getParameter("password");
+
+		meeting = allMeetings.get( meetingID );
+
+		String welcomeMsg = meeting.get( "welcomeMsg" );
+		String logoutURL = meeting.get( "logoutURL" );
+		Integer voiceBridge = Integer.parseInt( meeting.get( "voiceBridge" ).trim() );
+
+		String viewerPW = meeting.get( "viewerPW" );
+		String moderatorPW = meeting.get( "moderatorPW" );
+		Boolean guest = request.getParameter("guest") != null;
+		Boolean record = request.getParameter("record") != null;
+
+		//
+		// Check if we have a valid password
+		//
+		if ( ! password.equals(viewerPW) && ! password.equals(moderatorPW) ) {
+%>
+
+Invalid Password, please <a href="javascript:history.go(-1)">try again</a>.
+
+<%
+			return;
+		}
+
+		// create the meeting
+		String base_url_create = BigBlueButtonURL + "api/create?";
+		String base_url_join = BigBlueButtonURL + "api/join?";
+		String welcome_param = "&welcome=" + urlEncode(welcomeMsg);
+		String voiceBridge_param = "&voiceBridge=" + voiceBridge;
+		String moderator_password_param = "&moderatorPW=" + urlEncode(moderatorPW);
+		String attendee_password_param = "&attendeePW=" + urlEncode(viewerPW);
+		String logoutURL_param = "&logoutURL=" + urlEncode(logoutURL);
+
+		String create_parameters = "name=" + urlEncode(meetingID)
+			+ "&meetingID=" + urlEncode(meetingID) + welcome_param + voiceBridge_param
+			+ moderator_password_param + attendee_password_param + logoutURL_param
+			+ "&record=true";
+
+		// Attempt to create a meeting using meetingID
+		Document doc = null;
+		try {
+			String url = base_url_create + create_parameters
+				+ "&checksum="
+				+ checksum("create" + create_parameters + salt);
+			doc = parseXml( postURL( url, "" ) );
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+		if (! doc.getElementsByTagName("returncode").item(0).getTextContent()
+				.trim().equals("SUCCESS")) {
+%>
+
+Error: createMeeting() failed
+<p /><%=meetingID%>
+
+<%
+			return;
+		}
+
+		//
+		// Looks good, now return a URL to join that meeting
+		//
+
+		String join_parameters = "meetingID=" + urlEncode(meetingID)
+			+ "&fullName=" + urlEncode(username) + "&password=" + urlEncode(password) + "&guest="+ urlEncode(guest.toString());
+		String joinURL = base_url_join + join_parameters + "&checksum="
+			+ checksum("join" + join_parameters + salt);
+%>
+
+<script language="javascript" type="text/javascript">
+	// http://stackoverflow.com/a/11381730
+	mobileAndTabletcheck = function() {
+		var check = false;
+		(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
+		return check;
+	}
+
+	processJoinUrl = function(url) {
+		if (mobileAndTabletcheck()) {
+			return url.replace("http://", "bigbluebutton://");
+		} else {
+			return url;
+		}
+	}
+
+	window.location.href = processJoinUrl("<%=joinURL%>");
+</script>
+
+<%
+	}
+%>
+
+</body>
+</html>
+
+
diff --git a/bbb-api-demo/src/main/webapp/images/mconf.png b/bbb-api-demo/src/main/webapp/images/mconf.png
new file mode 100644
index 0000000000000000000000000000000000000000..82b0093af6659d22ada9e4eb90b982fe3c7e8c17
Binary files /dev/null and b/bbb-api-demo/src/main/webapp/images/mconf.png differ
diff --git a/bbb-client-check/.gitignore b/bbb-client-check/.gitignore
index ba9063624573321ccc76a03a47c2a5e3f5edbe51..914906d499e0030da3115091ac254a286c7eaf52 100644
--- a/bbb-client-check/.gitignore
+++ b/bbb-client-check/.gitignore
@@ -7,3 +7,5 @@ org.eclipse.ltk.core.refactoring.prefs
 FlexPrettyPrintCommand.prefs
 index.template.html
 conf/config.xml
+resources/lib/bbb_localization.js
+resources/lib/jquery-1.5.1.min.js
diff --git a/bbb-client-check/build.xml b/bbb-client-check/build.xml
index 78de46517c93b6c267d7843be8d0249624f81e2c..6941c7de68632980bd7cdc7145937533f174fcf3 100755
--- a/bbb-client-check/build.xml
+++ b/bbb-client-check/build.xml
@@ -55,7 +55,7 @@
 		<mxmlc file="${SRC_DIR}/BBBClientCheck.mxml"
 			   output="check/BBBClientCheck.swf"
 			   debug="false"
-			   locale="en_US"
+			   locale="en_US,pt_BR"
 			   actionscript-file-encoding="UTF-8"
 			   incremental="false">
 			<static-link-runtime-shared-libraries>false</static-link-runtime-shared-libraries>
@@ -103,6 +103,11 @@
 	</target>
 	<target name="Resolve-Dependency"
 			description="Generate HTML wrapper">
+		<copy todir="resources/lib/" >
+			<fileset file="../bigbluebutton-client/resources/prod/lib/bbb_localization.js" />
+			<fileset file="../bigbluebutton-client/resources/prod/lib/jquery-1.5.1.min.js" />
+		</copy>
+
 		<get src="${TEST_IMAGE_URL}" dest="${html.output}/test_image.jpg" skipexisting="true" />
 		<copy file="html-template/index.html"
 			  tofile="${html.output}/index.html"/>
diff --git a/bbb-client-check/html-template/index.html b/bbb-client-check/html-template/index.html
index 1032a8e289a68c1451d18cf652e7b82064185959..4fbb92fb91b27bfe764ce330fb78254a571ad923 100755
--- a/bbb-client-check/html-template/index.html
+++ b/bbb-client-check/html-template/index.html
@@ -34,10 +34,12 @@
         <script type="text/javascript" src="history/history.js"></script>
         <!-- END Browser History required section -->  
          
+        <script type="text/javascript" src="resources/lib/jquery-1.5.1.min.js"></script>
         <script type="text/javascript" src="resources/lib/api-bridge.js"></script>
         <script type="text/javascript" src="resources/lib/sip.js"></script>
         <script type="text/javascript" src="resources/lib/bbb_webrtc_bridge_sip.js"></script>
         <script type="text/javascript" src="resources/lib/deployJava.js"></script>
+        <script type="text/javascript" src="resources/lib/bbb_localization.js"></script>
         <script type="text/javascript" src="swfobject.js"></script>
         <script type="text/javascript">
             // For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection. 
diff --git a/bbb-client-check/html-template/index.template.html b/bbb-client-check/html-template/index.template.html
index 710134f4ce5ae367386d66ff52f5f42aee03f7eb..f7583f2543529a98ccd9398970fc7bd5762c022b 100755
--- a/bbb-client-check/html-template/index.template.html
+++ b/bbb-client-check/html-template/index.template.html
@@ -38,6 +38,7 @@
         <script type="text/javascript" src="resources/lib/sip.js"></script>
         <script type="text/javascript" src="resources/lib/bbb_webrtc_bridge_sip.js"></script>
         <script type="text/javascript" src="resources/lib/deployJava.js"></script>
+        <script type="text/javascript" src="resources/lib/bbb_localization.js"></script>
         <script type="text/javascript" src="swfobject.js"></script>
         <script type="text/javascript">
             // For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection. 
diff --git a/bbb-client-check/locale/en_US/resources.properties b/bbb-client-check/locale/en_US/resources.properties
index 09e02a687954da3ec747940d92cbca43a9336621..a5fae5ffee63c46ec66bca8949c9d76b9e85b14e 100755
--- a/bbb-client-check/locale/en_US/resources.properties
+++ b/bbb-client-check/locale/en_US/resources.properties
@@ -1,4 +1,4 @@
-bbbsystemcheck.title = BigBlueButton Client Check
+bbbsystemcheck.title = Mconf-Live Client Check
 bbbsystemcheck.refresh = Refresh
 bbbsystemcheck.mail = Mail
 bbbsystemcheck.version = Client Check Version
@@ -29,3 +29,12 @@ bbbsystemcheck.test.name.userAgent = User Agent
 bbbsystemcheck.test.name.webRTCEcho = WebRTC Echo Test
 bbbsystemcheck.test.name.webRTCSocket = WebRTC Socket Test
 bbbsystemcheck.test.name.webRTCSupported = WebRTC Supported
+bbbsystemcheck.test.name.port9123 = Port 9123
+bbbsystemcheck.test.name.rtmpBigBlueButton = RTMP main app
+bbbsystemcheck.test.name.rtmpDeskshare = RTMP deskshare app
+bbbsystemcheck.test.name.rtmpSip = RTMP sip app
+bbbsystemcheck.test.name.rtmpVideo = RTMP video app
+bbbsystemcheck.test.name.rtmptBigBlueButton = RTMPT main app
+bbbsystemcheck.test.name.rtmptDeskshare = RTMPT deskshare app
+bbbsystemcheck.test.name.rtmptSip = RTMPT sip app
+bbbsystemcheck.test.name.rtmptVideo = RTMPT video app
diff --git a/bbb-client-check/locale/pt_BR/resources.properties b/bbb-client-check/locale/pt_BR/resources.properties
new file mode 100644
index 0000000000000000000000000000000000000000..6bbc290dc71b057d0f9443e729fb0d1bd9fe96da
--- /dev/null
+++ b/bbb-client-check/locale/pt_BR/resources.properties
@@ -0,0 +1,40 @@
+bbbsystemcheck.title = Diagnóstico do cliente Mconf-Live
+bbbsystemcheck.refresh = Recarregar
+bbbsystemcheck.mail = E-mail
+bbbsystemcheck.version = Versão deste verificador
+bbbsystemcheck.dataGridColumn.item = Item
+bbbsystemcheck.dataGridColumn.status = Status
+bbbsystemcheck.dataGridColumn.result = Resultado
+bbbsystemcheck.copyAllText = Copiar resultados
+bbbsystemcheck.result.undefined = Indefinido
+bbbsystemcheck.result.javaEnabled.disabled = O Java está desabilitado em seu navegador
+bbbsystemcheck.result.javaEnabled.notDetected = Java não detectado
+bbbsystemcheck.result.browser.changeBrowser = Recomendamos o uso de Firefox ou Chrome para uma melhor qualidade de áudio
+bbbsystemcheck.result.browser.browserOutOfDate = Seu navegador está desatualizado. Recomendamos que você o atualize para uma versão mais nova.
+bbbsystemcheck.status.succeeded = Sucesso
+bbbsystemcheck.status.warning = Atenção
+bbbsystemcheck.status.failed = Falha
+bbbsystemcheck.status.loading = Carregando...
+bbbsystemcheck.test.name.browser = Navegador
+bbbsystemcheck.test.name.cookieEnabled = Cookies habilitados
+bbbsystemcheck.test.name.downloadSpeed = Velocidade de download
+bbbsystemcheck.test.name.flashVersion = Versão do Adobe Flash Player
+bbbsystemcheck.test.name.pepperFlash = Pepper Flash
+bbbsystemcheck.test.name.javaEnabled = Java habilitado
+bbbsystemcheck.test.name.language = Idioma
+bbbsystemcheck.test.name.ping = Ping
+bbbsystemcheck.test.name.screenSize = Tamanho da tela
+bbbsystemcheck.test.name.uploadSpeed = Velocidade de upload
+bbbsystemcheck.test.name.userAgent = User Agent
+bbbsystemcheck.test.name.webRTCEcho = Eco WebRTC
+bbbsystemcheck.test.name.webRTCSocket = Socket WebRTC
+bbbsystemcheck.test.name.webRTCSupported = Suporte a WebRTC
+bbbsystemcheck.test.name.port9123 = Porta 9123
+bbbsystemcheck.test.name.rtmpBigBlueButton = RTMP main app
+bbbsystemcheck.test.name.rtmpDeskshare = RTMP deskshare app
+bbbsystemcheck.test.name.rtmpSip = RTMP sip app
+bbbsystemcheck.test.name.rtmpVideo = RTMP video app
+bbbsystemcheck.test.name.rtmptBigBlueButton = RTMPT main app
+bbbsystemcheck.test.name.rtmptDeskshare = RTMPT deskshare app
+bbbsystemcheck.test.name.rtmptSip = RTMPT sip app
+bbbsystemcheck.test.name.rtmptVideo = RTMPT video app
diff --git a/bbb-client-check/resources/config.xml.template b/bbb-client-check/resources/config.xml.template
index 635d050cbd1858e858458a5cfbf9fc980f107ae5..5243a87b728342369cc228218f593287b282c710 100644
--- a/bbb-client-check/resources/config.xml.template
+++ b/bbb-client-check/resources/config.xml.template
@@ -9,35 +9,35 @@
 	</ports>
 	<rtmpapps>
 		<app>
-			<name>RTMP BigBlueButton app</name>
+			<name>bbbsystemcheck.test.name.rtmpBigBlueButton</name>
 			<uri>rtmp://HOST/bigbluebutton</uri>
 		</app>
 		<app>
-			<name>RTMP screenshare app</name>
+			<name>bbbsystemcheck.test.name.rtmpDeskshare</name>
 			<uri>rtmp://HOST/screenshare</uri>
 		</app>
 		<app>
-			<name>RTMP video app</name>
+			<name>bbbsystemcheck.test.name.rtmpVideo</name>
 			<uri>rtmp://HOST/video</uri>
 		</app>
 		<app>
-			<name>RTMP sip app</name>
+			<name>bbbsystemcheck.test.name.rtmpSip</name>
 			<uri>rtmp://HOST/sip</uri>
 		</app>
 		<app>
-			<name>RTMPT BigBlueButton app</name>
+			<name>bbbsystemcheck.test.name.rtmptBigBlueButton</name>
 			<uri>rtmpt://HOST/bigbluebutton</uri>
 		</app>
 		<app>
-			<name>RTMPT screenshare app</name>
+			<name>bbbsystemcheck.test.name.rtmptDeskshare</name>
 			<uri>rtmpt://HOST/screenshare</uri>
 		</app>
 		<app>
-			<name>RTMPT video app</name>
+			<name>bbbsystemcheck.test.name.rtmptVideo</name>
 			<uri>rtmpt://HOST/video</uri>
 		</app>
 		<app>
-			<name>RTMPT sip app</name>
+			<name>bbbsystemcheck.test.name.rtmptSip</name>
 			<uri>rtmpt://HOST/sip</uri>
 		</app>
 	</rtmpapps>
diff --git a/bbb-client-check/resources/lib/api-bridge.js b/bbb-client-check/resources/lib/api-bridge.js
index 6bf5a9f1d9442d85ec597fd6dcc89271d9b5252d..c31d93ec0ab5c6bb47c814bf284a4d3a87deb006 100644
--- a/bbb-client-check/resources/lib/api-bridge.js
+++ b/bbb-client-check/resources/lib/api-bridge.js
@@ -208,12 +208,9 @@
 		var swfObj = getSwfObj();
 		swfObj.webRTCEchoTest(success, errorcode);
 
-		webrtc_hangup(function() {
-			console.log("[BBBClientCheck] Handling webRTC hangup callback");
-			var userAgentTemp = userAgent;
-			userAgent = null;
-			userAgentTemp.stop();
-		});
+		if (callActive === true) {
+			leaveWebRTCVoiceConference();
+		}
 	}
 
 	BBB.getMyUserInfo = function(callback) {
@@ -224,7 +221,7 @@
 			myRole: "undefined",
 			amIPresenter: "undefined",
 			dialNumber: "undefined",
-			voiceBridge: "undefined",
+			voiceBridge: "00000",
 			customdata: "undefined"
 		}
 
@@ -232,67 +229,42 @@
 	}
 
 	// webrtc test callbacks
-	BBB.webRTCEchoTestFailed = function(errorcode) {
-		console.log("[BBBClientCheck] Handling webRTCEchoTestFailed");
-		sendWebRTCEchoTestAnswer(false, errorcode);
-	}
-
-	BBB.webRTCEchoTestEnded = function() {
-		console.log("[BBBClientCheck] Handling webRTCEchoTestEnded");
-	}
-
-	BBB.webRTCEchoTestStarted = function() {
-		console.log("[BBBClientCheck] Handling webRTCEchoTestStarted");
-		sendWebRTCEchoTestAnswer(true, 'Connected');
-	}
-
-	BBB.webRTCEchoTestConnecting = function() {
-		console.log("[BBBClientCheck] Handling webRTCEchoTestConnecting");
-	}
-
-	BBB.webRTCEchoTestWaitingForICE = function() {
-		console.log("[BBBClientCheck] Handling webRTCEchoTestWaitingForICE");
-	}
-
-	BBB.webRTCEchoTestWebsocketSucceeded = function() {
-		console.log("[BBBClientCheck] Handling webRTCEchoTestWebsocketSucceeded");
+	BBB.webRTCCallSucceeded = function() {
+		console.log("[BBBClientCheck] Handling webRTCCallSucceeded");
 		var swfObj = getSwfObj();
 		swfObj.webRTCSocketTest(true, 'Connected');
 	}
 
-	BBB.webRTCEchoTestWebsocketFailed = function(errorcode) {
-		console.log("[BBBClientCheck] Handling webRTCEchoTestWebsocketFailed");
-		var swfObj = getSwfObj();
-		swfObj.webRTCSocketTest(false, errorcode);
-	}
-
-	// webrtc callbacks
-	BBB.webRTCConferenceCallFailed = function(errorcode) {
-		console.log("[BBBClientCheck] Handling webRTCConferenceCallFailed");
-	}
-
-	BBB.webRTCConferenceCallEnded = function() {
-		console.log("[BBBClientCheck] Handling webRTCConferenceCallEnded");
+	BBB.webRTCCallFailed = function(inEchoTest, errorcode, cause) {
+		console.log("[BBBClientCheck] Handling webRTCCallFailed, errorcode " + errorcode + ", cause: " + cause);
+		if (errorcode == 1002) {
+			// failed to connect the websocket
+			var swfObj = getSwfObj();
+			swfObj.webRTCSocketTest(false, errorcode);
+		} else {
+			sendWebRTCEchoTestAnswer(false, errorcode);
+		}
 	}
 
-	BBB.webRTCConferenceCallStarted = function() {
-		console.log("[BBBClientCheck] Handling webRTCConferenceCallStarted");
+	BBB.webRTCCallEnded = function(inEchoTest) {
+		console.log("[BBBClientCheck] Handling webRTCCallEnded");
 	}
 
-	BBB.webRTCConferenceCallConnecting = function() {
-		console.log("[BBBClientCheck] Handling webRTCConferenceCallConnecting");
+	BBB.webRTCCallStarted = function(inEchoTest) {
+		console.log("[BBBClientCheck] Handling webRTCCallStarted");
+		sendWebRTCEchoTestAnswer(true, 'Connected');
 	}
 
-	BBB.webRTCConferenceCallWaitingForICE = function() {
-		console.log("[BBBClientCheck] Handling webRTCConferenceCallWaitingForICE");
+	BBB.webRTCCallConnecting = function(inEchoTest) {
+		console.log("[BBBClientCheck] Handling webRTCCallConnecting");
 	}
 
-	BBB.webRTCConferenceCallWebsocketSucceeded = function() {
-		console.log("[BBBClientCheck] Handling webRTCConferenceCallWebsocketSucceeded");
+	BBB.webRTCCallWaitingForICE = function(inEchoTest) {
+		console.log("[BBBClientCheck] Handling webRTCCallWaitingForICE");
 	}
 
-	BBB.webRTCConferenceCallWebsocketFailed = function(errorcode) {
-		console.log("[BBBClientCheck] Handling webRTCConferenceCallWebsocketFailed");
+	BBB.webRTCCallTransferring = function(inEchoTest) {
+		console.log("[BBBClientCheck] Handling webRTCCallTransferring");
 	}
 
 	BBB.webRTCMediaRequest = function() {
diff --git a/bbb-client-check/src/BBBClientCheck.mxml b/bbb-client-check/src/BBBClientCheck.mxml
index 2587d1ff739b6cc09092ec00bb219863596469a2..e9ebc0bc163a8a2646ba1ae2487074c0f547a8fe 100755
--- a/bbb-client-check/src/BBBClientCheck.mxml
+++ b/bbb-client-check/src/BBBClientCheck.mxml
@@ -18,6 +18,8 @@
 		<![CDATA[
 			import mx.events.FlexEvent;
 
+			import flash.external.ExternalInterface;
+
 			import org.bigbluebutton.clientcheck.AppConfig;
 			import org.bigbluebutton.clientcheck.view.mainview.MainViewConfig;
 			import org.bigbluebutton.clientcheck.view.mainview.RefreshButtonConfig;
@@ -31,12 +33,25 @@
 
 			private static var robotlegsContext:IContext;
 
+			private static var DEFAULT_LOCALE:String = "en_US";
+			private var language:String;
+
 			protected function preinitializeHandler(event:FlexEvent):void
 			{
+				setLanguage();
 				setupRobotlegsContext();
 				Security.allowDomain("*");
 			}
 
+			private function setLanguage():void
+			{
+				language = ExternalInterface.call("getLanguage");
+				if (resourceManager.getLocales().indexOf(language) != -1)
+				{
+					resourceManager.localeChain = [language, DEFAULT_LOCALE];
+				}
+			}
+
 			/**
 			 *  Setup robotlegs initial configuration
 			 */
diff --git a/bbb-client-check/src/org/bigbluebutton/clientcheck/command/GetConfigXMLDataCommand.as b/bbb-client-check/src/org/bigbluebutton/clientcheck/command/GetConfigXMLDataCommand.as
index 1f2bdb9f26dff284ed1d1421fb5bc78a69ebc9a6..014a54c780e076d612200d67bbed7c6439982ef6 100644
--- a/bbb-client-check/src/org/bigbluebutton/clientcheck/command/GetConfigXMLDataCommand.as
+++ b/bbb-client-check/src/org/bigbluebutton/clientcheck/command/GetConfigXMLDataCommand.as
@@ -23,6 +23,7 @@ package org.bigbluebutton.clientcheck.command
 	import flash.utils.getTimer;
 
 	import mx.core.FlexGlobals;
+	import mx.resources.ResourceManager;
 	import mx.utils.URLUtil;
 
 	import org.bigbluebutton.clientcheck.model.ISystemConfiguration;
@@ -78,7 +79,8 @@ package org.bigbluebutton.clientcheck.command
 			for each (var _port:Object in config.getPorts())
 			{
 				var port:IPortTest=new PortTest();
-				port.portName=_port.name;
+				port.portName=ResourceManager.getInstance().getString('resources', _port.name);
+				if (port.portName == "undefined") port.portName = _port.name;
 				port.portNumber=_port.number;
 				systemConfiguration.ports.push(port);
 			}
@@ -86,7 +88,8 @@ package org.bigbluebutton.clientcheck.command
 			for each (var _rtmpApp:Object in config.getRTMPApps())
 			{
 				var app:IRTMPAppTest=new RTMPAppTest();
-				app.applicationName=_rtmpApp.name;
+				app.applicationName=ResourceManager.getInstance().getString('resources', _rtmpApp.name);
+				if (app.applicationName == "undefined") app.applicationName = _rtmpApp.name;
 				app.applicationUri=_rtmpApp.uri;
 				systemConfiguration.rtmpApps.push(app);
 			}
diff --git a/bbb-client-check/src/org/bigbluebutton/clientcheck/view/mainview/CustomItemRenderer.mxml b/bbb-client-check/src/org/bigbluebutton/clientcheck/view/mainview/CustomItemRenderer.mxml
index e00154a38ed79bbaf3aa0498c47f1f553849f4d3..5fc83efa09eb7d54e0708a954daaf9818d5f2bf3 100755
--- a/bbb-client-check/src/org/bigbluebutton/clientcheck/view/mainview/CustomItemRenderer.mxml
+++ b/bbb-client-check/src/org/bigbluebutton/clientcheck/view/mainview/CustomItemRenderer.mxml
@@ -22,6 +22,9 @@
 
 				switch (value.StatusPriority) {
 					case SUCCEEDED:
+						colorRect.visible = true;
+						solid.color = 0x00FF00;
+						break;
 					case LOADING:
 						colorRect.visible = false;
 						break;
diff --git a/bbb-client-check/src/org/bigbluebutton/clientcheck/view/mainview/StatusENUM.as b/bbb-client-check/src/org/bigbluebutton/clientcheck/view/mainview/StatusENUM.as
index d42d1dd2cf66c8d1207de5a80900cb0d63cb0210..1544cb6fb4f9f0dc7c2f6dffabfd8ac913a789c0 100644
--- a/bbb-client-check/src/org/bigbluebutton/clientcheck/view/mainview/StatusENUM.as
+++ b/bbb-client-check/src/org/bigbluebutton/clientcheck/view/mainview/StatusENUM.as
@@ -25,6 +25,6 @@ package org.bigbluebutton.clientcheck.view.mainview
 		public static const FAILED:Object = {StatusMessage: ResourceManager.getInstance().getString('resources', 'bbbsystemcheck.status.failed'), StatusPriority: 1};
 		public static const WARNING:Object = {StatusMessage: ResourceManager.getInstance().getString('resources', 'bbbsystemcheck.status.warning'), StatusPriority: 2};
 		public static const LOADING:Object = {StatusMessage: ResourceManager.getInstance().getString('resources', 'bbbsystemcheck.status.loading'), StatusPriority: 3};
-		public static const SUCCEED:Object = {StatusMessage: "", StatusPriority: 4};
+		public static const SUCCEED:Object = {StatusMessage: ResourceManager.getInstance().getString('resources', 'bbbsystemcheck.status.succeeded'), StatusPriority: 4};
 	}
 }
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ActivityResponseMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ActivityResponseMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..d309aef331e7bd8a223ab4d79b8442b546ba28bb
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ActivityResponseMessage.java
@@ -0,0 +1,48 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class ActivityResponseMessage implements IBigBlueButtonMessage {
+	public static final String ACTIVITY_RESPONSE = "activity_response_message";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingId;
+
+	public ActivityResponseMessage(String meetingId) {
+		this.meetingId = meetingId;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(ACTIVITY_RESPONSE, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static ActivityResponseMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (ACTIVITY_RESPONSE.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+
+						return new ActivityResponseMessage(meetingId);
+					}
+				}
+			}
+		}
+
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ChangeUserRoleMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ChangeUserRoleMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..aef2845b57930337244ba0d08f516a62d077b9ba
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ChangeUserRoleMessage.java
@@ -0,0 +1,55 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class ChangeUserRoleMessage implements IBigBlueButtonMessage {
+	public static final String CHANGE_USER_ROLE = "change_user_role";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String userId;
+	public final String role;
+
+	public ChangeUserRoleMessage(String meetingId, String userId, String role) {
+		this.meetingId = meetingId;
+		this.userId = userId;
+		this.role = role;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.USER_ID, userId);
+		payload.put(Constants.ROLE, role);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(CHANGE_USER_ROLE, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static ChangeUserRoleMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (CHANGE_USER_ROLE.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.USER_ID)
+							&& payload.has(Constants.ROLE)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String userId = payload.get(Constants.USER_ID).getAsString();
+						String role = payload.get(Constants.ROLE).getAsString();
+
+						return new ChangeUserRoleMessage(meetingId, userId, role);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ClearPublicChatHistoryReplyMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ClearPublicChatHistoryReplyMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..db558327e690bfc4b41cbb41191a4eed754e9c86
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ClearPublicChatHistoryReplyMessage.java
@@ -0,0 +1,51 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class ClearPublicChatHistoryReplyMessage implements ISubscribedMessage {
+	public static final String CLEAR_PUBLIC_CHAT_HISTORY_REPLY = "clear_public_chat_history_reply";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String requesterId;
+
+
+	public ClearPublicChatHistoryReplyMessage(String meetingId, String requesterId) {
+		this.meetingId = meetingId;
+		this.requesterId = requesterId;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.REQUESTER_ID, requesterId);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(CLEAR_PUBLIC_CHAT_HISTORY_REPLY, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static ClearPublicChatHistoryReplyMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (CLEAR_PUBLIC_CHAT_HISTORY_REPLY.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+						&& payload.has(Constants.REQUESTER_ID)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterId = payload.get(Constants.REQUESTER_ID).getAsString();
+
+						return new ClearPublicChatHistoryReplyMessage(meetingId, requesterId);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ClearPublicChatHistoryRequestMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ClearPublicChatHistoryRequestMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..8cee18bdbfb701db3e1f7af2154b5541edaddc43
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/ClearPublicChatHistoryRequestMessage.java
@@ -0,0 +1,52 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class ClearPublicChatHistoryRequestMessage implements IBigBlueButtonMessage {
+	public static final String CLEAR_PUBLIC_CHAT_HISTORY_REQUEST = "clear_public_chat_history_request";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String requesterId;
+
+
+	public ClearPublicChatHistoryRequestMessage(String meetingId, String requesterId) {
+		this.meetingId = meetingId;
+		this.requesterId = requesterId;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.REQUESTER_ID, requesterId);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(CLEAR_PUBLIC_CHAT_HISTORY_REQUEST, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static ClearPublicChatHistoryRequestMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (CLEAR_PUBLIC_CHAT_HISTORY_REQUEST.equals(messageName)) {
+
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterId = payload.get(Constants.REQUESTER_ID).getAsString();
+
+						return new ClearPublicChatHistoryRequestMessage(meetingId, requesterId);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/Constants.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/Constants.java
index 704587ebf20c169b27e6f7a20e610fce2e0232e7..7aa30fdf3343513f8108af0230279e263db8960a 100755
--- a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/Constants.java
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/Constants.java
@@ -139,4 +139,20 @@ public class Constants {
   public static final String URL                             = "url";
   public static final String TTL                             = "ttl";
   public static final String PASSWORD                        = "password";
+  public static final String GUEST                           = "guest";
+  public static final String WAITING_FOR_ACCEPTANCE          = "waiting_for_acceptance";
+  public static final String DOWNLOADABLE                    = "downloadable";
+  public static final String GUEST_POLICY                    = "guest_policy";
+  public static final String NOTE_ID                         = "note_id";
+  public static final String PATCH                           = "patch";
+  public static final String PATCH_ID                        = "patch_id";
+  public static final String NOTE_NAME                       = "note_name";
+  public static final String NOTES                           = "notes";
+  public static final String ADDITIONAL_NOTES_SET_SIZE       = "additional_notes_set_size";
+  public static final String SET_BY                          = "set_by";
+  public static final String UNDO                            = "undo";
+  public static final String REDO                            = "redo";
+  public static final String OPERATION                       = "operation";
+  public static final String NOTE                            = "note";
+  public static final String METADATA                        = "metadata";
 }
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/CreateAdditionalNotesReplyMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/CreateAdditionalNotesReplyMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..fa499a8a6651d8e8a763fbd249b74569d5ffb8b3
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/CreateAdditionalNotesReplyMessage.java
@@ -0,0 +1,57 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class CreateAdditionalNotesReplyMessage implements ISubscribedMessage {
+	public static final String CREATE_ADDITIONAL_NOTES_REPLY = "create_additional_notes_reply";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String noteID;
+	public final String noteName;
+
+	public CreateAdditionalNotesReplyMessage(String meetingID, String noteID, String noteName) {
+		this.meetingID = meetingID;
+		this.noteID = noteID;
+		this.noteName = noteName;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.NOTE_ID, noteID);
+		payload.put(Constants.NOTE_NAME, noteName);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(CREATE_ADDITIONAL_NOTES_REPLY, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static CreateAdditionalNotesReplyMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (CREATE_ADDITIONAL_NOTES_REPLY.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.NOTE_ID)
+							&& payload.has(Constants.NOTE_NAME)) {
+						String meetingID = payload.get(Constants.MEETING_ID).getAsString();
+						String noteID = payload.get(Constants.NOTE_ID).getAsString();
+						String noteName = payload.get(Constants.NOTE_NAME).getAsString();
+
+						return new CreateAdditionalNotesReplyMessage(meetingID, noteID, noteName);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/CreateAdditionalNotesRequestMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/CreateAdditionalNotesRequestMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..3555e87fdd9cc697a951cb33308849ee98cf8562
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/CreateAdditionalNotesRequestMessage.java
@@ -0,0 +1,61 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class CreateAdditionalNotesRequestMessage implements ISubscribedMessage {
+	public static final String CREATE_ADDITIONAL_NOTES_REQUEST = "create_additional_notes_request";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String requesterID;
+	public final String noteName;
+
+	public CreateAdditionalNotesRequestMessage(String meetingID, String requesterID, String noteName) {
+		this.meetingID = meetingID;
+		this.requesterID = requesterID;
+		this.noteName = noteName;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.REQUESTER_ID, requesterID);
+		payload.put(Constants.NOTE_NAME, noteName);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(CREATE_ADDITIONAL_NOTES_REQUEST, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static CreateAdditionalNotesRequestMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (CREATE_ADDITIONAL_NOTES_REQUEST.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)
+							&& payload.has(Constants.NOTE_NAME)) {
+						String meetingID = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterID = payload.get(Constants.REQUESTER_ID).getAsString();
+						String noteName = payload.get(Constants.NOTE_NAME).getAsString();
+
+						return new CreateAdditionalNotesRequestMessage(meetingID, requesterID, noteName);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/CreateMeetingMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/CreateMeetingMessage.java
index 583b3fe2a45d1651dda7fdd3276f2c3f6a805f69..3fdda439dfc6d043535c9d436496d794a4d66393 100755
--- a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/CreateMeetingMessage.java
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/CreateMeetingMessage.java
@@ -1,5 +1,7 @@
 package org.bigbluebutton.common.messages;
 
+import java.util.Map;
+
 public class CreateMeetingMessage implements IBigBlueButtonMessage {
 	public static final String CREATE_MEETING_REQUEST_EVENT  = "create_meeting_request";
 	public static final String VERSION = "0.0.1";
@@ -16,11 +18,12 @@ public class CreateMeetingMessage implements IBigBlueButtonMessage {
 	public final String viewerPass;
 	public final Long createTime;
 	public final String createDate;
+	public final Map<String, String> metadata;
 	
 	public CreateMeetingMessage(String id, String externalId, String name, Boolean record, String voiceBridge, 
 			                        Long duration, Boolean autoStartRecording, 
 			                        Boolean allowStartStopRecording, String moderatorPass,
-			                        String viewerPass, Long createTime, String createDate) {
+			                        String viewerPass, Long createTime, String createDate, Map<String, String> metadata) {
 		this.id = id;
 		this.externalId = externalId;
 		this.name = name;
@@ -33,5 +36,6 @@ public class CreateMeetingMessage implements IBigBlueButtonMessage {
 		this.viewerPass = viewerPass;
 		this.createTime = createTime;
 		this.createDate = createDate;
+		this.metadata = metadata;
 	}
 }
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/DestroyAdditionalNotesReplyMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/DestroyAdditionalNotesReplyMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..c8d503f10646ec4e5ed1166eab0b9d14a8ccc489
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/DestroyAdditionalNotesReplyMessage.java
@@ -0,0 +1,52 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class DestroyAdditionalNotesReplyMessage implements ISubscribedMessage {
+	public static final String DESTROY_ADDITIONAL_NOTES_REPLY = "destroy_additional_notes_reply";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String noteID;
+
+	public DestroyAdditionalNotesReplyMessage(String meetingID, String noteID) {
+		this.meetingID = meetingID;
+		this.noteID = noteID;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.NOTE_ID, noteID);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(DESTROY_ADDITIONAL_NOTES_REPLY, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static DestroyAdditionalNotesReplyMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (DESTROY_ADDITIONAL_NOTES_REPLY.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.NOTE_ID)) {
+						String meetingID = payload.get(Constants.MEETING_ID).getAsString();
+						String noteID = payload.get(Constants.NOTE_ID).getAsString();
+
+						return new DestroyAdditionalNotesReplyMessage(meetingID, noteID);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/DestroyAdditionalNotesRequestMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/DestroyAdditionalNotesRequestMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..296df696144f46ba86eaa819aad98f7c6ffc4b37
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/DestroyAdditionalNotesRequestMessage.java
@@ -0,0 +1,57 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class DestroyAdditionalNotesRequestMessage implements ISubscribedMessage {
+	public static final String DESTROY_ADDITIONAL_NOTES_REQUEST = "destroy_additional_notes_request";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String requesterID;
+	public final String noteID;
+
+	public DestroyAdditionalNotesRequestMessage(String meetingID, String requesterID, String noteID) {
+		this.meetingID = meetingID;
+		this.requesterID = requesterID;
+		this.noteID = noteID;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.REQUESTER_ID, requesterID);
+		payload.put(Constants.NOTE_ID, noteID);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(DESTROY_ADDITIONAL_NOTES_REQUEST, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static DestroyAdditionalNotesRequestMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (DESTROY_ADDITIONAL_NOTES_REQUEST.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)
+							&& payload.has(Constants.NOTE_ID)) {
+						String meetingID = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterID = payload.get(Constants.REQUESTER_ID).getAsString();
+						String noteID = payload.get(Constants.NOTE_ID).getAsString();
+
+						return new DestroyAdditionalNotesRequestMessage(meetingID, requesterID, noteID);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetCurrentDocumentReplyMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetCurrentDocumentReplyMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ef8899dee90a702618229a9c071580edc691397
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetCurrentDocumentReplyMessage.java
@@ -0,0 +1,62 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import java.util.Map;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class GetCurrentDocumentReplyMessage implements ISubscribedMessage {
+	public static final String GET_CURRENT_DOCUMENT_REPLY = "get_current_document_reply";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String requesterID;
+	public final Map<String, Object> notes;
+
+	public GetCurrentDocumentReplyMessage(String meetingID, String requesterID, Map<String, Object> notes) {
+		this.meetingID = meetingID;
+		this.requesterID = requesterID;
+		this.notes = notes;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.REQUESTER_ID, requesterID);
+		payload.put(Constants.NOTES, notes);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(GET_CURRENT_DOCUMENT_REPLY, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static GetCurrentDocumentReplyMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (GET_CURRENT_DOCUMENT_REPLY.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)
+							&& payload.has(Constants.NOTES)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterId = payload.get(Constants.REQUESTER_ID).getAsString();
+
+						JsonObject notesObject = (JsonObject) payload.get(Constants.NOTES);
+
+						Util util = new Util();
+						Map<String, Object> notes = util.extractNotes(notesObject);
+
+						return new GetCurrentDocumentReplyMessage(meetingId, requesterId, notes);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetCurrentDocumentRequestMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetCurrentDocumentRequestMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..a688c1d77f1aa40a49ddb27cd2e173266dca377c
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetCurrentDocumentRequestMessage.java
@@ -0,0 +1,52 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class GetCurrentDocumentRequestMessage implements ISubscribedMessage {
+	public static final String GET_CURRENT_DOCUMENT_REQUEST = "get_current_document_request";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String requesterID;
+
+	public GetCurrentDocumentRequestMessage(String meetingID, String requesterID) {
+		this.meetingID = meetingID;
+		this.requesterID = requesterID;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.REQUESTER_ID, requesterID);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(GET_CURRENT_DOCUMENT_REQUEST, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static GetCurrentDocumentRequestMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (GET_CURRENT_DOCUMENT_REQUEST.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterId = payload.get(Constants.REQUESTER_ID).getAsString();
+
+						return new GetCurrentDocumentRequestMessage(meetingId, requesterId);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetGuestPolicyMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetGuestPolicyMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a8ebade5c5d7130bf9f7de79fe2b777cf46cedf
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetGuestPolicyMessage.java
@@ -0,0 +1,50 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class GetGuestPolicyMessage implements IBigBlueButtonMessage {
+	public static final String GET_GUEST_POLICY = "get_guest_policy";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String requesterId;
+
+	public GetGuestPolicyMessage(String meetingId, String requesterId) {
+		this.meetingId = meetingId;
+		this.requesterId = requesterId;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.REQUESTER_ID, requesterId);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(GET_GUEST_POLICY, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static GetGuestPolicyMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (GET_GUEST_POLICY.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterId = payload.get(Constants.REQUESTER_ID).getAsString();
+
+						return new GetGuestPolicyMessage(meetingId, requesterId);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetGuestPolicyReplyMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetGuestPolicyReplyMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..990a4584a78b172b80485547b3a96b09d1ec0b14
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GetGuestPolicyReplyMessage.java
@@ -0,0 +1,56 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class GetGuestPolicyReplyMessage implements IBigBlueButtonMessage {
+	public static final String GET_GUEST_POLICY_REPLY = "get_guest_policy_reply";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String requesterId;
+	public final String guestPolicy;
+
+	public GetGuestPolicyReplyMessage(String meetingId, String requesterId, String guestPolicy) {
+		this.meetingId = meetingId;
+		this.requesterId = requesterId;
+		this.guestPolicy = guestPolicy;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.REQUESTER_ID, requesterId);
+		payload.put(Constants.GUEST_POLICY, guestPolicy);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(GET_GUEST_POLICY_REPLY, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static GetGuestPolicyReplyMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (GET_GUEST_POLICY_REPLY.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)
+							&& payload.has(Constants.GUEST_POLICY)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterId = payload.get(Constants.REQUESTER_ID).getAsString();
+						String guestPolicy = payload.get(Constants.GUEST_POLICY).getAsString();
+
+						return new GetGuestPolicyReplyMessage(meetingId, requesterId, guestPolicy);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GuestAccessDeniedMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GuestAccessDeniedMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..6fa50085b4462ba48df90e43b5632b176f78ccc5
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GuestAccessDeniedMessage.java
@@ -0,0 +1,51 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class GuestAccessDeniedMessage implements IBigBlueButtonMessage {
+	public static final String GUEST_ACCESS_DENIED = "guest_access_denied";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String userId;
+
+	public GuestAccessDeniedMessage(String meetingId, String userId) {
+		this.meetingId = meetingId;
+		this.userId = userId;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.USER_ID, userId);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(GUEST_ACCESS_DENIED, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static GuestAccessDeniedMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (GUEST_ACCESS_DENIED.equals(messageName)) {
+
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.USER_ID)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String userId = payload.get(Constants.USER_ID).getAsString();
+
+						return new GuestAccessDeniedMessage(meetingId, userId);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GuestPolicyChangedMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GuestPolicyChangedMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6de259452dfdccab223bc9a1cb21090aa8961db
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/GuestPolicyChangedMessage.java
@@ -0,0 +1,50 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class GuestPolicyChangedMessage implements IBigBlueButtonMessage {
+	public static final String GUEST_POLICY_CHANGED = "guest_policy_changed";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String guestPolicy;
+
+	public GuestPolicyChangedMessage(String meetingId, String guestPolicy) {
+		this.meetingId = meetingId;
+		this.guestPolicy = guestPolicy;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.GUEST_POLICY, guestPolicy);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(GUEST_POLICY_CHANGED, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static GuestPolicyChangedMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (GUEST_POLICY_CHANGED.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.GUEST_POLICY)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String guestPolicy = payload.get(Constants.GUEST_POLICY).getAsString();
+
+						return new GuestPolicyChangedMessage(meetingId, guestPolicy);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/InactivityWarningMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/InactivityWarningMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..5369b8c4208a0fa42c2625adb8d31cb7258ea764
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/InactivityWarningMessage.java
@@ -0,0 +1,52 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class InactivityWarningMessage implements IBigBlueButtonMessage {
+	public static final String INACTIVITY_WARNING = "inactivity_warning_message";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final Long duration;
+
+	public InactivityWarningMessage(String meetingId, Long duration) {
+		this.meetingId = meetingId;
+		this.duration = duration;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.DURATION, duration);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(INACTIVITY_WARNING, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static InactivityWarningMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (INACTIVITY_WARNING.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.DURATION)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						Long duration = payload.get(Constants.DURATION).getAsLong();
+
+						return new InactivityWarningMessage(meetingId, duration);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/LogoutEndMeetingRequestMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/LogoutEndMeetingRequestMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..9da3d6b51e62fadf26ca48485f09ad7b04815200
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/LogoutEndMeetingRequestMessage.java
@@ -0,0 +1,51 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class LogoutEndMeetingRequestMessage implements ISubscribedMessage {
+	public static final String LOGOUT_END_MEETING_REQUEST_MESSAGE  = "logout_end_meeting_request_message";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String userId;
+
+	public LogoutEndMeetingRequestMessage(String meetingId, String userId) {
+		this.meetingId = meetingId;
+		this.userId = userId;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.USER_ID, userId);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(LOGOUT_END_MEETING_REQUEST_MESSAGE, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static LogoutEndMeetingRequestMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (LOGOUT_END_MEETING_REQUEST_MESSAGE.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.USER_ID)) {
+						String id = payload.get(Constants.MEETING_ID).getAsString();
+						String userid = payload.get(Constants.USER_ID).getAsString();
+
+						return new LogoutEndMeetingRequestMessage(id, userid);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MeetingIsActiveMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MeetingIsActiveMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..78448272d11431ef68913f1e1fa8d9b7d5307871
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MeetingIsActiveMessage.java
@@ -0,0 +1,47 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class MeetingIsActiveMessage implements IBigBlueButtonMessage {
+	public static final String MEETING_IS_ACTIVE = "meeting_is_active_message";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingId;
+
+	public MeetingIsActiveMessage(String meetingId) {
+		this.meetingId = meetingId;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(MEETING_IS_ACTIVE, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static MeetingIsActiveMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (MEETING_IS_ACTIVE.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+
+						return new MeetingIsActiveMessage(meetingId);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MessageFromJsonConverter.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MessageFromJsonConverter.java
index 11292043bbc1c72f2b62b214c17c203b82d2c4da..3653b836388ec3103df7591536d517574e8fa4c6 100755
--- a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MessageFromJsonConverter.java
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MessageFromJsonConverter.java
@@ -1,5 +1,6 @@
 package org.bigbluebutton.common.messages;
 
+import java.util.Map;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 
@@ -24,6 +25,8 @@ public class MessageFromJsonConverter {
 					  return processEndMeetingMessage(payload);
 				  case KeepAliveMessage.KEEP_ALIVE_REQUEST:
 					  return processKeepAlive(payload);
+				  case ActivityResponseMessage.ACTIVITY_RESPONSE:
+					  return processActivityResponseMessage(payload);
 				  case RegisterUserMessage.REGISTER_USER:
 					  return RegisterUserMessage.fromJson(message);
 				  case ValidateAuthTokenMessage.VALIDATE_AUTH_TOKEN:
@@ -64,10 +67,14 @@ public class MessageFromJsonConverter {
 		String viewerPassword = payload.get(Constants.VIEWER_PASS).getAsString();
 		Long createTime = payload.get(Constants.CREATE_TIME).getAsLong();
 		String createDate = payload.get(Constants.CREATE_DATE).getAsString();
+
+		Util util = new Util();
+		JsonObject metadataObject = (JsonObject) payload.get(Constants.METADATA);
+		Map<String, String> metadata = util.extractMetadata(metadataObject);
 		
 		return new CreateMeetingMessage(id, externalId, name, record, voiceBridge, 
 				          duration, autoStartRecording, allowStartStopRecording,
-				          moderatorPassword, viewerPassword, createTime, createDate);
+				          moderatorPassword, viewerPassword, createTime, createDate, metadata);
 	}
 	
 	private static IBigBlueButtonMessage processDestroyMeeting(JsonObject payload) {
@@ -85,4 +92,8 @@ public class MessageFromJsonConverter {
 		return new KeepAliveMessage(id);
 	}
 
+	private static IBigBlueButtonMessage processActivityResponseMessage(JsonObject payload) {
+		String id = payload.get(Constants.MEETING_ID).getAsString();
+		return new ActivityResponseMessage(id);
+	}
 }
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MessagingConstants.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MessagingConstants.java
index 62f6f6f551db11ce8ba061f3d45ca7cfb0ea69c3..07ff8c675feec58622149f1284a52e5c0e3e5bce 100755
--- a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MessagingConstants.java
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/MessagingConstants.java
@@ -31,6 +31,7 @@ public class MessagingConstants {
 	public static final String FROM_WHITEBOARD_CHANNEL = FROM_BBB_APPS_CHANNEL + ":whiteboard";
 	public static final String FROM_CAPTION_CHANNEL = FROM_BBB_APPS_CHANNEL + ":caption";
 	public static final String FROM_DESK_SHARE_CHANNEL = FROM_BBB_APPS_CHANNEL + ":deskshare";
+	public static final String FROM_SHAREDNOTES_CHANNEL = FROM_BBB_APPS_CHANNEL + ":sharednotes";
 
 	public static final String TO_BBB_APPS_CHANNEL = "bigbluebutton:to-bbb-apps";	
 	public static final String TO_BBB_APPS_PATTERN = TO_BBB_APPS_CHANNEL + ":*";
@@ -43,6 +44,7 @@ public class MessagingConstants {
 	public static final String TO_VOICE_CHANNEL = TO_BBB_APPS_CHANNEL + ":voice";
 	public static final String TO_WHITEBOARD_CHANNEL = TO_BBB_APPS_CHANNEL + ":whiteboard";
 	public static final String TO_CAPTION_CHANNEL = TO_BBB_APPS_CHANNEL + ":caption";
+	public static final String TO_SHAREDNOTES_CHANNEL = TO_BBB_APPS_CHANNEL + ":sharednotes";
 
 	public static final String BBB_APPS_KEEP_ALIVE_CHANNEL = "bigbluebutton:from-bbb-apps:keepalive";
 
@@ -54,6 +56,8 @@ public class MessagingConstants {
 	public static final String FROM_VOICE_CONF_CHANNEL = "bigbluebutton:from-voice-conf";	
 	public static final String FROM_VOICE_CONF_PATTERN = FROM_VOICE_CONF_CHANNEL + ":*";
 	public static final String FROM_VOICE_CONF_SYSTEM_CHAN = FROM_VOICE_CONF_CHANNEL + ":system";
+
+	public static final String FROM_BBB_RECORDING_CHANNEL  = "bigbluebutton:from-rap";
 	
 	public static final String DESTROY_MEETING_REQUEST_EVENT = "DestroyMeetingRequestEvent";
 	public static final String CREATE_MEETING_REQUEST_EVENT = "CreateMeetingRequestEvent";	
@@ -65,6 +69,7 @@ public class MessagingConstants {
 	public static final String USER_LEFT_EVENT = "UserLeftEvent";
 	public static final String USER_LEFT_VOICE_REQUEST = "user_left_voice_request";
 	public static final String USER_STATUS_CHANGE_EVENT = "UserStatusChangeEvent";	
+	public static final String USER_ROLE_CHANGE_EVENT = "UserRoleChangeEvent";
 	public static final String SEND_POLLS_EVENT = "SendPollsEvent";
 	public static final String RECORD_STATUS_EVENT = "RecordStatusEvent";
 	public static final String SEND_PUBLIC_CHAT_MESSAGE_REQUEST = "send_public_chat_message_request";
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/PatchDocumentReplyMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/PatchDocumentReplyMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..d5c207fbbb65245d7e68f15cdff8b3e83a912a4e
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/PatchDocumentReplyMessage.java
@@ -0,0 +1,77 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class PatchDocumentReplyMessage implements ISubscribedMessage {
+	public static final String PATCH_DOCUMENT_REPLY = "patch_document_reply";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String requesterID;
+	public final String noteID;
+	public final String patch;
+	public final Integer patchID;
+	public final Boolean undo;
+	public final Boolean redo;
+
+	public PatchDocumentReplyMessage(String meetingID, String requesterID, String noteID, String patch, Integer patchID, Boolean undo, Boolean redo) {
+		this.meetingID = meetingID;
+		this.requesterID = requesterID;
+		this.noteID = noteID;
+		this.patch = patch;
+		this.patchID = patchID;
+		this.undo = undo;
+		this.redo = redo;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.REQUESTER_ID, requesterID);
+		payload.put(Constants.NOTE_ID, noteID);
+		payload.put(Constants.PATCH, patch);
+		payload.put(Constants.PATCH_ID, patchID);
+		payload.put(Constants.UNDO, undo);
+		payload.put(Constants.REDO, redo);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(PATCH_DOCUMENT_REPLY, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static PatchDocumentReplyMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (PATCH_DOCUMENT_REPLY.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)
+							&& payload.has(Constants.NOTE_ID)
+							&& payload.has(Constants.PATCH)
+							&& payload.has(Constants.PATCH_ID)
+							&& payload.has(Constants.UNDO)
+							&& payload.has(Constants.REDO)) {
+						String meetingID = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterID = payload.get(Constants.REQUESTER_ID).getAsString();
+						String noteID = payload.get(Constants.NOTE_ID).getAsString();
+						String patch = payload.get(Constants.PATCH).getAsString();
+						Integer patchID = payload.get(Constants.PATCH_ID).getAsInt();
+						Boolean undo = payload.get(Constants.UNDO).getAsBoolean();
+						Boolean redo = payload.get(Constants.REDO).getAsBoolean();
+
+						return new PatchDocumentReplyMessage(meetingID, requesterID, noteID, patch, patchID, undo, redo);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/PatchDocumentRequestMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/PatchDocumentRequestMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a24067171baabe1f8506b29602bcd3e77fcc059
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/PatchDocumentRequestMessage.java
@@ -0,0 +1,67 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class PatchDocumentRequestMessage implements ISubscribedMessage {
+	public static final String PATCH_DOCUMENT_REQUEST = "patch_document_request";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String requesterID;
+	public final String noteID;
+	public final String patch;
+	public final String operation;
+
+	public PatchDocumentRequestMessage(String meetingID, String requesterID, String noteID, String patch, String operation) {
+		this.meetingID = meetingID;
+		this.requesterID = requesterID;
+		this.noteID = noteID;
+		this.patch = patch;
+		this.operation = operation;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.REQUESTER_ID, requesterID);
+		payload.put(Constants.NOTE_ID, noteID);
+		payload.put(Constants.PATCH, patch);
+		payload.put(Constants.OPERATION, operation);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(PATCH_DOCUMENT_REQUEST, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static PatchDocumentRequestMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (PATCH_DOCUMENT_REQUEST.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)
+							&& payload.has(Constants.NOTE_ID)
+							&& payload.has(Constants.PATCH)
+							&& payload.has(Constants.OPERATION)) {
+						String meetingID = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterID = payload.get(Constants.REQUESTER_ID).getAsString();
+						String noteID = payload.get(Constants.NOTE_ID).getAsString();
+						String patch = payload.get(Constants.PATCH).getAsString();
+						String operation = payload.get(Constants.OPERATION).getAsString();
+
+						return new PatchDocumentRequestMessage(meetingID, requesterID, noteID, patch, operation);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/PresentationConversionDoneMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/PresentationConversionDoneMessage.java
index cad2a8b9e487add175a2bd69edc586d711efea77..6aba2fac1eb3c27832038271ebd7c45d9c9230ff 100755
--- a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/PresentationConversionDoneMessage.java
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/PresentationConversionDoneMessage.java
@@ -58,7 +58,8 @@ public class PresentationConversionDoneMessage implements ISubscribedMessage {
 						if (presObj.has("id") 
 								&& presObj.has("name")
 								&& presObj.has("current")
-								&& presObj.has("pages")){
+								&& presObj.has("pages")
+								&& presObj.has("downloadable")) {
 
 							String id = presObj.get("id").getAsString();
 							boolean current = presObj.get("current").getAsBoolean();
@@ -75,6 +76,9 @@ public class PresentationConversionDoneMessage implements ISubscribedMessage {
 
 							presentation.put("pages", pagesList);
 
+							boolean downloadable = presObj.get("downloadable").getAsBoolean();
+							presentation.put("downloadable", downloadable);
+
 							return new PresentationConversionDoneMessage(meetingId, code, presentation);
 						}
 					}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RegisterUserMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RegisterUserMessage.java
index 74052848809f93034fff9efb0b66f36042581264..577fe0d6401acf254c31d07fab745302c12dd1c1 100755
--- a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RegisterUserMessage.java
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RegisterUserMessage.java
@@ -15,8 +15,9 @@ public class RegisterUserMessage implements IBigBlueButtonMessage {
 	public final String externUserID;
 	public final String authToken;
 	public final String avatarURL;
+	public final Boolean guest;
 
-	public RegisterUserMessage(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken, String avatarURL) {
+	public RegisterUserMessage(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken, String avatarURL, Boolean guest) {
 		this.meetingID = meetingID;
 		this.internalUserId = internalUserId;
 		this.fullname = fullname;
@@ -24,6 +25,7 @@ public class RegisterUserMessage implements IBigBlueButtonMessage {
 		this.externUserID = externUserID;
 		this.authToken = authToken;
 		this.avatarURL = avatarURL;
+		this.guest = guest;
 	}
 
 	public String toJson() {
@@ -36,6 +38,7 @@ public class RegisterUserMessage implements IBigBlueButtonMessage {
 		payload.put(Constants.EXT_USER_ID, externUserID);
 		payload.put(Constants.AUTH_TOKEN, authToken);
 		payload.put(Constants.AVATAR_URL, avatarURL);
+		payload.put(Constants.GUEST, guest.toString());
 
 		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(REGISTER_USER, VERSION, null);
 
@@ -56,7 +59,8 @@ public class RegisterUserMessage implements IBigBlueButtonMessage {
 							&& payload.has(Constants.NAME)
 							&& payload.has(Constants.ROLE)
 							&& payload.has(Constants.EXT_USER_ID)
-							&& payload.has(Constants.AUTH_TOKEN)) {
+							&& payload.has(Constants.AUTH_TOKEN)
+							&& payload.has(Constants.GUEST)) {
 
 						String meetingID = payload.get(Constants.MEETING_ID).getAsString();
 						String fullname = payload.get(Constants.NAME).getAsString();
@@ -64,9 +68,10 @@ public class RegisterUserMessage implements IBigBlueButtonMessage {
 						String externUserID = payload.get(Constants.EXT_USER_ID).getAsString();
 						String authToken = payload.get(Constants.AUTH_TOKEN).getAsString();
 						String avatarURL = payload.get(Constants.AVATAR_URL).getAsString();
+						Boolean guest = payload.get(Constants.GUEST).getAsBoolean();
 
 						//use externalUserId twice - once for external, once for internal
-						return new RegisterUserMessage(meetingID, externUserID, fullname, role, externUserID, authToken, avatarURL);
+						return new RegisterUserMessage(meetingID, externUserID, fullname, role, externUserID, authToken, avatarURL, guest);
 					}
 				}
 			}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RequestAdditionalNotesSetRequestMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RequestAdditionalNotesSetRequestMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..f08e252beeb07dd0ecf8202b07c2e0947bac78f5
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RequestAdditionalNotesSetRequestMessage.java
@@ -0,0 +1,57 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class RequestAdditionalNotesSetRequestMessage implements ISubscribedMessage {
+	public static final String REQUEST_ADDITIONAL_NOTES_SET_REQUEST = "request_additional_notes_set_request";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String requesterID;
+	public final int additionalNotesSetSize;
+
+	public RequestAdditionalNotesSetRequestMessage(String meetingID, String requesterID, int additionalNotesSetSize) {
+		this.meetingID = meetingID;
+		this.requesterID = requesterID;
+		this.additionalNotesSetSize = additionalNotesSetSize;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.REQUESTER_ID, requesterID);
+		payload.put(Constants.ADDITIONAL_NOTES_SET_SIZE, additionalNotesSetSize);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(REQUEST_ADDITIONAL_NOTES_SET_REQUEST, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static RequestAdditionalNotesSetRequestMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (REQUEST_ADDITIONAL_NOTES_SET_REQUEST.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)
+							&& payload.has(Constants.ADDITIONAL_NOTES_SET_SIZE)) {
+						String meetingID = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterID = payload.get(Constants.REQUESTER_ID).getAsString();
+						int additionalNotesSetSize = payload.get(Constants.ADDITIONAL_NOTES_SET_SIZE).getAsInt();
+
+						return new RequestAdditionalNotesSetRequestMessage(meetingID, requesterID, additionalNotesSetSize);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RespondToGuestMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RespondToGuestMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..2da32de6b8006f4b9ad1aa198663834f2691a392
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/RespondToGuestMessage.java
@@ -0,0 +1,64 @@
+
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class RespondToGuestMessage implements IBigBlueButtonMessage {
+	public static final String RESPOND_TO_GUEST = "respond_to_guest";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String userId;
+	public final Boolean response;
+	public final String requesterId;
+
+	public RespondToGuestMessage(String meetingId, String userId, Boolean response, String requesterId) {
+		this.meetingId = meetingId;
+		this.userId = userId;
+		this.response = response;
+		this.requesterId = requesterId;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.USER_ID, userId);
+		payload.put(Constants.RESPONSE, response);
+		payload.put(Constants.REQUESTER_ID, requesterId);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(RESPOND_TO_GUEST, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static RespondToGuestMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (RESPOND_TO_GUEST.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.RESPONSE)
+							&& payload.has(Constants.REQUESTER_ID)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String userId = null;
+						Boolean response = payload.get(Constants.RESPONSE).getAsBoolean();
+						String requesterId = payload.get(Constants.REQUESTER_ID).getAsString();
+
+						if (payload.has(Constants.USER_ID)) {
+							userId = payload.get(Constants.USER_ID).getAsString();
+						}
+
+						return new RespondToGuestMessage(meetingId, userId, response, requesterId);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SendConversionCompletedMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SendConversionCompletedMessage.java
index 593de02722108b2c9bd403b840544c1144cee5c2..ea9aa30c10879facee6d68ead31b697be554429d 100755
--- a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SendConversionCompletedMessage.java
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SendConversionCompletedMessage.java
@@ -16,9 +16,10 @@ public class SendConversionCompletedMessage implements IBigBlueButtonMessage {
 	public final int numPages;
 	public final String presName;
 	public final String presBaseUrl;
+	public final Boolean downloadable;
 
 	public SendConversionCompletedMessage(String messageKey, String meetingId,	String code,
-			String presId, int numPages, String presName,	String presBaseUrl) {
+			String presId, int numPages, String presName,	String presBaseUrl, Boolean downloadable) {
 		this.meetingId = meetingId;
 		this.messageKey = messageKey;
 		this.code = code;
@@ -26,6 +27,7 @@ public class SendConversionCompletedMessage implements IBigBlueButtonMessage {
 		this.numPages = numPages;
 		this.presName = presName;
 		this.presBaseUrl = presBaseUrl;
+		this.downloadable = downloadable;
 	}
 
 	public String toJson() {
@@ -37,6 +39,7 @@ public class SendConversionCompletedMessage implements IBigBlueButtonMessage {
 		payload.put(Constants.NUM_PAGES, numPages);
 		payload.put(Constants.PRESENTATION_NAME, presName);
 		payload.put(Constants.PRESENTATION_BASE_URL, presBaseUrl);
+		payload.put(Constants.DOWNLOADABLE, downloadable);
 
 		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(SEND_CONVERSION_COMPLETED, VERSION, null);
 
@@ -60,7 +63,8 @@ public class SendConversionCompletedMessage implements IBigBlueButtonMessage {
 							&& payload.has(Constants.PRESENTATION_ID)
 							&& payload.has(Constants.NUM_PAGES)
 							&& payload.has(Constants.PRESENTATION_NAME)
-							&& payload.has(Constants.PRESENTATION_BASE_URL)) {
+							&& payload.has(Constants.PRESENTATION_BASE_URL)
+							&& payload.has(Constants.DOWNLOADABLE)) {
 						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
 						String messageKey = payload.get(Constants.MESSAGE_KEY).getAsString();
 						String code = payload.get(Constants.CODE).getAsString();
@@ -68,8 +72,9 @@ public class SendConversionCompletedMessage implements IBigBlueButtonMessage {
 						int numPages = payload.get(Constants.NUM_PAGES).getAsInt();
 						String presName = payload.get(Constants.PRESENTATION_NAME).getAsString();
 						String presBaseUrl = payload.get(Constants.PRESENTATION_BASE_URL).getAsString();
+						Boolean downloadable = payload.get(Constants.DOWNLOADABLE).getAsBoolean();
 
-						return new SendConversionCompletedMessage(messageKey, meetingId, code, presId, numPages, presName, presBaseUrl);
+						return new SendConversionCompletedMessage(messageKey, meetingId, code, presId, numPages, presName, presBaseUrl, downloadable);
 					}
 				} 
 			}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SetGuestPolicyMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SetGuestPolicyMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..b56ea59abbe0e582ef4bb04f6bfe9d2ffe2eddde
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SetGuestPolicyMessage.java
@@ -0,0 +1,55 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class SetGuestPolicyMessage implements IBigBlueButtonMessage {
+	public static final String SET_GUEST_POLICY = "set_guest_policy";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String guestPolicy;
+	public final String setBy;
+
+	public SetGuestPolicyMessage(String meetingId, String guestPolicy, String setBy) {
+		this.meetingId = meetingId;
+		this.guestPolicy = guestPolicy;
+		this.setBy = setBy;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.GUEST_POLICY, guestPolicy);
+		payload.put(Constants.SET_BY, setBy);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(SET_GUEST_POLICY, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static SetGuestPolicyMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (SET_GUEST_POLICY.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.GUEST_POLICY)
+							&& payload.has(Constants.SET_BY)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String guestPolicy = payload.get(Constants.GUEST_POLICY).getAsString();
+						String setBy = payload.get(Constants.SET_BY).getAsString();
+
+						return new SetGuestPolicyMessage(meetingId, guestPolicy, setBy);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SharedNotesSyncNoteReplyMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SharedNotesSyncNoteReplyMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..4aad22cda535bb0c2385cf55ef06f1dac8f1d1d3
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SharedNotesSyncNoteReplyMessage.java
@@ -0,0 +1,66 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class SharedNotesSyncNoteReplyMessage implements ISubscribedMessage {
+	public static final String SHAREDNOTES_SYNC_NOTE_REPLY = "sharednotes_sync_note_reply";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String requesterID;
+	public final String noteID;
+	public final Object note;
+
+	public SharedNotesSyncNoteReplyMessage(String meetingID, String requesterID, String noteID, Object note) {
+		this.meetingID = meetingID;
+		this.requesterID = requesterID;
+		this.noteID = noteID;
+		this.note = note;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.REQUESTER_ID, requesterID);
+		payload.put(Constants.NOTE_ID, noteID);
+		payload.put(Constants.NOTE, note);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(SHAREDNOTES_SYNC_NOTE_REPLY, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static SharedNotesSyncNoteReplyMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (SHAREDNOTES_SYNC_NOTE_REPLY.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)
+							&& payload.has(Constants.NOTE_ID)
+							&& payload.has(Constants.NOTE)) {
+						String meetingID = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterID = payload.get(Constants.REQUESTER_ID).getAsString();
+						String noteID = payload.get(Constants.NOTE_ID).getAsString();
+
+						JsonObject noteObject = (JsonObject) payload.get(Constants.NOTE);
+
+						Util util = new Util();
+						Object note = util.extractNote(noteObject);
+
+						return new SharedNotesSyncNoteReplyMessage(meetingID, requesterID, noteID, note);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SharedNotesSyncNoteRequestMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SharedNotesSyncNoteRequestMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..399e63e923c2cdcd53eb02982d45c4afaaaa7a92
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/SharedNotesSyncNoteRequestMessage.java
@@ -0,0 +1,57 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class SharedNotesSyncNoteRequestMessage implements ISubscribedMessage {
+	public static final String SHAREDNOTES_SYNC_NOTE_REQUEST = "sharednotes_sync_note_request";
+	public final String VERSION = "0.0.1";
+
+	public final String meetingID;
+	public final String requesterID;
+	public final String noteID;
+
+	public SharedNotesSyncNoteRequestMessage(String meetingID, String requesterID, String noteID) {
+		this.meetingID = meetingID;
+		this.requesterID = requesterID;
+		this.noteID = noteID;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingID);
+		payload.put(Constants.REQUESTER_ID, requesterID);
+		payload.put(Constants.NOTE_ID, noteID);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(SHAREDNOTES_SYNC_NOTE_REQUEST, VERSION, null);
+
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static SharedNotesSyncNoteRequestMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (SHAREDNOTES_SYNC_NOTE_REQUEST.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.REQUESTER_ID)
+							&& payload.has(Constants.NOTE_ID)) {
+						String meetingID = payload.get(Constants.MEETING_ID).getAsString();
+						String requesterID = payload.get(Constants.REQUESTER_ID).getAsString();
+						String noteID = payload.get(Constants.NOTE_ID).getAsString();
+
+						return new SharedNotesSyncNoteRequestMessage(meetingID, requesterID, noteID);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/UserRoleChangeMessage.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/UserRoleChangeMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d6d76bde13df24c035ef97d840f30de7767d0d9
--- /dev/null
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/UserRoleChangeMessage.java
@@ -0,0 +1,55 @@
+package org.bigbluebutton.common.messages;
+
+import java.util.HashMap;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class UserRoleChangeMessage implements IBigBlueButtonMessage {
+	public static final String USER_ROLE_CHANGE = "user_role_change";
+	public static final String VERSION = "0.0.1";
+
+	public final String meetingId;
+	public final String userId;
+	public final String role;
+
+	public UserRoleChangeMessage(String meetingId, String userId, String role) {
+		this.meetingId = meetingId;
+		this.userId = userId;
+		this.role = role;
+	}
+
+	public String toJson() {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.MEETING_ID, meetingId);
+		payload.put(Constants.USER_ID, userId);
+		payload.put(Constants.ROLE, role);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(USER_ROLE_CHANGE, VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static UserRoleChangeMessage fromJson(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+			JsonObject payload = (JsonObject) obj.get("payload");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				if (USER_ROLE_CHANGE.equals(messageName)) {
+					if (payload.has(Constants.MEETING_ID)
+							&& payload.has(Constants.USER_ID)
+							&& payload.has(Constants.ROLE)) {
+						String meetingId = payload.get(Constants.MEETING_ID).getAsString();
+						String userId = payload.get(Constants.USER_ID).getAsString();
+						String role = payload.get(Constants.ROLE).getAsString();
+
+						return new UserRoleChangeMessage(meetingId, userId, role);
+					}
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/Util.java b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/Util.java
index 601a7daf93df60cc6f9379adc58cdb05bb69bfef..bf8d18646b3024229f21030ed7f8567f6912d658 100755
--- a/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/Util.java
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/common/messages/Util.java
@@ -74,7 +74,8 @@ public class Util {
 				&& user.has(Constants.EMOJI_STATUS) && user.has(Constants.PHONE_USER)
 				&& user.has(Constants.PRESENTER) && user.has(Constants.LOCKED)
 				&& user.has(Constants.EXTERN_USERID) && user.has(Constants.ROLE)
-				&& user.has(Constants.VOICEUSER) && user.has(Constants.WEBCAM_STREAM)){
+				&& user.has(Constants.VOICEUSER) && user.has(Constants.WEBCAM_STREAM)
+				&& user.has(Constants.GUEST) && user.has(Constants.WAITING_FOR_ACCEPTANCE)){
 				
 			Map<String, Object> userMap = new HashMap<String, Object>();					
 
@@ -89,6 +90,8 @@ public class Util {
 			String extUserId = user.get(Constants.EXTERN_USERID).getAsString();
 			String role = user.get(Constants.ROLE).getAsString();
 			String avatarURL = user.get(Constants.AVATAR_URL).getAsString();
+			Boolean guest = user.get(Constants.GUEST).getAsBoolean();
+			Boolean waitingForAcceptance = user.get(Constants.WAITING_FOR_ACCEPTANCE).getAsBoolean();
 			
 			JsonArray webcamStreamJArray = user.get(Constants.WEBCAM_STREAM).getAsJsonArray();
 			ArrayList<String> webcamStreams = extractWebcamStreams(webcamStreamJArray);
@@ -103,6 +106,8 @@ public class Util {
 			userMap.put("phoneUser", phoneUser);
 			userMap.put("locked", locked);
 			userMap.put("role", role);
+			userMap.put("guest", guest);
+			userMap.put("waitingForAcceptance", waitingForAcceptance);
 			userMap.put("presenter", presenter);
 			userMap.put("avatarURL", avatarURL);
 			
@@ -425,16 +430,19 @@ public class Util {
 
 	public Map<String, Object> extractPresentation(JsonObject presObj) {
 		if (presObj.has(Constants.ID) && presObj.has(Constants.NAME)
-				&& presObj.has(Constants.CURRENT) && presObj.has(Constants.PAGES)) {
+				&& presObj.has(Constants.CURRENT) && presObj.has(Constants.PAGES)
+				&& presObj.has(Constants.DOWNLOADABLE)) {
 			Map<String, Object> pres = new HashMap<String, Object>();
 
 			String presId = presObj.get(Constants.ID).getAsString();
 			String presName = presObj.get(Constants.NAME).getAsString();
 			Boolean currentPres = presObj.get(Constants.CURRENT).getAsBoolean();
+			Boolean downloadable = presObj.get(Constants.DOWNLOADABLE).getAsBoolean();
 
 			pres.put("id", presId);
 			pres.put("name", presName);
 			pres.put("current", currentPres);
+			pres.put("downloadable", downloadable);
 
 			JsonArray pagesJsonArray = presObj.get(Constants.PAGES).getAsJsonArray();
 
@@ -740,4 +748,55 @@ public class Util {
 		return collection;
 	}
 	
-}
+	class Note {
+		String name = "";
+		String document = "";
+		Integer patchCounter = 0;
+		Boolean undo = false;
+		Boolean redo = false;
+
+		public Note(String name, String document, Integer patchCounter, Boolean undo, Boolean redo) {
+			this.name = name;
+			this.document = document;
+			this.patchCounter = patchCounter;
+			this.undo = undo;
+			this.redo = redo;
+		}
+	}
+
+	public Object extractNote(JsonObject noteObject) {
+		String name = noteObject.get("name").getAsString();
+		String document = noteObject.get("document").getAsString();
+		Integer patchCounter = noteObject.get("patchCounter").getAsInt();
+		Boolean undo = noteObject.get("undo").getAsBoolean();
+		Boolean redo = noteObject.get("redo").getAsBoolean();
+
+		Note note = new Note(name, document, patchCounter, undo, redo);
+
+		return (Object) note;
+	}
+
+	public Map<String, Object> extractNotes(JsonObject notes) {
+		Map<String, Object> notesMap = new HashMap<String, Object>();
+
+		for (Map.Entry<String, JsonElement> entry : notes.entrySet()) {
+			JsonObject obj = entry.getValue().getAsJsonObject();
+			Object note = extractNote(obj);
+			notesMap.put(entry.getKey(), note);
+		}
+
+		return notesMap;
+	}
+
+	public Map<String, String> extractMetadata(JsonObject metadata) {
+		Map<String, String> metadataMap = new HashMap<String, String>();
+
+		for (Map.Entry<String, JsonElement> entry : metadata.entrySet()) {
+			String key = entry.getKey();
+			String value = entry.getValue().getAsString();
+			metadataMap.put(key, value);
+		}
+
+		return metadataMap;
+	}
+}
diff --git a/bbb-common-message/src/main/java/org/bigbluebutton/messages/CreateMeetingRequest.java b/bbb-common-message/src/main/java/org/bigbluebutton/messages/CreateMeetingRequest.java
index 48fbdb56281b809d148c5a5c7e6a84ec772cc296..081aec333ee2650e237c7d83878ce1e2ff24b4ba 100755
--- a/bbb-common-message/src/main/java/org/bigbluebutton/messages/CreateMeetingRequest.java
+++ b/bbb-common-message/src/main/java/org/bigbluebutton/messages/CreateMeetingRequest.java
@@ -2,6 +2,8 @@ package org.bigbluebutton.messages;
 
 import org.bigbluebutton.common.messages.IBigBlueButtonMessage;
 
+import java.util.Map;
+
 public class CreateMeetingRequest implements IBigBlueButtonMessage {
     public final static String NAME = "CreateMeetingRequest";
 
@@ -29,13 +31,15 @@ public class CreateMeetingRequest implements IBigBlueButtonMessage {
         public final String createDate;
         public final Boolean isBreakout;
         public final Integer sequence;
+        public final Map<String, String> metadata;
 
         public CreateMeetingRequestPayload(String id, String externalId,
                 String parentId, String name, Boolean record,
                 String voiceConfId, Integer duration,
                 Boolean autoStartRecording, Boolean allowStartStopRecording,
                 String moderatorPass, String viewerPass, Long createTime,
-                String createDate, Boolean isBreakout, Integer sequence) {
+                String createDate, Boolean isBreakout, Integer sequence,
+                Map<String, String> metadata) {
             this.id = id;
             this.externalId = externalId;
             this.parentId = parentId;
@@ -51,6 +55,7 @@ public class CreateMeetingRequest implements IBigBlueButtonMessage {
             this.createDate = createDate;
             this.isBreakout = isBreakout;
             this.sequence = sequence;
+            this.metadata = metadata;
         }
     }
 }
diff --git a/bbb-common-message/src/test/java/org/bigbluebutton/messages/CreateMeetingRequestTest.java b/bbb-common-message/src/test/java/org/bigbluebutton/messages/CreateMeetingRequestTest.java
index e25dfa81c73e13029390fb6fa69acee8a1879b46..c1475e17333e328b9fea4486307362cc75bfa8b0 100755
--- a/bbb-common-message/src/test/java/org/bigbluebutton/messages/CreateMeetingRequestTest.java
+++ b/bbb-common-message/src/test/java/org/bigbluebutton/messages/CreateMeetingRequestTest.java
@@ -1,6 +1,8 @@
 package org.bigbluebutton.messages;
 
 import java.util.Date;
+import java.util.Map;
+import java.util.HashMap;
 import org.bigbluebutton.messages.CreateMeetingRequest.CreateMeetingRequestPayload;
 import org.junit.Assert;
 import org.junit.Test;
@@ -25,12 +27,14 @@ public class CreateMeetingRequestTest {
     String moderatorPassword = "mp";
     long createTime = System.currentTimeMillis();
     String createDate = new Date(createTime).toString();
+    Map<String, String> metadata = new HashMap<String, String>();
+    metadata.put("meta_test", "test");
     
         CreateMeetingRequestPayload payload = new CreateMeetingRequestPayload(
                 meetingId, externalId, parentId, name, record, voiceConfId,
                 durationInMinutes, autoStartRecording, allowStartStopRecording,
                 moderatorPassword, viewerPassword, createTime, createDate,
-                isBreakout, sequence);
+                isBreakout, sequence, metadata);
     CreateMeetingRequest msg = new CreateMeetingRequest(payload);    
     Gson gson = new Gson();
     String json = gson.toJson(msg);
diff --git a/bbb-video/.classpath b/bbb-video/.classpath
deleted file mode 100755
index b7e0cf54c32b620145e1ef423794d409859935f9..0000000000000000000000000000000000000000
--- a/bbb-video/.classpath
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="src/main/java"/>
-	<classpathentry kind="src" path="src/test/java"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry kind="lib" path="lib/aopalliance-1.0.jar"/>
-	<classpathentry kind="lib" path="lib/commons-pool-1.5.6.jar"/>
-	<classpathentry kind="lib" path="lib/easymock-2.4.jar"/>
-	<classpathentry kind="lib" path="lib/gson-1.7.1.jar"/>
-	<classpathentry kind="lib" path="lib/jcip-annotations-1.0.jar"/>
-	<classpathentry kind="lib" path="lib/jcl-over-slf4j-1.7.9.jar"/>
-	<classpathentry kind="lib" path="lib/jedis-2.0.0.jar"/>
-	<classpathentry kind="lib" path="lib/jul-to-slf4j-1.7.9.jar"/>
-	<classpathentry kind="lib" path="lib/log4j-over-slf4j-1.7.9.jar"/>
-	<classpathentry kind="lib" path="lib/logback-classic-1.1.2.jar"/>
-	<classpathentry kind="lib" path="lib/logback-core-1.1.2.jar"/>
-	<classpathentry kind="lib" path="lib/mina-core-2.0.8.jar"/>
-	<classpathentry kind="lib" path="lib/mina-integration-beans-2.0.8.jar"/>
-	<classpathentry kind="lib" path="lib/mina-integration-jmx-2.0.8.jar"/>
-	<classpathentry kind="lib" path="lib/red5-io-1.0.5-RELEASE.jar"/>
-	<classpathentry kind="lib" path="lib/red5-server-1.0.5-RELEASE.jar"/>
-	<classpathentry kind="lib" path="lib/red5-server-common-1.0.5-RELEASE.jar"/>
-	<classpathentry kind="lib" path="lib/servlet-api-2.5.jar"/>
-	<classpathentry kind="lib" path="lib/slf4j-api-1.7.9.jar"/>
-	<classpathentry kind="lib" path="lib/spring-aop-4.0.8.RELEASE.jar"/>
-	<classpathentry kind="lib" path="lib/spring-beans-4.0.7.RELEASE.jar"/>
-	<classpathentry kind="lib" path="lib/spring-context-4.0.7.RELEASE.jar"/>
-	<classpathentry kind="lib" path="lib/spring-core-4.0.7.RELEASE.jar"/>
-	<classpathentry kind="lib" path="lib/spring-web-4.0.8.RELEASE.jar"/>
-	<classpathentry kind="lib" path="lib/bbb-common-message-0.0.5.jar"/>
-	<classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/bbb-video/.gitignore b/bbb-video/.gitignore
index 27584657a6b6e349e07bb6c58e0c899b75a6404c..51aacf96f5fb751b8fe597ebe5bf980ec244df90 100644
--- a/bbb-video/.gitignore
+++ b/bbb-video/.gitignore
@@ -2,4 +2,6 @@ bin
 build
 dist
 lib
-build
+.classpath
+.project
+.settings
diff --git a/bbb-video/.project b/bbb-video/.project
deleted file mode 100644
index dff16b260e4d10e4a1cbf017d678614759e9ff60..0000000000000000000000000000000000000000
--- a/bbb-video/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>bbb-video</name>
-	<comment></comment>
-	<projects>
-	</projects>
-	<buildSpec>
-		<buildCommand>
-			<name>org.eclipse.jdt.core.javabuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-	</buildSpec>
-	<natures>
-		<nature>org.eclipse.jdt.core.javanature</nature>
-	</natures>
-</projectDescription>
diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java
index ce1c25bb2329733c64c0dad0034ac1260f29e624..94ac0b7be04a6ac5cfbc7fbcd4e6966628866f84 100755
--- a/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java
+++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/VideoApplication.java
@@ -23,6 +23,8 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import org.bigbluebutton.app.video.converter.H263Converter;
+import org.bigbluebutton.app.video.converter.VideoRotator;
 import org.bigbluebutton.red5.pubsub.MessagePublisher;
 import org.red5.logging.Red5LoggerFactory;
 import org.red5.server.adapter.MultiThreadedApplicationAdapter;
@@ -30,8 +32,10 @@ import org.red5.server.api.IConnection;
 import org.red5.server.api.Red5;
 import org.red5.server.api.scope.IScope;
 import org.red5.server.api.stream.IBroadcastStream;
+import org.red5.server.api.stream.IPlayItem;
 import org.red5.server.api.stream.IServerStream;
 import org.red5.server.api.stream.IStreamListener;
+import org.red5.server.api.stream.ISubscriberStream;
 import org.red5.server.stream.ClientBroadcastStream;
 import org.slf4j.Logger;
 
@@ -47,6 +51,12 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
 	
 	private int packetTimeout = 10000;
 	
+	private final Map<String, H263Converter> h263Converters = new HashMap<String, H263Converter>();
+	private final Map<String, String> h263Users = new HashMap<String, String>(); //viewers
+	private final Map<String, String> h263PublishedStreams = new HashMap<String,String>(); //publishers
+
+	private final Map<String, VideoRotator> videoRotators = new HashMap<String, VideoRotator>();
+
     @Override
 	public boolean appStart(IScope app) {
 	    super.appStart(app);
@@ -62,6 +72,13 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
   @Override
 	public boolean roomConnect(IConnection connection, Object[] params) {
 		log.info("BBB Video roomConnect");
+
+		if(params.length == 0) {
+			params = new Object[2];
+			params[0] = "UNKNOWN-MEETING-ID";
+			params[1] = "UNKNOWN-USER-ID";
+		}
+
 		String meetingId = ((String) params[0]).toString();
 		String userId = ((String) params[1]).toString();
 
@@ -147,6 +164,7 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
 	
   @Override
 	public void appDisconnect(IConnection conn) {
+		clearH263UserVideo(getUserId());
 		super.appDisconnect(conn);
 	}
 
@@ -195,7 +213,14 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
         stream.addStreamListener(listener); 
         streamListeners.put(conn.getScope().getName() + "-" + stream.getPublishedName(), listener);
         
-        if (recordVideoStream) {
+        addH263PublishedStream(streamId);
+        if (streamId.contains("/")) {
+            if(VideoRotator.getDirection(streamId) != null) {
+                VideoRotator rotator = new VideoRotator(streamId);
+                videoRotators.put(streamId, rotator);
+            }
+        }
+        else if (recordVideoStream) {
 	    	recordStream(stream);
         }
     }
@@ -204,6 +229,11 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
     	return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
     }
     
+    private boolean isH263Stream(ISubscriberStream stream) {
+        String streamName = stream.getBroadcastStreamPublishName();
+        return streamName.startsWith(H263Converter.H263PREFIX);
+    }
+
     @Override
     public void streamBroadcastClose(IBroadcastStream stream) {
       super.streamBroadcastClose(stream);   	
@@ -240,6 +270,13 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
         event.put("eventName", "StopWebcamShareEvent");
         recordingService.record(scopeName, event);    		
       }
+
+      removeH263ConverterIfNeeded(streamId);
+      if(videoRotators.containsKey(streamId)) {
+        // Stop rotator
+        videoRotators.remove(streamId).stop();
+      }
+      removeH263PublishedStream(streamId);
     }
     
     /**
@@ -277,4 +314,130 @@ public class VideoApplication extends MultiThreadedApplicationAdapter {
 		this.publisher = publisher;
 	}
 
+	@Override
+	public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive) {
+		// log w3c connect event
+		String streamName = item.getName();
+		streamName = streamName.replaceAll(H263Converter.H263PREFIX, "");
+
+		if(isH263Stream(stream)) {
+			log.debug("Detected H263 stream request [{}]", streamName);
+
+			synchronized (h263Converters) {
+				// Check if a new stream converter is necessary
+				H263Converter converter;
+				if(!h263Converters.containsKey(streamName) && !isStreamPublished(streamName)) {
+					converter = new H263Converter(streamName);
+					h263Converters.put(streamName, converter);
+				}
+				else {
+					converter = h263Converters.get(streamName);
+				}
+
+				if(!isH263UserListening(getUserId())){
+					converter.addListener();
+					addH263User(getUserId(),streamName);
+				}
+			}
+		}
+	}
+
+	@Override
+	public void streamSubscriberClose(ISubscriberStream stream) {
+		String streamName = stream.getBroadcastStreamPublishName();
+		streamName = streamName.replaceAll(H263Converter.H263PREFIX, "");
+		String userId = getUserId();
+
+		if(isH263Stream(stream)) {
+			log.debug("Detected H263 stream close [{}]", streamName);
+
+			synchronized (h263Converters) {
+				// Remove prefix
+				if(h263Converters.containsKey(streamName)) {
+					H263Converter converter = h263Converters.get(streamName);
+					if (isH263UserListening(userId)){
+						converter.removeListener();
+						removeH263User(userId);
+					}
+				}
+				else {
+					log.warn("Converter not found for H263 stream [{}]. This may has been closed already", streamName);
+				}
+			}
+		}
+	}
+
+    private void removeH263User(String userId){
+        if (h263Users.containsKey(userId)){
+            log.debug("REMOVE |Removing h263 user from h263User's list [uid={}]",userId);
+            h263Users.remove(userId);
+        }
+    }
+
+    private void addH263User(String userId, String streamName){
+        log.debug("ADD |Add h263 user to h263User's list [uid={} streamName={}]",userId,streamName);
+        h263Users.put(userId,streamName);
+    }
+
+    private void clearH263UserVideo(String userId) {
+        /*
+         * If this is an h263User, clear it's video.
+         * */
+        synchronized (h263Converters){
+            if (isH263UserListening(userId)){
+                String streamName = h263Users.get(userId);
+                H263Converter converter = h263Converters.get(streamName);
+                if(converter == null ) log.debug("er... something went wrong. User was listening to the stream, but there's no more converter for this stream [stream={}] [uid={}]",userId,streamName);
+                converter.removeListener();
+                removeH263User(userId);
+                log.debug("h263's user data cleared.");
+            }
+        }
+    }
+
+    private void clearH263Users(String streamName) {
+        /*
+         * Remove all the users associated with the streamName
+         * */
+        log.debug("Clearing h263Users's list for the stream {}",streamName);
+        if (h263Users != null)
+            while( h263Users.values().remove(streamName) );
+        log.debug("h263Users cleared.");
+    }
+
+    private boolean isH263UserListening(String userId) {
+        return (h263Users.containsKey(userId));
+    }
+
+    private void addH263PublishedStream(String streamName){
+        if (streamName.contains(H263Converter.H263PREFIX)) {
+            log.debug("Publishing an h263 stream. StreamName={}.",streamName);
+            h263PublishedStreams.put(streamName, getUserId());
+        }
+    }
+
+    private void removeH263PublishedStream(String streamName){
+        if(isH263Stream(streamName) && h263PublishedStreams.containsKey(streamName))
+            h263PublishedStreams.remove(streamName);
+    }
+
+    private boolean isStreamPublished(String streamName){
+        return h263PublishedStreams.containsKey(streamName);
+    }
+
+    private boolean isH263Stream(String streamName){
+        return streamName.startsWith(H263Converter.H263PREFIX);
+    }
+
+    private void removeH263ConverterIfNeeded(String streamName){
+        String h263StreamName = streamName.replaceAll(H263Converter.H263PREFIX, "");
+        synchronized (h263Converters){
+            if(isH263Stream(streamName) && h263Converters.containsKey(h263StreamName)) {
+              // Stop converter
+              log.debug("h263 stream is being closed {}",streamName);
+              h263Converters.remove(h263StreamName).stopConverter();
+              clearH263Users(h263StreamName);
+            }
+        }
+    }
 }
diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/converter/H263Converter.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/converter/H263Converter.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5185125d7e0818aa774066f2d69468cd67a3638
--- /dev/null
+++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/converter/H263Converter.java
@@ -0,0 +1,129 @@
+package org.bigbluebutton.app.video.converter;
+
+import org.bigbluebutton.app.video.ffmpeg.FFmpegCommand;
+import org.bigbluebutton.app.video.ffmpeg.ProcessMonitor;
+import org.bigbluebutton.app.video.ffmpeg.ProcessMonitorObserver;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.IConnection;
+import org.red5.server.api.Red5;
+import org.slf4j.Logger;
+
+/**
+ * Represents a stream converter to H263. This class is responsible
+ * for managing the execution of FFmpeg based on the number of listeners
+ * connected to the stream. When the first listener is added FFmpef is
+ * launched, and when the last listener is removed FFmpeg is stopped.
+ * Converted streams are published in the same scope as the original ones,
+ * with 'h263/' appended in the beginning.
+ */
+public class H263Converter implements ProcessMonitorObserver{
+
+	private static Logger log = Red5LoggerFactory.getLogger(H263Converter.class, "video");
+
+	public final static String H263PREFIX = "h263/";
+
+	private String origin;
+	private Integer numListeners = 0;
+
+	private FFmpegCommand ffmpeg;
+	private ProcessMonitor processMonitor;
+
+	/**
+	 * Creates a H263Converter from a given streamName. It is assumed
+	 * that one listener is responsible for this creation, therefore
+	 * FFmpeg is launched.
+	 *
+	 * @param origin streamName of the stream that should be converted
+	 */
+	public H263Converter(String origin) {
+		log.info("Spawn FFMpeg to convert H264 to H263 for stream [{}]", origin);
+		this.origin = origin;
+		IConnection conn = Red5.getConnectionLocal();
+		String ip = conn.getHost();
+		String conf = conn.getScope().getName();
+		String inputLive = "rtmp://" + ip + "/video/" + conf + "/" + origin + " live=1";
+
+		String output = "rtmp://" + ip + "/video/" + conf + "/" + H263PREFIX + origin;
+
+		ffmpeg = new FFmpegCommand();
+		ffmpeg.setFFmpegPath("/usr/local/bin/ffmpeg");
+		ffmpeg.setInput(inputLive);
+		ffmpeg.setCodec("flv1"); // Sorensen H263
+		ffmpeg.setFormat("flv");
+		ffmpeg.setOutput(output);
+		ffmpeg.setAudioEnabled(false);
+		ffmpeg.setLoglevel("quiet");
+		ffmpeg.setAnalyzeDuration("10000"); // 10ms
+
+	}
+
+	/**
+	 * Launches the process monitor responsible for FFmpeg.
+	 */
+	private void startConverter() {
+		if (processMonitor == null){
+			String[] command = ffmpeg.getFFmpegCommand(true);
+			processMonitor = new ProcessMonitor(command,"FFMPEG");
+			processMonitor.setProcessMonitorObserver(this);
+			processMonitor.start();
+		}else log.debug("No need to start transcoder, it is already running");
+	}
+
+	/**
+	 * Adds a listener to H263Converter. If there were
+	 * zero listeners, FFmpeg is launched for this stream.
+	 */
+	public synchronized void addListener() {
+		this.numListeners++;
+		log.debug("Adding listener to [{}] ; [{}] current listeners ", origin, this.numListeners);
+
+		if(this.numListeners.equals(1)) {
+			log.debug("First listener just joined, must start H263Converter for [{}]", origin);
+			startConverter();
+		}
+	}
+
+	/**
+	 * Removes a listener from H263Converter. There are
+	 * zero listeners left, FFmpeg is stopped this stream.
+	 */
+	public synchronized void removeListener() {
+		this.numListeners--;
+		log.debug("Removing listener from [{}] ; [{}] current listeners ", origin, this.numListeners);
+
+		if(this.numListeners <= 0) {
+			log.debug("No more listeners, may close H263Converter for [{}]", origin);
+			this.stopConverter();
+		}
+	}
+
+	/**
+	 * Stops FFmpeg for this stream and sets the number of
+	 * listeners to zero.
+	 */
+	public synchronized void stopConverter() {
+		if(processMonitor != null) {
+			this.numListeners = 0;
+			processMonitor.forceDestroy();
+			processMonitor = null;
+			log.debug("Transcoder force-stopped");
+		}else log.debug("No need to stop transcoder, it already stopped");
+	}
+
+    private synchronized void clearConverterData(){
+        if(processMonitor!=null){
+            log.debug("Clearing process monitor's data.");
+            this.numListeners = 0;
+            processMonitor=null;
+        }
+    }
+
+    @Override
+    public void handleProcessFinishedUnsuccessfully(String processName, String processOutput){}
+
+    @Override
+    public void handleProcessFinishedWithSuccess(String processName, String processOutput){
+        log.debug("{} finished successfully [output={}]. ",processName,processOutput);
+        //clearConverterData();
+    }
+}
diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/converter/VideoRotator.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/converter/VideoRotator.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c87aa93041ba6c6fe25f81a71a9a68a5bee752e
--- /dev/null
+++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/converter/VideoRotator.java
@@ -0,0 +1,116 @@
+package org.bigbluebutton.app.video.converter;
+
+import org.bigbluebutton.app.video.ffmpeg.FFmpegCommand;
+import org.bigbluebutton.app.video.ffmpeg.ProcessMonitor;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.IConnection;
+import org.red5.server.api.Red5;
+import org.slf4j.Logger;
+
+/**
+ * Represents a stream rotator. This class is responsible
+ * for choosing the rotate direction based on the stream name
+ * and starting FFmpeg to rotate and re-publish the stream.
+ */
+public class VideoRotator {
+
+	private static Logger log = Red5LoggerFactory.getLogger(VideoRotator.class, "video");
+
+	public static final String ROTATE_LEFT = "rotate_left";
+	public static final String ROTATE_RIGHT = "rotate_right";
+
+	private String streamName;
+	private FFmpegCommand.ROTATE direction;
+
+	private FFmpegCommand ffmpeg;
+	private ProcessMonitor processMonitor;
+
+	/**
+	 * Create a new video rotator for the specified stream.
+	 * The streamName should be of the form:
+	 * rotate_[left|right]/streamName
+	 * The rotated stream will be published as streamName.
+	 *
+	 * @param origin Name of the stream that will be rotated
+	 */
+	public VideoRotator(String origin) {
+		this.streamName = getStreamName(origin);
+		this.direction = getDirection(origin);
+
+		log.debug("Setting up VideoRotator: StreamName={}, Direction={}",this.streamName,this.direction);
+		IConnection conn = Red5.getConnectionLocal();
+		String ip = conn.getHost();
+		String conf = conn.getScope().getName();
+		String inputLive = "rtmp://" + ip + "/video/" + conf + "/" + origin + " live=1";
+
+		String output = "rtmp://" + ip + "/video/" + conf + "/" + streamName;
+
+		ffmpeg = new FFmpegCommand();
+		ffmpeg.setFFmpegPath("/usr/local/bin/ffmpeg");
+		ffmpeg.setInput(inputLive);
+		ffmpeg.setFormat("flv");
+		ffmpeg.setOutput(output);
+		ffmpeg.setLoglevel("warning");
+		ffmpeg.setRotation(direction);
+		ffmpeg.setAnalyzeDuration("10000"); // 10ms
+
+		start();
+	}
+
+	/**
+	 * Get the stream name from the direction/streamName string
+	 * @param streamName Name of the stream with rotate direction
+	 * @return The stream name used for re-publish
+	 */
+	private String getStreamName(String streamName) {
+		String parts[] = streamName.split("/");
+		if(parts.length > 1)
+			return parts[parts.length-1];
+		return "";
+	}
+
+	/**
+	 * Get the rotate direction from the streamName string.
+	 * @param streamName Name of the stream with rotate direction
+	 * @return FFmpegCommand.ROTATE for the given direction if present, null otherwise
+	 */
+	public static FFmpegCommand.ROTATE getDirection(String streamName) {
+		String parts[] = streamName.split("/");
+
+		switch(parts[0]) {
+			case ROTATE_LEFT:
+				return FFmpegCommand.ROTATE.LEFT;
+			case ROTATE_RIGHT:
+				return FFmpegCommand.ROTATE.RIGHT;
+			default:
+				return null;
+		}
+	}
+
+	/**
+	 * Start FFmpeg process to rotate and re-publish the stream.
+	 */
+	public void start() {
+		log.debug("Spawn FFMpeg to rotate [{}] stream [{}]", direction.name(), streamName);
+		String[] command = ffmpeg.getFFmpegCommand(true);
+		if (processMonitor == null) {
+			processMonitor = new ProcessMonitor(command,"FFMPEG");
+		}
+		processMonitor.start();
+	}
+
+	/**
+	 * Stop FFmpeg process that is rotating and re-publishing the stream.
+	 */
+	public void stop() {
+		log.debug("Stopping FFMpeg from rotate [{}] stream [{}]", direction.name(), streamName);
+		if(processMonitor != null) {
+			processMonitor.destroy();
+			processMonitor = null;
+		}
+	}
+
+    public static boolean isRotatedStream(String streamName){
+        return (getDirection(streamName) != null);
+    }
+}
diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/FFmpegCommand.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/FFmpegCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae2f3762c5cdea74c762dbf6872ebc0040538178
--- /dev/null
+++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/FFmpegCommand.java
@@ -0,0 +1,202 @@
+package org.bigbluebutton.app.video.ffmpeg;
+
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+public class FFmpegCommand {
+
+    /**
+     * Indicate the direction to rotate the video
+     */
+    public enum ROTATE { LEFT, RIGHT };
+
+    private HashMap args;
+    private HashMap x264Params;
+
+    private String[] command;
+
+    private String ffmpegPath;
+    private String input;
+    private String output;
+    private Boolean audioEnabled;
+
+    /* Analyze duration is a special parameter that MUST come before the input */
+    private String analyzeDuration;
+
+    public FFmpegCommand() {
+        this.args = new HashMap();
+        this.x264Params = new HashMap();
+
+        /* Prevent quality loss by default */
+        try {
+            this.setVideoQualityScale(1);
+        } catch (InvalidParameterException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        };
+
+        this.ffmpegPath = null;
+        this.audioEnabled = false;
+    }
+
+    public String[] getFFmpegCommand(boolean shouldBuild) {
+        if(shouldBuild)
+            buildFFmpegCommand();
+
+        return this.command;
+    }
+
+    public void buildFFmpegCommand() {
+        List comm = new ArrayList<String>();
+
+        if(this.ffmpegPath == null)
+            this.ffmpegPath = "/usr/local/bin/ffmpeg";
+
+        comm.add(this.ffmpegPath);
+
+        /* Analyze duration MUST come before the input */
+        if(analyzeDuration != null && !analyzeDuration.isEmpty()) {
+            comm.add("-analyzeduration");
+            comm.add(analyzeDuration);
+        }
+
+        comm.add("-i");
+        comm.add(input);
+
+        Iterator argsIter = this.args.entrySet().iterator();
+        while (argsIter.hasNext()) {
+            Map.Entry pairs = (Map.Entry)argsIter.next();
+            comm.add(pairs.getKey());
+            comm.add(pairs.getValue());
+        }
+
+        if (!this.audioEnabled) {
+            comm.add("-an");
+        }
+
+        if(!x264Params.isEmpty()) {
+            comm.add("-x264-params");
+            String params = "";
+            Iterator x264Iter = this.x264Params.entrySet().iterator();
+            while (x264Iter.hasNext()) {
+                Map.Entry pairs = (Map.Entry)x264Iter.next();
+                String argValue = pairs.getKey() + "=" + pairs.getValue();
+                params += argValue;
+                // x264-params are separated by ':'
+                params += ":";
+            }
+            // Remove trailing ':'
+            params.replaceAll(":+$", "");
+            comm.add(params);
+        }
+
+        comm.add(this.output);
+
+        this.command = new String[comm.size()];
+        comm.toArray(this.command);
+    }
+
+    public void setFFmpegPath(String arg) {
+        this.ffmpegPath = arg;
+    }
+
+    public void setInput(String arg) {
+        this.input = arg;
+    }
+
+    public void setOutput(String arg) {
+        this.output = arg;
+    }
+
+    public void setCodec(String arg) {
+        this.args.put("-vcodec", arg);
+    }
+
+    public void setLevel(String arg) {
+        this.args.put("-level", arg);
+    }
+
+    public void setPreset(String arg) {
+        this.args.put("-preset", arg);
+    }
+
+    public void setProfile(String arg) {
+        this.args.put("-profile:v", arg);
+    }
+
+    public void setFormat(String arg) {
+        this.args.put("-f", arg);
+    }
+
+    public void setPayloadType(String arg) {
+        this.args.put("-payload_type", arg);
+    }
+
+    public void setLoglevel(String arg) {
+        this.args.put("-loglevel", arg);
+    }
+
+    public void setSliceMaxSize(String arg) {
+        this.x264Params.put("slice-max-size", arg);
+    }
+
+    public void setMaxKeyFrameInterval(String arg) {
+        this.x264Params.put("keyint", arg);
+    }
+
+    public void setResolution(String arg) {
+        this.args.put("-s", arg);
+    }
+
+    /**
+     * Set the direction to rotate the video
+     * @param arg Rotate direction
+     */
+    public void setRotation(ROTATE arg) {
+        switch (arg) {
+            case LEFT:
+                this.args.put("-vf", "transpose=2");
+                break;
+            case RIGHT:
+                this.args.put("-vf", "transpose=1");
+                break;
+        }
+    }
+
+    /**
+     * Set how much time FFmpeg should  analyze stream
+     * data to get stream information. Note that this
+     * affects directly the delay to start the stream.
+     *
+     * @param duration Rotate direction
+     */
+    public void setAnalyzeDuration(String duration) {
+        this.analyzeDuration = duration;
+    }
+
+    /**
+     * Set video quality scale to a value (1-31).
+     * 1 is the highest quality and 31 the lowest.
+     * <p>
+     * <b> Note: Does NOT apply to h264 encoder. </b>
+     * </p>
+     *
+     * @param scale Scale value (1-31)
+     * @throws InvalidParameterException
+     */
+    public void setVideoQualityScale(Integer scale) throws InvalidParameterException {
+        if(scale < 1 || scale > 31)
+            throw new InvalidParameterException("Scale must be a value in 1-31 range");
+
+        this.args.put("-q:v", scale.toString());
+    }
+
+    public void setAudioEnabled(Boolean enabled) {
+        this.audioEnabled = enabled;
+    }
+
+}
diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/ProcessMonitor.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/ProcessMonitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..4034aa9317758ef5c3a4bb1c731a1e39676ad0a5
--- /dev/null
+++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/ProcessMonitor.java
@@ -0,0 +1,175 @@
+package org.bigbluebutton.app.video.ffmpeg;
+
+import java.io.InputStream;
+
+import org.slf4j.Logger;
+import org.red5.logging.Red5LoggerFactory;
+import java.lang.reflect.Field;
+
+import java.io.IOException;
+
+public class ProcessMonitor implements Runnable {
+    private static Logger log = Red5LoggerFactory.getLogger(ProcessMonitor.class, "video");
+
+    private String[] command;
+    private Process process;
+
+    ProcessStream inputStreamMonitor;
+    ProcessStream errorStreamMonitor;
+
+    private Thread thread = null;
+    private ProcessMonitorObserver observer;
+    private String name;
+    private Boolean alive;
+
+    public ProcessMonitor(String[] command, String name) {
+        this.command = command;
+        this.process = null;
+        this.inputStreamMonitor = null;
+        this.errorStreamMonitor = null;
+        this.name = name;
+        this.alive = false;
+    }
+
+    public String toString() {
+        if (this.command == null || this.command.length == 0) {
+            return "";
+        }
+
+        StringBuffer result = new StringBuffer();
+        String delim = "";
+        for (String i : this.command) {
+        	result.append(delim).append(i);
+            delim = " ";
+        }
+        return result.toString();
+    }
+
+    public void run() {
+        try {
+            log.debug("Creating thread to execute FFmpeg");
+            this.process = Runtime.getRuntime().exec(this.command);
+            log.debug("Executing [pid={}]: " + this.toString(),getPid());
+
+            if(this.process == null) {
+                log.debug("process is null");
+                return;
+            }
+
+            if (!this.alive){
+                log.debug("Process status was changed to 'not alive' between it's triggering and system execution. Killing it...");
+                this.forceDestroy();
+                return;
+            }
+
+            InputStream is = this.process.getInputStream();
+            InputStream es = this.process.getErrorStream();
+
+            inputStreamMonitor = new ProcessStream(is);
+            errorStreamMonitor = new ProcessStream(es);
+
+            inputStreamMonitor.start();
+            errorStreamMonitor.start();
+
+            this.process.waitFor();
+
+            int ret = this.process.exitValue();
+            log.debug("Exit value: " + ret);
+
+            destroy();
+        }
+        catch(SecurityException se) {
+            log.debug("Security Exception");
+        }
+        catch(IOException ioe) {
+            log.debug("IO Exception");
+        }
+        catch(NullPointerException npe) {
+            log.debug("NullPointer Exception");
+        }
+        catch(IllegalArgumentException iae) {
+            log.debug("IllegalArgument Exception");
+        }
+        catch(InterruptedException ie) {
+            log.debug("Interrupted Excetion");
+        }
+
+        log.debug("Exiting thread that executes FFmpeg");
+        notifyProcessMonitorObserverOnFinished();
+    }
+
+    public synchronized void start() {
+        if(this.thread == null){
+            this.thread = new Thread(this);
+            this.alive = true;
+            this.thread.start();
+        }else{
+            log.debug("Can't start a new process monitor: It is already running.");
+        }
+    }
+
+    public void destroy() {
+        if(this.inputStreamMonitor != null
+            && this.errorStreamMonitor != null) {
+            this.inputStreamMonitor.close();
+            this.errorStreamMonitor.close();
+        }
+
+        if(this.process != null) {
+            log.debug("Closing FFmpeg process");
+            this.process.destroy();
+            this.process = null;
+        }
+    }
+
+    public int getPid(){
+        Field f;
+        int pid;
+        if (this.process == null) return -1;
+        try {
+           f = this.process.getClass().getDeclaredField("pid");
+           f.setAccessible(true);
+           pid = (int)f.get(this.process);
+           return pid;
+        } catch (IllegalArgumentException | IllegalAccessException
+               | NoSuchFieldException | SecurityException e) {
+           log.debug("Error when obtaining {} PID",this.name);
+           return -1;
+        }
+    }
+
+    public synchronized void forceDestroy(){
+        if (this.thread != null) {
+            try {
+               this.alive=false;
+               int pid = getPid();
+               if (pid < 0){
+                   log.debug("Process doesn't exist. Not destroying it...");
+                   return;
+               }
+               else
+                   Runtime.getRuntime().exec("kill -9 "+ pid);
+            } catch (IOException e) {
+               log.debug("Failed to force-kill {} process",this.name);
+               e.printStackTrace();
+            }
+        }else
+           log.debug("Can't force-destroy this process monitor: There's no process running.");
+    }
+
+    private void notifyProcessMonitorObserverOnFinished() {
+        if(observer != null){
+            log.debug("Notifying ProcessMonitorObserver that {} successfully finished",this.name);
+            observer.handleProcessFinishedWithSuccess(this.name,"");
+        }else {
+            log.debug("Cannot notify ProcessMonitorObserver that {} finished: ProcessMonitorObserver null",this.name);
+        }
+    }
+
+    public void setProcessMonitorObserver(ProcessMonitorObserver observer){
+        if (observer==null){
+            log.debug("Cannot assign observer: ProcessMonitorObserver null");
+        }else this.observer = observer;
+    }
+
+    }
diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/ProcessMonitorObserver.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/ProcessMonitorObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..0529863531e19cd37861a73e167b399b973ee0d8
--- /dev/null
+++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/ProcessMonitorObserver.java
@@ -0,0 +1,7 @@
+package org.bigbluebutton.app.video.ffmpeg;
+
+public interface ProcessMonitorObserver {
+        public void handleProcessFinishedUnsuccessfully(String processName, String processOutput);
+            public void handleProcessFinishedWithSuccess(String processName, String processOutput);
+}
+
diff --git a/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/ProcessStream.java b/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/ProcessStream.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0af5a13d635a73388bd1c30af3d45e518915832
--- /dev/null
+++ b/bbb-video/src/main/java/org/bigbluebutton/app/video/ffmpeg/ProcessStream.java
@@ -0,0 +1,59 @@
+package org.bigbluebutton.app.video.ffmpeg;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.slf4j.Logger;
+import org.red5.logging.Red5LoggerFactory;
+
+import java.io.IOException;
+
+public class ProcessStream implements Runnable {
+    private static Logger log = Red5LoggerFactory.getLogger(ProcessStream.class, "video");
+    private InputStream stream;
+    private Thread thread;
+
+    ProcessStream(InputStream stream) {
+        if(stream != null)
+            this.stream = stream;
+    }
+
+    public void run() {
+        try {
+            log.debug("Creating thread to execute the process stream");
+            String line;
+            InputStreamReader isr = new InputStreamReader(this.stream);
+            BufferedReader ibr = new BufferedReader(isr);
+            while ((line = ibr.readLine()) != null) {
+                //log.debug(line);
+            }
+
+            close();
+        }
+        catch(IOException ioe) {
+            log.debug("IOException");
+            close();
+        }
+
+        log.debug("Exiting thread that handles process stream");
+    }
+
+    public void start() {
+        this.thread = new Thread(this);
+        this.thread.start();
+    }
+
+    public void close() {
+        try {
+            if(this.stream != null) {
+                log.debug("Closing process stream");
+                this.stream.close();
+                this.stream = null;
+            }
+        }
+        catch(IOException ioe) {
+            log.debug("IOException");
+        }
+    }
+}
\ No newline at end of file
diff --git a/bbb-voice/src/main/java/org/bigbluebutton/voiceconf/sip/CallAgent.java b/bbb-voice/src/main/java/org/bigbluebutton/voiceconf/sip/CallAgent.java
index 8f0047ccab499aa89b144a8fff21daa062de7df8..29af4ce241afe3e822e3ff9efe739faba51b6446 100644
--- a/bbb-voice/src/main/java/org/bigbluebutton/voiceconf/sip/CallAgent.java
+++ b/bbb-voice/src/main/java/org/bigbluebutton/voiceconf/sip/CallAgent.java
@@ -139,10 +139,10 @@ public class CallAgent extends CallListenerAdapter implements CallStreamObserver
     }
 
     private void setupCallerDisplayName(String callerName, String destination) {
-    	String fromURL = "\"" + callerName + "\" <sip:" + destination + "@" + portProvider.getHost() + ">";
+    	String fromURL = "\"" + callerName + "\" <sip:" + destination + "@" + clientRtpIp + ">";
     	userProfile.username = callerName;
     	userProfile.fromUrl = fromURL;
-		userProfile.contactUrl = "sip:" + destination + "@" + sipProvider.getViaAddress();
+		userProfile.contactUrl = "sip:" + destination + "@" + clientRtpIp;
         if (sipProvider.getPort() != SipStack.default_port) {
             userProfile.contactUrl += ":" + sipProvider.getPort();
         }
diff --git a/bbb-voice/src/main/java/org/zoolu/sip/call/CallListenerAdapter.java b/bbb-voice/src/main/java/org/zoolu/sip/call/CallListenerAdapter.java
index 9dc7efbfa3319884d6ac45fd6a3e1490816152aa..994d94a591ef8a9c56161cb83219474bed4f93c2 100755
--- a/bbb-voice/src/main/java/org/zoolu/sip/call/CallListenerAdapter.java
+++ b/bbb-voice/src/main/java/org/zoolu/sip/call/CallListenerAdapter.java
@@ -98,17 +98,7 @@ public abstract class CallListenerAdapter implements ExtendedCallListener
    {  
 	   //printLog("RE-INVITE/MODIFY");
 	   String local_session;
-	   if (sdp!=null && sdp.length()>0)
-	   {  
-		   SessionDescriptor remote_sdp = new SessionDescriptor(sdp);
-		   SessionDescriptor local_sdp = new SessionDescriptor(call.getLocalSessionDescriptor());
-		   SessionDescriptor new_sdp = new SessionDescriptor(remote_sdp.getOrigin(),remote_sdp.getSessionName(),local_sdp.getConnection(),local_sdp.getTime());
-		   new_sdp.addMediaDescriptors(local_sdp.getMediaDescriptors());
-		   new_sdp = SdpTools.sdpMediaProduct(new_sdp,remote_sdp.getMediaDescriptors());
-		   new_sdp = SdpTools.sdpAttirbuteSelection(new_sdp,"rtpmap");
-		   local_session = new_sdp.toString();
-      }
-      else local_session=call.getLocalSessionDescriptor();
+      local_session=call.getLocalSessionDescriptor();
       // accept immediatly
       call.accept(local_session);
    }
@@ -218,4 +208,3 @@ public abstract class CallListenerAdapter implements ExtendedCallListener
    }
 
 }
-
diff --git a/bbb-web-api/src/main/java/org/bigbluebutton/api/messaging/RedisMessagingService.java b/bbb-web-api/src/main/java/org/bigbluebutton/api/messaging/RedisMessagingService.java
index 206df68b158ae6bad11593b913744996ed7b09a7..959f2898a1769296d55e062629fbc942f92113c9 100755
--- a/bbb-web-api/src/main/java/org/bigbluebutton/api/messaging/RedisMessagingService.java
+++ b/bbb-web-api/src/main/java/org/bigbluebutton/api/messaging/RedisMessagingService.java
@@ -72,11 +72,11 @@ public class RedisMessagingService implements MessagingService {
 			                      String voiceBridge, Integer duration, 
 			                      Boolean autoStartRecording, Boolean allowStartStopRecording,
 			                      String moderatorPass, String viewerPass, Long createTime,
-			                      String createDate, Boolean isBreakout) {
+			                      String createDate, Boolean isBreakout, Map<String, String> metadata) {
 	  CreateMeetingRequestPayload payload = new CreateMeetingRequestPayload(meetingID, externalMeetingID, meetingName, 
 				                                  recorded, voiceBridge, duration, 
 				                                  autoStartRecording, allowStartStopRecording,
-				                                  moderatorPass, viewerPass, createTime, createDate, isBreakout);
+				                                  moderatorPass, viewerPass, createTime, createDate, isBreakout, metadata);
 	  CreateMeetingRequest msg = new CreateMeetingRequest(payload);
 	  
 	  Gson gson = new Gson();
diff --git a/bbb-webhooks/config.coffee b/bbb-webhooks/config.coffee
index 74776f4e39b018eb68042f721498583aafb29f1d..2a680c788ca9d843ea536729b0b07e9a688a8cc0 100644
--- a/bbb-webhooks/config.coffee
+++ b/bbb-webhooks/config.coffee
@@ -23,6 +23,11 @@ config.hooks.events or= [
   { channel: "bigbluebutton:from-bbb-apps:meeting", name: "meeting_destroyed_event" },
   { channel: "bigbluebutton:from-bbb-apps:users", name: "user_joined_message" },
   { channel: "bigbluebutton:from-bbb-apps:users", name: "user_left_message" },
+  { channel: "bigbluebutton:from-bbb-apps:users", name: "user_listening_only" },
+  { channel: "bigbluebutton:from-bbb-apps:users", name: "user_joined_voice_message" },
+  { channel: "bigbluebutton:from-bbb-apps:users", name: "user_left_voice_message" },
+  { channel: "bigbluebutton:from-bbb-apps:users", name: "user_shared_webcam_message" },
+  { channel: "bigbluebutton:from-bbb-apps:users", name: "user_unshared_webcam_message" },
   { channel: "bigbluebutton:from-rap", name: "sanity_started" },
   { channel: "bigbluebutton:from-rap", name: "sanity_ended" },
   { channel: "bigbluebutton:from-rap", name: "archive_started" },
@@ -36,7 +41,10 @@ config.hooks.events or= [
   { channel: "bigbluebutton:from-rap", name: "publish_started" },
   { channel: "bigbluebutton:from-rap", name: "publish_ended" },
   { channel: "bigbluebutton:from-rap", name: "post_publish_started" },
-  { channel: "bigbluebutton:from-rap", name: "post_publish_ended" }
+  { channel: "bigbluebutton:from-rap", name: "post_publish_ended" },
+  { channel: "bigbluebutton:from-rap", name: "unpublished" },
+  { channel: "bigbluebutton:from-rap", name: "published" },
+  { channel: "bigbluebutton:from-rap", name: "deleted" }
 ]
 
 # Retry intervals for failed attempts for perform callback calls.
diff --git a/bbb-webhooks/config_local.coffee.example b/bbb-webhooks/config_local.coffee.example
index af67af11464f5713c28ed1eb3b6da2d101b5023c..d8348a0a0835ce5cec5da6ab1ed14cc64e69c224 100644
--- a/bbb-webhooks/config_local.coffee.example
+++ b/bbb-webhooks/config_local.coffee.example
@@ -11,26 +11,15 @@ config.server = {}
 config.server.port = 3005
 
 # Callbacks will be triggered for all the events in this list and only for these events.
-config.hooks = {}
-config.hooks.events = [
-  { channel: "bigbluebutton:from-bbb-apps:meeting", name: "meeting_created_message" },
-  { channel: "bigbluebutton:from-bbb-apps:meeting", name: "meeting_destroyed_event" },
-  { channel: "bigbluebutton:from-bbb-apps:users", name: "user_joined_message" },
-  { channel: "bigbluebutton:from-bbb-apps:users", name: "user_left_message" },
-  { channel: "bigbluebutton:from-rap", name: "sanity_started" },
-  { channel: "bigbluebutton:from-rap", name: "sanity_ended" },
-  { channel: "bigbluebutton:from-rap", name: "archive_started" },
-  { channel: "bigbluebutton:from-rap", name: "archive_ended" },
-  { channel: "bigbluebutton:from-rap", name: "post_archive_started" },
-  { channel: "bigbluebutton:from-rap", name: "post_archive_ended" },
-  { channel: "bigbluebutton:from-rap", name: "process_started" },
-  { channel: "bigbluebutton:from-rap", name: "process_ended" },
-  { channel: "bigbluebutton:from-rap", name: "post_process_started" },
-  { channel: "bigbluebutton:from-rap", name: "post_process_ended" },
-  { channel: "bigbluebutton:from-rap", name: "publish_started" },
-  { channel: "bigbluebutton:from-rap", name: "publish_ended" },
-  { channel: "bigbluebutton:from-rap", name: "post_publish_started" },
-  { channel: "bigbluebutton:from-rap", name: "post_publish_ended" }
-]
+# You only need to specify it if you want events that are not used by default or
+# if you want to restrict the events used. See `config.coffee` for the default list.
+#
+# config.hooks = {}
+# config.hooks.events = [
+#   { channel: "bigbluebutton:from-bbb-apps:meeting", name: "meeting_created_message" },
+#   { channel: "bigbluebutton:from-bbb-apps:meeting", name: "meeting_destroyed_event" },
+#   { channel: "bigbluebutton:from-bbb-apps:users", name: "user_joined_message" },
+#   { channel: "bigbluebutton:from-bbb-apps:users", name: "user_left_message" }
+# ]
 
 module.exports = config
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/BigBlueButtonApplication.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/BigBlueButtonApplication.java
index 32fda841503b309bee6dc762a3eaff73142f7966..9b5201e079392e094455a9e27f2241dfe8d3bb89 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/BigBlueButtonApplication.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/BigBlueButtonApplication.java
@@ -160,6 +160,11 @@ public class BigBlueButtonApplication extends MultiThreadedApplicationAdapter {
 				lsMap = new HashMap<String, Boolean>();
 			}
 		}
+
+		Boolean guest  = false;
+		if (params.length >= 9 && ((Boolean) params[9])) {
+			guest = true;
+		}
 		   	    	
 		String userId = internalUserID;
 		String sessionId = Red5.getConnectionLocal().getSessionId();
@@ -198,7 +203,7 @@ public class BigBlueButtonApplication extends MultiThreadedApplicationAdapter {
 
 
 		BigBlueButtonSession bbbSession = new BigBlueButtonSession(room, internalUserID,  username, role, 
-    			voiceBridge, record, externalUserID, muted, sessionId);
+    			voiceBridge, record, externalUserID, muted, sessionId, guest);
 		connection.setAttribute(Constants.SESSION, bbbSession);        
 		connection.setAttribute("INTERNAL_USER_ID", internalUserID);
 		connection.setAttribute("USER_SESSION_ID", sessionId);
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/BigBlueButtonSession.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/BigBlueButtonSession.java
index 0d4de10fa15b02762006a1835423d8e45aab20a0..50d7975cf317153cf2c94c279529e779a1d6f66f 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/BigBlueButtonSession.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/BigBlueButtonSession.java
@@ -29,10 +29,11 @@ public class BigBlueButtonSession {
 	private final String externalUserID;
 	private final Boolean startAsMuted;
 	private final String sessionId;
+	private final Boolean guest;
 	
 	public BigBlueButtonSession(String room, String internalUserID, String username, 
 				String role, String voiceBridge, Boolean record, 
-				String externalUserID, Boolean startAsMuted, String sessionId){
+				String externalUserID, Boolean startAsMuted, String sessionId, Boolean guest) {
 		this.internalUserID = internalUserID;
 		this.username = username;
 		this.role = role;
@@ -42,6 +43,7 @@ public class BigBlueButtonSession {
 		this.externalUserID = externalUserID;
 		this.startAsMuted = startAsMuted;
 		this.sessionId = sessionId;
+		this.guest = guest;
 	}
 
 	public String getUsername() {
@@ -79,4 +81,8 @@ public class BigBlueButtonSession {
 	public String getSessionId() {
 	  return sessionId;
 	}
+
+	public Boolean isGuest() {
+		return guest;
+	}
 }
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/ChatClientMessageSender.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/ChatClientMessageSender.java
index db2487eca59c4edeec3ef2cc9162995accf751b1..756dbc30c08ad4bb393bc23badf283582b8d2c44 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/ChatClientMessageSender.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/ChatClientMessageSender.java
@@ -6,6 +6,7 @@ import java.util.Map;
 import org.bigbluebutton.common.messages.GetChatHistoryReplyMessage;
 import org.bigbluebutton.common.messages.SendPrivateChatMessage;
 import org.bigbluebutton.common.messages.SendPublicChatMessage;
+import org.bigbluebutton.common.messages.ClearPublicChatHistoryReplyMessage;
 import org.bigbluebutton.red5.client.messaging.BroadcastClientMessage;
 import org.bigbluebutton.red5.client.messaging.ConnectionInvokerService;
 import org.bigbluebutton.red5.client.messaging.DirectClientMessage;
@@ -54,6 +55,13 @@ public class ChatClientMessageSender {
 							processGetChatHistoryReply(gch);
 						}
 						break;
+					case ClearPublicChatHistoryReplyMessage.CLEAR_PUBLIC_CHAT_HISTORY_REPLY:
+						ClearPublicChatHistoryReplyMessage gcl = ClearPublicChatHistoryReplyMessage.fromJson(message);
+
+						if (gcl != null) {
+							processClearPublicChatHistoryReply(gcl);
+						}
+						break;
 				}
 			}
 		}
@@ -111,4 +119,18 @@ public class ChatClientMessageSender {
 		service.sendMessage(m);
 	}
 
+	private void processClearPublicChatHistoryReply(ClearPublicChatHistoryReplyMessage gcl) {
+
+		Map<String, Object> args = new HashMap<String, Object>();
+		args.put("meetingId", gcl.meetingId);
+		args.put("requester_id", gcl.requesterId);
+
+		Map<String, Object> message = new HashMap<String, Object>();
+		Gson gson = new Gson();
+		message.put("msg", gson.toJson(args));
+
+		BroadcastClientMessage m = new BroadcastClientMessage(gcl.meetingId, "ChatClearPublicMessageCommand", message);
+		service.sendMessage(m);
+	}
+
 }
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/MeetingClientMessageSender.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/MeetingClientMessageSender.java
index 4b632fda5e25b6877992a83ed487ff70b163152d..610d8fea8f8d67d100672a99ac37e66fd723d1aa 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/MeetingClientMessageSender.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/MeetingClientMessageSender.java
@@ -6,9 +6,11 @@ import java.util.Map;
 import org.bigbluebutton.common.messages.Constants;
 import org.bigbluebutton.common.messages.DisconnectAllUsersMessage;
 import org.bigbluebutton.common.messages.DisconnectUserMessage;
+import org.bigbluebutton.common.messages.InactivityWarningMessage;
 import org.bigbluebutton.common.messages.MeetingEndedMessage;
 import org.bigbluebutton.common.messages.MeetingEndingMessage;
 import org.bigbluebutton.common.messages.MeetingHasEndedMessage;
+import org.bigbluebutton.common.messages.MeetingIsActiveMessage;
 import org.bigbluebutton.common.messages.MeetingMutedMessage;
 import org.bigbluebutton.common.messages.MeetingStateMessage;
 import org.bigbluebutton.common.messages.NewPermissionsSettingMessage;
@@ -95,6 +97,18 @@ public class MeetingClientMessageSender {
 						  processUserLockedMessage(ulm);
 					  }
 					  break;
+				  case InactivityWarningMessage.INACTIVITY_WARNING:
+					  InactivityWarningMessage iwm = InactivityWarningMessage.fromJson(message);
+					  if (iwm != null) {
+						  processInactivityWarningMessage(iwm);
+					  }
+					  break;
+				  case MeetingIsActiveMessage.MEETING_IS_ACTIVE:
+					  MeetingIsActiveMessage miam = MeetingIsActiveMessage.fromJson(message);
+					  if (miam != null) {
+						  processMeetingIsActiveMessage(miam);
+					  }
+					  break;
 				}
 			}
 		}		
@@ -204,4 +218,29 @@ public class MeetingClientMessageSender {
 	  	BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingId, "userLocked", message);
 		service.sendMessage(m);
 	}
+
+	private void processInactivityWarningMessage(InactivityWarningMessage msg) {
+		Map<String, Object> args = new HashMap<String, Object>();
+		args.put("status", "Meeting seems inactive.");
+		args.put("duration", msg.duration);
+
+		Map<String, Object> message = new HashMap<String, Object>();
+		Gson gson = new Gson();
+		message.put("msg", gson.toJson(args));
+
+		BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingId, "inactivityWarning", message);
+		service.sendMessage(m);
+	}
+
+	private void processMeetingIsActiveMessage(MeetingIsActiveMessage msg) {
+		Map<String, Object> args = new HashMap<String, Object>();
+		args.put("status", "Meeting is active.");
+
+		Map<String, Object> message = new HashMap<String, Object>();
+		Gson gson = new Gson();
+		message.put("msg", gson.toJson(args));
+
+		BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingId, "meetingIsActive", message);
+		service.sendMessage(m);
+	}
 }
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/PresentationClientMessageSender.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/PresentationClientMessageSender.java
index d7b0b9c409b243efa1315897fd9213320e4357c1..b60d9f058c9735b902f1bb40803a054200778966 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/PresentationClientMessageSender.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/PresentationClientMessageSender.java
@@ -120,6 +120,7 @@ public class PresentationClientMessageSender {
 			presentation.put("name", msg.presentation.get("name"));
 			presentation.put("current", msg.presentation.get("current"));
 			presentation.put("pages", msg.presentation.get("pages"));
+			presentation.put("downloadable", msg.presentation.get("downloadable"));
 
 			Map<String, Object> args = new HashMap<String, Object>();
 			args.put("presentation", presentation);
@@ -173,6 +174,7 @@ public class PresentationClientMessageSender {
 			presentation.put("name", msg.presentation.get("name"));
 			presentation.put("current", msg.presentation.get("current"));
 			presentation.put("pages", msg.presentation.get("pages"));
+			presentation.put("downloadable", msg.presentation.get("downloadable"));
 
 			args.put("presentation", presentation);
 
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/SharedNotesClientMessageSender.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/SharedNotesClientMessageSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..4223fd49e6a10f69125c920e138201c190189ec1
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/SharedNotesClientMessageSender.java
@@ -0,0 +1,137 @@
+package org.bigbluebutton.red5.client;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.bigbluebutton.common.messages.PatchDocumentReplyMessage;
+import org.bigbluebutton.common.messages.GetCurrentDocumentReplyMessage;
+import org.bigbluebutton.common.messages.CreateAdditionalNotesReplyMessage;
+import org.bigbluebutton.common.messages.DestroyAdditionalNotesReplyMessage;
+import org.bigbluebutton.common.messages.SharedNotesSyncNoteReplyMessage;
+import org.bigbluebutton.red5.client.messaging.BroadcastClientMessage;
+import org.bigbluebutton.red5.client.messaging.ConnectionInvokerService;
+import org.bigbluebutton.red5.client.messaging.DirectClientMessage;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class SharedNotesClientMessageSender {
+	private ConnectionInvokerService service;
+
+	public SharedNotesClientMessageSender(ConnectionInvokerService service) {
+		this.service = service;
+	}
+
+	public void handleSharedNotesMessage(String message) {
+		JsonParser parser = new JsonParser();
+		JsonObject obj = (JsonObject) parser.parse(message);
+
+		if (obj.has("header") && obj.has("payload")) {
+			JsonObject header = (JsonObject) obj.get("header");
+
+			if (header.has("name")) {
+				String messageName = header.get("name").getAsString();
+				switch (messageName) {
+					case PatchDocumentReplyMessage.PATCH_DOCUMENT_REPLY:
+						processPatchDocumentReplyMessage(message);
+						break;
+					case GetCurrentDocumentReplyMessage.GET_CURRENT_DOCUMENT_REPLY:
+						processGetCurrentDocumentReplyMessage(message);
+						break;
+					case CreateAdditionalNotesReplyMessage.CREATE_ADDITIONAL_NOTES_REPLY:
+						processCreateAdditionalNotesReplyMessage(message);
+						break;
+					case DestroyAdditionalNotesReplyMessage.DESTROY_ADDITIONAL_NOTES_REPLY:
+						processDestroyAdditionalNotesReplyMessage(message);
+						break;
+					case SharedNotesSyncNoteReplyMessage.SHAREDNOTES_SYNC_NOTE_REPLY:
+						processSharedNotesSyncNoteReplyMessage(message);
+						break;
+				}
+			}
+		}
+	}
+
+	private void processPatchDocumentReplyMessage(String json) {
+		PatchDocumentReplyMessage msg = PatchDocumentReplyMessage.fromJson(json);
+		if (msg != null) {
+			Map<String, Object> args = new HashMap<String, Object>();
+			args.put("userID", msg.requesterID);
+			args.put("noteID", msg.noteID);
+			args.put("patch", msg.patch);
+			args.put("patchID", msg.patchID);
+			args.put("undo", msg.undo);
+			args.put("redo", msg.redo);
+
+			Map<String, Object> message = new HashMap<String, Object>();
+			Gson gson = new Gson();
+			message.put("msg", gson.toJson(args));
+
+			BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingID, "PatchDocumentCommand", message);
+			service.sendMessage(m);
+		}
+	}
+
+	private void processGetCurrentDocumentReplyMessage(String json) {
+		GetCurrentDocumentReplyMessage msg = GetCurrentDocumentReplyMessage.fromJson(json);
+		if (msg != null) {
+			Map<String, Object> args = new HashMap<String, Object>();
+			args.put("notes", msg.notes);
+
+			Map<String, Object> message = new HashMap<String, Object>();
+			Gson gson = new Gson();
+			message.put("msg", gson.toJson(args));
+
+			DirectClientMessage m = new DirectClientMessage(msg.meetingID, msg.requesterID, "GetCurrentDocumentCommand", message);
+			service.sendMessage(m);
+		}
+	}
+
+	private void processCreateAdditionalNotesReplyMessage(String json) {
+		CreateAdditionalNotesReplyMessage msg = CreateAdditionalNotesReplyMessage.fromJson(json);
+		if (msg != null) {
+			Map<String, Object> args = new HashMap<String, Object>();
+			args.put("noteID", msg.noteID);
+			args.put("noteName", msg.noteName);
+
+			Map<String, Object> message = new HashMap<String, Object>();
+			Gson gson = new Gson();
+			message.put("msg", gson.toJson(args));
+
+			BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingID, "CreateAdditionalNotesCommand", message);
+			service.sendMessage(m);
+		}
+	}
+
+	private void processDestroyAdditionalNotesReplyMessage(String json) {
+		DestroyAdditionalNotesReplyMessage msg = DestroyAdditionalNotesReplyMessage.fromJson(json);
+		if (msg != null) {
+			Map<String, Object> args = new HashMap<String, Object>();
+			args.put("noteID", msg.noteID);
+
+			Map<String, Object> message = new HashMap<String, Object>();
+			Gson gson = new Gson();
+			message.put("msg", gson.toJson(args));
+
+			BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingID, "DestroyAdditionalNotesCommand", message);
+			service.sendMessage(m);
+		}
+	}
+
+	private void processSharedNotesSyncNoteReplyMessage(String json) {
+		SharedNotesSyncNoteReplyMessage msg = SharedNotesSyncNoteReplyMessage.fromJson(json);
+		if (msg != null) {
+			Map<String, Object> args = new HashMap<String, Object>();
+			args.put("noteID", msg.noteID);
+			args.put("note", msg.note);
+
+			Map<String, Object> message = new HashMap<String, Object>();
+			Gson gson = new Gson();
+			message.put("msg", gson.toJson(args));
+
+			DirectClientMessage m = new DirectClientMessage(msg.meetingID, msg.requesterID, "SharedNotesSyncNoteCommand", message);
+			service.sendMessage(m);
+		}
+	}
+}
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/UserClientMessageSender.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/UserClientMessageSender.java
index 2eb260122716195725ebea91ddf34e596ddc9166..4cc42bf4fa60f739699e42dbe115e0f442208783 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/UserClientMessageSender.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/UserClientMessageSender.java
@@ -8,8 +8,11 @@ import java.util.Map;
 
 import org.bigbluebutton.common.messages.BroadcastLayoutMessage;
 import org.bigbluebutton.common.messages.GetCurrentLayoutReplyMessage;
+import org.bigbluebutton.common.messages.GuestPolicyChangedMessage;
+import org.bigbluebutton.common.messages.GetGuestPolicyReplyMessage;
 import org.bigbluebutton.common.messages.GetRecordingStatusReplyMessage;
 import org.bigbluebutton.common.messages.GetUsersReplyMessage;
+import org.bigbluebutton.common.messages.GuestAccessDeniedMessage;
 import org.bigbluebutton.common.messages.LockLayoutMessage;
 import org.bigbluebutton.common.messages.PresenterAssignedMessage;
 import org.bigbluebutton.common.messages.RecordingStatusChangedMessage;
@@ -21,6 +24,7 @@ import org.bigbluebutton.common.messages.UserLeftVoiceMessage;
 import org.bigbluebutton.common.messages.UserListeningOnlyMessage;
 import org.bigbluebutton.common.messages.UserSharedWebcamMessage;
 import org.bigbluebutton.common.messages.UserStatusChangedMessage;
+import org.bigbluebutton.common.messages.UserRoleChangeMessage;
 import org.bigbluebutton.common.messages.UserUnsharedWebcamMessage;
 import org.bigbluebutton.common.messages.UserVoiceMutedMessage;
 import org.bigbluebutton.common.messages.UserVoiceTalkingMessage;
@@ -101,6 +105,11 @@ public class UserClientMessageSender {
             if (usm != null) {
               processUserStatusChangedMessage(usm);
             }
+          case UserRoleChangeMessage.USER_ROLE_CHANGE:
+            UserRoleChangeMessage urcm = UserRoleChangeMessage.fromJson(message);
+            if (urcm != null) {
+              processUserRoleChangeMessage(urcm);
+            }
             break;
           case UserEmojiStatusMessage.USER_EMOJI_STATUS:
             UserEmojiStatusMessage urhm = UserEmojiStatusMessage.fromJson(message);
@@ -168,6 +177,24 @@ public class UserClientMessageSender {
               processGetUsersReplyMessage(gurm);
             }
             break;
+          case GetGuestPolicyReplyMessage.GET_GUEST_POLICY_REPLY:
+            GetGuestPolicyReplyMessage ggprm = GetGuestPolicyReplyMessage.fromJson(message);
+            if (ggprm != null) {
+              processGetGuestPolicyReplyMessage(ggprm);
+            }
+            break;
+          case GuestPolicyChangedMessage.GUEST_POLICY_CHANGED:
+            GuestPolicyChangedMessage gpcm = GuestPolicyChangedMessage.fromJson(message);
+            if (gpcm != null) {
+              processGuestPolicyChangedMessage(gpcm);
+            }
+            break;
+          case GuestAccessDeniedMessage.GUEST_ACCESS_DENIED:
+            GuestAccessDeniedMessage gadm = GuestAccessDeniedMessage.fromJson(message);
+            if (gadm != null) {
+              processGuestAccessDeniedMessage(gadm);
+            }
+            break;
           case GetCurrentLayoutReplyMessage.GET_CURRENT_LAYOUT_REPLY:
             processGetCurrentLayoutReplyMessage(message);
             break;
@@ -396,6 +423,19 @@ public class UserClientMessageSender {
     service.sendMessage(m);
   }
 
+  private void processUserRoleChangeMessage(UserRoleChangeMessage msg) {
+    Map<String, Object> args = new HashMap<String, Object>();
+    args.put("userID", msg.userId);
+    args.put("role", msg.role);
+
+    Map<String, Object> message = new HashMap<String, Object>();
+    Gson gson = new Gson();
+    message.put("msg", gson.toJson(args));
+
+    BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingId, "participantRoleChange", message);
+    service.sendMessage(m);
+  }
+
   private void processUserSharedWebcamMessage(UserSharedWebcamMessage msg) {	  	
     Map<String, Object> args = new HashMap<String, Object>();	
     args.put("userId", msg.userId);
@@ -624,4 +664,40 @@ public class UserClientMessageSender {
 	  BroadcastClientMessage m = new BroadcastClientMessage(msg.payload.parentMeetingId, "breakoutRoomClosed", message);
       service.sendMessage(m);
   }
+
+  private void processGetGuestPolicyReplyMessage(GetGuestPolicyReplyMessage msg) {
+    Map<String, Object> args = new HashMap<String, Object>();
+    args.put("guestPolicy", msg.guestPolicy.toString());
+
+    Map<String, Object> message = new HashMap<String, Object>();
+    Gson gson = new Gson();
+    message.put("msg", gson.toJson(args));
+
+    DirectClientMessage m = new DirectClientMessage(msg.meetingId, msg.requesterId, "get_guest_policy_reply", message);
+    service.sendMessage(m);
+  }
+
+  private void processGuestPolicyChangedMessage(GuestPolicyChangedMessage msg) {
+    Map<String, Object> args = new HashMap<String, Object>();
+    args.put("guestPolicy", msg.guestPolicy.toString());
+
+    Map<String, Object> message = new HashMap<String, Object>();
+    Gson gson = new Gson();
+    message.put("msg", gson.toJson(args));
+
+    BroadcastClientMessage m = new BroadcastClientMessage(msg.meetingId, "guest_policy_changed", message);
+    service.sendMessage(m);
+  }
+
+  private void processGuestAccessDeniedMessage(GuestAccessDeniedMessage msg) {
+    Map<String, Object> args = new HashMap<String, Object>();
+    args.put("userId", msg.userId);
+
+    Map<String, Object> message = new HashMap<String, Object>();
+    Gson gson = new Gson();
+    message.put("msg", gson.toJson(args));
+
+    DirectClientMessage m = new DirectClientMessage(msg.meetingId, msg.userId, "guest_access_denied", message);
+    service.sendMessage(m);
+  }
 }
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/pubsub/MessagePublisher.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/pubsub/MessagePublisher.java
index c2e44ba6d986247414c7643c10bf7069b48e75a0..9abd08146401bc518174ff7de345673de129e672 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/pubsub/MessagePublisher.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/pubsub/MessagePublisher.java
@@ -108,6 +108,26 @@ public class MessagePublisher {
 		sender.send(MessagingConstants.TO_USERS_CHANNEL, msg.toJson());		
 	}
 
+	public void getGuestPolicy(String meetingID, String userID) {
+		GetGuestPolicyMessage msg = new GetGuestPolicyMessage(meetingID, userID);
+		sender.send(MessagingConstants.TO_USERS_CHANNEL, msg.toJson());
+	}
+
+	public void newGuestPolicy(String meetingID, String guestPolicy, String setBy) {
+		SetGuestPolicyMessage msg = new SetGuestPolicyMessage(meetingID, guestPolicy, setBy);
+		sender.send(MessagingConstants.TO_USERS_CHANNEL, msg.toJson());
+	}
+
+	public void responseToGuest(String meetingID, String userID, Boolean response, String requesterID) {
+		RespondToGuestMessage msg = new RespondToGuestMessage(meetingID, userID, response, requesterID);
+		sender.send(MessagingConstants.TO_USERS_CHANNEL, msg.toJson());
+	}
+
+	public void setParticipantRole(String meetingID, String userID, String role) {
+		ChangeUserRoleMessage msg = new ChangeUserRoleMessage(meetingID, userID, role);
+		sender.send(MessagingConstants.TO_USERS_CHANNEL, msg.toJson());
+	}
+
 	public void initAudioSettings(String meetingID, String requesterID, Boolean muted) {
 		InitAudioSettingsMessage msg = new InitAudioSettingsMessage(meetingID, requesterID, muted);
 		sender.send(MessagingConstants.TO_USERS_CHANNEL, msg.toJson());	
@@ -202,9 +222,9 @@ public class MessagePublisher {
 
 	public void sendConversionCompleted(String messageKey, String meetingId,
 			String code, String presId, int numPages, String presName,
-			String presBaseUrl) {
+			String presBaseUrl, Boolean downloadable) {
 		SendConversionCompletedMessage msg = new SendConversionCompletedMessage(messageKey, meetingId,
-				code, presId, numPages, presName, presBaseUrl);
+				code, presId, numPages, presName, presBaseUrl, downloadable);
 		sender.send(MessagingConstants.TO_PRESENTATION_CHANNEL, msg.toJson());
 	}
 
@@ -223,6 +243,11 @@ public class MessagePublisher {
 		sender.send(MessagingConstants.TO_CHAT_CHANNEL, msg.toJson());
 	}
 
+	public void clearPublicChatMessages(String meetingID, String requesterID) {
+		ClearPublicChatHistoryRequestMessage msg = new ClearPublicChatHistoryRequestMessage(meetingID, requesterID);
+		sender.send(MessagingConstants.TO_CHAT_CHANNEL, msg.toJson());
+	}
+
 	public void sendPublicMessage(String meetingID, String requesterID, Map<String, String> message) {
 		SendPublicChatMessage msg = new SendPublicChatMessage(meetingID, requesterID, message);
 		sender.send(MessagingConstants.TO_CHAT_CHANNEL, msg.toJson());
@@ -308,4 +333,44 @@ public class MessagePublisher {
 		EditCaptionHistoryMessage msg = new EditCaptionHistoryMessage(meetingID, userID, startIndex, endIndex, locale, localeCode, text);
 		sender.send(MessagingConstants.TO_CAPTION_CHANNEL, msg.toJson());
 	}
+
+	public void patchDocument(String meetingID, String requesterID, String noteID, String patch, String operation) {
+		PatchDocumentRequestMessage msg = new PatchDocumentRequestMessage(meetingID, requesterID, noteID, patch, operation);
+		sender.send(MessagingConstants.TO_SHAREDNOTES_CHANNEL, msg.toJson());
+	}
+
+	public void getCurrentDocument(String meetingID, String requesterID) {
+		GetCurrentDocumentRequestMessage msg = new GetCurrentDocumentRequestMessage(meetingID, requesterID);
+		sender.send(MessagingConstants.TO_SHAREDNOTES_CHANNEL, msg.toJson());
+	}
+
+	public void createAdditionalNotes(String meetingID, String requesterID, String noteName) {
+		CreateAdditionalNotesRequestMessage msg = new CreateAdditionalNotesRequestMessage(meetingID, requesterID, noteName);
+		sender.send(MessagingConstants.TO_SHAREDNOTES_CHANNEL, msg.toJson());
+	}
+
+	public void destroyAdditionalNotes(String meetingID, String requesterID, String noteID) {
+		DestroyAdditionalNotesRequestMessage msg = new DestroyAdditionalNotesRequestMessage(meetingID, requesterID, noteID);
+		sender.send(MessagingConstants.TO_SHAREDNOTES_CHANNEL, msg.toJson());
+	}
+
+	public void requestAdditionalNotesSet(String meetingID, String requesterID, int additionalNotesSetSize) {
+		RequestAdditionalNotesSetRequestMessage msg = new RequestAdditionalNotesSetRequestMessage(meetingID, requesterID, additionalNotesSetSize);
+		sender.send(MessagingConstants.TO_SHAREDNOTES_CHANNEL, msg.toJson());
+	}
+
+	public void sharedNotesSyncNoteRequest(String meetingID, String requesterID, String noteID) {
+		SharedNotesSyncNoteRequestMessage msg = new SharedNotesSyncNoteRequestMessage(meetingID, requesterID, noteID);
+		sender.send(MessagingConstants.TO_SHAREDNOTES_CHANNEL, msg.toJson());
+	}
+
+	public void logoutEndMeeting(String meetingId, String userId) {
+		LogoutEndMeetingRequestMessage msg = new LogoutEndMeetingRequestMessage(meetingId, userId);
+		sender.send(MessagingConstants.TO_USERS_CHANNEL, msg.toJson());
+	}
+
+	public void activityResponse(String meetingID) {
+		ActivityResponseMessage msg = new ActivityResponseMessage(meetingID);
+		sender.send(MessagingConstants.TO_MEETING_CHANNEL, msg.toJson());
+	}
 }
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/pubsub/redis/RedisPubSubMessageHandler.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/pubsub/redis/RedisPubSubMessageHandler.java
index 81f52151f48b52636f1cdc6c1da932b98cfeda24..6e140852d7e73a7a401390613b90cf8c2cbf03da 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/pubsub/redis/RedisPubSubMessageHandler.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/pubsub/redis/RedisPubSubMessageHandler.java
@@ -6,6 +6,7 @@ import org.bigbluebutton.red5.client.PollingClientMessageSender;
 import org.bigbluebutton.red5.client.PresentationClientMessageSender;
 import org.bigbluebutton.red5.client.UserClientMessageSender;
 import org.bigbluebutton.red5.client.ChatClientMessageSender;
+import org.bigbluebutton.red5.client.SharedNotesClientMessageSender;
 import org.bigbluebutton.red5.client.WhiteboardClientMessageSender;
 import org.bigbluebutton.red5.client.CaptionClientMessageSender;
 import org.bigbluebutton.red5.client.DeskShareMessageSender;
@@ -27,6 +28,7 @@ public class RedisPubSubMessageHandler implements MessageHandler {
 	private BbbAppsIsKeepAliveHandler bbbAppsIsKeepAliveHandler;
 	private PollingClientMessageSender pollingMessageSender;
 	private CaptionClientMessageSender captionMessageSender;
+	private SharedNotesClientMessageSender sharedNotesMessageSender;
 	
 	public void setConnectionInvokerService(ConnectionInvokerService s) {
 		this.service = s;
@@ -38,6 +40,7 @@ public class RedisPubSubMessageHandler implements MessageHandler {
 		deskShareMessageSender = new DeskShareMessageSender(service);
 		pollingMessageSender = new PollingClientMessageSender(service);
 		captionMessageSender = new CaptionClientMessageSender(service);
+		sharedNotesMessageSender = new SharedNotesClientMessageSender(service);
 	}
 	
 	public void setBbbAppsIsKeepAliveHandler(BbbAppsIsKeepAliveHandler handler) {
@@ -65,6 +68,8 @@ public class RedisPubSubMessageHandler implements MessageHandler {
 			pollingMessageSender.handlePollMessage(message);
 		} else if (channel.equalsIgnoreCase(MessagingConstants.FROM_CAPTION_CHANNEL)) {
 			captionMessageSender.handleCaptionMessage(message);
+		} else if (channel.equalsIgnoreCase(MessagingConstants.FROM_SHAREDNOTES_CHANNEL)) {
+			sharedNotesMessageSender.handleSharedNotesMessage(message);
 		}
 	}
 
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/ChatService.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/ChatService.java
index 51e0905491953637376c2146c01da520867843a8..79530f00271893c716a37d070e983bab47ac0f5d 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/ChatService.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/ChatService.java
@@ -20,6 +20,7 @@ package org.bigbluebutton.red5.service;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Date;
 
 import org.bigbluebutton.red5.BigBlueButtonSession;
 import org.bigbluebutton.red5.Constants;
@@ -43,6 +44,13 @@ public class ChatService {
 		red5BBBInGw.getChatHistory(meetingID, requesterID, replyTo);
 	}
 	
+	public void clearPublicChatMessages() {
+		String meetingID = Red5.getConnectionLocal().getScope().getName();
+		String requesterID = getBbbSession().getInternalUserID();
+
+		red5BBBInGw.clearPublicChatMessages(meetingID, requesterID);
+	}
+
 	private BigBlueButtonSession getBbbSession() {
 		return (BigBlueButtonSession) Red5.getConnectionLocal().getAttribute(Constants.SESSION);
 	}
@@ -53,7 +61,7 @@ public class ChatService {
 		String fromUserID = msg.get(ChatKeyUtil.FROM_USERID).toString();
 		String fromUsername = msg.get(ChatKeyUtil.FROM_USERNAME ).toString();
 		String fromColor = msg.get(ChatKeyUtil.FROM_COLOR).toString();
-		String fromTime = msg.get(ChatKeyUtil.FROM_TIME).toString();   
+		String fromTime = Long.toString(new Date().getTime());
 		String fromTimezoneOffset = msg.get(ChatKeyUtil.FROM_TZ_OFFSET).toString();
 		String toUserID = msg.get(ChatKeyUtil.TO_USERID).toString();
 		String toUsername = msg.get(ChatKeyUtil.TO_USERNAME).toString();
@@ -96,7 +104,7 @@ public class ChatService {
 		String fromUserID = msg.get(ChatKeyUtil.FROM_USERID).toString();
 		String fromUsername = msg.get(ChatKeyUtil.FROM_USERNAME ).toString();
 		String fromColor = msg.get(ChatKeyUtil.FROM_COLOR).toString();
-		String fromTime = msg.get(ChatKeyUtil.FROM_TIME).toString();   
+		String fromTime = Long.toString(new Date().getTime());
 		String fromTimezoneOffset = msg.get(ChatKeyUtil.FROM_TZ_OFFSET).toString();
 		String toUserID = msg.get(ChatKeyUtil.TO_USERID).toString();
 		String toUsername = msg.get(ChatKeyUtil.TO_USERNAME).toString();
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/ParticipantsService.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/ParticipantsService.java
index 39b51754601e71f9bcb6ae964b658b67f76b9edb..b84be08eb14bc0fa613f64f5d0d8859dfe71953d 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/ParticipantsService.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/ParticipantsService.java
@@ -55,6 +55,12 @@ public class ParticipantsService {
 		red5InGW.getUsers(meetingId, userId);
 	}
 	
+	public void activityResponse() {
+		IScope scope = Red5.getConnectionLocal().getScope();
+		String meetingId = scope.getName();
+		red5InGW.activityResponse(meetingId);
+	}
+
 	public void userEmojiStatus(Map<String, String> msg) {
 		IScope scope = Red5.getConnectionLocal().getScope();
 		String meetingId = scope.getName();
@@ -140,6 +146,39 @@ public class ParticipantsService {
         return (BigBlueButtonSession) Red5.getConnectionLocal().getAttribute(Constants.SESSION);
     }
 
+	public void getGuestPolicy() {
+		String requesterId = getBbbSession().getInternalUserID();
+		String roomName = Red5.getConnectionLocal().getScope().getName();
+		red5InGW.getGuestPolicy(roomName, requesterId);
+	}
+
+	public void setGuestPolicy(String guestPolicy) {
+		String requesterId = getBbbSession().getInternalUserID();
+		String roomName = Red5.getConnectionLocal().getScope().getName();
+		red5InGW.newGuestPolicy(roomName, guestPolicy, requesterId);
+	}
+
+	public void responseToGuest(Map<String, Object> msg) {
+		String requesterId = getBbbSession().getInternalUserID();
+		String roomName = Red5.getConnectionLocal().getScope().getName();
+		red5InGW.responseToGuest(roomName, (String) msg.get("userId"), (Boolean) msg.get("response"), requesterId);
+	}
+
+	public void setParticipantRole(Map<String, String> msg) {
+		String roomName = Red5.getConnectionLocal().getScope().getName();
+		String userId = (String) msg.get("userId");
+		String role = (String) msg.get("role");
+		log.debug("Setting participant role " + roomName + " " + userId + " " + role);
+		red5InGW.setParticipantRole(roomName, userId, role);
+	}
+
+	public void logoutEndMeeting(Map<String, Object> msg) {
+		IScope scope = Red5.getConnectionLocal().getScope();
+		String meetingId = scope.getName();
+		String userId = (String) msg.get("userId");
+		red5InGW.logoutEndMeeting(meetingId, userId);
+	}
+
 	public void setRed5Publisher(MessagePublisher red5InGW) {
 		this.red5InGW = red5InGW;
 	}
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/PresentationApplication.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/PresentationApplication.java
index 55fa80f33b169bef43551a8844103484ddbdddd0..45375188da97143c351a1e0c0ce99475724d9503 100755
--- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/PresentationApplication.java
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/PresentationApplication.java
@@ -59,10 +59,10 @@ public class PresentationApplication {
 
 	public void sendConversionCompleted(String messageKey, String meetingId,
 			String code, String presentation, int numberOfPages,
-			String presName, String presBaseUrl) {
+			String presName, String presBaseUrl, Boolean downloadable) {
 
 		red5BBBInGW.sendConversionCompleted(messageKey, meetingId,
-				code, presentation, numberOfPages, presName, presBaseUrl);
+				code, presentation, numberOfPages, presName, presBaseUrl, downloadable);
 	}
 
 	public void removePresentation(String meetingID, String presentationID){
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/SharedNotesApplication.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/SharedNotesApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..cac6f6fe94b1b81a23a4c20c66d3d305f3f31afd
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/SharedNotesApplication.java
@@ -0,0 +1,61 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Felipe Cecagno <felipe@mconf.org>
+*/
+package org.bigbluebutton.red5.service;
+
+import org.slf4j.Logger;
+import org.bigbluebutton.red5.pubsub.MessagePublisher;
+import org.red5.logging.Red5LoggerFactory;
+
+public class SharedNotesApplication {
+	private static Logger log = Red5LoggerFactory.getLogger( SharedNotesApplication.class, "bigbluebutton" );
+
+	private MessagePublisher red5BBBInGW;
+
+	public void setRed5Publisher(MessagePublisher inGW) {
+		red5BBBInGW = inGW;
+	}
+
+	public void clear(String meetingID) {
+	}
+
+	public void patchDocument(String meetingID, String requesterID, String noteID, String patch, String operation) {
+		red5BBBInGW.patchDocument(meetingID, requesterID, noteID, patch, operation);
+	}
+
+	public void currentDocument(String meetingID, String requesterID) {
+		red5BBBInGW.getCurrentDocument(meetingID, requesterID);
+	}
+
+	public void createAdditionalNotes(String meetingID, String requesterID, String noteName) {
+		red5BBBInGW.createAdditionalNotes(meetingID, requesterID, noteName);
+	}
+
+	public void destroyAdditionalNotes(String meetingID, String requesterID, String noteID) {
+		red5BBBInGW.destroyAdditionalNotes(meetingID, requesterID, noteID);
+	}
+
+	public void requestAdditionalNotesSet(String meetingID, String requesterID, int additionalNotesSetSize) {
+		red5BBBInGW.requestAdditionalNotesSet(meetingID, requesterID, additionalNotesSetSize);
+	}
+
+	public void sharedNotesSyncNoteRequest(String meetingID, String requesterID, String noteID) {
+		red5BBBInGW.sharedNotesSyncNoteRequest(meetingID, requesterID, noteID);
+	}
+}
diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/SharedNotesService.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/SharedNotesService.java
new file mode 100644
index 0000000000000000000000000000000000000000..2092e8564abcd8a3fd6be0d67aac17ec3f1bdc9b
--- /dev/null
+++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/service/SharedNotesService.java
@@ -0,0 +1,103 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Hugo Lazzari <hslazzari@gmail.com>
+ */
+package org.bigbluebutton.red5.service;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.api.Red5;
+import org.bigbluebutton.red5.BigBlueButtonSession;
+import org.bigbluebutton.red5.Constants;
+
+public class SharedNotesService {
+
+	private static Logger log = Red5LoggerFactory.getLogger( SharedNotesService.class, "bigbluebutton" );
+
+	private SharedNotesApplication sharedNotesApplication;
+
+	private BigBlueButtonSession getBbbSession() {
+		return (BigBlueButtonSession) Red5.getConnectionLocal().getAttribute(Constants.SESSION);
+	}
+
+	public void currentDocument() {
+		log.debug("SharedNotesService.currentDocument");
+		String meetingID = Red5.getConnectionLocal().getScope().getName();
+		String requesterID = getBbbSession().getInternalUserID();
+
+		sharedNotesApplication.currentDocument(meetingID, requesterID);
+	}
+
+	public void patchDocument(Map<String, Object> msg) {
+		log.debug("SharedNotesService.patchDocument");
+		String noteID = msg.get("noteID").toString();
+		String patch = msg.get("patch").toString();
+		String operation = msg.get("operation").toString();
+
+		String meetingID = Red5.getConnectionLocal().getScope().getName();
+		String requesterID = getBbbSession().getInternalUserID();
+
+		sharedNotesApplication.patchDocument(meetingID, requesterID, noteID, patch, operation);
+	}
+
+	public void createAdditionalNotes(Map<String, Object> msg) {
+		log.debug("SharedNotesService.createAdditionalNotes");
+		String meetingID = Red5.getConnectionLocal().getScope().getName();
+		String requesterID = getBbbSession().getInternalUserID();
+		String noteName = msg.get("noteName").toString();
+
+		sharedNotesApplication.createAdditionalNotes(meetingID, requesterID, noteName);
+	}
+
+	public void destroyAdditionalNotes(Map<String, Object> msg) {
+		log.debug("SharedNotesService.destroyAdditionalNotes");
+		String noteID = msg.get("noteID").toString();
+
+		String meetingID = Red5.getConnectionLocal().getScope().getName();
+		String requesterID = getBbbSession().getInternalUserID();
+
+		sharedNotesApplication.destroyAdditionalNotes(meetingID, requesterID, noteID);
+	}
+
+	public void requestAdditionalNotesSet(Map<String, Object> msg) {
+		log.debug("SharedNotesService.requestAdditionalNotesSet");
+		Integer additionalNotesSetSize = (Integer) msg.get("additionalNotesSetSize");
+
+		String meetingID = Red5.getConnectionLocal().getScope().getName();
+		String requesterID = getBbbSession().getInternalUserID();
+
+		sharedNotesApplication.requestAdditionalNotesSet(meetingID, requesterID, additionalNotesSetSize);
+	}
+
+	public void sharedNotesSyncNoteRequest(Map<String, Object> msg) {
+		log.debug("SharedNotesService.sharedNotesSyncNoteRequest");
+		String noteID = msg.get("noteID").toString();
+
+		String meetingID = Red5.getConnectionLocal().getScope().getName();
+		String requesterID = getBbbSession().getInternalUserID();
+
+		sharedNotesApplication.sharedNotesSyncNoteRequest(meetingID, requesterID, noteID);
+	}
+
+	public void setSharedNotesApplication(SharedNotesApplication a) {
+		log.debug("Setting sharedNotes sharedNotesApplication");
+		sharedNotesApplication = a;
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml b/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml
index cca11835fa8fab563252f1f245c704070e32be9c..304d29c0bfda651092e5ccedb902b2143e264fad 100755
--- a/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml
+++ b/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml
@@ -91,6 +91,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     <bean id="presentation.service" class="org.bigbluebutton.red5.service.PresentationService">
         <property name="presentationApplication"> <ref local="presentationApplication"/></property>
     </bean>
+
+    <bean id="sharedNotesApplication" class="org.bigbluebutton.red5.service.SharedNotesApplication">
+        <property name="red5Publisher"><ref bean="red5Publisher"/></property>
+    </bean>
+
+    <bean id="sharednotes.service" class="org.bigbluebutton.red5.service.SharedNotesService">
+        <property name="sharedNotesApplication"> <ref local="sharedNotesApplication"/></property>
+    </bean>
     
     <bean id="whiteboardApplication" class="org.bigbluebutton.red5.service.WhiteboardApplication">
         <property name="red5Publisher"> <ref bean="red5Publisher"/></property>
diff --git a/bigbluebutton-client/branding/default/style/css/BBBDefault.css b/bigbluebutton-client/branding/default/style/css/BBBDefault.css
index 80da61a02d50572f8dc0000103a5fe52b1e431d4..c981aa9661647c9ff1883722cd822cb6bc5611fb 100755
--- a/bigbluebutton-client/branding/default/style/css/BBBDefault.css
+++ b/bigbluebutton-client/branding/default/style/css/BBBDefault.css
@@ -50,6 +50,17 @@ ToolTip {
   paddingRight: 3;
 }
 
+.chatToolbarStyle {
+  backgroundColor: #CCCCCC;
+  cornerRadius: 5;
+  borderStyle: solid;
+  borderThickness: 1;
+  paddingBottom: 2;
+  paddingTop: 2;
+  paddingLeft: 2;
+  paddingRight: 2;
+}
+
 .meetingNameLabelStyle {
   fontWeight: bold;
   fontSize: 15;
@@ -107,7 +118,7 @@ ToolTip {
 	fontWeight: bold;
 }
 
-Button, .logoutButtonStyle, .chatSendButtonStyle, .helpLinkButtonStyle, .cameraDisplaySettingsWindowProfileComboStyle, .cameraDisplaySettingsWindowCameraSelector, .languageSelectorStyle, .testJavaLinkButtonStyle, .recordButtonStyleNormal, .recordButtonStyleStart, .recordButtonStyleStop, .micSettingsWindowHelpButtonStyle {
+Button, .logoutButtonStyle, .chatSendButtonStyle, .helpLinkButtonStyle, .cameraDisplaySettingsWindowProfileComboStyle, .cameraDisplaySettingsWindowCameraSelector, .languageSelectorStyle, .testJavaLinkButtonStyle, .recordButtonStyleNormal, .recordButtonStyleStart, .recordButtonStyleStop, .micSettingsWindowHelpButtonStyle, .bandwidthButtonStyle, .settingsButtonStyle, .acceptButtonStyle, .denyButtonStyle {
   textIndent: 0;
   paddingLeft: 10;
   paddingRight: 10;
@@ -177,6 +188,18 @@ Button, .logoutButtonStyle, .chatSendButtonStyle, .helpLinkButtonStyle, .cameraD
   icon: Embed('assets/images/logout.png');
 }
 
+.settingsButtonStyle {
+  icon: Embed('assets/images/ic_settings_16px.png');
+}
+
+.acceptButtonStyle {
+  icon: Embed('assets/images/ic_thumb_up_16px.png');
+}
+
+.denyButtonStyle {
+  icon: Embed('assets/images/ic_thumb_down_16px.png');
+}
+
 DataGrid {
   backgroundColor: #e1e2e5;
   rollOverColor: #f3f3f3;
@@ -199,7 +222,8 @@ DataGrid {
 
 .whiteboardUndoButtonStyle, .whiteboardCircleButtonStyle, .whiteboardClearButtonStyle,
 .whiteboardTriangleButtonStyle, .whiteboardTextButtonStyle, .whiteboardRectangleButtonStyle,
-.whiteboardPanZoomButtonStyle, .whiteboardLineButtonStyle, .whiteboardScribbleButtonStyle
+.whiteboardPanZoomButtonStyle, .whiteboardLineButtonStyle, .whiteboardScribbleButtonStyle,
+.chatClearButtonStyle
 {
   textIndent: 0;
   paddingLeft: 0;
@@ -231,6 +255,10 @@ DataGrid {
   icon: Embed('assets/images/delete.png');    
 }
 
+.chatClearButtonStyle {
+  icon: Embed('assets/images/delete.png');
+}
+
 .whiteboardScribbleButtonStyle{
   icon: Embed('assets/images/pencil.png');  
 }
@@ -293,7 +321,8 @@ DataGrid {
 
 
 .presentationUploadButtonStyle, .pollStartButtonStyle, .presentationBackButtonStyle, .presentationBackButtonDisabledStyle, .presentationForwardButtonStyle, .presentationForwardButtonDisabledStyle,
-.presentationFitToWidthButtonStyle, .presentationFitToPageButtonStyle 
+.presentationFitToWidthButtonStyle, .presentationFitToPageButtonStyle, .presentationDownloadButtonStyle, .presentationDownloadButtonDisabledStyle,
+.sharedNotesSaveButtonStyle, .sharedNotesNewButtonStyle, .sharedNotesEnabledUndoButtonStyle, .sharedNotesDisabledUndoButtonStyle, .sharedNotesEnabledRedoButtonStyle, .sharedNotesDisabledRedoButtonStyle, .sharedNotesFormatButtonStyle, .chatCopyButtonStyle, .chatSaveButtonStyle
 {
   textIndent: 0;
   paddingLeft: 10;
@@ -312,8 +341,36 @@ DataGrid {
   fontSize: 12;
 }
 
+.sharedNotesSaveButtonStyle, .chatSaveButtonStyle {
+  icon: Embed('assets/images/ic_save_16px.png');
+}
+
+.sharedNotesNewButtonStyle {
+  icon: Embed('assets/images/ic_note_add_16px.png');
+}
+
+.sharedNotesEnabledUndoButtonStyle {
+  icon: Embed('assets/images/arrows_undo_icon.png');
+}
+
+.sharedNotesDisabledUndoButtonStyle {
+  icon: Embed('assets/images/arrows_undo_icon_grey.png');
+}
+
+.sharedNotesEnabledRedoButtonStyle {
+  icon: Embed('assets/images/arrows_redo_icon.png');
+}
+
+.sharedNotesDisabledRedoButtonStyle {
+  icon: Embed('assets/images/arrows_redo_icon_grey.png');
+}
+
+.sharedNotesFormatButtonStyle {
+  icon: Embed('assets/images/ic_note_format_16px.png');
+}
+
 .presentationUploadButtonStyle {
-  icon:   Embed('assets/images/upload.png');   
+  icon:   Embed('assets/images/ic_file_upload_16px.png');
 }
 
 .pollStartButtonStyle {
@@ -321,19 +378,19 @@ DataGrid {
 }
 
 .presentationBackButtonStyle {
-  icon:   Embed('assets/images/left-arrow.png'); 
+  icon:   Embed('assets/images/ic_arrow_back_24px.png');
 }
 
 .presentationBackButtonDisabledStyle {
-	icon:   Embed('assets/images/left-arrow-disabled.png'); 
+	icon:   Embed('assets/images/ic_arrow_back_grey_24px.png');
 }
 
 .presentationForwardButtonStyle {
-  icon:   Embed('assets/images/right-arrow.png'); 
+  icon:   Embed('assets/images/ic_arrow_forward_24px.png');
 }
 
 .presentationForwardButtonDisabledStyle {
-	icon:   Embed('assets/images/right-arrow-disabled.png'); 
+	icon:   Embed('assets/images/ic_arrow_forward_grey_24px.png');
 }
 
 .presentationFitToWidthButtonStyle {
@@ -344,6 +401,14 @@ DataGrid {
   icon:   Embed('assets/images/fit-to-screen.png'); 
 }
 
+.presentationDownloadButtonStyle {
+  icon:   Embed('assets/images/ic_file_download_16px.png');
+}
+
+.presentationDownloadButtonDisabledStyle {
+  icon:   Embed('assets/images/ic_file_download_grey_16px.png');
+}
+
 .presentationZoomSliderStyle{
   labelOffset: 0;
   thumbOffset: 3;
@@ -377,6 +442,18 @@ DataGrid {
   cornerRadius: 17;
 }
 
+.deskshareWarningLabelStyle {
+  fontWeight: bold;
+  fontSize: 18;
+  fontFamily: Arial;
+  color: #003399;
+}
+
+.deskshareWarningBackgroundStyle {
+  backgroundAlpha: 0.6;
+  backgroundColor: #78797e;
+}
+
 .videoMuteButtonStyle, .videoUnmutedButtonStyle, .videoSwitchPresenterButtonStyle, .videoEjectUserButtonStyle, .videoPrivateChatButtonStyle {
   fillAlphas: 1, 1, 1, 1;
   fillColors: #fefeff, #e1e2e5, #ffffff, #eeeeee;
@@ -652,11 +729,24 @@ TitleWindow {
   fontWeight: bold;    
 }
 
-.micSettingsWindowHearFromHeadsetLabelStyle, .micSettingsWindowSpeakIntoMicLabelStyle, .micSettingsWindowMicNameLabelStyle, .webcamPermissionSettingsTextStyle {
+.micSettingsWindowHearFromHeadsetLabelStyle, .micSettingsWindowSpeakIntoMicLabelStyle, .micSettingsWindowMicNameLabelStyle, .webcamPermissionSettingsTextStyle, .inactivityWarningTextStyle {
   fontFamily: Arial;
   fontSize: 14;    
 }
 
+.micSettingsWindowOpenDialogLabelStyle {
+  fontFamily: Arial;
+  fontSize: 14;
+  fontWeight: bold;
+  color: #e1e2e5;
+}
+
+.micSettingsWindowShareMicrophoneLabelStyle {
+  fontFamily: Arial;
+  fontSize: 14;
+  color: #5e5f63;
+}
+
 .micSettingsWindowPlaySoundButtonStyle, .micSettingsWindowChangeMicButtonStyle {
   fillAlphas: 1, 1, 1, 1;
   fillColors: #fefeff, #e1e2e5, #ffffff, #eeeeee;
@@ -680,7 +770,7 @@ TitleWindow {
 	icon:   Embed('assets/images/headset.png');
 }
 
-.micSettingsWindowCancelButtonStyle {
+.micSettingsWindowCancelButtonStyle, inactivityWarningWindowCancelButtonStyle {
   fillAlphas: 1, 1, 1, 1;
   fillColors: #ffffff, #eeeeee, #ffffff, #eeeeee;
   rollOverColor: #eeeeee;
@@ -979,6 +1069,18 @@ AlertForm {
 	fontWeight: bold;    
 }
 
+.logoutWindowStyle {
+	borderColor: #DFDFDF;
+	backgroundColor: #EFEFEF;
+	borderAlpha: 1;
+	shadowDistance: 1;
+	dropShadowColor: #FFFFFF;
+	color: #000000;
+	headerHeight: 32;
+	/* we need to set transparency duration to avoid the blur effect when two alerts are displayed sequentially */
+	modalTransparencyDuration: 250;
+}
+
 .lockSettingsDefaultLabelStyle {
 	fontFamily: Arial;
 	fontSize: 14;
@@ -1002,6 +1104,13 @@ AlertForm {
   icon:   Embed('assets/images/control-record-stop.png');
 }
 
+.bandwidthButtonStyle {
+  paddingTop: 0;
+  paddingBottom: 0;
+  height: 22;
+  icon:   Embed('assets/images/ic_swap_vert_16px.png');
+}
+
 .statusImageStyle {
   successImage:   Embed(source='assets/images/status_success.png');
   warningImage:   Embed(source='assets/images/status_warning.png');
@@ -1029,6 +1138,22 @@ AlertForm {
   paddingTop: 0;
 }
 
+.addLayoutButtonStyle {
+  icon:   Embed('assets/images/ic_add_circle_outline_16px.png');
+}
+
+.saveLayoutButtonStyle {
+  icon:   Embed('assets/images/ic_file_download_16px.png');
+}
+
+.loadLayoutButtonStyle {
+  icon:   Embed('assets/images/ic_file_upload_16px.png');
+}
+
+.broadcastLayoutButtonStyle {
+  icon:   Embed('assets/images/ic_send_16px.png');
+}
+
 PollChoicesModal {
 	fontSize: 14;
 	paddingLeft: 16;
@@ -1093,3 +1218,51 @@ EmojiGrid {
 	verticalAlign: middle;
 	horizontalAlign: center;
 }
+
+.moodStyle {
+  icon:   Embed('assets/images/ic_mood_black_18dp.png');
+}
+
+.moodRaiseHandStyle {
+  icon:   Embed('assets/images/icon-3-high-five.png');
+}
+
+.moodAgreedStyle {
+  icon:   Embed('assets/images/icon-6-thumb-up.png');
+}
+
+.moodDisagreedStyle {
+  icon:   Embed('assets/images/icon-7-thumb-down.png');
+}
+
+.moodSpeakFasterStyle {
+  icon:   Embed('assets/images/ic_fast_forward_black_18dp.png');
+}
+
+.moodSpeakSlowerStyle {
+  icon:   Embed('assets/images/ic_fast_rewind_black_18dp.png');
+}
+
+.moodSpeakLouderStyle {
+  icon:   Embed('assets/images/ic_volume_up_black_18dp.png');
+}
+
+.moodSpeakSofterStyle {
+  icon:   Embed('assets/images/ic_volume_down_black_18dp.png');
+}
+
+.moodBeRightBackStyle {
+  icon:   Embed('assets/images/ic_access_time_black_18dp.png');
+}
+
+.moodHappyStyle {
+  icon:   Embed('assets/images/icon-6-smiling-face.png');
+}
+
+.moodSadStyle {
+  icon:   Embed('assets/images/icon-7-sad-face.png');
+}
+
+.chatCopyButtonStyle{
+  icon:   Embed('assets/images/ic_content_copy_black_16px.png');
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/arrows_redo_icon.png b/bigbluebutton-client/branding/default/style/css/assets/images/arrows_redo_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..7aa2e5847c88bd2f3dc134af7c96ea1663659f28
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/arrows_redo_icon.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/arrows_redo_icon_grey.png b/bigbluebutton-client/branding/default/style/css/assets/images/arrows_redo_icon_grey.png
new file mode 100644
index 0000000000000000000000000000000000000000..0c348f929499eb3c6fd4c26c669a8c506e351b0e
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/arrows_redo_icon_grey.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/arrows_undo_icon.png b/bigbluebutton-client/branding/default/style/css/assets/images/arrows_undo_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..5c24a934c439aa0a97f16dba647e46ea678686cb
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/arrows_undo_icon.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/arrows_undo_icon_grey.png b/bigbluebutton-client/branding/default/style/css/assets/images/arrows_undo_icon_grey.png
new file mode 100644
index 0000000000000000000000000000000000000000..2657cb174101acb1080d44af1419d7541808436f
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/arrows_undo_icon_grey.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/bandwidth.png b/bigbluebutton-client/branding/default/style/css/assets/images/bandwidth.png
new file mode 100644
index 0000000000000000000000000000000000000000..58f33a59d663acb039a7d1b5604438e139ee83af
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/bandwidth.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_access_time_black_18dp.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_access_time_black_18dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..1fd032f2d667900c0a6e4803e4b22f5bbe66c25c
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_access_time_black_18dp.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_add_circle_outline_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_add_circle_outline_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..62c8a130134f8cf9fe65888d0f53bc29271f70c4
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_add_circle_outline_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_back_24px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_back_24px.png
new file mode 100644
index 0000000000000000000000000000000000000000..9cf8af82f846bd0f88de0247b5a578aaabefb28f
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_back_24px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_back_grey_24px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_back_grey_24px.png
new file mode 100644
index 0000000000000000000000000000000000000000..99cf9f7c9960e4e1f38d71ef4c748eed5aaaf257
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_back_grey_24px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_forward_24px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_forward_24px.png
new file mode 100644
index 0000000000000000000000000000000000000000..d407e3dcdd5d4f051859711b50928e10ec2cfc59
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_forward_24px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_forward_grey_24px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_forward_grey_24px.png
new file mode 100644
index 0000000000000000000000000000000000000000..70df2653996db6071dcf7b66b0e967a95228d867
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_arrow_forward_grey_24px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_clear_black_18dp.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_clear_black_18dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..082c9bdfd9ca005efdacb9295c9a281fff1c1cf1
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_clear_black_18dp.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_content_copy_black_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_content_copy_black_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..5f460b1bb009d772cce0786b44fe942fe9605af2
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_content_copy_black_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_fast_forward_black_18dp.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_fast_forward_black_18dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..a1394ab3215683ef21c4c993af1bdbfdad663631
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_fast_forward_black_18dp.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_fast_rewind_black_18dp.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_fast_rewind_black_18dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..30fdf6e706b346a87914b3ae3c15172ddd15f75c
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_fast_rewind_black_18dp.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_file_download_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_file_download_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..0521c6210b4570b403ee4f51d00b10ecae0c3702
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_file_download_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_file_download_grey_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_file_download_grey_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..c375962ff327e242b5d63cf51df5c253c9042d6b
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_file_download_grey_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_file_upload_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_file_upload_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..b9089febd06bc90f08a7fefdf6c4867f70ba165e
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_file_upload_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_mood_black_18dp.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_mood_black_18dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..4ca438be9b3df3a1c4556dcd2051150df9db8e90
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_mood_black_18dp.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_note_add_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_note_add_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..efe50b413b11446ae64ba09642e4d7592b842e3f
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_note_add_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_note_format_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_note_format_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..d00faa64a486165552992297d0677a03e148b0ed
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_note_format_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_save_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_save_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..a3ef221d2d969ac54ebc43bd1f889d93608e6540
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_save_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_send_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_send_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..61ac36eb4b0508596b250075ee2606e998311727
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_send_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_settings_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_settings_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..e269e38c5f2fd86d09ba489d3daa76b9f8b2b8cf
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_settings_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_swap_vert_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_swap_vert_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..27d7ef68261109b4625a34f6571e33c5a41868d3
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_swap_vert_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_thumb_down_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_thumb_down_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..5f7a7853aceab7b258520a5cdedf91b6e339b62c
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_thumb_down_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_thumb_up_16px.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_thumb_up_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..19ec42fc3afbff6747e89f114256abfe6ed360e4
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_thumb_up_16px.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_volume_down_black_18dp.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_volume_down_black_18dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..b51479f4cacce573c97f5a38522a3d320defe1f4
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_volume_down_black_18dp.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/ic_volume_up_black_18dp.png b/bigbluebutton-client/branding/default/style/css/assets/images/ic_volume_up_black_18dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..58f4e270760ae3b7483a86de06bc21453e05dba4
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/ic_volume_up_black_18dp.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icon-3-high-five.png b/bigbluebutton-client/branding/default/style/css/assets/images/icon-3-high-five.png
new file mode 100644
index 0000000000000000000000000000000000000000..4361fea6534359e9b1150d56718b8296101d5c35
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/icon-3-high-five.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icon-3-high-five.svg b/bigbluebutton-client/branding/default/style/css/assets/images/icon-3-high-five.svg
new file mode 100644
index 0000000000000000000000000000000000000000..4c563540df1f21f23244b33d76e89864ded4cb4a
--- /dev/null
+++ b/bigbluebutton-client/branding/default/style/css/assets/images/icon-3-high-five.svg
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="32px"
+   height="32px"
+   viewBox="0 0 32 32"
+   version="1.1"
+   id="svg2"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="icon-3-high-five.svg"
+   inkscape:export-filename="/var/lib/lxc/bbb-dev090-14/rootfs/home/ubuntu/dev/bigbluebutton/bigbluebutton-client/branding/default/style/css/assets/images/icon-3-high-five.png"
+   inkscape:export-xdpi="50"
+   inkscape:export-ydpi="50">
+  <metadata
+     id="metadata15">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>icon 3 high five</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="753"
+     inkscape:window-height="480"
+     id="namedview13"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="39.864407"
+     inkscape:cy="16"
+     inkscape:window-x="75"
+     inkscape:window-y="34"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2" />
+  <!-- Generator: Sketch 3.0.3 (7891) - http://www.bohemiancoding.com/sketch -->
+  <title
+     id="title4">icon 3 high five</title>
+  <desc
+     id="desc6">Created with Sketch.</desc>
+  <defs
+     id="defs8" />
+  <g
+     id="Page-1"
+     stroke="none"
+     stroke-width="1"
+     fill="none"
+     fill-rule="evenodd"
+     sketch:type="MSPage"
+     style="fill:#000000;stroke:#000000;stroke-opacity:1">
+    <g
+       id="icon-3-high-five"
+       sketch:type="MSArtboardGroup"
+       fill="#929292"
+       style="fill:#000000;stroke:#000000;stroke-opacity:1">
+      <path
+         d="M28.1244203,21.5 C28.1244203,26.1944206 24.3188409,30 19.6244203,30.0000003 C16.5115051,30.0000003 13.2262274,28.5474856 10.9652407,24.4282229 C7.70175208,18.4825159 3.52827319,14.5832077 5.51553361,12.5959473 C6.9371827,11.1742982 9.16926196,12.5381668 11.1244203,14.3667868 L11.1244203,14.3667868 L11.1244203,6.50840855 C11.1244203,5.11541748 12.2437085,4 13.6244203,4 C14.1892809,4 14.7078132,4.18537107 15.1244253,4.49839144 C15.1271484,3.1148807 16.2453908,2 17.6244203,2 C19.014265,2 20.1236329,3.12004027 20.1244199,4.50198455 C20.5422503,4.18708451 21.0616172,4 21.6244203,4 C23.0147583,4 24.1244203,5.12055197 24.1244203,6.50282288 L24.1244203,7.49767249 C24.5422506,7.18504628 25.0616174,7 25.6244203,7 C27.0147583,7 28.1244203,8.11599243 28.1244203,9.49263886 L28.1244203,21.5 L28.1244203,21.5 Z M19.6244203,29 C15.8647052,28.9995418 13.6344162,26.9488875 11.8717958,23.9830936 C7.95978233,17.4007216 5.15828327,14.3887562 6.24545305,13.2957153 C7.35605012,12.1791206 10.0660207,14.5979243 12.1244203,16.7983451 L12.1244203,6.49309635 C12.1244203,5.66388585 12.7959932,5 13.6244203,5 C14.4586231,5 15.1244203,5.66848201 15.1244203,6.49309635 L15.1244203,16 L16.1244203,16 L16.1244203,4.49089813 C16.1244203,3.67622006 16.7959932,3 17.6244203,3 C18.4586231,3 19.1244203,3.66749783 19.1244203,4.49089813 L19.1244203,15 L20.1244203,15 L20.1244203,6.50370994 C20.1244203,5.66197696 20.7959932,5 21.6244203,5 C22.4586231,5 23.1244203,5.67323387 23.1244203,6.50370994 L23.1244203,16 L24.1244203,16 L24.1244203,9.4912653 C24.1244203,8.66254437 24.7959932,8 25.6244203,8 C26.4586231,8 27.1244203,8.66766222 27.1244203,9.4912653 L27.1244203,17.7543674 L27.1244203,21.5 C27.1244203,25.6421358 23.7665562,29 19.6244203,29 L19.6244203,29 Z"
+         id="high-five"
+         sketch:type="MSShapeGroup"
+         style="fill:#000000;stroke:#000000;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-smiling-face.png b/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-smiling-face.png
new file mode 100644
index 0000000000000000000000000000000000000000..860284020f261ccd08003396b182237b7699b10d
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-smiling-face.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-smiling-face.svg b/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-smiling-face.svg
new file mode 100644
index 0000000000000000000000000000000000000000..ed5064c6a86b3f2a84c2dc382410d75162a469fc
--- /dev/null
+++ b/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-smiling-face.svg
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="32px"
+   height="32px"
+   viewBox="0 0 32 32"
+   version="1.1"
+   id="svg2"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="icon-6-smiling-face.svg"
+   inkscape:export-filename="/var/lib/lxc/bbb-dev090-14/rootfs/home/ubuntu/dev/bigbluebutton/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-smiling-face.png"
+   inkscape:export-xdpi="50"
+   inkscape:export-ydpi="50">
+  <metadata
+     id="metadata15">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>icon 6 smiling face</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="753"
+     inkscape:window-height="480"
+     id="namedview13"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="16"
+     inkscape:cy="16"
+     inkscape:window-x="75"
+     inkscape:window-y="34"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2" />
+  <!-- Generator: Sketch 3.0.3 (7891) - http://www.bohemiancoding.com/sketch -->
+  <title
+     id="title4">icon 6 smiling face</title>
+  <desc
+     id="desc6">Created with Sketch.</desc>
+  <defs
+     id="defs8" />
+  <g
+     id="Page-1"
+     stroke="none"
+     stroke-width="1"
+     fill="none"
+     fill-rule="evenodd"
+     sketch:type="MSPage"
+     style="fill:#000000;stroke:#000000;stroke-opacity:1">
+    <g
+       id="icon-6-smiling-face"
+       sketch:type="MSArtboardGroup"
+       fill="#929292"
+       style="fill:#000000;stroke:#000000;stroke-opacity:1">
+      <path
+         d="M16.5,29 C23.4035597,29 29,23.4035597 29,16.5 C29,9.59644029 23.4035597,4 16.5,4 C9.59644029,4 4,9.59644029 4,16.5 C4,23.4035597 9.59644029,29 16.5,29 L16.5,29 Z M16.5,28 C22.8512749,28 28,22.8512749 28,16.5 C28,10.1487251 22.8512749,5 16.5,5 C10.1487251,5 5,10.1487251 5,16.5 C5,22.8512749 10.1487251,28 16.5,28 L16.5,28 Z M12,14 C12.5522848,14 13,13.5522848 13,13 C13,12.4477152 12.5522848,12 12,12 C11.4477152,12 11,12.4477152 11,13 C11,13.5522848 11.4477152,14 12,14 L12,14 Z M21,14 C21.5522848,14 22,13.5522848 22,13 C22,12.4477152 21.5522848,12 21,12 C20.4477152,12 20,12.4477152 20,13 C20,13.5522848 20.4477152,14 21,14 L21,14 Z M16.4813232,22 C13,22 11,20 11,20 L11,21 C11,21 13,23 16.4813232,23 C19.9626465,23 22,21 22,21 L22,20 C22,20 19.9626465,22 16.4813232,22 L16.4813232,22 Z"
+         id="smiling-face"
+         sketch:type="MSShapeGroup"
+         style="fill:#000000;stroke:#000000;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-thumb-up.png b/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-thumb-up.png
new file mode 100644
index 0000000000000000000000000000000000000000..3f2b76b33d690d289e8e22f05d913393797e6fd7
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-thumb-up.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-thumb-up.svg b/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-thumb-up.svg
new file mode 100644
index 0000000000000000000000000000000000000000..4610328cf75886c6daaffd48c061fd94020f3234
--- /dev/null
+++ b/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-thumb-up.svg
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="32px"
+   height="32px"
+   viewBox="0 0 32 32"
+   version="1.1"
+   id="svg2992"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="icon-6-thumb-up.svg"
+   inkscape:export-filename="/var/lib/lxc/bbb-dev090-14/rootfs/home/ubuntu/dev/bigbluebutton/bigbluebutton-client/branding/default/style/css/assets/images/icon-6-thumb-up.png"
+   inkscape:export-xdpi="50"
+   inkscape:export-ydpi="50">
+  <metadata
+     id="metadata3005">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>icon 6 thumb up</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="753"
+     inkscape:window-height="480"
+     id="namedview3003"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="16"
+     inkscape:cy="16"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2992" />
+  <!-- Generator: Sketch 3.0.3 (7891) - http://www.bohemiancoding.com/sketch -->
+  <title
+     id="title2994">icon 6 thumb up</title>
+  <desc
+     id="desc2996">Created with Sketch.</desc>
+  <defs
+     id="defs2998" />
+  <g
+     id="Page-1"
+     stroke="none"
+     stroke-width="1"
+     fill="none"
+     fill-rule="evenodd"
+     sketch:type="MSPage"
+     style="fill:#000000;stroke:#000000;stroke-opacity:1">
+    <g
+       id="icon-6-thumb-up"
+       sketch:type="MSArtboardGroup"
+       fill="#929292"
+       style="fill:#000000;stroke:#000000;stroke-opacity:1">
+      <path
+         d="M19.2488133,30 L23.5023733,30 C24.8817744,30 26,28.8903379 26,27.5 C26,26.9371936 25.8126296,26.417824 25.4978577,25.9999924 C26.8803322,25.9966522 28,24.8882411 28,23.5 C28,22.864214 27.763488,22.28386 27.3722702,21.8426992 L27.3722702,21.8426992 C28.3231922,21.4895043 29,20.5793268 29,19.5 C29,18.864214 28.763488,18.28386 28.3722702,17.8426992 C29.3231922,17.4895043 30,16.5793268 30,15.5 C30,14.1192881 28.8845825,13 27.4915915,13 L21.4997555,13 C22.5490723,7.9831543 22.0463867,1.99999928 18,2 C13.9536133,2.00000073 16.066359,6.78764706 14.5,9.76269531 C12.9337003,12.7376303 10.000223,12.9999801 10,13 L3.99508929,13 C2.8932319,13 2,13.8933973 2,14.9918842 L2,26.0081158 C2,27.1082031 2.88670635,28 3.99810135,28 L10,28 L16,30 L19.2488133,30 L19.2488133,30 Z M10.5,14 C10.5000014,13.9999997 13.8047349,13.276317 15.3710938,10.3012695 C16.9374527,7.32622128 15.1291504,3.00000043 18,3 C21.1514893,2.99999957 21.5007324,8.5 20.2999878,14 L20.2999878,14 L27.5069036,14 C28.3361142,14 29,14.6715729 29,15.5 C29,16.3342028 28.331518,17 27.5069036,17 L24,17 L24,18 L26.5069036,18 C27.3361142,18 28,18.6715729 28,19.5 C28,20.3342028 27.331518,21 26.5069036,21 L23,21 L23,21 L23,22 L25.5069036,22 C26.3361142,22 27,22.6715729 27,23.5 C27,24.3342028 26.331518,25 25.5069036,25 L22,25 L22,25 L22,26 L23.4983244,26 C24.3288106,26 25,26.6715729 25,27.5 C25,28.3342028 24.3276769,29 23.4983244,29 L19.7508378,29 L16,29 L10,27 L4.00292933,27 C3.43788135,27 3,26.5529553 3,26.0014977 L3,14.9985023 C3,14.4474894 3.44769743,14 3.9999602,14 L10.5,14 L10.5,14 L10.5,14 Z"
+         id="thumb-up"
+         sketch:type="MSShapeGroup"
+         style="fill:#000000;stroke:#000000;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-sad-face.png b/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-sad-face.png
new file mode 100644
index 0000000000000000000000000000000000000000..63a079cddb4ee5a7180f69be8ec6e91bc34ccf97
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-sad-face.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-sad-face.svg b/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-sad-face.svg
new file mode 100644
index 0000000000000000000000000000000000000000..584001036e0f441e05f91c04880642ca3ac3e5a5
--- /dev/null
+++ b/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-sad-face.svg
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="32px"
+   height="32px"
+   viewBox="0 0 32 32"
+   version="1.1"
+   id="svg2992"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="icon-7-sad-face.svg"
+   inkscape:export-filename="/var/lib/lxc/bbb-dev090-14/rootfs/home/ubuntu/dev/bigbluebutton/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-sad-face.png"
+   inkscape:export-xdpi="50"
+   inkscape:export-ydpi="50">
+  <metadata
+     id="metadata3005">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>icon 7 sad face</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="753"
+     inkscape:window-height="480"
+     id="namedview3003"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="16"
+     inkscape:cy="16"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg2992" />
+  <!-- Generator: Sketch 3.0.3 (7891) - http://www.bohemiancoding.com/sketch -->
+  <title
+     id="title2994">icon 7 sad face</title>
+  <desc
+     id="desc2996">Created with Sketch.</desc>
+  <defs
+     id="defs2998" />
+  <g
+     id="Page-1"
+     stroke="none"
+     stroke-width="1"
+     fill="none"
+     fill-rule="evenodd"
+     sketch:type="MSPage"
+     style="fill:#000000;stroke:#000000;stroke-opacity:1">
+    <g
+       id="icon-7-sad-face"
+       sketch:type="MSArtboardGroup"
+       fill="#929292"
+       style="fill:#000000;stroke:#000000;stroke-opacity:1">
+      <path
+         d="M16.5,29 C23.4035597,29 29,23.4035597 29,16.5 C29,9.59644029 23.4035597,4 16.5,4 C9.59644029,4 4,9.59644029 4,16.5 C4,23.4035597 9.59644029,29 16.5,29 L16.5,29 Z M16.5,28 C22.8512749,28 28,22.8512749 28,16.5 C28,10.1487251 22.8512749,5 16.5,5 C10.1487251,5 5,10.1487251 5,16.5 C5,22.8512749 10.1487251,28 16.5,28 L16.5,28 Z M12,15 C12.5522848,15 13,14.5522848 13,14 C13,13.4477152 12.5522848,13 12,13 C11.4477152,13 11,13.4477152 11,14 C11,14.5522848 11.4477152,15 12,15 L12,15 Z M21,15 C21.5522848,15 22,14.5522848 22,14 C22,13.4477152 21.5522848,13 21,13 C20.4477152,13 20,13.4477152 20,14 C20,14.5522848 20.4477152,15 21,15 L21,15 Z M16.4813232,21 C13,21 11,23 11,23 L11,22 C11,22 13,20 16.4813232,20 C19.9626465,20 22,22 22,22 L22,23 C22,23 19.9626465,21 16.4813232,21 L16.4813232,21 Z"
+         id="sad-face"
+         sketch:type="MSShapeGroup"
+         style="fill:#000000;stroke:#000000;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-thumb-down.png b/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-thumb-down.png
new file mode 100644
index 0000000000000000000000000000000000000000..e9b46550cad5ab24985d53da86c2f2cb88ca3653
Binary files /dev/null and b/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-thumb-down.png differ
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-thumb-down.svg b/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-thumb-down.svg
new file mode 100644
index 0000000000000000000000000000000000000000..20a8802c2fa50ae14d980337dd1ff8e4ade52d98
--- /dev/null
+++ b/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-thumb-down.svg
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="32px"
+   height="32px"
+   viewBox="0 0 32 32"
+   version="1.1"
+   id="svg3007"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="icon-7-thumb-down.svg"
+   inkscape:export-filename="/var/lib/lxc/bbb-dev090-14/rootfs/home/ubuntu/dev/bigbluebutton/bigbluebutton-client/branding/default/style/css/assets/images/icon-7-thumb-down.png"
+   inkscape:export-xdpi="50"
+   inkscape:export-ydpi="50">
+  <metadata
+     id="metadata3020">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>icon 7 thumb down</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="753"
+     inkscape:window-height="480"
+     id="namedview3018"
+     showgrid="false"
+     inkscape:zoom="7.375"
+     inkscape:cx="16"
+     inkscape:cy="16"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg3007" />
+  <!-- Generator: Sketch 3.0.3 (7891) - http://www.bohemiancoding.com/sketch -->
+  <title
+     id="title3009">icon 7 thumb down</title>
+  <desc
+     id="desc3011">Created with Sketch.</desc>
+  <defs
+     id="defs3013" />
+  <g
+     id="Page-1"
+     stroke="none"
+     stroke-width="1"
+     fill="none"
+     fill-rule="evenodd"
+     sketch:type="MSPage"
+     style="fill:#000000;stroke:#000000;stroke-opacity:1">
+    <g
+       id="icon-7-thumb-down"
+       sketch:type="MSArtboardGroup"
+       fill="#929292"
+       style="fill:#000000;stroke:#000000;stroke-opacity:1">
+      <path
+         d="M19.2488133,2 L23.5023733,2 C24.8817744,2 26,3.10966206 26,4.5 C26,5.06280636 25.8126296,5.58217601 25.4978577,6.00000757 C26.8803322,6.00334775 28,7.11175892 28,8.5 C28,9.13578601 27.763488,9.71613998 27.3722702,10.1573008 L27.3722702,10.1573008 C28.3231922,10.5104957 29,11.4206732 29,12.5 C29,13.135786 28.763488,13.71614 28.3722702,14.1573008 C29.3231922,14.5104957 30,15.4206732 30,16.5 C30,17.8807119 28.8845825,19 27.4915915,19 L21.4997555,19 C22.5490723,24.0168457 22.0463867,30.0000007 18,30 C13.9536133,29.9999993 16.066359,25.2123529 14.5,22.2373047 C12.9337003,19.2623697 10.000223,19.0000199 10,19 L3.99508929,19 C2.8932319,19 2,18.1066027 2,17.0081158 L2,5.99188419 C2,4.89179693 2.88670635,4 3.99810135,4 L10,4 L16,2 L19.2488133,2 L19.2488133,2 Z M10.5,18 C10.5000014,18.0000003 13.8047349,18.723683 15.3710938,21.6987305 C16.9374527,24.6737787 15.1291504,28.9999996 18,29 C21.1514893,29.0000004 21.5007324,23.5 20.2999878,18 L20.2999878,18 L27.5069036,18 C28.3361142,18 29,17.3284271 29,16.5 C29,15.6657972 28.331518,15 27.5069036,15 L24,15 L24,14 L26.5069036,14 C27.3361142,14 28,13.3284271 28,12.5 C28,11.6657972 27.331518,11 26.5069036,11 L23,11 L23,11 L23,10 L25.5069036,10 C26.3361142,10 27,9.32842712 27,8.5 C27,7.66579723 26.331518,7 25.5069036,7 L22,7 L22,7 L22,6 L23.4983244,6 C24.3288106,6 25,5.32842712 25,4.5 C25,3.66579723 24.3276769,3 23.4983244,3 L19.7508378,3 L16,3 L10,5 L4.00292933,5 C3.43788135,5 3,5.44704472 3,5.99850233 L3,17.0014977 C3,17.5525106 3.44769743,18 3.9999602,18 L10.5,18 L10.5,18 L10.5,18 Z"
+         id="thumb-down"
+         sketch:type="MSShapeGroup"
+         style="fill:#000000;stroke:#000000;stroke-opacity:1" />
+    </g>
+  </g>
+</svg>
diff --git a/bigbluebutton-client/branding/default/style/css/assets/images/icons-license.txt b/bigbluebutton-client/branding/default/style/css/assets/images/icons-license.txt
index 952a5f97637e24ee48a56d62c9109c957a4b7aa4..6d3c50ba645568a1c8c33a3436479b847e063d83 100755
--- a/bigbluebutton-client/branding/default/style/css/assets/images/icons-license.txt
+++ b/bigbluebutton-client/branding/default/style/css/assets/images/icons-license.txt
@@ -36,6 +36,25 @@ I'm unavailable for custom icon design work. But your
 suggestions are always welcome!
 <mailto:p@yusukekamiyamane.com>
 ====================
+# Hawcons
+
+Created by *Yannick Lung*, 2014
+* [Web](http://www.hawcons.com)
+* [Twitter](http://www.twitter.com/Hawcons)
+* [Facebook](http://www.facebook.com/Hawcons)
+* [Mail](mailto:support@hawcons.com)
+* [Tumblr](http://hawcons.tumblr.com)
+* [Google+](http://www.google.com/+)
+
+## Version 1.0
+
+## LICENSE
+You are free to use Hawcons for commercial and personal purposes without attribution, however a credit for the work would be appreciated. You may not sell or redistribute the icons themselves as icons. Do not claim creative credit.
+
+If you would like to support my work you can do this with the donate button on the website.
+
+If you have any additional questions please contact Hawcons via email or social networks.
+====================
 Some of the client icons were generated using the following online tool:
 
 http://romannurik.github.io/AndroidAssetStudio/icons-launcher.html#foreground.type=clipart&foreground.space.trim=1&foreground.space.pad=0.15&foreground.clipart=res%2Fclipart%2Ficons%2Fnavigation_refresh.svg&foreColor=4b4b4b%2C0&crop=0&backgroundShape=none&backColor=ffffff%2C100&effects=none
diff --git a/bigbluebutton-client/build.xml b/bigbluebutton-client/build.xml
index 1091448b900ee3057cc41825be376e208e531bff..b19f94f949014371e35186125ece60cab72d8e90 100755
--- a/bigbluebutton-client/build.xml
+++ b/bigbluebutton-client/build.xml
@@ -38,6 +38,7 @@
 	<property name="LAYOUT" value="LayoutModule" />
 	<property name="USERS" value="UsersModule" />
 	<property name="CAPTION" value="CaptionModule" />
+	<property name="SHAREDNOTES" value="SharedNotesModule" />
 	
 	<xmlproperty file="${SRC_DIR}/conf/locales.xml" collapseAttributes="true"/>
 
@@ -83,6 +84,7 @@
 				debug="${DEBUG}"
 				mxml.compatibility-version="3.0.0"
 				swf-version="13"
+				default-background-color="0xFFFFFF"
 				optimize="true">
 			</mxmlc>
 		</sequential>
@@ -176,6 +178,7 @@
 				<include-resource-bundles>skins</include-resource-bundles>
 				<include-resource-bundles>styles</include-resource-bundles>
 				<source-path path-element="${FLEX_HOME}/frameworks"/>
+				<default-background-color>0xFFFFFF</default-background-color>
 			</mxmlc>
 		</sequential>
 	</macrodef>
@@ -278,9 +281,15 @@
 			<build-module src="${SRC_DIR}" target="${CAPTION}" />
 	</target>
 	
+	<target name="build-sharednotes" description="Compile SharedNotes Module">
+		<build-module src="${SRC_DIR}" target="${SHAREDNOTES}" />
+		<copy file="${BASE_DIR}/src/org/bigbluebutton/modules/sharednotes/util/shared_notes.js" todir="${OUTPUT_DIR}/lib/">
+		</copy>
+	</target>
+
 	<!-- just a grouping of modules to compile -->
 	<target name="build-main-chat-present" 
-			depends="build-bbb-main, build-chat, build-present, build-layout, build-broadcast, build-users, build-caption"
+			depends="build-bbb-main, build-chat, build-present, build-layout, build-broadcast, build-users, build-caption, build-sharednotes"
 			description="Compile main, chat, present modules">
 	</target>
 
@@ -299,6 +308,7 @@
 				<mxmlc file="@{src}/@{target}.mxml" output="${OUTPUT_DIR}/@{target}.swf" debug="${DEBUG}" mxml.compatibility-version="3.0.0" swf-version="13" optimize="true" link-report="linker-report.xml">
 					<target-player>11</target-player>
 					<load-config filename="@{flex}/frameworks/flex-config.xml" />
+					<default-background-color>0xFFFFFF</default-background-color>
 					<source-path path-element="@{flex}/frameworks" />
 
 					<!--
@@ -367,7 +377,7 @@
 				<load-config filename="@{flex}/frameworks/flex-config.xml" />
 				<source-path path-element="@{flex}/frameworks" />
 				<static-link-runtime-shared-libraries>${STATIC_RSL}</static-link-runtime-shared-libraries>
-
+				<default-background-color>0xFFFFFF</default-background-color>
 				<compiler.library-path dir="@{flex}/frameworks" append="true">
 					<include name="libs" />
 					<include name="../bundles/{locale}" />
@@ -421,11 +431,13 @@
 			<fileset dir="${PROD_RESOURCES_DIR}/help"/>
 		</copy>
 		<copy file="${PROD_RESOURCES_DIR}/BigBlueButtonTest.html" todir="${OUTPUT_DIR}" overwrite="true"/>
-		<copy file="${PROD_RESOURCES_DIR}/BigBlueButton.html" todir="${OUTPUT_DIR}" overwrite="true"/>
+		<copy file="${PROD_RESOURCES_DIR}/MconfLive.html" todir="${OUTPUT_DIR}" overwrite="true"/>
 		<copy file="${PROD_RESOURCES_DIR}/ScreenshareStandalone.html" todir="${OUTPUT_DIR}" overwrite="true"/>
 		<copy file="${PROD_RESOURCES_DIR}/get_flash_player.gif" todir="${OUTPUT_DIR}" overwrite="true"/>
 		<copy file="${PROD_RESOURCES_DIR}/bbb.gif" todir="${OUTPUT_DIR}" overwrite="true"/>
 		<copy file="${PROD_RESOURCES_DIR}/avatar.png" todir="${OUTPUT_DIR}" overwrite="true"/>
+		<copy file="${PROD_RESOURCES_DIR}/logo.png" todir="${OUTPUT_DIR}" overwrite="true"/>
+		<copy file="${PROD_RESOURCES_DIR}/background.jpg" todir="${OUTPUT_DIR}" overwrite="true"/>
 		<copy file="${PROD_RESOURCES_DIR}/locales.xml" todir="${OUTPUT_DIR}/conf" overwrite="true"/>
 		<copy file="${PROD_RESOURCES_DIR}/expressInstall.swf" todir="${OUTPUT_DIR}" overwrite="true"/>
 		<copy file="${PROD_RESOURCES_DIR}/example-info-data.xml" todir="${OUTPUT_DIR}/conf" overwrite="true"/>
@@ -449,8 +461,8 @@
 
 	<target name="generate-html-wrapper">
 		<html-wrapper
-			title="BigBlueButton"
-			file="BigBlueButton.html"
+			title="Mconf-Live"
+			file="MconfLive.html"
 			height="100%"
 			width="100%"
 			bgcolor="grey"
diff --git a/bigbluebutton-client/locale/en_US/bbbResources.properties b/bigbluebutton-client/locale/en_US/bbbResources.properties
index 311fdc1774c34f457c21b8f3fff897bd8b6fb073..d584581bd2be6504d5b470748aa606bc2e64bf9f 100755
--- a/bigbluebutton-client/locale/en_US/bbbResources.properties
+++ b/bigbluebutton-client/locale/en_US/bbbResources.properties
@@ -9,6 +9,7 @@ bbb.mainshell.invalidAuthToken = Invalid Authentication Token
 bbb.mainshell.resetLayoutBtn.toolTip = Reset Layout
 bbb.mainshell.notification.tunnelling = Tunnelling
 bbb.mainshell.notification.webrtc = WebRTC Audio
+bbb.mainshell.fullscreenBtn.toolTip = Toggle full screen
 bbb.oldlocalewindow.reminder1 = You may have an old language translations of BigBlueButton.
 bbb.oldlocalewindow.reminder2 = Please clear your browser's cache and try again.
 bbb.oldlocalewindow.windowTitle = Warning: Old Language Translations
@@ -56,8 +57,8 @@ bbb.micSettings.webrtc.transferring = Transferring
 bbb.micSettings.webrtc.endingecho = Joining audio
 bbb.micSettings.webrtc.endedecho = Echo test ended.
 bbb.micPermissions.firefox.title = Firefox Microphone Permissions
-bbb.micPermissions.firefox.message1 = Choose your mic and then click Share.
-bbb.micPermissions.firefox.message2 = If you don't see the list of microphones, click on the microphone icon.
+bbb.micPermissions.firefox.message1 = Choose your mic and then click "Share Selected Device"
+bbb.micPermissions.firefox.message2 = If you're seeing this message, click on the microphone icon next to the address bar
 bbb.micPermissions.chrome.title = Chrome Microphone Permissions
 bbb.micPermissions.chrome.message1 = Click Allow to give Chrome permission to use your microphone.
 bbb.micWarning.title = Audio Warning
@@ -95,6 +96,9 @@ bbb.mainToolbar.recordBtn.toolTip.start = Start recording
 bbb.mainToolbar.recordBtn.toolTip.stop = Stop recording
 bbb.mainToolbar.recordBtn.toolTip.recording = The session is being recorded
 bbb.mainToolbar.recordBtn.toolTip.notRecording = The session isn't being recorded
+bbb.mainToolbar.recordBtn.toolTip.onlyModerators = Only moderators can start and stop recordings
+bbb.mainToolbar.recordBtn.toolTip.wontInterrupt = This recording can't be interrupted
+bbb.mainToolbar.recordBtn.toolTip.wontRecord = This session cannot be recorded
 bbb.mainToolbar.recordBtn.confirm.title = Confirm recording
 bbb.mainToolbar.recordBtn.confirm.message.start = Are you sure you want to start recording the session?
 bbb.mainToolbar.recordBtn.confirm.message.stop = Are you sure you want to stop recording the session?
@@ -103,6 +107,20 @@ bbb.mainToolbar.recordBtn..notification.message1 = You can record this meeting.
 bbb.mainToolbar.recordBtn..notification.message2 = You must click the Start/Stop Recording button in the title bar to begin/end recording.
 bbb.mainToolbar.recordingLabel.recording = (Recording)
 bbb.mainToolbar.recordingLabel.notRecording = Not Recording
+bbb.waitWindow.waitMessage.message = You are a guest, please wait moderator approval.
+bbb.waitWindow.waitMessage.title = Waiting
+bbb.guests.title = Guests
+bbb.guests.message.singular = {0} user wants to join this meeting
+bbb.guests.message.plural = {0} users want to join this meeting
+bbb.guests.allowBtn.toolTip = Allow
+bbb.guests.allowEveryoneBtn.text = Allow everyone
+bbb.guests.denyBtn.toolTip = Deny
+bbb.guests.denyEveryoneBtn.text = Deny everyone
+bbb.guests.rememberAction.text = Remember choice
+bbb.guests.alwaysAccept = Always accept
+bbb.guests.alwaysDeny = Always deny
+bbb.guests.askModerator = Ask moderator
+bbb.guests.Management = Guest management
 bbb.clientstatus.title = Configuration Notifications
 bbb.clientstatus.notification = Unread notifications
 bbb.clientstatus.close = Close
@@ -114,6 +132,10 @@ bbb.clientstatus.flash.title = Flash Player
 bbb.clientstatus.flash.message = Your Flash Player plugin ({0}) is out-of-date. Recommend updating to the latest version.
 bbb.clientstatus.webrtc.title = Audio
 bbb.clientstatus.webrtc.message = Recommend using either Firefox or Chrome for better audio.
+bbb.clientstatus.java.title = Java
+bbb.clientstatus.java.notdetected = Java version not detected.
+bbb.clientstatus.java.notinstalled = You have no Java installed, please click <font color='#0a4a7a'><a href='http://www.java.com/download/' target='_blank'>HERE</a></font> to install the latest Java to use the desktop sharing feature.
+bbb.clientstatus.java.oldversion = You have an old Java installed, please click <font color='#0a4a7a'><a href='http://www.java.com/download/' target='_blank'>HERE</a></font> to install the latest Java to use the desktop sharing feature.
 bbb.window.minimizeBtn.toolTip = Minimize
 bbb.window.maximizeRestoreBtn.toolTip = Maximize
 bbb.window.closeBtn.toolTip = Close
@@ -149,6 +171,16 @@ bbb.users.usersGrid.statusItemRenderer = Status
 bbb.users.usersGrid.statusItemRenderer.changePresenter = Click To Make Presenter
 bbb.users.usersGrid.statusItemRenderer.presenter = Presenter
 bbb.users.usersGrid.statusItemRenderer.moderator = Moderator
+bbb.users.usersGrid.statusItemRenderer.raiseHand = Hand Raised
+bbb.users.usersGrid.statusItemRenderer.agree = Agree
+bbb.users.usersGrid.statusItemRenderer.disagree = Disagree
+bbb.users.usersGrid.statusItemRenderer.speakLouder = Speak louder
+bbb.users.usersGrid.statusItemRenderer.speakSofter = Speak softer
+bbb.users.usersGrid.statusItemRenderer.speakFaster = Speak faster
+bbb.users.usersGrid.statusItemRenderer.speakSlower = Speak slower
+bbb.users.usersGrid.statusItemRenderer.beRightBack = Be Right Back
+bbb.users.usersGrid.statusItemRenderer.laughter = :)
+bbb.users.usersGrid.statusItemRenderer.sad = :(
 bbb.users.usersGrid.statusItemRenderer.clearStatus = Clear status
 bbb.users.usersGrid.statusItemRenderer.viewer = Viewer
 bbb.users.usersGrid.statusItemRenderer.streamIcon.toolTip = Sharing webcam.
@@ -166,26 +198,37 @@ bbb.users.usersGrid.mediaItemRenderer.webcam = Webcam shared
 bbb.users.usersGrid.mediaItemRenderer.micOff = Microphone off
 bbb.users.usersGrid.mediaItemRenderer.micOn = Microphone on
 bbb.users.usersGrid.mediaItemRenderer.noAudio = Not in audio conference
+bbb.users.usersGrid.mediaItemRenderer.promoteUser = Promote {0} to moderator
+bbb.users.usersGrid.mediaItemRenderer.demoteUser = Demote {0} to viewer
 bbb.users.emojiStatus.clear = Clear
 bbb.users.emojiStatus.clear.toolTip = Clear status
 bbb.users.emojiStatus.close = Close
 bbb.users.emojiStatus.close.toolTip = Close status popup
-bbb.users.emojiStatus.raiseHand = Raise hand status
-bbb.users.emojiStatus.happy = Happy status
+bbb.users.emojiStatus.raiseHand = Raise hand
+bbb.users.emojiStatus.happy = :)
 bbb.users.emojiStatus.smile = Smile status
-bbb.users.emojiStatus.sad = Sad status
+bbb.users.emojiStatus.sad = :(
 bbb.users.emojiStatus.confused = Confused status
 bbb.users.emojiStatus.neutral = Neutral status
 bbb.users.emojiStatus.away = Away status
 bbb.users.emojiStatus.thumbsUp = Thumbs Up status
 bbb.users.emojiStatus.thumbsDown = Thumbs Down status
-bbb.users.emojiStatus.applause = Applause status
+bbb.users.emojiStatus.applause = Applause
+bbb.users.emojiStatus.agree = I agree
+bbb.users.emojiStatus.disagree = I disagree
+bbb.users.emojiStatus.speakLouder = Could you please speak louder?
+bbb.users.emojiStatus.speakSofter = Could you please speak softer?
+bbb.users.emojiStatus.speakFaster = Could you please speak faster?
+bbb.users.emojiStatus.speakSlower = Could you please speak slower?
+bbb.users.emojiStatus.beRightBack = I'll be right back
 bbb.presentation.title = Presentation
 bbb.presentation.titleWithPres = Presentation: {0}
 bbb.presentation.quickLink.label = Presentation Window
 bbb.presentation.fitToWidth.toolTip = Fit Presentation To Width
 bbb.presentation.fitToPage.toolTip = Fit Presentation To Page
 bbb.presentation.uploadPresBtn.toolTip = Upload Presentation
+bbb.presentation.downloadPresBtn.toolTip = Download Presentations
+bbb.presentation.downloadPresBtn.disabledToolTip = No presentations available for download
 bbb.presentation.backBtn.toolTip = Previous slide
 bbb.presentation.btnSlideNum.accessibilityName = Slide {0} of {1}
 bbb.presentation.btnSlideNum.toolTip = Select a slide
@@ -229,6 +272,13 @@ bbb.fileupload.okCancelBtn.toolTip = Close the File Upload dialog box
 bbb.fileupload.genThumbText = Generating thumbnails..
 bbb.fileupload.progBarLbl = Progress:
 bbb.fileupload.fileFormatHint = Upload any office document or Portable Document Format (PDF) file.  For best results upload PDF.
+bbb.fileupload.letUserDownload = Let the users download the presentation
+bbb.fileupload.letUserDownload.tooltip = Check here if you want the other users to download your presentation
+bbb.filedownload.title = Download the Presentations
+bbb.filedownload.fileLbl = Choose File to Download:
+bbb.filedownload.downloadBtn = Download
+bbb.filedownload.downloadBtn.toolTip = Download Presentation
+bbb.filedownload.thisFileIsDownloadable = File is downloadable
 bbb.chat.title = Chat
 bbb.chat.quickLink.label = Chat Window
 bbb.chat.cmpColorPicker.toolTip = Text Color
@@ -236,6 +286,20 @@ bbb.chat.input.accessibilityName = Chat Message Editing Field
 bbb.chat.sendBtn = Send
 bbb.chat.sendBtn.toolTip = Send Message
 bbb.chat.sendBtn.accessibilityName = Send chat message
+bbb.chat.saveBtn.toolTip = Save chat
+bbb.chat.saveBtn.accessibilityName = Save chat in text file
+bbb.chat.saveBtn.label = Save
+bbb.chat.save.complete = Chat successfully saved
+bbb.chat.save.filename = public-chat
+bbb.chat.copyBtn.toolTip = Copy chat
+bbb.chat.copyBtn.accessibilityName = Copy chat to clipboard
+bbb.chat.copyBtn.label = Copy
+bbb.chat.copy.complete = Chat copied to clipboard
+bbb.chat.clearBtn.toolTip = Clear Public chat
+bbb.chat.clearBtn.accessibilityName = Clear the public chat history
+bbb.chat.clearBtn.chatMessage = The public chat history was cleared by a moderator
+bbb.chat.clearBtn.alert.title = Warning
+bbb.chat.clearBtn.alert.text = You are clearing the public chat history and this action cannot be undone. Do you want to proceed?
 bbb.chat.contextmenu.copyalltext = Copy All Text
 bbb.chat.publicChatUsername = Public
 bbb.chat.optionsTabName = Options
@@ -334,22 +398,26 @@ bbb.screensharePublish.commonErrorMessage.label = Select 'Cancel' and try again.
 bbb.screensharePublish.cancelButton.label = Cancel
 bbb.screensharePublish.startButton.label = Start
 bbb.screensharePublish.stopButton.label = Stop
+bbb.screensharePublish.sharingMessage= This is your screen being shared
 bbb.screenshareView.title = Screen Sharing
 bbb.screenshareView.fitToWindow = Fit to Window
 bbb.screenshareView.actualSize = Display actual size
 bbb.screenshareView.minimizeBtn.accessibilityName = Minimize the Screen Sharing View Window
 bbb.screenshareView.maximizeRestoreBtn.accessibilityName = Maximize the Screen Sharing View Window
 bbb.screenshareView.closeBtn.accessibilityName = Close the Screen Sharing View Window
-bbb.toolbar.phone.toolTip.start = Share Your Microphone
-bbb.toolbar.phone.toolTip.stop = Stop Sharing Your Microphone
+bbb.toolbar.phone.toolTip.start = Enable Audio (microphone or listen only)
+bbb.toolbar.phone.toolTip.stop = Disable Audio
 bbb.toolbar.phone.toolTip.mute = Stop listening the conference
 bbb.toolbar.phone.toolTip.unmute = Start listening the conference
 bbb.toolbar.phone.toolTip.nomic = No microphone detected
 bbb.toolbar.deskshare.toolTip.start = Share Your Screen
 bbb.toolbar.deskshare.toolTip.stop = Stop Sharing Your Screen
+bbb.toolbar.sharednotes.toolTip = Open Shared Notes
 bbb.toolbar.video.toolTip.start = Share Your Webcam
 bbb.toolbar.video.toolTip.stop = Stop Sharing Your Webcam
 bbb.layout.addButton.toolTip = Add the custom layout to the list
+bbb.layout.overwriteLayoutName.title = Overwrite layout
+bbb.layout.overwriteLayoutName.text = Name already in use. Do you want to overwrite?
 bbb.layout.broadcastButton.toolTip = Apply Current Layout to All Viewers
 bbb.layout.combo.toolTip = Change Your Layout
 bbb.layout.loadButton.toolTip = Load layouts from a file
@@ -359,9 +427,11 @@ bbb.layout.combo.prompt = Apply a layout
 bbb.layout.combo.custom = * Custom layout
 bbb.layout.combo.customName = Custom layout
 bbb.layout.combo.remote = Remote
+bbb.layout.window.name = Layout name
 bbb.layout.save.complete = Layouts were successfully saved
 bbb.layout.load.complete = Layouts were successfully loaded
 bbb.layout.load.failed = Unable to load the layouts
+bbb.layout.sync = Your layout has been sent to all participants
 bbb.layout.name.defaultlayout = Default Layout
 bbb.layout.name.closedcaption = Closed Caption
 bbb.layout.name.videochat = Video Chat
@@ -369,6 +439,10 @@ bbb.layout.name.webcamsfocus = Webcam Meeting
 bbb.layout.name.presentfocus = Presentation Meeting
 bbb.layout.name.lectureassistant = Lecture Assistant
 bbb.layout.name.lecture = Lecture
+bbb.layout.addCurrentToFileWindow.title = Add current Layout to file
+bbb.layout.addCurrentToFileWindow.text = Do you want to save the current layout to file?
+bbb.layout.denyAddToFile.toolTip = Deny adding the current layout
+bbb.layout.confirmAddToFile.toolTip = Confirm adding the current layout
 bbb.highlighter.toolbar.pencil = Pencil
 bbb.highlighter.toolbar.pencil.accessibilityName = Switch whiteboard cursor to pencil
 bbb.highlighter.toolbar.ellipse = Circle
@@ -394,19 +468,27 @@ bbb.logout.connectionfailed = The connection to the server has ended
 bbb.logout.rejected = The connection to the server has been rejected
 bbb.logout.invalidapp = The red5 app does not exist
 bbb.logout.unknown = Your client has lost connection with the server
+bbb.logout.guestkickedout = The moderator didn't allow you to join this meeting
 bbb.logout.usercommand = You have logged out of the conference
 bbb.logour.breakoutRoomClose = Your browser window will be closed
 bbb.logout.ejectedFromMeeting = A moderator has kicked you out of the meeting.
 bbb.logout.refresh.message = If this logout was unexpected click the button below to reconnect.
 bbb.logout.refresh.label = Reconnect
+bbb.settings.title = Settings
+bbb.settings.ok = OK
+bbb.settings.cancel = Cancel
+bbb.settings.btn.toolTip = Open configuration window
 bbb.logout.confirm.title = Confirm Logout
 bbb.logout.confirm.message = Are you sure you want to log out?
+bbb.logout.confirm.endMeeting = Yes and close the session
 bbb.logout.confirm.yes = Yes
 bbb.logout.confirm.no = No
+bbb.endSession.confirm.title = Warning
+bbb.endSession.confirm.message = If you close the session, all participants will be disconnected. Do you want to proceed?
 bbb.connection.failure=Detected Connectivity Problems
 bbb.connection.reconnecting=Reconnecting
 bbb.connection.reestablished=Connection reestablished
-bbb.connection.bigbluebutton=BigBlueButton
+bbb.connection.bigbluebutton=Main
 bbb.connection.sip=SIP
 bbb.connection.video=Video
 bbb.connection.deskshare=Deskshare
@@ -414,9 +496,24 @@ bbb.notes.title = Notes
 bbb.notes.cmpColorPicker.toolTip = Text Color
 bbb.notes.saveBtn = Save
 bbb.notes.saveBtn.toolTip = Save Note
+bbb.sharedNotes.title = Shared notes
+bbb.sharedNotes.name = Note name
+bbb.sharedNotes.save.toolTip = Save notes to file
+bbb.sharedNotes.save.complete = Notes were successfully saved
+bbb.sharedNotes.save.htmlLabel = Formatted text (.html)
+bbb.sharedNotes.save.txtLabel = Plain text (.txt)
+bbb.sharedNotes.new.toolTip = Create additional shared notes
+bbb.sharedNotes.undo.toolTip = Undo modification
+bbb.sharedNotes.redo.toolTip = Redo modification
+bbb.sharedNotes.toolbar.toolTip = Text formatting toolbar
+bbb.sharedNotes.additionalNotes.closeWarning.title = Closing shared notes
+bbb.sharedNotes.additionalNotes.closeWarning.message = This action will destroy the notes on this window for everyone, and there's no way to undo. Are you sure you want to close these notes?
 bbb.settings.deskshare.instructions = Choose Allow on the prompt that pops up to check that desktop sharing is working properly for you
 bbb.settings.deskshare.start = Check Desktop Sharing
 bbb.settings.voice.volume = Microphone Activity
+bbb.settings.java.label = Java version error
+bbb.settings.java.text = You have Java {0} installed, but you need at least version {1} to use the BigBlueButton desktop sharing feature. The button below will install the newest Java JRE version.
+bbb.settings.java.command = Install newest Java
 bbb.settings.flash.label = Flash version error
 bbb.settings.flash.text = You have Flash {0} installed, but you need at least version {1} to run BigBlueButton properly. The button below will install the newest Adobe Flash version.
 bbb.settings.flash.command = Install newest Flash
@@ -427,6 +524,15 @@ bbb.settings.warning.label = Warning
 bbb.settings.warning.close = Close this Warning
 bbb.settings.noissues = No outstanding issues have been detected.
 bbb.settings.instructions = Accept the Flash prompt that asks you for webcam permissions. If the output matches what is expected, your browser has been set up correctly. Other potentials issues are below. Examine them to find a possible solution.
+bbb.bwmonitor.title = Network monitor
+bbb.bwmonitor.upload = Upload
+bbb.bwmonitor.upload.short = Up
+bbb.bwmonitor.download = Download
+bbb.bwmonitor.download.short = Down
+bbb.bwmonitor.total = Total
+bbb.bwmonitor.current = Current
+bbb.bwmonitor.available = Available
+bbb.bwmonitor.latency = Latency
 ltbcustom.bbb.highlighter.toolbar.triangle = Triangle
 ltbcustom.bbb.highlighter.toolbar.triangle.accessibilityName = Switch whiteboard cursor to triangle
 ltbcustom.bbb.highlighter.toolbar.line = Line
@@ -668,3 +774,55 @@ bbb.users.roomsGrid.action = Action
 bbb.users.roomsGrid.transfer = Transfer Audio
 bbb.users.roomsGrid.join = Join
 bbb.users.roomsGrid.noUsers = No users is this room
+
+bbb.langSelector.default=Default language
+bbb.langSelector.ar_SY=Arabic (Syria)
+bbb.langSelector.az_AZ=Azerbaijani
+bbb.langSelector.eu_EU=Basque
+bbb.langSelector.bn_BN=Bengali
+bbb.langSelector.bg_BG=Bulgarian
+bbb.langSelector.ca_ES=Catalan
+bbb.langSelector.zh_CN=Chinese (Simplified)
+bbb.langSelector.zh_TW=Chinese (Traditional)
+bbb.langSelector.hr_HR=Croatian
+bbb.langSelector.cs_CZ=Czech
+bbb.langSelector.da_DK=Danish
+bbb.langSelector.nl_NL=Dutch
+bbb.langSelector.en_US=English
+bbb.langSelector.et_EE=Estonian
+bbb.langSelector.fa_IR=Farsi
+bbb.langSelector.fi_FI=Finnish
+bbb.langSelector.fr_FR=French
+bbb.langSelector.fr_CA=French (Canadian)
+bbb.langSelector.ff_SN=Fulah
+bbb.langSelector.de_DE=German
+bbb.langSelector.el_GR=Greek
+bbb.langSelector.he_IL=Hebrew
+bbb.langSelector.hu_HU=Hungarian
+bbb.langSelector.id_ID=Indonesian
+bbb.langSelector.it_IT=Italian
+bbb.langSelector.ja_JP=Japanese
+bbb.langSelector.ko_KR=Korean
+bbb.langSelector.lv_LV=Latvian
+bbb.langSelector.lt_LT=Lithuania
+bbb.langSelector.mn_MN=Mongolian
+bbb.langSelector.ne_NE=Nepali
+bbb.langSelector.no_NO=Norwegian
+bbb.langSelector.pl_PL=Polish
+bbb.langSelector.pt_BR=Portuguese (Brazilian)
+bbb.langSelector.pt_PT=Portuguese
+bbb.langSelector.ro_RO=Romanian
+bbb.langSelector.ru_RU=Russian
+bbb.langSelector.sr_SR=Serbian (Cyrillic)
+bbb.langSelector.sr_RS=Serbian (Latin)
+bbb.langSelector.si_LK=Sinhala
+bbb.langSelector.sk_SK=Slovak
+bbb.langSelector.sl_SL=Slovenian
+bbb.langSelector.es_ES=Spanish
+bbb.langSelector.es_LA=Spanish (Latin American)
+bbb.langSelector.sv_SE=Swedish
+bbb.langSelector.th_TH=Thai
+bbb.langSelector.tr_TR=Turkish
+bbb.langSelector.uk_UA=Ukrainian
+bbb.langSelector.vi_VN=Vietnamese
+bbb.langSelector.cy_GB=Welsh
diff --git a/bigbluebutton-client/locale/es_LA/bbbResources.properties b/bigbluebutton-client/locale/es_LA/bbbResources.properties
index 467fbd321de8d06602b16b03e89a7bec9c3ee9d2..b28d9f57ab8a2de88da9ed5d8f00fccbd21619c9 100644
--- a/bigbluebutton-client/locale/es_LA/bbbResources.properties
+++ b/bigbluebutton-client/locale/es_LA/bbbResources.properties
@@ -9,6 +9,7 @@ bbb.mainshell.invalidAuthToken = Token de autenticación inválido
 bbb.mainshell.resetLayoutBtn.toolTip = Restaurar Diseño
 bbb.mainshell.notification.tunnelling = Tunelización
 bbb.mainshell.notification.webrtc = Audio WebRTC
+bbb.mainshell.fullscreenBtn.toolTip = Cambiar pantalla completa
 bbb.oldlocalewindow.reminder1 = Usted tiene una versión no actualizada de la traducción para Bigbluebutton
 bbb.oldlocalewindow.reminder2 = Por favor limpie el cache de su explorador y pruebe de nuevo.
 bbb.oldlocalewindow.windowTitle = Advertencia\: Traducciones de lenguaje no actualizadas
@@ -103,6 +104,20 @@ bbb.mainToolbar.recordBtn..notification.message1 = Usted puede grabar esta sesi
 bbb.mainToolbar.recordBtn..notification.message2 = Debe hacer click en el botón Iniciar/Detener Grabación en la barra de título para empezar o dejar de grabar.
 bbb.mainToolbar.recordingLabel.recording = (Grabación)
 bbb.mainToolbar.recordingLabel.notRecording = No grabando
+bbb.waitWindow.waitMessage.message = Usted es un invitado, por favor espere la aprobación del moderador.
+bbb.waitWindow.waitMessage.title = Esperando
+bbb.guests.title = Invitados
+bbb.guests.message.singular = {0} usuarios esperan unirse a esta reunión
+bbb.guests.message.plural = {o} usuarios desean unirse a esta reunión
+bbb.guests.allowBtn.toolTip = Permitir
+bbb.guests.allowEveryoneBtn.text = Permitir todos
+bbb.guests.denyBtn.toolTip = Denegar
+bbb.guests.denyEveryoneBtn.text = Denegar todos
+bbb.guests.rememberAction.text = Recordar elección
+bbb.guests.alwaysAccept = Aceptar siempre
+bbb.guests.alwaysDeny = Denegar siempre
+bbb.guests.askModerator = Preguntar al moderador
+bbb.guests.Management = Gestión de invitados
 bbb.clientstatus.title = Notificaciones de configuración
 bbb.clientstatus.notification = Notificaciones sin leer
 bbb.clientstatus.close = Cerrar
@@ -149,6 +164,16 @@ bbb.users.usersGrid.statusItemRenderer = Estado
 bbb.users.usersGrid.statusItemRenderer.changePresenter = Haga click para cambiar a presentador
 bbb.users.usersGrid.statusItemRenderer.presenter = Presentador
 bbb.users.usersGrid.statusItemRenderer.moderator = Moderador
+bbb.users.usersGrid.statusItemRenderer.raiseHand = Mano levantada
+bbb.users.usersGrid.statusItemRenderer.agree = De acuerdo
+bbb.users.usersGrid.statusItemRenderer.disagree = En desacuerdo
+bbb.users.usersGrid.statusItemRenderer.speakLouder = Hablar más alto
+bbb.users.usersGrid.statusItemRenderer.speakSofter = Hablar más bajo
+bbb.users.usersGrid.statusItemRenderer.speakFaster = Hablar más rápido
+bbb.users.usersGrid.statusItemRenderer.speakSlower = Hablar más lento
+bbb.users.usersGrid.statusItemRenderer.beRightBack = Volver
+bbb.users.usersGrid.statusItemRenderer.laughter = :)
+bbb.users.usersGrid.statusItemRenderer.sad = :(
 bbb.users.usersGrid.statusItemRenderer.clearStatus = Reiniciar el estado de todos los participantes
 bbb.users.usersGrid.statusItemRenderer.viewer = Espectador
 bbb.users.usersGrid.statusItemRenderer.streamIcon.toolTip = Compartiendo cámara web
@@ -166,26 +191,36 @@ bbb.users.usersGrid.mediaItemRenderer.webcam = Compartiendo cámara Web
 bbb.users.usersGrid.mediaItemRenderer.micOff = Micrófono apagado
 bbb.users.usersGrid.mediaItemRenderer.micOn = Micrófono encendido
 bbb.users.usersGrid.mediaItemRenderer.noAudio = No está en la Conferencia de Voz
+bbb.users.usersGrid.mediaItemRenderer.promoteUser = Promover a {0} a moderador
+bbb.users.usersGrid.mediaItemRenderer.demoteUser = Retornar a {0} a espectador
 bbb.users.emojiStatus.clear = Limpiar
 bbb.users.emojiStatus.clear.toolTip = Limpiar estado de los participantes
 bbb.users.emojiStatus.close = Cerrar
 bbb.users.emojiStatus.close.toolTip = Cerrar el popup de estado
 bbb.users.emojiStatus.raiseHand = Levantar la mano
-bbb.users.emojiStatus.happy = Estado feliz
+bbb.users.emojiStatus.happy = :)
 bbb.users.emojiStatus.smile = Estado sonriente
-bbb.users.emojiStatus.sad = Estado triste
+bbb.users.emojiStatus.sad = :(
 bbb.users.emojiStatus.confused = Estado confundido
 bbb.users.emojiStatus.neutral = Estado neutral
 bbb.users.emojiStatus.away = Estado fuera de línea
 bbb.users.emojiStatus.thumbsUp = Estado Pulgares Arriba
 bbb.users.emojiStatus.thumbsDown = Estado Pulgares Abajo
-bbb.users.emojiStatus.applause = Estado Aplauso
+bbb.users.emojiStatus.applause = Aplausos
+bbb.users.emojiStatus.agree = De acuerdo
+bbb.users.emojiStatus.disagree = En desacuerdo
+bbb.users.emojiStatus.speakLouder = Hablar más alto
+bbb.users.emojiStatus.speakSofter = Hablar más bajo
+bbb.users.emojiStatus.speakFaster = Hablar más rápido
+bbb.users.emojiStatus.speakSlower = Hablar más lento
+bbb.users.emojiStatus.beRightBack = Volver
 bbb.presentation.title = Presentación
 bbb.presentation.titleWithPres = Presentación\: {0}
 bbb.presentation.quickLink.label = Ventana de Presentación
 bbb.presentation.fitToWidth.toolTip = Ajustar presentación a lo ancho
 bbb.presentation.fitToPage.toolTip = Ajustar presentación a la página
 bbb.presentation.uploadPresBtn.toolTip = Cargar presentación
+bbb.presentation.downloadPresBtn.toolTip = Descargar presentaciones
 bbb.presentation.backBtn.toolTip = Diapositiva anterior.
 bbb.presentation.btnSlideNum.accessibilityName = Diapositiva {0} de {1}
 bbb.presentation.btnSlideNum.toolTip = Seleccionar una diapositiva
@@ -229,6 +264,13 @@ bbb.fileupload.okCancelBtn.toolTip = Cerrar la ventana para subir archivos
 bbb.fileupload.genThumbText = Generando vistas en miniatura..
 bbb.fileupload.progBarLbl = Progreso\:
 bbb.fileupload.fileFormatHint = Cargue documento en cualquier formato de Office o archivo en formato PDF. Para un mejor resultado cargue archivo en formato PDF.
+bbb.fileupload.letUserDownload = Permitir que los usuarios descarguen este archivo
+bbb.fileupload.letUserDownload.tooltip = Marque aquí si desea que los otros usuarios descarguen su presentación
+bbb.filedownload.title = Descargar las Presentaciones
+bbb.filedownload.fileLbl = Elija el archivo a descargar\:
+bbb.filedownload.downloadBtn = Descargar
+bbb.filedownload.downloadBtn.toolTip = Descargar presentación
+bbb.filedownload.thisFileIsDownloadable = El archivo se puede descargar
 bbb.chat.title = Chat
 bbb.chat.quickLink.label = Ventana del Chat
 bbb.chat.cmpColorPicker.toolTip = Color del texto
@@ -236,6 +278,15 @@ bbb.chat.input.accessibilityName = Campo para editar el mensaje del chat.
 bbb.chat.sendBtn = Enviar
 bbb.chat.sendBtn.toolTip = Enviar Mensaje
 bbb.chat.sendBtn.accessibilityName = Enviar mensaje del chat
+bbb.chat.saveBtn.toolTip = Guardar conversación
+bbb.chat.saveBtn.accessibilityName = Guardar conversación en archivo de texto
+bbb.chat.saveBtn.label = Guardar
+bbb.chat.save.complete = Conversación guardada exitosamente
+bbb.chat.save.filename = Conversación pública
+bbb.chat.copyBtn.toolTip = Copiar conversación
+bbb.chat.copyBtn.accessibilityName = Copiar conversación al portapapeles
+bbb.chat.copyBtn.label = Copiar
+bbb.chat.copy.complete = Conversación copiada al portapapeles
 bbb.chat.contextmenu.copyalltext = Copiar todo el texto
 bbb.chat.publicChatUsername = Todos
 bbb.chat.optionsTabName = Opciones
@@ -362,6 +413,7 @@ bbb.layout.combo.remote = Remoto
 bbb.layout.save.complete = Los diseños fueron guardados exitosamente
 bbb.layout.load.complete = Los diseños fueron cargados
 bbb.layout.load.failed = Error al cargar diseños
+bbb.layout.sync = Su disposición gráfica ha sido enviada a todos los participantes
 bbb.layout.name.defaultlayout = Alineación de ventanas por defecto
 bbb.layout.name.closedcaption = Closed Caption
 bbb.layout.name.videochat = Chat de Video
@@ -394,11 +446,16 @@ bbb.logout.connectionfailed = La conexión al servidor ha terminado
 bbb.logout.rejected = La conexión al servidor ha sido rechazada
 bbb.logout.invalidapp = La aplicación red5 no existe
 bbb.logout.unknown = Su cliente ha perdido conexión con el servidor
+bbb.logout.guestkickedout = El moderador no permitió su ingreso a la conferencia
 bbb.logout.usercommand = Usted ha salido de la conferencia
 bbb.logour.breakoutRoomClose = Your browser window will be closed
 bbb.logout.ejectedFromMeeting = Un moderador te ha sacado de la conferencia
 bbb.logout.refresh.message = Si esta desconexión no estaba planificada, pulse el botón para reconectar.
 bbb.logout.refresh.label = Reconectar
+bbb.settings.title = Preferencias
+bbb.settings.ok = OK
+bbb.settings.cancel = Cancelar
+bbb.settings.btn.toolTip = Abrir la ventana de configuración
 bbb.logout.confirm.title = Confirmar Cerrar Sesión
 bbb.logout.confirm.message = ¿Esta seguro que desea cerrar sesión?
 bbb.logout.confirm.yes = Si
@@ -414,6 +471,12 @@ bbb.notes.title = Notas
 bbb.notes.cmpColorPicker.toolTip = Color de Texto
 bbb.notes.saveBtn = Guardar
 bbb.notes.saveBtn.toolTip = Guardar Nota
+bbb.sharedNotes.title = Notas compartidas
+bbb.sharedNotes.save.toolTip = Guardar las notas en un archivo
+bbb.sharedNotes.save.complete = Las notas fueron guardadas exitósamente
+bbb.sharedNotes.new.toolTip = Crear notas compartidas adicionales
+bbb.sharedNotes.additionalNotes.closeWarning.title = Cerrando notas compartidas
+bbb.sharedNotes.additionalNotes.closeWarning.message = Esta acción destruirá las notas en esta ventana para todos los participantes y no hay forma de restaurarlas. ¿Está seguro de cerrar estas notas?
 bbb.settings.deskshare.instructions = Presione Permitir en la ventana emergente para verificar que la compartición del escritorio está funcionando adecuadamente para usted
 bbb.settings.deskshare.start = Revisar Escritorio Compartido
 bbb.settings.voice.volume = Actividad del Micrófono
@@ -427,6 +490,15 @@ bbb.settings.warning.label = Advertencia
 bbb.settings.warning.close = Alerta
 bbb.settings.noissues = Ninguna edicion excepcional se ha detectado
 bbb.settings.instructions = Acepte el mensaje de Flash que le pide permisos de cámara. Si usted puede verse y oírse, su navegador se ha configurado correctamente. Otros problemas potenciales se muestran a continuación. Haga clic en cada uno para encontrar una posible solución.
+bbb.bwmonitor.title = Monitor de red
+bbb.bwmonitor.upload = Subida
+bbb.bwmonitor.upload.short = Arriba
+bbb.bwmonitor.download = Descargar
+bbb.bwmonitor.download.short = Abajo
+bbb.bwmonitor.total = Total
+bbb.bwmonitor.current = Actual
+bbb.bwmonitor.available = Disponible
+bbb.bwmonitor.latency = Latencia
 ltbcustom.bbb.highlighter.toolbar.triangle = Triángulo
 ltbcustom.bbb.highlighter.toolbar.triangle.accessibilityName = Cambiar Cursor de Pizarra a Triángulo
 ltbcustom.bbb.highlighter.toolbar.line = Línea
diff --git a/bigbluebutton-client/locale/pt_BR/bbbResources.properties b/bigbluebutton-client/locale/pt_BR/bbbResources.properties
old mode 100755
new mode 100644
index ef5e3e3be6cded78fe4341fcbf7297b55ece4f60..720b3391189a9d2174f13b061e05919e28d1b7f8
--- a/bigbluebutton-client/locale/pt_BR/bbbResources.properties
+++ b/bigbluebutton-client/locale/pt_BR/bbbResources.properties
@@ -9,6 +9,7 @@ bbb.mainshell.invalidAuthToken = Token de autenticação inválido
 bbb.mainshell.resetLayoutBtn.toolTip = Restaurar layout
 bbb.mainshell.notification.tunnelling = Tunelando
 bbb.mainshell.notification.webrtc = Áudio WebRTC
+bbb.mainshell.fullscreenBtn.toolTip = Alternar tela cheia
 bbb.oldlocalewindow.reminder1 = Você deve ter uma versão antiga da tradução do BigBlueButton.
 bbb.oldlocalewindow.reminder2 = Por favor, apague os arquivos temporários do seu navegador e tente novamente.
 bbb.oldlocalewindow.windowTitle = Aviso\: versão antiga da tradução
@@ -43,7 +44,7 @@ bbb.micSettings.cancel = Cancelar
 bbb.micSettings.connectingtoecho = Conectando
 bbb.micSettings.connectingtoecho.error = Erro no teste de eco\: Por favor, contate o administrador.
 bbb.micSettings.cancel.toolTip = Cancelar a entrada na conferência de voz
-bbb.micSettings.access.helpButton = Ajuda (abrir vídeos tutoriais em uma nova página)
+bbb.micSettings.access.helpButton = Abrir os vídeos tutoriais em uma nova janela.
 bbb.micSettings.access.title = Configurações de som. O foco permanecerá na janela de configurações de som até que a janela seja fechada.
 bbb.micSettings.webrtc.title = Suporte a WebRTC
 bbb.micSettings.webrtc.capableBrowser = Seu navegador suporte WebRTC.
@@ -56,8 +57,8 @@ bbb.micSettings.webrtc.transferring = Transferindo
 bbb.micSettings.webrtc.endingecho = Habilitando o áudio
 bbb.micSettings.webrtc.endedecho = Teste de eco encerrado.
 bbb.micPermissions.firefox.title = Permissões de microfone do Firefox
-bbb.micPermissions.firefox.message1 = Selecione seu microfone e clique em Compartilhar
-bbb.micPermissions.firefox.message2 = Se você não enxerga a lista de microfones, clique no ícone de microfone.
+bbb.micPermissions.firefox.message1 = Selecione seu microfone e clique em "Compartilhar dispositivo selecionado"
+bbb.micPermissions.firefox.message2 = Se você está visualizando esta região, clique no ícone do microfone localizado à esquerda da barra de endereços
 bbb.micPermissions.chrome.title = Permissões de microfone do Chrome
 bbb.micPermissions.chrome.message1 = Clique em Permitir para dar ao Chrome permissão para utilizar seu microfone.
 bbb.micWarning.title = Aviso sonoro
@@ -80,9 +81,13 @@ bbb.webrtcWarning.failedError.1011 = Erro 1011\: Coleta de candidatos ICE expiro
 bbb.webrtcWarning.failedError.unknown = Erro {0}\: Código de erro desconhecido
 bbb.webrtcWarning.failedError.mediamissing = Não foi possível acessar seu microfone para a chamada WebRTC
 bbb.webrtcWarning.failedError.endedunexpectedly = O teste de eco WebRTC terminou inesperadamente
-bbb.webrtcWarning.connection.dropped = Conexão WebRTC foi perdida
-bbb.webrtcWarning.connection.reconnecting = Tentando reconectar
+bbb.webrtcWarning.connection.dropped = Falha na conexão WebRTC
+bbb.webrtcWarning.connection.reconnecting = Reconectando
 bbb.webrtcWarning.connection.reestablished = Conexão WebRTC restabelecida
+bbb.inactivityWarning.title = Nenhuma atividade detectada
+bbb.inactivityWarning.message = Esta sessão parece estar inativa. Encerrando automaticamente...
+bbb.shuttingDown.message = Esta sessão está sendo encerrada por inatividade
+bbb.inactivityWarning.cancel = Cancelar
 bbb.mainToolbar.helpBtn = Ajuda
 bbb.mainToolbar.logoutBtn = Sair
 bbb.mainToolbar.logoutBtn.toolTip = Sair da sessão
@@ -95,6 +100,9 @@ bbb.mainToolbar.recordBtn.toolTip.start = Iniciar gravação
 bbb.mainToolbar.recordBtn.toolTip.stop = Parar gravação
 bbb.mainToolbar.recordBtn.toolTip.recording = A sessão está sendo gravada
 bbb.mainToolbar.recordBtn.toolTip.notRecording = A sessão não está sendo gravada
+bbb.mainToolbar.recordBtn.toolTip.onlyModerators = Somente moderadores podem iniciar e parar gravações
+bbb.mainToolbar.recordBtn.toolTip.wontInterrupt = Essa gravação não pode ser interrompida
+bbb.mainToolbar.recordBtn.toolTip.wontRecord = Essa sessão não pode ser gravada
 bbb.mainToolbar.recordBtn.confirm.title = Confirmar gravação
 bbb.mainToolbar.recordBtn.confirm.message.start = Você tem certeza que deseja iniciar a gravação?
 bbb.mainToolbar.recordBtn.confirm.message.stop = Você tem certeza que deseja parar a gravação?
@@ -103,6 +111,20 @@ bbb.mainToolbar.recordBtn..notification.message1 = Você pode gravar esta sessã
 bbb.mainToolbar.recordBtn..notification.message2 = Você precisa clicar no botão de Iniciar/Encerrar gravação na barra superior para começar/terminar a gravação.
 bbb.mainToolbar.recordingLabel.recording = (Gravando)
 bbb.mainToolbar.recordingLabel.notRecording = Não gravando
+bbb.waitWindow.waitMessage.message = Você é um convidado, por favor aguarde a aprovação do moderador da sessão.
+bbb.waitWindow.waitMessage.title = Aguardando
+bbb.guests.title = Convidados
+bbb.guests.message.singular = {0} usuário deseja entrar na sessão
+bbb.guests.message.plural = {0} usuários desejam entrar na sessão
+bbb.guests.allowBtn.toolTip = Permitir
+bbb.guests.allowEveryoneBtn.text = Permitir todos
+bbb.guests.denyBtn.toolTip = Rejeitar
+bbb.guests.denyEveryoneBtn.text = Rejeitar todos
+bbb.guests.rememberAction.text = Lembrar escolha
+bbb.guests.alwaysAccept = Sempre permitir
+bbb.guests.alwaysDeny = Sempre rejeitar
+bbb.guests.askModerator = Perguntar para o moderador
+bbb.guests.Management = Gerenciar convidados
 bbb.clientstatus.title = Configuração de Notificações
 bbb.clientstatus.notification = Notificações não lidas
 bbb.clientstatus.close = Fechar
@@ -166,26 +188,37 @@ bbb.users.usersGrid.mediaItemRenderer.webcam = Webcam sendo transmitida
 bbb.users.usersGrid.mediaItemRenderer.micOff = Microfone desativado
 bbb.users.usersGrid.mediaItemRenderer.micOn = Microfone ativado
 bbb.users.usersGrid.mediaItemRenderer.noAudio = Não está na conferência de voz
+bbb.users.usersGrid.mediaItemRenderer.promoteUser = Promover {0} para moderador
+bbb.users.usersGrid.mediaItemRenderer.demoteUser = Despromover {0} para participante
 bbb.users.emojiStatus.clear = Lmpar
 bbb.users.emojiStatus.clear.toolTip = Limpar status
 bbb.users.emojiStatus.close = Fechar
 bbb.users.emojiStatus.close.toolTip = Fechar popup de status
 bbb.users.emojiStatus.raiseHand = Levantar a mão
-bbb.users.emojiStatus.happy = Alegre
+bbb.users.emojiStatus.happy = :)
 bbb.users.emojiStatus.smile = Sorriso
-bbb.users.emojiStatus.sad = Triste
+bbb.users.emojiStatus.sad = :(
 bbb.users.emojiStatus.confused = Confuso
 bbb.users.emojiStatus.neutral = Neutro
 bbb.users.emojiStatus.away = Ausente
 bbb.users.emojiStatus.thumbsUp = Afirmativo
 bbb.users.emojiStatus.thumbsDown = Negativo
 bbb.users.emojiStatus.applause = Aplauso
+bbb.users.emojiStatus.agree = Concorda
+bbb.users.emojiStatus.disagree = Discorda
+bbb.users.emojiStatus.speakLouder = Fale mais alto
+bbb.users.emojiStatus.speakSofter = Fale mais baixo
+bbb.users.emojiStatus.speakFaster = Fale mais rápido
+bbb.users.emojiStatus.speakSlower = Fale mais devagar
+bbb.users.emojiStatus.beRightBack = Já volta
 bbb.presentation.title = Apresentação
 bbb.presentation.titleWithPres = Apresentação\: {0}
 bbb.presentation.quickLink.label = Janela de apresentação
 bbb.presentation.fitToWidth.toolTip = Ajustar apresentação à largura
 bbb.presentation.fitToPage.toolTip = Ajustar apresentação à página
 bbb.presentation.uploadPresBtn.toolTip = Carregar apresentação
+bbb.presentation.downloadPresBtn.toolTip = Baixar apresentação
+bbb.presentation.downloadPresBtn.disabledToolTip = Nenhuma apresentação disponível para download
 bbb.presentation.backBtn.toolTip = Slide anterior
 bbb.presentation.btnSlideNum.accessibilityName = Slide {0} de {1}
 bbb.presentation.btnSlideNum.toolTip = Selecionar um slide
@@ -195,7 +228,7 @@ bbb.presentation.uploadcomplete = Envio finalizado. Por favor, aguarde enquanto
 bbb.presentation.uploaded = carregado.
 bbb.presentation.document.supported = O documento carregado é suportado. Iniciando a conversão...
 bbb.presentation.document.converted = O documento foi convertido com sucesso.
-bbb.presentation.error.document.convert.failed = Erro\: Não foi possível converter o documento do Office
+bbb.presentation.error.document.convert.failed = Erro\: Falha ao converter o documento.
 bbb.presentation.error.io = Erro de entrada e saída\: Por favor, contate o administrador.
 bbb.presentation.error.security = Erro de segurança\: Por favor, contate o administrador.
 bbb.presentation.error.convert.notsupported = Erro\: O documento carregado não é suportado. Por favor, envie um arquivo compatível.
@@ -229,6 +262,13 @@ bbb.fileupload.okCancelBtn.toolTip = Fechar a caixa de diálogo para envio de ar
 bbb.fileupload.genThumbText = Gerando miniaturas dos slides...
 bbb.fileupload.progBarLbl = Progresso\:
 bbb.fileupload.fileFormatHint = Carregar qualquer documento Office ou arquivo PDF. Para melhores resultados, opte pelo PDF.
+bbb.fileupload.letUserDownload = Permitir que os usuários baixem esse arquivo
+bbb.fileupload.letUserDownload.tooltip = Clique aqui se você deseja permitir que os usuários baixem sua apresentação
+bbb.filedownload.title = Baixar apresentações
+bbb.filedownload.fileLbl = Escolha o arquivo que deseja baixar\:
+bbb.filedownload.downloadBtn = Baixar
+bbb.filedownload.downloadBtn.toolTip = Baixar arquivo
+bbb.filedownload.thisFileIsDownloadable = Os usuários podem baixar este arquivo
 bbb.chat.title = Bate-papo
 bbb.chat.quickLink.label = Janela de bate-papo
 bbb.chat.cmpColorPicker.toolTip = Cor do texto
@@ -237,6 +277,20 @@ bbb.chat.sendBtn = Enviar
 bbb.chat.sendBtn.toolTip = Enviar mensagem
 bbb.chat.sendBtn.accessibilityName = Enviar mensagem de bate-papo
 bbb.chat.contextmenu.copyalltext = Copiar todo o texto
+bbb.chat.saveBtn.toolTip = Salvar bate-papo
+bbb.chat.saveBtn.accessibilityName = Salvar bate-papo em arquivo texto
+bbb.chat.saveBtn.label = Salvar
+bbb.chat.save.complete = Bate-papo salvo com sucesso
+bbb.chat.save.filename = bate-papo-publico
+bbb.chat.copyBtn.toolTip = Copiar bate-papo
+bbb.chat.copyBtn.accessibilityName = Copiar bate-papo para a área de transferência
+bbb.chat.copyBtn.label = Copiar
+bbb.chat.copy.complete = Bate-papo copiado para a área de transferência
+bbb.chat.clearBtn.toolTip = Limpar bate-papo público
+bbb.chat.clearBtn.accessibilityName = Limpar conteúdo do histórico do Bate-papo público
+bbb.chat.clearBtn.chatMessage = O histórico de bate-papo público foi apagado por um moderador
+bbb.chat.clearBtn.alert.title = Atenção
+bbb.chat.clearBtn.alert.text = Você está limpando o histórico do bate-papo público e esta ação não pode ser desfeita. Deseja continuar?
 bbb.chat.publicChatUsername = Público
 bbb.chat.optionsTabName = Opções
 bbb.chat.privateChatSelect = Selecione uma pessoa para um bate-papo privado
@@ -345,11 +399,13 @@ bbb.toolbar.phone.toolTip.stop = Interromper transmissão do seu microfone
 bbb.toolbar.phone.toolTip.mute = Parar de escutar a conferência
 bbb.toolbar.phone.toolTip.unmute = Começar a escutar a conferência
 bbb.toolbar.phone.toolTip.nomic = Nenhum microfone detectado
-bbb.toolbar.deskshare.toolTip.start = Share Your Screen
-bbb.toolbar.deskshare.toolTip.stop = Stop Sharing Your Screen
+bbb.toolbar.deskshare.toolTip.start = Compartilhar sua tela
+bbb.toolbar.deskshare.toolTip.stop = Interromper compartilhamento da sua tela
 bbb.toolbar.video.toolTip.start = Transmitir sua câmera
 bbb.toolbar.video.toolTip.stop = Interromper compartilhamento da sua câmera
 bbb.layout.addButton.toolTip = Adicionar layout atual à lista
+bbb.layout.overwriteLayoutName.title = Sobrescrever layout
+bbb.layout.overwriteLayoutName.text = O nome já está em uso. Você quer sobrescrever?
 bbb.layout.broadcastButton.toolTip = Aplicar layout atual a todos os participantes
 bbb.layout.combo.toolTip = Modificar seu layout
 bbb.layout.loadButton.toolTip = Carregar layouts de um arquivo
@@ -359,9 +415,11 @@ bbb.layout.combo.prompt = Aplicar um layout
 bbb.layout.combo.custom = * Layout personalizado
 bbb.layout.combo.customName = Layout personalizado
 bbb.layout.combo.remote = Remoto
+bbb.layout.window.name = Nome do layout
 bbb.layout.save.complete = Layouts salvos com sucesso
 bbb.layout.load.complete = Layouts carregados com sucesso
-bbb.layout.load.failed = Não foi possível carregar os layouts
+bbb.layout.load.failed = Falha ao carregar layouts
+bbb.layout.sync = Seu layout foi enviado para todos os participantes
 bbb.layout.name.defaultlayout = Layout padrão
 bbb.layout.name.closedcaption = Closed Caption
 bbb.layout.name.videochat = Vídeo Chamada
@@ -369,6 +427,10 @@ bbb.layout.name.webcamsfocus = Reunião com câmeras
 bbb.layout.name.presentfocus = Reunião com apresentação
 bbb.layout.name.lectureassistant = Assistente de aula
 bbb.layout.name.lecture = Aula
+bbb.layout.addCurrentToFileWindow.title = Adicionar o layout atual ao arquivo
+bbb.layout.addCurrentToFileWindow.text = Você quer salvar o layout atual ao arquivo?
+bbb.layout.denyAddToFile.toolTip = Recusar inclusão do layout atual
+bbb.layout.confirmAddToFile.toolTip = Confirmar inclusão do layout atual
 bbb.highlighter.toolbar.pencil = Lápis
 bbb.highlighter.toolbar.pencil.accessibilityName = Mudar o cursor do quadro branco para lápis
 bbb.highlighter.toolbar.ellipse = Círculo
@@ -390,10 +452,15 @@ bbb.logout.button.label = OK
 bbb.logout.appshutdown = A aplicação no servidor foi interrompida
 bbb.logout.asyncerror = Um erro assíncrono ocorreu
 bbb.logout.connectionclosed = A conexão com o servidor foi fechada
-bbb.logout.connectionfailed = A conexão com o servidor foi encerrada
+bbb.logout.connectionfailed = A conexão com o servidor falhou
 bbb.logout.rejected = A conexão com o servidor foi rejeitada
 bbb.logout.invalidapp = O aplicativo red5 não existe
 bbb.logout.unknown = Seu cliente perdeu conexão com o servidor
+bbb.logout.guestkickedout = O moderador não permitiu sua entrada na sala
+bbb.settings.title = Configurações
+bbb.settings.ok = OK
+bbb.settings.cancel = Cancelar
+bbb.settings.btn.toolTip = Abrir janela de configurações
 bbb.logout.usercommand = Você saiu da conferência
 bbb.logour.breakoutRoomClose = A janela do navegador será fechada
 bbb.logout.ejectedFromMeeting = Um moderador expulsou você da sala.
@@ -401,12 +468,15 @@ bbb.logout.refresh.message = Se você foi desconectado de maneira inesperada, cl
 bbb.logout.refresh.label = Reconectar
 bbb.logout.confirm.title = Confirmação de saída
 bbb.logout.confirm.message = Você tem certeza que deseja sair da sessão?
+bbb.logout.confirm.endMeeting = Sim e encerrar a sessão
 bbb.logout.confirm.yes = Sim
 bbb.logout.confirm.no = Não
+bbb.endSession.confirm.title = Atenção
+bbb.endSession.confirm.message = Se você encerrar a sessão, todos os participantes serão desconectados. Deseja continuar?
 bbb.connection.failure=Problemas de conectividade detectados
 bbb.connection.reconnecting=Reconectando
 bbb.connection.reestablished=Conexão restabelecida
-bbb.connection.bigbluebutton=BigBlueButton
+bbb.connection.bigbluebutton=Principal
 bbb.connection.sip=SIP
 bbb.connection.video=Video
 bbb.connection.deskshare=Deskshare
@@ -414,6 +484,18 @@ bbb.notes.title = Notas
 bbb.notes.cmpColorPicker.toolTip = Cor do texto
 bbb.notes.saveBtn = Salvar
 bbb.notes.saveBtn.toolTip = Salvar nota
+bbb.sharedNotes.title = Notas compartilhadas
+bbb.sharedNotes.name = Nome da nota
+bbb.sharedNotes.save.toolTip = Salvar notas em arquivo
+bbb.sharedNotes.save.complete = Notas salvas com sucesso
+bbb.sharedNotes.save.htmlLabel = Texto formatado (.html)
+bbb.sharedNotes.save.txtLabel = Texto não formatado (.txt)
+bbb.sharedNotes.new.toolTip = Criar novas notas compartilhadas
+bbb.sharedNotes.undo.toolTip = Desfazer modificação
+bbb.sharedNotes.redo.toolTip = Refazer modificação
+bbb.sharedNotes.toolbar.toolTip = Barra de formatação de texto
+bbb.sharedNotes.additionalNotes.closeWarning.title = Fechando notas compartilhadas
+bbb.sharedNotes.additionalNotes.closeWarning.message = Esta ação irá destruir as notas desta janela para todos, e não haverá maneira de recuperá-las. Você tem certeza que deseja fechar estas notas?
 bbb.settings.deskshare.instructions = Clique em Permitir na janela que será aberta para verificar se o compartilhamento de tela está funcionando corretamente
 bbb.settings.deskshare.start = Verificar compartilhamento de tela
 bbb.settings.voice.volume = Atividade do microfone
@@ -427,6 +509,15 @@ bbb.settings.warning.label = Aviso
 bbb.settings.warning.close = Fechar esse aviso
 bbb.settings.noissues = Nenhum problema foi detectado.
 bbb.settings.instructions = Aceite a notificação do Flash quando ele requisitar permissão para acessar sua câmera. Se você consegue ver e ouvir a si mesmo, seu navegador foi configurado corretamente. Outros erros em potencial estão indicados abaixo. Verifique cada um para encontrar uma possível solução.
+bbb.bwmonitor.title = Monitor de rede
+bbb.bwmonitor.upload = Upload
+bbb.bwmonitor.upload.short = Up
+bbb.bwmonitor.download = Download
+bbb.bwmonitor.download.short = Down
+bbb.bwmonitor.total = Total
+bbb.bwmonitor.current = Atual
+bbb.bwmonitor.available = Disponível
+bbb.bwmonitor.latency = Latência
 ltbcustom.bbb.highlighter.toolbar.triangle = Triângulo
 ltbcustom.bbb.highlighter.toolbar.triangle.accessibilityName = Mudar o cursor do quadro branco para triângulo
 ltbcustom.bbb.highlighter.toolbar.line = Linha
@@ -668,3 +759,55 @@ bbb.users.roomsGrid.action = Ação
 bbb.users.roomsGrid.transfer = Trasferir Áudio
 bbb.users.roomsGrid.join = Entrar
 bbb.users.roomsGrid.noUsers = Nenhum usuário nesta sala
+
+bbb.langSelector.default=Idioma padrão
+bbb.langSelector.ar_SY=Árabe (Síria)
+bbb.langSelector.az_AZ=Azeri
+bbb.langSelector.eu_EU=Basco
+bbb.langSelector.bn_BN=Bengali
+bbb.langSelector.bg_BG=Búlgaro
+bbb.langSelector.ca_ES=Catalão
+bbb.langSelector.zh_CN=Chinês (Simplificado)
+bbb.langSelector.zh_TW=Chinês (Tradicional)
+bbb.langSelector.hr_HR=Croata
+bbb.langSelector.cs_CZ=Tcheco
+bbb.langSelector.da_DK=Dinamarquês
+bbb.langSelector.nl_NL=Holandês
+bbb.langSelector.en_US=Inglês
+bbb.langSelector.et_EE=Estoniano
+bbb.langSelector.fa_IR=Persa
+bbb.langSelector.fi_FI=Finlandês
+bbb.langSelector.fr_FR=Francês
+bbb.langSelector.fr_CA=Francês (Canadense)
+bbb.langSelector.ff_SN=Fula
+bbb.langSelector.de_DE=Alemão
+bbb.langSelector.el_GR=Grego
+bbb.langSelector.he_IL=Hebraico
+bbb.langSelector.hu_HU=Húngaro
+bbb.langSelector.id_ID=Indonésio
+bbb.langSelector.it_IT=Italiano
+bbb.langSelector.ja_JP=Japonês
+bbb.langSelector.ko_KR=Coreano
+bbb.langSelector.lv_LV=Letão
+bbb.langSelector.lt_LT=Lituano
+bbb.langSelector.mn_MN=Mongol
+bbb.langSelector.ne_NE=Nepali
+bbb.langSelector.no_NO=Norueguês
+bbb.langSelector.pl_PL=Polonês
+bbb.langSelector.pt_BR=Português (Brasileiro)
+bbb.langSelector.pt_PT=Português
+bbb.langSelector.ro_RO=Romeno
+bbb.langSelector.ru_RU=Russo
+bbb.langSelector.sr_SR=Sérvio (Cirílico)
+bbb.langSelector.sr_RS=Sérvio (Latino)
+bbb.langSelector.si_LK=Cingalês
+bbb.langSelector.sk_SK=Eslovaco
+bbb.langSelector.sl_SL=Esloveno
+bbb.langSelector.es_ES=Espanhol
+bbb.langSelector.es_LA=Espanhol (América Latina)
+bbb.langSelector.sv_SE=Sueco
+bbb.langSelector.th_TH=Tailandês
+bbb.langSelector.tr_TR=Turco
+bbb.langSelector.uk_UA=Ucraniano
+bbb.langSelector.vi_VN=Vietnamita
+bbb.langSelector.cy_GB=Galês
diff --git a/bigbluebutton-client/resources/config.xml.template b/bigbluebutton-client/resources/config.xml.template
index a161119e849d1415bca6a06f774c19b2ec927748..6c315e98d8427a186d9cec36f0e5910c1b4b5e49 100755
--- a/bigbluebutton-client/resources/config.xml.template
+++ b/bigbluebutton-client/resources/config.xml.template
@@ -9,11 +9,12 @@
     <application uri="rtmp://HOST/bigbluebutton" host="http://HOST/bigbluebutton/api/enter"/>
     <language userSelectionEnabled="true" />
     <skinning enabled="true" url="http://HOST/client/branding/css/BBBDefault.css.swf?v=VERSION" />
+    <branding logo="logo.png" copyright="&#169; 2016 &lt;u&gt;&lt;a href=&quot;http://www.mconf.org&quot; target=&quot;_blank&quot;&gt;http://www.mconf.org&lt;/a&gt;&lt;/u&gt;" background="" toolbarColor="" toolbarColorAlphas="" />
     <shortcutKeys showButton="true" />
     <browserVersions chrome="CHROME_VERSION" firefox="FIREFOX_VERSION" flash="FLASH_VERSION" java="1.7.0_51" />
     <layout showLogButton="false" defaultLayout="bbb.layout.name.defaultlayout"
             showToolbar="true" showFooter="true" showMeetingName="true" showHelpButton="true" 
-            showLogoutWindow="true" showLayoutTools="true" confirmLogout="true"
+            showLogoutWindow="true" showLayoutTools="true" confirmLogout="true" showNetworkMonitor="true"
             showRecordingNotification="true" logoutOnStopRecording="false"/>
     <meeting muteOnStart="false" />
     <breakoutRooms enabled="true" record="false" />
@@ -45,7 +46,7 @@
 		<module name="ScreenshareModule"
 			url="http://HOST/client/ScreenshareModule.swf?v=VERSION"
 			uri="rtmp://HOST/screenshare"
-			showButton="true"
+			showButton="false"
 			baseTabIndex="201"
 			tryWebRTCFirst="false"
 			chromeExtensionKey=""
@@ -56,6 +57,7 @@
 			uri="rtmp://HOST/sip" 
 			autoJoin="true"
 			listenOnlyMode="true"
+			forceListenOnly="false"
 			presenterShareOnly="false"
 			skipCheck="false"
 			showButton="true"
@@ -113,6 +115,7 @@
 			dependsOn="UsersModule"
 			baseTabIndex="501"
 			maxFileSize="30"
+			enableDownload="true"
 		/>
 		
 		<module name="CaptionModule" url="http://HOST/client/CaptionModule.swf?v=VERSION" 
@@ -125,7 +128,18 @@
 		<module name="LayoutModule" url="http://HOST/client/LayoutModule.swf?v=VERSION"
 			uri="rtmp://HOST/bigbluebutton"
 			layoutConfig="http://HOST/client/conf/layout.xml"
-			enableEdit="false"
+			enableEdit="true"
+		/>
+
+		<module name="SharedNotesModule" url="http://HOST/client/SharedNotesModule.swf?v=VERSION"
+			uri="rtmp://HOST/bigbluebutton"
+			refreshDelay="500"
+			enableMultipleNotes="true"
+			dependsOn="UsersModule"
+			position="bottom-left"
+			toolbarVisibleByDefault="false"
+			showToolbarButton="true"
+			fontSize="12"
 		/>
 
 <!--
diff --git a/bigbluebutton-client/resources/prod/BigBlueButton.html b/bigbluebutton-client/resources/prod/MconfLive.html
similarity index 97%
rename from bigbluebutton-client/resources/prod/BigBlueButton.html
rename to bigbluebutton-client/resources/prod/MconfLive.html
index f5ae92175c473d818f443e5ef2ce663534ccf56a..0707ddb5ae33d931806156bc5256a87922a9a2ac 100755
--- a/bigbluebutton-client/resources/prod/BigBlueButton.html
+++ b/bigbluebutton-client/resources/prod/MconfLive.html
@@ -45,6 +45,8 @@
       params.quality = "high";
       params.bgcolor = "#869ca7";
       params.allowfullscreen = "true";
+      params.allowfullscreeninteractive = "true";
+
       if (ffHangWorkaround()) {
         console.log("Applying Firefox Flash hang workaround");
 	// wmode = opaque causes button clicks to be sometimes unresponsive,
@@ -62,9 +64,9 @@
       attributes.name = "BigBlueButton";
       attributes.align = "middle";
       attributes.tabIndex = 0;
-      
-      // In Chrome 56 Google started blocking Flash by default so we force the SWF to 
-      // be loaded in the DOM rather than relying on the SWFObject code to detect 
+
+      // In Chrome 56 Google started blocking Flash by default so we force the SWF to
+      // be loaded in the DOM rather than relying on the SWFObject code to detect
       // Flash because it can't.
       var browserInfo = determineBrowser();
       if (browserInfo && browserInfo[0] === "Chrome") {
@@ -78,7 +80,7 @@
       } else {
         swfobject.embedSWF("BigBlueButton.swf?v=VERSION", "altFlash", "100%", "100%", "11.0.0", "expressInstall.swf", flashvars, params, attributes, embedCallback);
       }
-      
+
       function embedCallback(e) {
         // Work around pixel alignment bug with Chrome 21 on Mac.
         // See: http://code.google.com/p/bigbluebutton/issues/detail?id=1294
@@ -125,6 +127,8 @@
     <script src="lib/bbb_webrtc_bridge_sip.js?v=VERSION" language="javascript"></script>
     <script src="lib/weburl_regex.js?v=VERSION" language="javascript"></script>
     <script src="lib/jsnlog.min.js?v=VERSION" language="javascript"></script>
+    <script src="lib/diff_match_patch_uncompressed.js?v=VERSION" language="javascript"></script>
+    <script src="lib/shared_notes.js?v=VERSION" language="javascript"></script>
     <script>
       window.chatLinkClicked = function(url) {
         window.open(url, '_blank');
@@ -142,7 +146,7 @@
             document.getElementById('html5Section').style.display='inherit';
           }
         });
-        
+
         if (fillContent) fillContent();
       };
 
diff --git a/bigbluebutton-client/resources/prod/background.jpg b/bigbluebutton-client/resources/prod/background.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4e043c17469332492be05af752cd7dcb5233998f
Binary files /dev/null and b/bigbluebutton-client/resources/prod/background.jpg differ
diff --git a/bigbluebutton-client/resources/prod/bbb-deskshare-applet-0.9.0.jar b/bigbluebutton-client/resources/prod/bbb-deskshare-applet-0.9.0.jar
index 3bbf00894974a2d2d37b16d955af85ce935cc44a..58a3e02dee79bf6f4ef7414fe38a7bc1a728204b 100755
Binary files a/bigbluebutton-client/resources/prod/bbb-deskshare-applet-0.9.0.jar and b/bigbluebutton-client/resources/prod/bbb-deskshare-applet-0.9.0.jar differ
diff --git a/bigbluebutton-client/resources/prod/bbb-deskshare-applet-unsigned-0.9.0.jar b/bigbluebutton-client/resources/prod/bbb-deskshare-applet-unsigned-0.9.0.jar
index be5ab14479cd66ad96e9dbbbcadbd536174688c1..d9c083b6b23b969d9cd25206a4bfe96c08b7b2a0 100755
Binary files a/bigbluebutton-client/resources/prod/bbb-deskshare-applet-unsigned-0.9.0.jar and b/bigbluebutton-client/resources/prod/bbb-deskshare-applet-unsigned-0.9.0.jar differ
diff --git a/bigbluebutton-client/resources/prod/bbb.gif b/bigbluebutton-client/resources/prod/bbb.gif
index b01a452375a5213065dc237f34f22d97c3f69473..b532f3b80eef7306bf4f29ab3a9ad286c83c7c2e 100644
Binary files a/bigbluebutton-client/resources/prod/bbb.gif and b/bigbluebutton-client/resources/prod/bbb.gif differ
diff --git a/bigbluebutton-client/resources/prod/layout.xml b/bigbluebutton-client/resources/prod/layout.xml
index 5ef4afede5bd0eb81a15701245c8fe52b0375b06..99f5f748df630beed9bee969e55357edaf947240 100755
--- a/bigbluebutton-client/resources/prod/layout.xml
+++ b/bigbluebutton-client/resources/prod/layout.xml
@@ -1,126 +1,43 @@
 <?xml version="1.0"?>
 <layouts>
   <layout name="bbb.layout.name.defaultlayout" default="true">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="PresentationWindow" width="0.513" height="1" x="0.180" y="0" />
-    <window name="CaptionWindow" hidden="true" width="0.513" height="0.308" x="0.180" y="0.692" />
-    <window name="VideoDock" width="0.177" height="0.313" x="0" y="0.687" minWidth="280" />
-    <window name="ChatWindow" width="0.304" height="1" x="0.696" y="0" />
-    <window name="UsersWindow" width="0.177" height="0.679" x="0" y="0" minWidth="280" />
-  </layout>
-  <layout name="bbb.layout.name.closedcaption">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="PresentationWindow" width="0.513" height="0.684" x="0.180" y="0" />
-    <window name="CaptionWindow" width="0.513" height="0.308" x="0.180" y="0.692" />
-    <window name="VideoDock" width="0.177" height="0.308" x="0" y="0.687" minWidth="280" />
-    <window name="ChatWindow" width="0.304" height="1" x="0.696" y="0" />
-    <window name="UsersWindow" width="0.177" height="0.679" x="0" y="0" minWidth="280" />
+    <window name="VideoDock" minimized="false" maximized="false" hidden="false" width="0.2888030888030888" height="0.4113821138211382" minWidth="-1" x="0.7104247104247104" y="0.5804878048780487" order="2"/>
+    <window name="UsersWindow" minimized="false" maximized="false" hidden="false" width="0.21621621621621623" height="0.6780487804878049" minWidth="-1" x="0" y="0" order="3"/>
+    <window name="PresentationWindow" minimized="false" maximized="false" hidden="false" width="0.4888030888030888" height="0.9934959349593496" minWidth="-1" x="0.21853281853281853" y="0" order="1"/>
+      <window name="CaptionWindow" minimized="false" maximized="false" hidden="true" width="0.4888030888030888" height="0.3073170731707317" minWidth="-1" x="0.21853281853281853" y="0.6861788617886179" order="1"/>
+    <window name="SharedNotesWindow" minimized="false" maximized="false" hidden="false" width="0.21621621621621623" height="0.3073170731707317" minWidth="-1" x="0" y="0.6861788617886179" order="4"/>
+    <window name="ChatWindow" minimized="false" maximized="false" hidden="false" width="0.2888030888030888" height="0.5756097560975609" minWidth="-1" x="0.7104247104247104" y="0" order="0"/>
   </layout>
   <layout name="bbb.layout.name.videochat">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="VideoDock" width="1" height="1" x="0" y="0" order="0"/>
-    <window name="ChatWindow" width="0.303125" height="0.9955703211517165" x="0.3229166666666667" y="0.9656699889258029" order="4" hidden="true" />
-    <window name="PresentationWindow" minimized="true" order="1" hidden="true" />
-    <window name="UsersWindow" minimized="true" hidden="true" order="2"/>
-    <window name="CaptionWindow" hidden="true" width="0.513" height="0.308" x="0.180" y="0.692" />
+    <window name="VideoDock" minimized="false" maximized="true" hidden="false" width="0.2888030888030888" height="0.4113821138211382" minWidth="-1" x="0.7104247104247104" y="0.5804878048780487" order="0"/>
+    <window name="UsersWindow" minimized="true" maximized="false" hidden="false" width="0.21621621621621623" height="0.6780487804878049" minWidth="-1" x="0" y="0" order="2"/>
+    <window name="PresentationWindow" minimized="true" maximized="false" hidden="false" width="0.4888030888030888" height="0.9934959349593496" minWidth="-1" x="0.21853281853281853" y="0" order="3"/>
+    <window name="CaptionWindow" minimized="false" maximized="false" hidden="true" width="0.4888030888030888" height="0.3073170731707317" minWidth="-1" x="0.21853281853281853" y="0.6861788617886179" order="1"/>
+    <window name="SharedNotesWindow" minimized="true" maximized="false" hidden="false" width="0.21621621621621623" height="0.3073170731707317" minWidth="-1" x="0" y="0.6861788617886179" order="1"/>
+    <window name="ChatWindow" minimized="true" maximized="false" hidden="false" width="0.2888030888030888" height="0.5756097560975609" minWidth="-1" x="0.7104247104247104" y="0" order="4"/>
   </layout>
   <layout name="bbb.layout.name.webcamsfocus">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="VideoDock" width="0.6570188133140377" height="0.9960106382978723" x="0" y="0" />
-    <window name="ChatWindow" width="0.3393632416787265" height="0.5305851063829787" x="0.658465991316932" y="0" />
-    <window name="UsersWindow" hidden="true" />
-    <window name="PresentationWindow" width="0.34008683068017365" height="0.4601063829787234" x="0.658465991316932" y="0.535904255319149" />
-    <window name="CaptionWindow" hidden="true" width="0.513" height="0.308" x="0.180" y="0.692" />
+    <window name="VideoDock" minimized="false" maximized="false" hidden="false" width="0.6563706563706564" height="0.9951219512195122" minWidth="-1" x="0" y="0" order="2"/>
+    <window name="UsersWindow" minimized="true" maximized="false" hidden="false" width="0.21621621621621623" height="0.6780487804878049" minWidth="-1" x="0" y="0" order="2"/>
+    <window name="PresentationWindow" minimized="false" maximized="false" hidden="false" width="0.33976833976833976" height="0.4585365853658537" minWidth="-1" x="0.6579150579150579" y="0.5349593495934959" order="4"/>
+    <window name="CaptionWindow" minimized="false" maximized="false" hidden="true" width="0.4888030888030888" height="0.3073170731707317" minWidth="-1" x="0.21853281853281853" y="0.6861788617886179" order="1"/>
+    <window name="SharedNotesWindow" minimized="true" maximized="false" hidden="false" width="0.21621621621621623" height="0.3073170731707317" minWidth="-1" x="0" y="0.6861788617886179" order="1"/>
+    <window name="ChatWindow" minimized="false" maximized="false" hidden="false" width="0.338996138996139" height="0.5300813008130081" minWidth="-1" x="0.6579150579150579" y="0" order="0"/>
   </layout>
   <layout name="bbb.layout.name.presentfocus">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="UsersWindow" minimized="true" />
-    <window name="VideoDock" width="0.2923611111111111" height="0.4640957446808511" x="0.7048611111111112" y="0.535904255319149" />
-    <window name="PresentationWindow" width="0.7027777777777777" height="0.9986702127659575" x="0" y="0" />
-    <window name="ChatWindow" width="0.2923611111111111" height="0.5305851063829787" x="0.7048611111111112" y="0" />
-    <window name="CaptionWindow" hidden="true" width="0.513" height="0.308" x="0.180" y="0.692" />
-  </layout>
-  <layout name="bbb.layout.name.lectureassistant">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="ChatWindow" width="0.4597222222222222" height="0.9958677685950413" x="0.2263888888888889" y="0" />
-    <window name="UsersWindow" width="0.22152777777777777" height="0.9958677685950413" x="0" y="0" minWidth="280" />
-    <window name="PresentationWindow" width="0.3104166666666667" height="0.5537190082644629" x="0.6895833333333333" y="0" />
-    <window name="VideoDock" width="0.30972222222222223" height="0.4357198347107438" x="0.6902777777777778" y="0.558870523415978" />
-    <window name="CaptionWindow" hidden="true" width="0.513" height="0.308" x="0.180" y="0.692" />
-  </layout>	
-  <layout name="bbb.layout.name.lecture">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="UsersWindow" hidden="true" />
-    <window name="VideoDock" width="0.2923611111111111" height="0.4640957446808511" x="0.7048611111111112" y="0.535904255319149" />
-    <window name="PresentationWindow" width="0.7027777777777777" height="0.9986702127659575" x="0" y="0" />
-    <window name="ChatWindow" width="0.2923611111111111" height="0.5305851063829787" x="0.7048611111111112" y="0" />
-    <window name="CaptionWindow" hidden="true" width="0.513" height="0.308" x="0.180" y="0.692" />
-  </layout>	
-  <layout name="bbb.layout.name.lecture" role="presenter">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="ChatWindow" hidden="true" />
-    <window name="UsersWindow" hidden="true" />
-    <window name="PresentationWindow" maximized="true" />
-    <window name="VideoDock" hidden="true" />
-    <window name="CaptionWindow" hidden="true" width="0.513" height="0.308" x="0.180" y="0.692" />
-  </layout>	
-  <layout name="bbb.layout.name.lecture" role="moderator">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="ChatWindow" width="0.4597222222222222" height="0.9958677685950413" x="0.2263888888888889" y="0" />
-    <window name="UsersWindow" width="0.22152777777777777" height="0.9944903581267218" x="0" y="0" minWidth="280" />
-    <window name="PresentationWindow" width="0.3104166666666667" height="0.5537190082644629" x="0.6895833333333333" y="0" />
-    <window name="VideoDock" width="0.30972222222222223" height="0.4256198347107438" x="0.6902777777777778" y="0.568870523415978" />
-    <window name="CaptionWindow" hidden="true" width="0.513" height="0.308" x="0.180" y="0.692" />
-  </layout>	
-<!--
-  <layout name="Users">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="UsersWindow" width="0.1772793053545586" height="0.6795212765957446" x="0" y="0" />
-    <window name="PresentationWindow" width="0.5137481910274964" height="0.9946808510638298" x="0.18017366136034732" y="0" />
-    <window name="VideoDock" width="0.1772793053545586" height="0.30851063829787234" x="0" y="0.6875" />
-    <window name="ChatWindow" width="0.3031837916063676" height="0.9960106382978723" x="0.6968162083936325" y="0" />
-  </layout>
-  <layout name="S2SPresentation">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="ChatWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="UsersWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="PresentationWindow" width="0.8" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="VideoDock" hidden="true" draggable="false" resizable="false"/>
+    <window name="PresentationWindow" minimized="false" maximized="false" hidden="false" width="0.6563706563706564" height="0.9951219512195122" minWidth="-1" x="0" y="0" order="2"/>
+    <window name="CaptionWindow" minimized="false" maximized="false" hidden="true" width="0.4888030888030888" height="0.3073170731707317" minWidth="-1" x="0.21853281853281853" y="0.6861788617886179" order="1"/>
+    <window name="UsersWindow" minimized="true" maximized="false" hidden="false" width="0.21621621621621623" height="0.6780487804878049" minWidth="-1" x="0" y="0" order="2"/>
+    <window name="VideoDock" minimized="false" maximized="false" hidden="false" width="0.33976833976833976" height="0.4585365853658537" minWidth="-1" x="0.6579150579150579" y="0.5349593495934959" order="4"/>
+    <window name="SharedNotesWindow" minimized="true" maximized="false" hidden="false" width="0.21621621621621623" height="0.3073170731707317" minWidth="-1" x="0" y="0.6861788617886179" order="1"/>
+    <window name="ChatWindow" minimized="false" maximized="false" hidden="false" width="0.338996138996139" height="0.5300813008130081" minWidth="-1" x="0.6579150579150579" y="0" order="0"/>
   </layout>
-  <layout name="S2SVideoChat">
-    <window name="NotesWindow" hidden="true" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="UsersWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="VideoDock" width="1" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="ChatWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="PresentationWindow" hidden="true" draggable="false" resizable="false"/>
-  </layout>
-    <layout name="Notes">
-    <window name="NotesWindow" hidden="false" width="0.7" height="0.4" x="0" y="0.6" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="false" width="0.7" height="0.6" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="UsersWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="VideoDock" hidden="true" draggable="false" resizable="false"/>
-    <window name="ChatWindow" width="0.3" height="1" x="0.7" y="0" draggable="false" resizable="false"/>
-    <window name="PresentationWindow" hidden="true" draggable="false" resizable="false"/>
-  </layout>
-  <layout name="Broadcast">
-    <window name="NotesWindow" hidden="false" width="0.7" height="1" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="BroadcastWindow" hidden="false" width="0.7" height="0.9" x="0" y="0" draggable="false" resizable="false"/>
-    <window name="UsersWindow" hidden="true" draggable="false" resizable="false"/>
-    <window name="VideoDock" hidden="true" draggable="false" resizable="false"/>
-    <window name="ChatWindow" width="0.3" height="1" x="0.7" y="0" draggable="false" resizable="false"/>
-    <window name="PresentationWindow" hidden="true" draggable="false" resizable="false"/>
+  <layout name="bbb.layout.name.closedcaption">
+    <window name="VideoDock" minimized="false" maximized="false" hidden="false" width="0.2888030888030888" height="0.4113821138211382" minWidth="-1" x="0.7104247104247104" y="0.5804878048780487" order="2"/>
+    <window name="UsersWindow" minimized="false" maximized="false" hidden="false" width="0.21621621621621623" height="0.6780487804878049" minWidth="-1" x="0" y="0" order="3"/>
+    <window name="PresentationWindow" minimized="false" maximized="false" hidden="false" width="0.4888030888030888" height="0.6780487804878049" minWidth="-1" x="0.21853281853281853" y="0" order="1"/>
+    <window name="CaptionWindow" minimized="false" maximized="false" hidden="false" width="0.4888030888030888" height="0.3073170731707317" minWidth="-1" x="0.21853281853281853" y="0.6861788617886179" order="1"/>
+    <window name="SharedNotesWindow" minimized="false" maximized="false" hidden="false" width="0.21621621621621623" height="0.3073170731707317" minWidth="-1" x="0" y="0.6861788617886179" order="4"/>
+    <window name="ChatWindow" minimized="false" maximized="false" hidden="false" width="0.2888030888030888" height="0.5756097560975609" minWidth="-1" x="0.7104247104247104" y="0" order="0"/>
   </layout>
--->
 </layouts>
diff --git a/bigbluebutton-client/resources/prod/lib/bbb_api_bridge.js b/bigbluebutton-client/resources/prod/lib/bbb_api_bridge.js
index c3e8e668fe30e5d62e2d8a0204efed89338cf41d..b1f247602a5e8b61198c8aff742f7bb4329d9211 100755
--- a/bigbluebutton-client/resources/prod/lib/bbb_api_bridge.js
+++ b/bigbluebutton-client/resources/prod/lib/bbb_api_bridge.js
@@ -435,6 +435,10 @@
      *
      */
      
+    BBB.webRTCCallSucceeded = function() {
+      // do nothing on this callback
+    }
+
     BBB.webRTCCallStarted = function(inEchoTest) {
       var swfObj = getSwfObj();
       if (swfObj) {
diff --git a/bigbluebutton-client/resources/prod/lib/bbb_blinker.js b/bigbluebutton-client/resources/prod/lib/bbb_blinker.js
index 1eb2bc24632649fca521c878144bfd91a287b40e..ec3e3221e9197af2b9595667581761cc2a8525aa 100755
--- a/bigbluebutton-client/resources/prod/lib/bbb_blinker.js
+++ b/bigbluebutton-client/resources/prod/lib/bbb_blinker.js
@@ -1,5 +1,5 @@
 function setTitle(title){
-    document.title= "BigBlueButton - " + title;
+    document.title= title;
 }
 
 function clientReady(message){
diff --git a/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js b/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js
index 066aeedadfddd641e3b4e87d6f2e7ef780d0f747..5288ff3e4820b6d68442fbb24cbd3c4434cdac55 100755
--- a/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js
+++ b/bigbluebutton-client/resources/prod/lib/bbb_webrtc_bridge_sip.js
@@ -5,6 +5,9 @@ var html5StunTurn = {};
 
 function webRTCCallback(message) {
 	switch (message.status) {
+		case 'succeded':
+			BBB.webRTCCallSucceeded();
+			break;
 		case 'failed':
 			if (message.errorcode !== 1004) {
 				message.cause = null;
@@ -186,13 +189,19 @@ function createUA(username, server, callback, makeCallFunc) {
 function createUAWithStuns(username, server, callback, stunsConfig, makeCallFunc) {
 	console.log("Creating new user agent");
 
+	var wsServer;
+	if (window.location.protocol == 'https:') {
+		wsServer = 'wss://' + server + '/wss';
+	} else {
+		wsServer = 'ws://' + server + '/ws';
+	}
 	/* VERY IMPORTANT 
 	 *	- You must escape the username because spaces will cause the connection to fail
 	 *	- We are connecting to the websocket through an nginx redirect instead of directly to 5066
 	 */
 	var configuration = {
 		uri: 'sip:' + encodeURIComponent(username) + '@' + server,
-		wsServers: 'ws://' + server + '/ws',
+		wsServers: wsServer,
 		displayName: username,
 		register: false,
 		traceSip: true,
@@ -214,6 +223,7 @@ function setUserAgentListeners(callback, makeCallFunc) {
 	userAgent.removeAllListeners('connected');
 	userAgent.on('connected', function() {
 		uaConnected = true;
+		callback({'status':'succeded'});
 		makeCallFunc();
 	});
 	userAgent.removeAllListeners('disconnected');
@@ -462,6 +472,17 @@ function make_call(username, voiceBridge, server, callback, recall, isListenOnly
 			console.log('bye event already received');
 		}
 	});
+	currentSession.on('cancel', function(request) {
+		callActive = false;
+
+		if (currentSession) {
+			console.log('call canceled');
+			clearTimeout(callTimeout);
+			currentSession = null;
+		} else {
+			console.log('cancel event already received');
+		}
+	});
 	currentSession.on('accepted', function(data){
 		callActive = true;
 		console.log('BigBlueButton call accepted');
@@ -472,7 +493,7 @@ function make_call(username, voiceBridge, server, callback, recall, isListenOnly
 			callback({'status':'waitingforice'});
 			console.log('Waiting for ICE negotiation');
 			iceConnectedTimeout = setTimeout(function() {
-				console.log('60 seconds without ICE finishing');
+				console.log('5 seconds without ICE finishing');
 				callback({'status':'failed', 'errorcode': 1010}); // ICE negotiation timeout
 				currentSession = null;
 				if (userAgent != null) {
@@ -480,7 +501,7 @@ function make_call(username, voiceBridge, server, callback, recall, isListenOnly
 					userAgent = null;
 					userAgentTemp.stop();
 				}
-			}, 60000);
+			}, 5000);
 		}
 		clearTimeout(callTimeout);
 	});
@@ -532,7 +553,12 @@ function webrtc_hangup(callback) {
 	if (callback) {
 	  currentSession.on('bye', callback);
 	}
-	currentSession.bye();
+	try {
+		currentSession.bye();
+	} catch (err) {
+		console.log("Forcing to cancel current session");
+		currentSession.cancel();
+	}
 }
 
 function isWebRTCAvailable() {
diff --git a/bigbluebutton-client/resources/prod/lib/diff_match_patch_uncompressed.js b/bigbluebutton-client/resources/prod/lib/diff_match_patch_uncompressed.js
new file mode 100644
index 0000000000000000000000000000000000000000..bee148ba34f265566d8ca30c6856712f83a35213
--- /dev/null
+++ b/bigbluebutton-client/resources/prod/lib/diff_match_patch_uncompressed.js
@@ -0,0 +1,2274 @@
+/**
+ * Diff Match and Patch
+ *
+ * Copyright 2006 Google Inc.
+ * http://code.google.com/p/google-diff-match-patch/
+ *
+ * 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.
+ */
+
+/**
+ * @fileoverview Computes the difference between two texts to create a patch.
+ * Applies the patch onto another text, allowing for errors.
+ * @author fraser@google.com (Neil Fraser)
+ */
+
+/**
+ * Modified by Islam El-Ashi <ielashi@gmail.com>
+ *  - Added unpatching support
+ */
+
+/**
+ * Class containing the diff, match and patch methods.
+ * @constructor
+ */
+function diff_match_patch() {
+
+  // Defaults.
+  // Redefine these in your program to override the defaults.
+
+  // Number of seconds to map a diff before giving up (0 for infinity).
+  this.Diff_Timeout = 1.0;
+  // Cost of an empty edit operation in terms of edit characters.
+  this.Diff_EditCost = 4;
+  // At what point is no match declared (0.0 = perfection, 1.0 = very loose).
+  this.Match_Threshold = 0.5;
+  // How far to search for a match (0 = exact location, 1000+ = broad match).
+  // A match this many characters away from the expected location will add
+  // 1.0 to the score (0.0 is a perfect match).
+  this.Match_Distance = 1000;
+  // When deleting a large block of text (over ~64 characters), how close does
+  // the contents have to match the expected contents. (0.0 = perfection,
+  // 1.0 = very loose).  Note that Match_Threshold controls how closely the
+  // end points of a delete need to match.
+  this.Patch_DeleteThreshold = 0.5;
+  // Chunk size for context length.
+  this.Patch_Margin = 4;
+
+  // The number of bits in an int.
+  this.Match_MaxBits = 32;
+}
+
+
+//  DIFF FUNCTIONS
+
+
+/**
+ * The data structure representing a diff is an array of tuples:
+ * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
+ * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
+ */
+var DIFF_DELETE = -1;
+var DIFF_INSERT = 1;
+var DIFF_EQUAL = 0;
+
+/** @typedef {!Array.<number|string>} */
+diff_match_patch.Diff;
+
+
+/**
+ * Find the differences between two texts.  Simplifies the problem by stripping
+ * any common prefix or suffix off the texts before diffing.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {boolean=} opt_checklines Optional speedup flag. If present and false,
+ *     then don't run a line-level diff first to identify the changed areas.
+ *     Defaults to true, which does a faster, slightly less optimal diff.
+ * @param {number} opt_deadline Optional time when the diff should be complete
+ *     by.  Used internally for recursive calls.  Users should set DiffTimeout
+ *     instead.
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
+ */
+diff_match_patch.prototype.diff_main = function(text1, text2, opt_checklines,
+    opt_deadline) {
+  // Set a deadline by which time the diff must be complete.
+  if (typeof opt_deadline == 'undefined') {
+    if (this.Diff_Timeout <= 0) {
+      opt_deadline = Number.MAX_VALUE;
+    } else {
+      opt_deadline = (new Date).getTime() + this.Diff_Timeout * 1000;
+    }
+  }
+  var deadline = opt_deadline;
+
+  // Check for null inputs.
+  if (text1 == null || text2 == null) {
+    throw new Error('Null input. (diff_main)');
+  }
+
+  // Check for equality (speedup).
+  if (text1 == text2) {
+    if (text1) {
+      return [[DIFF_EQUAL, text1]];
+    }
+    return [];
+  }
+
+  if (typeof opt_checklines == 'undefined') {
+    opt_checklines = true;
+  }
+  var checklines = opt_checklines;
+
+  // Trim off common prefix (speedup).
+  var commonlength = this.diff_commonPrefix(text1, text2);
+  var commonprefix = text1.substring(0, commonlength);
+  text1 = text1.substring(commonlength);
+  text2 = text2.substring(commonlength);
+
+  // Trim off common suffix (speedup).
+  commonlength = this.diff_commonSuffix(text1, text2);
+  var commonsuffix = text1.substring(text1.length - commonlength);
+  text1 = text1.substring(0, text1.length - commonlength);
+  text2 = text2.substring(0, text2.length - commonlength);
+
+  // Compute the diff on the middle block.
+  var diffs = this.diff_compute_(text1, text2, checklines, deadline);
+
+  // Restore the prefix and suffix.
+  if (commonprefix) {
+    diffs.unshift([DIFF_EQUAL, commonprefix]);
+  }
+  if (commonsuffix) {
+    diffs.push([DIFF_EQUAL, commonsuffix]);
+  }
+  this.diff_cleanupMerge(diffs);
+  return diffs;
+};
+
+
+/**
+ * Find the differences between two texts.  Assumes that the texts do not
+ * have any common prefix or suffix.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {boolean} checklines Speedup flag.  If false, then don't run a
+ *     line-level diff first to identify the changed areas.
+ *     If true, then run a faster, slightly less optimal diff.
+ * @param {number} deadline Time when the diff should be complete by.
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
+ * @private
+ */
+diff_match_patch.prototype.diff_compute_ = function(text1, text2, checklines,
+    deadline) {
+  var diffs;
+
+  if (!text1) {
+    // Just add some text (speedup).
+    return [[DIFF_INSERT, text2]];
+  }
+
+  if (!text2) {
+    // Just delete some text (speedup).
+    return [[DIFF_DELETE, text1]];
+  }
+
+  var longtext = text1.length > text2.length ? text1 : text2;
+  var shorttext = text1.length > text2.length ? text2 : text1;
+  var i = longtext.indexOf(shorttext);
+  if (i != -1) {
+    // Shorter text is inside the longer text (speedup).
+    diffs = [[DIFF_INSERT, longtext.substring(0, i)],
+             [DIFF_EQUAL, shorttext],
+             [DIFF_INSERT, longtext.substring(i + shorttext.length)]];
+    // Swap insertions for deletions if diff is reversed.
+    if (text1.length > text2.length) {
+      diffs[0][0] = diffs[2][0] = DIFF_DELETE;
+    }
+    return diffs;
+  }
+
+  if (shorttext.length == 1) {
+    // Single character string.
+    // After the previous speedup, the character can't be an equality.
+    return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
+  }
+  longtext = shorttext = null;  // Garbage collect.
+
+  // Check to see if the problem can be split in two.
+  var hm = this.diff_halfMatch_(text1, text2);
+  if (hm) {
+    // A half-match was found, sort out the return data.
+    var text1_a = hm[0];
+    var text1_b = hm[1];
+    var text2_a = hm[2];
+    var text2_b = hm[3];
+    var mid_common = hm[4];
+    // Send both pairs off for separate processing.
+    var diffs_a = this.diff_main(text1_a, text2_a, checklines, deadline);
+    var diffs_b = this.diff_main(text1_b, text2_b, checklines, deadline);
+    // Merge the results.
+    return diffs_a.concat([[DIFF_EQUAL, mid_common]], diffs_b);
+  }
+
+  if (checklines && text1.length > 100 && text2.length > 100) {
+    return this.diff_lineMode_(text1, text2, deadline);
+  }
+
+  return this.diff_bisect_(text1, text2, deadline);
+};
+
+
+/**
+ * Do a quick line-level diff on both strings, then rediff the parts for
+ * greater accuracy.
+ * This speedup can produce non-minimal diffs.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {number} deadline Time when the diff should be complete by.
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
+ * @private
+ */
+diff_match_patch.prototype.diff_lineMode_ = function(text1, text2, deadline) {
+  // Scan the text on a line-by-line basis first.
+  var a = this.diff_linesToChars_(text1, text2);
+  text1 = /** @type {string} */(a[0]);
+  text2 = /** @type {string} */(a[1]);
+  var linearray = /** @type {!Array.<string>} */(a[2]);
+
+  var diffs = this.diff_bisect_(text1, text2, deadline);
+
+  // Convert the diff back to original text.
+  this.diff_charsToLines_(diffs, linearray);
+  // Eliminate freak matches (e.g. blank lines)
+  this.diff_cleanupSemantic(diffs);
+
+  // Rediff any replacement blocks, this time character-by-character.
+  // Add a dummy entry at the end.
+  diffs.push([DIFF_EQUAL, '']);
+  var pointer = 0;
+  var count_delete = 0;
+  var count_insert = 0;
+  var text_delete = '';
+  var text_insert = '';
+  while (pointer < diffs.length) {
+    switch (diffs[pointer][0]) {
+      case DIFF_INSERT:
+        count_insert++;
+        text_insert += diffs[pointer][1];
+        break;
+      case DIFF_DELETE:
+        count_delete++;
+        text_delete += diffs[pointer][1];
+        break;
+      case DIFF_EQUAL:
+        // Upon reaching an equality, check for prior redundancies.
+        if (count_delete >= 1 && count_insert >= 1) {
+          // Delete the offending records and add the merged ones.
+          var a = this.diff_main(text_delete, text_insert, false, deadline);
+          diffs.splice(pointer - count_delete - count_insert,
+                       count_delete + count_insert);
+          pointer = pointer - count_delete - count_insert;
+          for (var j = a.length - 1; j >= 0; j--) {
+            diffs.splice(pointer, 0, a[j]);
+          }
+          pointer = pointer + a.length;
+        }
+        count_insert = 0;
+        count_delete = 0;
+        text_delete = '';
+        text_insert = '';
+        break;
+    }
+    pointer++;
+  }
+  diffs.pop();  // Remove the dummy entry at the end.
+
+  return diffs;
+};
+
+
+/**
+ * Find the 'middle snake' of a diff, split the problem in two
+ * and return the recursively constructed diff.
+ * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {number} deadline Time at which to bail if not yet complete.
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
+ * @private
+ */
+diff_match_patch.prototype.diff_bisect_ = function(text1, text2, deadline) {
+  // Cache the text lengths to prevent multiple calls.
+  var text1_length = text1.length;
+  var text2_length = text2.length;
+  var max_d = Math.ceil((text1_length + text2_length) / 2);
+  var v_offset = max_d;
+  var v_length = 2 * max_d;
+  var v1 = new Array(v_length);
+  var v2 = new Array(v_length);
+  // Setting all elements to -1 is faster in Chrome & Firefox than mixing
+  // integers and undefined.
+  for (var x = 0; x < v_length; x++) {
+    v1[x] = -1;
+    v2[x] = -1;
+  }
+  v1[v_offset + 1] = 0;
+  v2[v_offset + 1] = 0;
+  var delta = text1_length - text2_length;
+  // If the total number of characters is odd, then the front path will collide
+  // with the reverse path.
+  var front = (delta % 2 != 0);
+  // Offsets for start and end of k loop.
+  // Prevents mapping of space beyond the grid.
+  var k1start = 0;
+  var k1end = 0;
+  var k2start = 0;
+  var k2end = 0;
+  for (var d = 0; d < max_d; d++) {
+    // Bail out if deadline is reached.
+    if ((new Date()).getTime() > deadline) {
+      break;
+    }
+
+    // Walk the front path one step.
+    for (var k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
+      var k1_offset = v_offset + k1;
+      var x1;
+      if (k1 == -d || k1 != d && v1[k1_offset - 1] < v1[k1_offset + 1]) {
+        x1 = v1[k1_offset + 1];
+      } else {
+        x1 = v1[k1_offset - 1] + 1;
+      }
+      var y1 = x1 - k1;
+      while (x1 < text1_length && y1 < text2_length &&
+             text1.charAt(x1) == text2.charAt(y1)) {
+        x1++;
+        y1++;
+      }
+      v1[k1_offset] = x1;
+      if (x1 > text1_length) {
+        // Ran off the right of the graph.
+        k1end += 2;
+      } else if (y1 > text2_length) {
+        // Ran off the bottom of the graph.
+        k1start += 2;
+      } else if (front) {
+        var k2_offset = v_offset + delta - k1;
+        if (k2_offset >= 0 && k2_offset < v_length && v2[k2_offset] != -1) {
+          // Mirror x2 onto top-left coordinate system.
+          var x2 = text1_length - v2[k2_offset];
+          if (x1 >= x2) {
+            // Overlap detected.
+            return this.diff_bisectSplit_(text1, text2, x1, y1, deadline);
+          }
+        }
+      }
+    }
+
+    // Walk the reverse path one step.
+    for (var k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
+      var k2_offset = v_offset + k2;
+      var x2;
+      if (k2 == -d || k2 != d && v2[k2_offset - 1] < v2[k2_offset + 1]) {
+        x2 = v2[k2_offset + 1];
+      } else {
+        x2 = v2[k2_offset - 1] + 1;
+      }
+      var y2 = x2 - k2;
+      while (x2 < text1_length && y2 < text2_length &&
+             text1.charAt(text1_length - x2 - 1) ==
+             text2.charAt(text2_length - y2 - 1)) {
+        x2++;
+        y2++;
+      }
+      v2[k2_offset] = x2;
+      if (x2 > text1_length) {
+        // Ran off the left of the graph.
+        k2end += 2;
+      } else if (y2 > text2_length) {
+        // Ran off the top of the graph.
+        k2start += 2;
+      } else if (!front) {
+        var k1_offset = v_offset + delta - k2;
+        if (k1_offset >= 0 && k1_offset < v_length && v1[k1_offset] != -1) {
+          var x1 = v1[k1_offset];
+          var y1 = v_offset + x1 - k1_offset;
+          // Mirror x2 onto top-left coordinate system.
+          x2 = text1_length - x2;
+          if (x1 >= x2) {
+            // Overlap detected.
+            return this.diff_bisectSplit_(text1, text2, x1, y1, deadline);
+          }
+        }
+      }
+    }
+  }
+  // Diff took too long and hit the deadline or
+  // number of diffs equals number of characters, no commonality at all.
+  return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
+};
+
+
+/**
+ * Given the location of the 'middle snake', split the diff in two parts
+ * and recurse.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {number} x Index of split point in text1.
+ * @param {number} y Index of split point in text2.
+ * @param {number} deadline Time at which to bail if not yet complete.
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
+ * @private
+ */
+diff_match_patch.prototype.diff_bisectSplit_ = function(text1, text2, x, y,
+    deadline) {
+  var text1a = text1.substring(0, x);
+  var text2a = text2.substring(0, y);
+  var text1b = text1.substring(x);
+  var text2b = text2.substring(y);
+
+  // Compute both diffs serially.
+  var diffs = this.diff_main(text1a, text2a, false, deadline);
+  var diffsb = this.diff_main(text1b, text2b, false, deadline);
+
+  return diffs.concat(diffsb);
+};
+
+
+/**
+ * Split two texts into an array of strings.  Reduce the texts to a string of
+ * hashes where each Unicode character represents one line.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {!Array.<string|!Array.<string>>} Three element Array, containing the
+ *     encoded text1, the encoded text2 and the array of unique strings.  The
+ *     zeroth element of the array of unique strings is intentionally blank.
+ * @private
+ */
+diff_match_patch.prototype.diff_linesToChars_ = function(text1, text2) {
+  var lineArray = [];  // e.g. lineArray[4] == 'Hello\n'
+  var lineHash = {};   // e.g. lineHash['Hello\n'] == 4
+
+  // '\x00' is a valid character, but various debuggers don't like it.
+  // So we'll insert a junk entry to avoid generating a null character.
+  lineArray[0] = '';
+
+  /**
+   * Split a text into an array of strings.  Reduce the texts to a string of
+   * hashes where each Unicode character represents one line.
+   * Modifies linearray and linehash through being a closure.
+   * @param {string} text String to encode.
+   * @return {string} Encoded string.
+   * @private
+   */
+  function diff_linesToCharsMunge_(text) {
+    var chars = '';
+    // Walk the text, pulling out a substring for each line.
+    // text.split('\n') would would temporarily double our memory footprint.
+    // Modifying text would create many large strings to garbage collect.
+    var lineStart = 0;
+    var lineEnd = -1;
+    // Keeping our own length variable is faster than looking it up.
+    var lineArrayLength = lineArray.length;
+    while (lineEnd < text.length - 1) {
+      lineEnd = text.indexOf('\n', lineStart);
+      if (lineEnd == -1) {
+        lineEnd = text.length - 1;
+      }
+      var line = text.substring(lineStart, lineEnd + 1);
+      lineStart = lineEnd + 1;
+
+      if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) :
+          (lineHash[line] !== undefined)) {
+        chars += String.fromCharCode(lineHash[line]);
+      } else {
+        chars += String.fromCharCode(lineArrayLength);
+        lineHash[line] = lineArrayLength;
+        lineArray[lineArrayLength++] = line;
+      }
+    }
+    return chars;
+  }
+
+  var chars1 = diff_linesToCharsMunge_(text1);
+  var chars2 = diff_linesToCharsMunge_(text2);
+  return [chars1, chars2, lineArray];
+};
+
+
+/**
+ * Rehydrate the text in a diff from a string of line hashes to real lines of
+ * text.
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ * @param {!Array.<string>} lineArray Array of unique strings.
+ * @private
+ */
+diff_match_patch.prototype.diff_charsToLines_ = function(diffs, lineArray) {
+  for (var x = 0; x < diffs.length; x++) {
+    var chars = diffs[x][1];
+    var text = [];
+    for (var y = 0; y < chars.length; y++) {
+      text[y] = lineArray[chars.charCodeAt(y)];
+    }
+    diffs[x][1] = text.join('');
+  }
+};
+
+
+/**
+ * Determine the common prefix of two strings.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the start of each
+ *     string.
+ */
+diff_match_patch.prototype.diff_commonPrefix = function(text1, text2) {
+  // Quick check for common null cases.
+  if (!text1 || !text2 || text1.charAt(0) != text2.charAt(0)) {
+    return 0;
+  }
+  // Binary search.
+  // Performance analysis: http://neil.fraser.name/news/2007/10/09/
+  var pointermin = 0;
+  var pointermax = Math.min(text1.length, text2.length);
+  var pointermid = pointermax;
+  var pointerstart = 0;
+  while (pointermin < pointermid) {
+    if (text1.substring(pointerstart, pointermid) ==
+        text2.substring(pointerstart, pointermid)) {
+      pointermin = pointermid;
+      pointerstart = pointermin;
+    } else {
+      pointermax = pointermid;
+    }
+    pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
+  }
+  return pointermid;
+};
+
+
+/**
+ * Determine the common suffix of two strings.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the end of each string.
+ */
+diff_match_patch.prototype.diff_commonSuffix = function(text1, text2) {
+  // Quick check for common null cases.
+  if (!text1 || !text2 ||
+      text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) {
+    return 0;
+  }
+  // Binary search.
+  // Performance analysis: http://neil.fraser.name/news/2007/10/09/
+  var pointermin = 0;
+  var pointermax = Math.min(text1.length, text2.length);
+  var pointermid = pointermax;
+  var pointerend = 0;
+  while (pointermin < pointermid) {
+    if (text1.substring(text1.length - pointermid, text1.length - pointerend) ==
+        text2.substring(text2.length - pointermid, text2.length - pointerend)) {
+      pointermin = pointermid;
+      pointerend = pointermin;
+    } else {
+      pointermax = pointermid;
+    }
+    pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
+  }
+  return pointermid;
+};
+
+
+/**
+ * Determine if the suffix of one string is the prefix of another.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the end of the first
+ *     string and the start of the second string.
+ * @private
+ */
+diff_match_patch.prototype.diff_commonOverlap_ = function(text1, text2) {
+  // Cache the text lengths to prevent multiple calls.
+  var text1_length = text1.length;
+  var text2_length = text2.length;
+  // Eliminate the null case.
+  if (text1_length == 0 || text2_length == 0) {
+    return 0;
+  }
+  // Truncate the longer string.
+  if (text1_length > text2_length) {
+    text1 = text1.substring(text1_length - text2_length);
+  } else if (text1_length < text2_length) {
+    text2 = text2.substring(0, text1_length);
+  }
+  var text_length = Math.min(text1_length, text2_length);
+  // Quick check for the worst case.
+  if (text1 == text2) {
+    return text_length;
+  }
+
+  // Start by looking for a single character match
+  // and increase length until no match is found.
+  // Performance analysis: http://neil.fraser.name/news/2010/11/04/
+  var best = 0;
+  var length = 1;
+  while (true) {
+    var pattern = text1.substring(text_length - length);
+    var found = text2.indexOf(pattern);
+    if (found == -1) {
+      return best;
+    }
+    length += found;
+    if (found == 0 || text1.substring(text_length - length) ==
+        text2.substring(0, length)) {
+      best = length;
+      length++;
+    }
+  }
+};
+
+
+/**
+ * Do the two texts share a substring which is at least half the length of the
+ * longer text?
+ * This speedup can produce non-minimal diffs.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {Array.<string>} Five element Array, containing the prefix of
+ *     text1, the suffix of text1, the prefix of text2, the suffix of
+ *     text2 and the common middle.  Or null if there was no match.
+ * @private
+ */
+diff_match_patch.prototype.diff_halfMatch_ = function(text1, text2) {
+  if (this.Diff_Timeout <= 0) {
+    // Don't risk returning a non-optimal diff if we have unlimited time.
+    return null;
+  }
+  var longtext = text1.length > text2.length ? text1 : text2;
+  var shorttext = text1.length > text2.length ? text2 : text1;
+  if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {
+    return null;  // Pointless.
+  }
+  var dmp = this;  // 'this' becomes 'window' in a closure.
+
+  /**
+   * Does a substring of shorttext exist within longtext such that the substring
+   * is at least half the length of longtext?
+   * Closure, but does not reference any external variables.
+   * @param {string} longtext Longer string.
+   * @param {string} shorttext Shorter string.
+   * @param {number} i Start index of quarter length substring within longtext.
+   * @return {Array.<string>} Five element Array, containing the prefix of
+   *     longtext, the suffix of longtext, the prefix of shorttext, the suffix
+   *     of shorttext and the common middle.  Or null if there was no match.
+   * @private
+   */
+  function diff_halfMatchI_(longtext, shorttext, i) {
+    // Start with a 1/4 length substring at position i as a seed.
+    var seed = longtext.substring(i, i + Math.floor(longtext.length / 4));
+    var j = -1;
+    var best_common = '';
+    var best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b;
+    while ((j = shorttext.indexOf(seed, j + 1)) != -1) {
+      var prefixLength = dmp.diff_commonPrefix(longtext.substring(i),
+                                               shorttext.substring(j));
+      var suffixLength = dmp.diff_commonSuffix(longtext.substring(0, i),
+                                               shorttext.substring(0, j));
+      if (best_common.length < suffixLength + prefixLength) {
+        best_common = shorttext.substring(j - suffixLength, j) +
+            shorttext.substring(j, j + prefixLength);
+        best_longtext_a = longtext.substring(0, i - suffixLength);
+        best_longtext_b = longtext.substring(i + prefixLength);
+        best_shorttext_a = shorttext.substring(0, j - suffixLength);
+        best_shorttext_b = shorttext.substring(j + prefixLength);
+      }
+    }
+    if (best_common.length * 2 >= longtext.length) {
+      return [best_longtext_a, best_longtext_b,
+              best_shorttext_a, best_shorttext_b, best_common];
+    } else {
+      return null;
+    }
+  }
+
+  // First check if the second quarter is the seed for a half-match.
+  var hm1 = diff_halfMatchI_(longtext, shorttext,
+                             Math.ceil(longtext.length / 4));
+  // Check again based on the third quarter.
+  var hm2 = diff_halfMatchI_(longtext, shorttext,
+                             Math.ceil(longtext.length / 2));
+  var hm;
+  if (!hm1 && !hm2) {
+    return null;
+  } else if (!hm2) {
+    hm = hm1;
+  } else if (!hm1) {
+    hm = hm2;
+  } else {
+    // Both matched.  Select the longest.
+    hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
+  }
+
+  // A half-match was found, sort out the return data.
+  var text1_a, text1_b, text2_a, text2_b;
+  if (text1.length > text2.length) {
+    text1_a = hm[0];
+    text1_b = hm[1];
+    text2_a = hm[2];
+    text2_b = hm[3];
+  } else {
+    text2_a = hm[0];
+    text2_b = hm[1];
+    text1_a = hm[2];
+    text1_b = hm[3];
+  }
+  var mid_common = hm[4];
+  return [text1_a, text1_b, text2_a, text2_b, mid_common];
+};
+
+
+/**
+ * Reduce the number of edits by eliminating semantically trivial equalities.
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ */
+diff_match_patch.prototype.diff_cleanupSemantic = function(diffs) {
+  var changes = false;
+  var equalities = [];  // Stack of indices where equalities are found.
+  var equalitiesLength = 0;  // Keeping our own length var is faster in JS.
+  /** @type {?string} */
+  var lastequality = null;  // Always equal to equalities[equalitiesLength-1][1]
+  var pointer = 0;  // Index of current position.
+  // Number of characters that changed prior to the equality.
+  var length_insertions1 = 0;
+  var length_deletions1 = 0;
+  // Number of characters that changed after the equality.
+  var length_insertions2 = 0;
+  var length_deletions2 = 0;
+  while (pointer < diffs.length) {
+    if (diffs[pointer][0] == DIFF_EQUAL) {  // Equality found.
+      equalities[equalitiesLength++] = pointer;
+      length_insertions1 = length_insertions2;
+      length_deletions1 = length_deletions2;
+      length_insertions2 = 0;
+      length_deletions2 = 0;
+      lastequality = /** @type {string} */(diffs[pointer][1]);
+    } else {  // An insertion or deletion.
+      if (diffs[pointer][0] == DIFF_INSERT) {
+        length_insertions2 += diffs[pointer][1].length;
+      } else {
+        length_deletions2 += diffs[pointer][1].length;
+      }
+      // Eliminate an equality that is smaller or equal to the edits on both
+      // sides of it.
+      if (lastequality !== null && (lastequality.length <=
+          Math.max(length_insertions1, length_deletions1)) &&
+          (lastequality.length <= Math.max(length_insertions2,
+                                           length_deletions2))) {
+        // Duplicate record.
+        diffs.splice(equalities[equalitiesLength - 1], 0,
+                     [DIFF_DELETE, lastequality]);
+        // Change second copy to insert.
+        diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
+        // Throw away the equality we just deleted.
+        equalitiesLength--;
+        // Throw away the previous equality (it needs to be reevaluated).
+        equalitiesLength--;
+        pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
+        length_insertions1 = 0;  // Reset the counters.
+        length_deletions1 = 0;
+        length_insertions2 = 0;
+        length_deletions2 = 0;
+        lastequality = null;
+        changes = true;
+      }
+    }
+    pointer++;
+  }
+
+  // Normalize the diff.
+  if (changes) {
+    this.diff_cleanupMerge(diffs);
+  }
+  this.diff_cleanupSemanticLossless(diffs);
+
+  // Find any overlaps between deletions and insertions.
+  // e.g: <del>abcxxx</del><ins>xxxdef</ins>
+  //   -> <del>abc</del>xxx<ins>def</ins>
+  // Only extract an overlap if it is as big as the edit ahead or behind it.
+  pointer = 1;
+  while (pointer < diffs.length) {
+    if (diffs[pointer - 1][0] == DIFF_DELETE &&
+        diffs[pointer][0] == DIFF_INSERT) {
+      var deletion = /** @type {string} */(diffs[pointer - 1][1]);
+      var insertion = /** @type {string} */(diffs[pointer][1]);
+      var overlap_length = this.diff_commonOverlap_(deletion, insertion);
+      if (overlap_length >= deletion.length / 2 ||
+          overlap_length >= insertion.length / 2) {
+        // Overlap found.  Insert an equality and trim the surrounding edits.
+        diffs.splice(pointer, 0,
+            [DIFF_EQUAL, insertion.substring(0, overlap_length)]);
+        diffs[pointer - 1][1] =
+            deletion.substring(0, deletion.length - overlap_length);
+        diffs[pointer + 1][1] = insertion.substring(overlap_length);
+        pointer++;
+      }
+      pointer++;
+    }
+    pointer++;
+  }
+};
+
+
+/**
+ * Look for single edits surrounded on both sides by equalities
+ * which can be shifted sideways to align the edit to a word boundary.
+ * e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ */
+diff_match_patch.prototype.diff_cleanupSemanticLossless = function(diffs) {
+  // Define some regex patterns for matching boundaries.
+  var punctuation = /[^a-zA-Z0-9]/;
+  var whitespace = /\s/;
+  var linebreak = /[\r\n]/;
+  var blanklineEnd = /\n\r?\n$/;
+  var blanklineStart = /^\r?\n\r?\n/;
+
+  /**
+   * Given two strings, compute a score representing whether the internal
+   * boundary falls on logical boundaries.
+   * Scores range from 5 (best) to 0 (worst).
+   * Closure, makes reference to regex patterns defined above.
+   * @param {string} one First string.
+   * @param {string} two Second string.
+   * @return {number} The score.
+   * @private
+   */
+  function diff_cleanupSemanticScore_(one, two) {
+    if (!one || !two) {
+      // Edges are the best.
+      return 5;
+    }
+
+    // Each port of this function behaves slightly differently due to
+    // subtle differences in each language's definition of things like
+    // 'whitespace'.  Since this function's purpose is largely cosmetic,
+    // the choice has been made to use each language's native features
+    // rather than force total conformity.
+    var score = 0;
+    // One point for non-alphanumeric.
+    if (one.charAt(one.length - 1).match(punctuation) ||
+        two.charAt(0).match(punctuation)) {
+      score++;
+      // Two points for whitespace.
+      if (one.charAt(one.length - 1).match(whitespace) ||
+          two.charAt(0).match(whitespace)) {
+        score++;
+        // Three points for line breaks.
+        if (one.charAt(one.length - 1).match(linebreak) ||
+            two.charAt(0).match(linebreak)) {
+          score++;
+          // Four points for blank lines.
+          if (one.match(blanklineEnd) || two.match(blanklineStart)) {
+            score++;
+          }
+        }
+      }
+    }
+    return score;
+  }
+
+  var pointer = 1;
+  // Intentionally ignore the first and last element (don't need checking).
+  while (pointer < diffs.length - 1) {
+    if (diffs[pointer - 1][0] == DIFF_EQUAL &&
+        diffs[pointer + 1][0] == DIFF_EQUAL) {
+      // This is a single edit surrounded by equalities.
+      var equality1 = /** @type {string} */(diffs[pointer - 1][1]);
+      var edit = /** @type {string} */(diffs[pointer][1]);
+      var equality2 = /** @type {string} */(diffs[pointer + 1][1]);
+
+      // First, shift the edit as far left as possible.
+      var commonOffset = this.diff_commonSuffix(equality1, edit);
+      if (commonOffset) {
+        var commonString = edit.substring(edit.length - commonOffset);
+        equality1 = equality1.substring(0, equality1.length - commonOffset);
+        edit = commonString + edit.substring(0, edit.length - commonOffset);
+        equality2 = commonString + equality2;
+      }
+
+      // Second, step character by character right, looking for the best fit.
+      var bestEquality1 = equality1;
+      var bestEdit = edit;
+      var bestEquality2 = equality2;
+      var bestScore = diff_cleanupSemanticScore_(equality1, edit) +
+          diff_cleanupSemanticScore_(edit, equality2);
+      while (edit.charAt(0) === equality2.charAt(0)) {
+        equality1 += edit.charAt(0);
+        edit = edit.substring(1) + equality2.charAt(0);
+        equality2 = equality2.substring(1);
+        var score = diff_cleanupSemanticScore_(equality1, edit) +
+            diff_cleanupSemanticScore_(edit, equality2);
+        // The >= encourages trailing rather than leading whitespace on edits.
+        if (score >= bestScore) {
+          bestScore = score;
+          bestEquality1 = equality1;
+          bestEdit = edit;
+          bestEquality2 = equality2;
+        }
+      }
+
+      if (diffs[pointer - 1][1] != bestEquality1) {
+        // We have an improvement, save it back to the diff.
+        if (bestEquality1) {
+          diffs[pointer - 1][1] = bestEquality1;
+        } else {
+          diffs.splice(pointer - 1, 1);
+          pointer--;
+        }
+        diffs[pointer][1] = bestEdit;
+        if (bestEquality2) {
+          diffs[pointer + 1][1] = bestEquality2;
+        } else {
+          diffs.splice(pointer + 1, 1);
+          pointer--;
+        }
+      }
+    }
+    pointer++;
+  }
+};
+
+
+/**
+ * Reduce the number of edits by eliminating operationally trivial equalities.
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ */
+diff_match_patch.prototype.diff_cleanupEfficiency = function(diffs) {
+  var changes = false;
+  var equalities = [];  // Stack of indices where equalities are found.
+  var equalitiesLength = 0;  // Keeping our own length var is faster in JS.
+  var lastequality = '';  // Always equal to equalities[equalitiesLength-1][1]
+  var pointer = 0;  // Index of current position.
+  // Is there an insertion operation before the last equality.
+  var pre_ins = false;
+  // Is there a deletion operation before the last equality.
+  var pre_del = false;
+  // Is there an insertion operation after the last equality.
+  var post_ins = false;
+  // Is there a deletion operation after the last equality.
+  var post_del = false;
+  while (pointer < diffs.length) {
+    if (diffs[pointer][0] == DIFF_EQUAL) {  // Equality found.
+      if (diffs[pointer][1].length < this.Diff_EditCost &&
+          (post_ins || post_del)) {
+        // Candidate found.
+        equalities[equalitiesLength++] = pointer;
+        pre_ins = post_ins;
+        pre_del = post_del;
+        lastequality = diffs[pointer][1];
+      } else {
+        // Not a candidate, and can never become one.
+        equalitiesLength = 0;
+        lastequality = '';
+      }
+      post_ins = post_del = false;
+    } else {  // An insertion or deletion.
+      if (diffs[pointer][0] == DIFF_DELETE) {
+        post_del = true;
+      } else {
+        post_ins = true;
+      }
+      /*
+       * Five types to be split:
+       * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
+       * <ins>A</ins>X<ins>C</ins><del>D</del>
+       * <ins>A</ins><del>B</del>X<ins>C</ins>
+       * <ins>A</del>X<ins>C</ins><del>D</del>
+       * <ins>A</ins><del>B</del>X<del>C</del>
+       */
+      if (lastequality && ((pre_ins && pre_del && post_ins && post_del) ||
+                           ((lastequality.length < this.Diff_EditCost / 2) &&
+                            (pre_ins + pre_del + post_ins + post_del) == 3))) {
+        // Duplicate record.
+        diffs.splice(equalities[equalitiesLength - 1], 0,
+                     [DIFF_DELETE, lastequality]);
+        // Change second copy to insert.
+        diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
+        equalitiesLength--;  // Throw away the equality we just deleted;
+        lastequality = '';
+        if (pre_ins && pre_del) {
+          // No changes made which could affect previous entry, keep going.
+          post_ins = post_del = true;
+          equalitiesLength = 0;
+        } else {
+          equalitiesLength--;  // Throw away the previous equality.
+          pointer = equalitiesLength > 0 ?
+              equalities[equalitiesLength - 1] : -1;
+          post_ins = post_del = false;
+        }
+        changes = true;
+      }
+    }
+    pointer++;
+  }
+
+  if (changes) {
+    this.diff_cleanupMerge(diffs);
+  }
+};
+
+
+/**
+ * Reorder and merge like edit sections.  Merge equalities.
+ * Any edit section can move as long as it doesn't cross an equality.
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ */
+diff_match_patch.prototype.diff_cleanupMerge = function(diffs) {
+  diffs.push([DIFF_EQUAL, '']);  // Add a dummy entry at the end.
+  var pointer = 0;
+  var count_delete = 0;
+  var count_insert = 0;
+  var text_delete = '';
+  var text_insert = '';
+  var commonlength;
+  while (pointer < diffs.length) {
+    switch (diffs[pointer][0]) {
+      case DIFF_INSERT:
+        count_insert++;
+        text_insert += diffs[pointer][1];
+        pointer++;
+        break;
+      case DIFF_DELETE:
+        count_delete++;
+        text_delete += diffs[pointer][1];
+        pointer++;
+        break;
+      case DIFF_EQUAL:
+        // Upon reaching an equality, check for prior redundancies.
+        if (count_delete + count_insert > 1) {
+          if (count_delete !== 0 && count_insert !== 0) {
+            // Factor out any common prefixies.
+            commonlength = this.diff_commonPrefix(text_insert, text_delete);
+            if (commonlength !== 0) {
+              if ((pointer - count_delete - count_insert) > 0 &&
+                  diffs[pointer - count_delete - count_insert - 1][0] ==
+                  DIFF_EQUAL) {
+                diffs[pointer - count_delete - count_insert - 1][1] +=
+                    text_insert.substring(0, commonlength);
+              } else {
+                diffs.splice(0, 0, [DIFF_EQUAL,
+                                    text_insert.substring(0, commonlength)]);
+                pointer++;
+              }
+              text_insert = text_insert.substring(commonlength);
+              text_delete = text_delete.substring(commonlength);
+            }
+            // Factor out any common suffixies.
+            commonlength = this.diff_commonSuffix(text_insert, text_delete);
+            if (commonlength !== 0) {
+              diffs[pointer][1] = text_insert.substring(text_insert.length -
+                  commonlength) + diffs[pointer][1];
+              text_insert = text_insert.substring(0, text_insert.length -
+                  commonlength);
+              text_delete = text_delete.substring(0, text_delete.length -
+                  commonlength);
+            }
+          }
+          // Delete the offending records and add the merged ones.
+          if (count_delete === 0) {
+            diffs.splice(pointer - count_delete - count_insert,
+                count_delete + count_insert, [DIFF_INSERT, text_insert]);
+          } else if (count_insert === 0) {
+            diffs.splice(pointer - count_delete - count_insert,
+                count_delete + count_insert, [DIFF_DELETE, text_delete]);
+          } else {
+            diffs.splice(pointer - count_delete - count_insert,
+                count_delete + count_insert, [DIFF_DELETE, text_delete],
+                [DIFF_INSERT, text_insert]);
+          }
+          pointer = pointer - count_delete - count_insert +
+                    (count_delete ? 1 : 0) + (count_insert ? 1 : 0) + 1;
+        } else if (pointer !== 0 && diffs[pointer - 1][0] == DIFF_EQUAL) {
+          // Merge this equality with the previous one.
+          diffs[pointer - 1][1] += diffs[pointer][1];
+          diffs.splice(pointer, 1);
+        } else {
+          pointer++;
+        }
+        count_insert = 0;
+        count_delete = 0;
+        text_delete = '';
+        text_insert = '';
+        break;
+    }
+  }
+  if (diffs[diffs.length - 1][1] === '') {
+    diffs.pop();  // Remove the dummy entry at the end.
+  }
+
+  // Second pass: look for single edits surrounded on both sides by equalities
+  // which can be shifted sideways to eliminate an equality.
+  // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
+  var changes = false;
+  pointer = 1;
+  // Intentionally ignore the first and last element (don't need checking).
+  while (pointer < diffs.length - 1) {
+    if (diffs[pointer - 1][0] == DIFF_EQUAL &&
+        diffs[pointer + 1][0] == DIFF_EQUAL) {
+      // This is a single edit surrounded by equalities.
+      if (diffs[pointer][1].substring(diffs[pointer][1].length -
+          diffs[pointer - 1][1].length) == diffs[pointer - 1][1]) {
+        // Shift the edit over the previous equality.
+        diffs[pointer][1] = diffs[pointer - 1][1] +
+            diffs[pointer][1].substring(0, diffs[pointer][1].length -
+                                        diffs[pointer - 1][1].length);
+        diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
+        diffs.splice(pointer - 1, 1);
+        changes = true;
+      } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) ==
+          diffs[pointer + 1][1]) {
+        // Shift the edit over the next equality.
+        diffs[pointer - 1][1] += diffs[pointer + 1][1];
+        diffs[pointer][1] =
+            diffs[pointer][1].substring(diffs[pointer + 1][1].length) +
+            diffs[pointer + 1][1];
+        diffs.splice(pointer + 1, 1);
+        changes = true;
+      }
+    }
+    pointer++;
+  }
+  // If shifts were made, the diff needs reordering and another shift sweep.
+  if (changes) {
+    this.diff_cleanupMerge(diffs);
+  }
+};
+
+
+/**
+ * loc is a location in text1, compute and return the equivalent location in
+ * text2.
+ * e.g. 'The cat' vs 'The big cat', 1->1, 5->8
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ * @param {number} loc Location within text1.
+ * @return {number} Location within text2.
+ */
+diff_match_patch.prototype.diff_xIndex = function(diffs, loc) {
+  var chars1 = 0;
+  var chars2 = 0;
+  var last_chars1 = 0;
+  var last_chars2 = 0;
+  var x;
+  for (x = 0; x < diffs.length; x++) {
+    if (diffs[x][0] !== DIFF_INSERT) {  // Equality or deletion.
+      chars1 += diffs[x][1].length;
+    }
+    if (diffs[x][0] !== DIFF_DELETE) {  // Equality or insertion.
+      chars2 += diffs[x][1].length;
+    }
+    if (chars1 > loc) {  // Overshot the location.
+      break;
+    }
+    last_chars1 = chars1;
+    last_chars2 = chars2;
+  }
+  // Was the location was deleted?
+  if (diffs.length != x && diffs[x][0] === DIFF_DELETE) {
+    return last_chars2;
+  }
+  // Add the remaining character length.
+  return last_chars2 + (loc - last_chars1);
+};
+
+
+/**
+ * Convert a diff array into a pretty HTML report.
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ * @return {string} HTML representation.
+ */
+diff_match_patch.prototype.diff_prettyHtml = function(diffs) {
+  var html = [];
+  var i = 0;
+  var pattern_amp = /&/g;
+  var pattern_lt = /</g;
+  var pattern_gt = />/g;
+  var pattern_para = /\n/g;
+  for (var x = 0; x < diffs.length; x++) {
+    var op = diffs[x][0];    // Operation (insert, delete, equal)
+    var data = diffs[x][1];  // Text of change.
+    var text = data.replace(pattern_amp, '&amp;').replace(pattern_lt, '&lt;')
+        .replace(pattern_gt, '&gt;').replace(pattern_para, '&para;<br>');
+    switch (op) {
+      case DIFF_INSERT:
+        html[x] = '<ins style="background:#e6ffe6;">' + text + '</ins>';
+        break;
+      case DIFF_DELETE:
+        html[x] = '<del style="background:#ffe6e6;">' + text + '</del>';
+        break;
+      case DIFF_EQUAL:
+        html[x] = '<span>' + text + '</span>';
+        break;
+    }
+    if (op !== DIFF_DELETE) {
+      i += data.length;
+    }
+  }
+  return html.join('');
+};
+
+
+/**
+ * Compute and return the source text (all equalities and deletions).
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ * @return {string} Source text.
+ */
+diff_match_patch.prototype.diff_text1 = function(diffs) {
+  var text = [];
+  for (var x = 0; x < diffs.length; x++) {
+    if (diffs[x][0] !== DIFF_INSERT) {
+      text[x] = diffs[x][1];
+    }
+  }
+  return text.join('');
+};
+
+
+/**
+ * Compute and return the destination text (all equalities and insertions).
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ * @return {string} Destination text.
+ */
+diff_match_patch.prototype.diff_text2 = function(diffs) {
+  var text = [];
+  for (var x = 0; x < diffs.length; x++) {
+    if (diffs[x][0] !== DIFF_DELETE) {
+      text[x] = diffs[x][1];
+    }
+  }
+  return text.join('');
+};
+
+
+/**
+ * Compute the Levenshtein distance; the number of inserted, deleted or
+ * substituted characters.
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ * @return {number} Number of changes.
+ */
+diff_match_patch.prototype.diff_levenshtein = function(diffs) {
+  var levenshtein = 0;
+  var insertions = 0;
+  var deletions = 0;
+  for (var x = 0; x < diffs.length; x++) {
+    var op = diffs[x][0];
+    var data = diffs[x][1];
+    switch (op) {
+      case DIFF_INSERT:
+        insertions += data.length;
+        break;
+      case DIFF_DELETE:
+        deletions += data.length;
+        break;
+      case DIFF_EQUAL:
+        // A deletion and an insertion is one substitution.
+        levenshtein += Math.max(insertions, deletions);
+        insertions = 0;
+        deletions = 0;
+        break;
+    }
+  }
+  levenshtein += Math.max(insertions, deletions);
+  return levenshtein;
+};
+
+
+/**
+ * Crush the diff into an encoded string which describes the operations
+ * required to transform text1 into text2.
+ * E.g. =3\t-2\t+ing  -> Keep 3 chars, delete 2 chars, insert 'ing'.
+ * Operations are tab-separated.  Inserted text is escaped using %xx notation.
+ * @param {!Array.<!diff_match_patch.Diff>} diffs Array of diff tuples.
+ * @return {string} Delta text.
+ */
+diff_match_patch.prototype.diff_toDelta = function(diffs) {
+  var text = [];
+  for (var x = 0; x < diffs.length; x++) {
+    switch (diffs[x][0]) {
+      case DIFF_INSERT:
+        text[x] = '+' + encodeURI(diffs[x][1]);
+        break;
+      case DIFF_DELETE:
+        text[x] = '-' + diffs[x][1].length;
+        break;
+      case DIFF_EQUAL:
+        text[x] = '=' + diffs[x][1].length;
+        break;
+    }
+  }
+  return text.join('\t').replace(/%20/g, ' ');
+};
+
+
+/**
+ * Given the original text1, and an encoded string which describes the
+ * operations required to transform text1 into text2, compute the full diff.
+ * @param {string} text1 Source string for the diff.
+ * @param {string} delta Delta text.
+ * @return {!Array.<!diff_match_patch.Diff>} Array of diff tuples.
+ * @throws {!Error} If invalid input.
+ */
+diff_match_patch.prototype.diff_fromDelta = function(text1, delta) {
+  var diffs = [];
+  var diffsLength = 0;  // Keeping our own length var is faster in JS.
+  var pointer = 0;  // Cursor in text1
+  var tokens = delta.split(/\t/g);
+  for (var x = 0; x < tokens.length; x++) {
+    // Each token begins with a one character parameter which specifies the
+    // operation of this token (delete, insert, equality).
+    var param = tokens[x].substring(1);
+    switch (tokens[x].charAt(0)) {
+      case '+':
+        try {
+          diffs[diffsLength++] = [DIFF_INSERT, decodeURI(param)];
+        } catch (ex) {
+          // Malformed URI sequence.
+          throw new Error('Illegal escape in diff_fromDelta: ' + param);
+        }
+        break;
+      case '-':
+        // Fall through.
+      case '=':
+        var n = parseInt(param, 10);
+        if (isNaN(n) || n < 0) {
+          throw new Error('Invalid number in diff_fromDelta: ' + param);
+        }
+        var text = text1.substring(pointer, pointer += n);
+        if (tokens[x].charAt(0) == '=') {
+          diffs[diffsLength++] = [DIFF_EQUAL, text];
+        } else {
+          diffs[diffsLength++] = [DIFF_DELETE, text];
+        }
+        break;
+      default:
+        // Blank tokens are ok (from a trailing \t).
+        // Anything else is an error.
+        if (tokens[x]) {
+          throw new Error('Invalid diff operation in diff_fromDelta: ' +
+                          tokens[x]);
+        }
+    }
+  }
+  if (pointer != text1.length) {
+    throw new Error('Delta length (' + pointer +
+        ') does not equal source text length (' + text1.length + ').');
+  }
+  return diffs;
+};
+
+
+//  MATCH FUNCTIONS
+
+
+/**
+ * Locate the best instance of 'pattern' in 'text' near 'loc'.
+ * @param {string} text The text to search.
+ * @param {string} pattern The pattern to search for.
+ * @param {number} loc The location to search around.
+ * @return {number} Best match index or -1.
+ */
+diff_match_patch.prototype.match_main = function(text, pattern, loc) {
+  // Check for null inputs.
+  if (text == null || pattern == null || loc == null) {
+    throw new Error('Null input. (match_main)');
+  }
+
+  loc = Math.max(0, Math.min(loc, text.length));
+  if (text == pattern) {
+    // Shortcut (potentially not guaranteed by the algorithm)
+    return 0;
+  } else if (!text.length) {
+    // Nothing to match.
+    return -1;
+  } else if (text.substring(loc, loc + pattern.length) == pattern) {
+    // Perfect match at the perfect spot!  (Includes case of null pattern)
+    return loc;
+  } else {
+    // Do a fuzzy compare.
+    return this.match_bitap_(text, pattern, loc);
+  }
+};
+
+
+/**
+ * Locate the best instance of 'pattern' in 'text' near 'loc' using the
+ * Bitap algorithm.
+ * @param {string} text The text to search.
+ * @param {string} pattern The pattern to search for.
+ * @param {number} loc The location to search around.
+ * @return {number} Best match index or -1.
+ * @private
+ */
+diff_match_patch.prototype.match_bitap_ = function(text, pattern, loc) {
+  if (pattern.length > this.Match_MaxBits) {
+    throw new Error('Pattern too long for this browser.');
+  }
+
+  // Initialise the alphabet.
+  var s = this.match_alphabet_(pattern);
+
+  var dmp = this;  // 'this' becomes 'window' in a closure.
+
+  /**
+   * Compute and return the score for a match with e errors and x location.
+   * Accesses loc and pattern through being a closure.
+   * @param {number} e Number of errors in match.
+   * @param {number} x Location of match.
+   * @return {number} Overall score for match (0.0 = good, 1.0 = bad).
+   * @private
+   */
+  function match_bitapScore_(e, x) {
+    var accuracy = e / pattern.length;
+    var proximity = Math.abs(loc - x);
+    if (!dmp.Match_Distance) {
+      // Dodge divide by zero error.
+      return proximity ? 1.0 : accuracy;
+    }
+    return accuracy + (proximity / dmp.Match_Distance);
+  }
+
+  // Highest score beyond which we give up.
+  var score_threshold = this.Match_Threshold;
+  // Is there a nearby exact match? (speedup)
+  var best_loc = text.indexOf(pattern, loc);
+  if (best_loc != -1) {
+    score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold);
+    // What about in the other direction? (speedup)
+    best_loc = text.lastIndexOf(pattern, loc + pattern.length);
+    if (best_loc != -1) {
+      score_threshold =
+          Math.min(match_bitapScore_(0, best_loc), score_threshold);
+    }
+  }
+
+  // Initialise the bit arrays.
+  var matchmask = 1 << (pattern.length - 1);
+  best_loc = -1;
+
+  var bin_min, bin_mid;
+  var bin_max = pattern.length + text.length;
+  var last_rd;
+  for (var d = 0; d < pattern.length; d++) {
+    // Scan for the best match; each iteration allows for one more error.
+    // Run a binary search to determine how far from 'loc' we can stray at this
+    // error level.
+    bin_min = 0;
+    bin_mid = bin_max;
+    while (bin_min < bin_mid) {
+      if (match_bitapScore_(d, loc + bin_mid) <= score_threshold) {
+        bin_min = bin_mid;
+      } else {
+        bin_max = bin_mid;
+      }
+      bin_mid = Math.floor((bin_max - bin_min) / 2 + bin_min);
+    }
+    // Use the result from this iteration as the maximum for the next.
+    bin_max = bin_mid;
+    var start = Math.max(1, loc - bin_mid + 1);
+    var finish = Math.min(loc + bin_mid, text.length) + pattern.length;
+
+    var rd = Array(finish + 2);
+    rd[finish + 1] = (1 << d) - 1;
+    for (var j = finish; j >= start; j--) {
+      // The alphabet (s) is a sparse hash, so the following line generates
+      // warnings.
+      var charMatch = s[text.charAt(j - 1)];
+      if (d === 0) {  // First pass: exact match.
+        rd[j] = ((rd[j + 1] << 1) | 1) & charMatch;
+      } else {  // Subsequent passes: fuzzy match.
+        rd[j] = ((rd[j + 1] << 1) | 1) & charMatch |
+                (((last_rd[j + 1] | last_rd[j]) << 1) | 1) |
+                last_rd[j + 1];
+      }
+      if (rd[j] & matchmask) {
+        var score = match_bitapScore_(d, j - 1);
+        // This match will almost certainly be better than any existing match.
+        // But check anyway.
+        if (score <= score_threshold) {
+          // Told you so.
+          score_threshold = score;
+          best_loc = j - 1;
+          if (best_loc > loc) {
+            // When passing loc, don't exceed our current distance from loc.
+            start = Math.max(1, 2 * loc - best_loc);
+          } else {
+            // Already passed loc, downhill from here on in.
+            break;
+          }
+        }
+      }
+    }
+    // No hope for a (better) match at greater error levels.
+    if (match_bitapScore_(d + 1, loc) > score_threshold) {
+      break;
+    }
+    last_rd = rd;
+  }
+  return best_loc;
+};
+
+
+/**
+ * Initialise the alphabet for the Bitap algorithm.
+ * @param {string} pattern The text to encode.
+ * @return {!Object} Hash of character locations.
+ * @private
+ */
+diff_match_patch.prototype.match_alphabet_ = function(pattern) {
+  var s = {};
+  for (var i = 0; i < pattern.length; i++) {
+    s[pattern.charAt(i)] = 0;
+  }
+  for (var i = 0; i < pattern.length; i++) {
+    s[pattern.charAt(i)] |= 1 << (pattern.length - i - 1);
+  }
+  return s;
+};
+
+
+//  PATCH FUNCTIONS
+
+
+/**
+ * Increase the context until it is unique,
+ * but don't let the pattern expand beyond Match_MaxBits.
+ * @param {!patch_obj} patch The patch to grow.
+ * @param {string} text Source text.
+ * @private
+ */
+diff_match_patch.prototype.patch_addContext_ = function(patch, text) {
+  if (text.length == 0) {
+    return;
+  }
+  var pattern = text.substring(patch.start2, patch.start2 + patch.length1);
+  var padding = 0;
+
+  // Look for the first and last matches of pattern in text.  If two different
+  // matches are found, increase the pattern length.
+  while (text.indexOf(pattern) != text.lastIndexOf(pattern) &&
+         pattern.length < this.Match_MaxBits - this.Patch_Margin -
+         this.Patch_Margin) {
+    padding += this.Patch_Margin;
+    pattern = text.substring(patch.start2 - padding,
+                             patch.start2 + patch.length1 + padding);
+  }
+  // Add one chunk for good luck.
+  padding += this.Patch_Margin;
+
+  // Add the prefix.
+  var prefix = text.substring(patch.start2 - padding, patch.start2);
+  if (prefix) {
+    patch.diffs.unshift([DIFF_EQUAL, prefix]);
+  }
+  // Add the suffix.
+  var suffix = text.substring(patch.start2 + patch.length1,
+                              patch.start2 + patch.length1 + padding);
+  if (suffix) {
+    patch.diffs.push([DIFF_EQUAL, suffix]);
+  }
+
+  // Roll back the start points.
+  patch.start1 -= prefix.length;
+  patch.start2 -= prefix.length;
+  // Extend the lengths.
+  patch.length1 += prefix.length + suffix.length;
+  patch.length2 += prefix.length + suffix.length;
+};
+
+
+/**
+ * Compute a list of patches to turn text1 into text2.
+ * Use diffs if provided, otherwise compute it ourselves.
+ * There are four ways to call this function, depending on what data is
+ * available to the caller:
+ * Method 1:
+ * a = text1, b = text2
+ * Method 2:
+ * a = diffs
+ * Method 3 (optimal):
+ * a = text1, b = diffs
+ * Method 4 (deprecated, use method 3):
+ * a = text1, b = text2, c = diffs
+ *
+ * @param {string|!Array.<!diff_match_patch.Diff>} a text1 (methods 1,3,4) or
+ * Array of diff tuples for text1 to text2 (method 2).
+ * @param {string|!Array.<!diff_match_patch.Diff>} opt_b text2 (methods 1,4) or
+ * Array of diff tuples for text1 to text2 (method 3) or undefined (method 2).
+ * @param {string|!Array.<!diff_match_patch.Diff>} opt_c Array of diff tuples
+ * for text1 to text2 (method 4) or undefined (methods 1,2,3).
+ * @return {!Array.<!patch_obj>} Array of patch objects.
+ */
+diff_match_patch.prototype.patch_make = function(a, opt_b, opt_c) {
+  var text1, diffs;
+  if (typeof a == 'string' && typeof opt_b == 'string' &&
+      typeof opt_c == 'undefined') {
+    // Method 1: text1, text2
+    // Compute diffs from text1 and text2.
+    text1 = /** @type {string} */(a);
+    diffs = this.diff_main(text1, /** @type {string} */(opt_b), true);
+    if (diffs.length > 2) {
+      this.diff_cleanupSemantic(diffs);
+      this.diff_cleanupEfficiency(diffs);
+    }
+  } else if (a && typeof a == 'object' && typeof opt_b == 'undefined' &&
+      typeof opt_c == 'undefined') {
+    // Method 2: diffs
+    // Compute text1 from diffs.
+    diffs = /** @type {!Array.<!diff_match_patch.Diff>} */(a);
+    text1 = this.diff_text1(diffs);
+  } else if (typeof a == 'string' && opt_b && typeof opt_b == 'object' &&
+      typeof opt_c == 'undefined') {
+    // Method 3: text1, diffs
+    text1 = /** @type {string} */(a);
+    diffs = /** @type {!Array.<!diff_match_patch.Diff>} */(opt_b);
+  } else if (typeof a == 'string' && typeof opt_b == 'string' &&
+      opt_c && typeof opt_c == 'object') {
+    // Method 4: text1, text2, diffs
+    // text2 is not used.
+    text1 = /** @type {string} */(a);
+    diffs = /** @type {!Array.<!diff_match_patch.Diff>} */(opt_c);
+  } else {
+    throw new Error('Unknown call format to patch_make.');
+  }
+
+  if (diffs.length === 0) {
+    return [];  // Get rid of the null case.
+  }
+  var patches = [];
+  var patch = new patch_obj();
+  var patchDiffLength = 0;  // Keeping our own length var is faster in JS.
+  var char_count1 = 0;  // Number of characters into the text1 string.
+  var char_count2 = 0;  // Number of characters into the text2 string.
+  // Start with text1 (prepatch_text) and apply the diffs until we arrive at
+  // text2 (postpatch_text).  We recreate the patches one by one to determine
+  // context info.
+  var prepatch_text = text1;
+  var postpatch_text = text1;
+  for (var x = 0; x < diffs.length; x++) {
+    var diff_type = diffs[x][0];
+    var diff_text = diffs[x][1];
+
+    if (!patchDiffLength && diff_type !== DIFF_EQUAL) {
+      // A new patch starts here.
+      patch.start1 = char_count1;
+      patch.start2 = char_count2;
+    }
+
+    switch (diff_type) {
+      case DIFF_INSERT:
+        patch.diffs[patchDiffLength++] = diffs[x];
+        patch.length2 += diff_text.length;
+        postpatch_text = postpatch_text.substring(0, char_count2) + diff_text +
+                         postpatch_text.substring(char_count2);
+        break;
+      case DIFF_DELETE:
+        patch.length1 += diff_text.length;
+        patch.diffs[patchDiffLength++] = diffs[x];
+        postpatch_text = postpatch_text.substring(0, char_count2) +
+                         postpatch_text.substring(char_count2 +
+                             diff_text.length);
+        break;
+      case DIFF_EQUAL:
+        if (diff_text.length <= 2 * this.Patch_Margin &&
+            patchDiffLength && diffs.length != x + 1) {
+          // Small equality inside a patch.
+          patch.diffs[patchDiffLength++] = diffs[x];
+          patch.length1 += diff_text.length;
+          patch.length2 += diff_text.length;
+        } else if (diff_text.length >= 2 * this.Patch_Margin) {
+          // Time for a new patch.
+          if (patchDiffLength) {
+            this.patch_addContext_(patch, prepatch_text);
+            patches.push(patch);
+            patch = new patch_obj();
+            patchDiffLength = 0;
+            // Unlike Unidiff, our patch lists have a rolling context.
+            // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff
+            // Update prepatch text & pos to reflect the application of the
+            // just completed patch.
+            prepatch_text = postpatch_text;
+            char_count1 = char_count2;
+          }
+        }
+        break;
+    }
+
+    // Update the current character count.
+    if (diff_type !== DIFF_INSERT) {
+      char_count1 += diff_text.length;
+    }
+    if (diff_type !== DIFF_DELETE) {
+      char_count2 += diff_text.length;
+    }
+  }
+  // Pick up the leftover patch if not empty.
+  if (patchDiffLength) {
+    this.patch_addContext_(patch, prepatch_text);
+    patches.push(patch);
+  }
+
+  return patches;
+};
+
+
+/**
+ * Given an array of patches, return another array that is identical.
+ * @param {!Array.<!patch_obj>} patches Array of patch objects.
+ * @return {!Array.<!patch_obj>} Array of patch objects.
+ */
+diff_match_patch.prototype.patch_deepCopy = function(patches) {
+  // Making deep copies is hard in JavaScript.
+  var patchesCopy = [];
+  for (var x = 0; x < patches.length; x++) {
+    var patch = patches[x];
+    var patchCopy = new patch_obj();
+    patchCopy.diffs = [];
+    for (var y = 0; y < patch.diffs.length; y++) {
+      patchCopy.diffs[y] = patch.diffs[y].slice();
+    }
+    patchCopy.start1 = patch.start1;
+    patchCopy.start2 = patch.start2;
+    patchCopy.length1 = patch.length1;
+    patchCopy.length2 = patch.length2;
+    patchesCopy[x] = patchCopy;
+  }
+  return patchesCopy;
+};
+
+
+/**
+ * Merge a set of patches onto the text.  Return a patched text, as well
+ * as a list of true/false values indicating which patches were applied.
+ * @param {!Array.<!patch_obj>} patches Array of patch objects.
+ * @param {string} text Old text.
+ * @return {!Array.<string|!Array.<boolean>>} Two element Array, containing the
+ *      new text and an array of boolean values.
+ */
+diff_match_patch.prototype.patch_apply = function(patches, text) {
+  if (patches.length == 0) {
+    return [text, []];
+  }
+
+  // Deep copy the patches so that no changes are made to originals.
+  patches = this.patch_deepCopy(patches);
+
+  var nullPadding = this.patch_addPadding(patches);
+  text = nullPadding + text + nullPadding;
+
+  this.patch_splitMax(patches);
+  // delta keeps track of the offset between the expected and actual location
+  // of the previous patch.  If there are patches expected at positions 10 and
+  // 20, but the first patch was found at 12, delta is 2 and the second patch
+  // has an effective expected position of 22.
+  var delta = 0;
+  var results = [];
+  for (var x = 0; x < patches.length; x++) {
+    var expected_loc = patches[x].start2 + delta;
+    var text1 = this.diff_text1(patches[x].diffs);
+    var start_loc;
+    var end_loc = -1;
+    if (text1.length > this.Match_MaxBits) {
+      // patch_splitMax will only provide an oversized pattern in the case of
+      // a monster delete.
+      start_loc = this.match_main(text, text1.substring(0, this.Match_MaxBits),
+                                  expected_loc);
+      if (start_loc != -1) {
+        end_loc = this.match_main(text,
+            text1.substring(text1.length - this.Match_MaxBits),
+            expected_loc + text1.length - this.Match_MaxBits);
+        if (end_loc == -1 || start_loc >= end_loc) {
+          // Can't find valid trailing context.  Drop this patch.
+          start_loc = -1;
+        }
+      }
+    } else {
+      start_loc = this.match_main(text, text1, expected_loc);
+    }
+    if (start_loc == -1) {
+      // No match found.  :(
+      results[x] = false;
+      // Subtract the delta for this failed patch from subsequent patches.
+      delta -= patches[x].length2 - patches[x].length1;
+    } else {
+      // Found a match.  :)
+      results[x] = true;
+      delta = start_loc - expected_loc;
+      var text2;
+      if (end_loc == -1) {
+        text2 = text.substring(start_loc, start_loc + text1.length);
+      } else {
+        text2 = text.substring(start_loc, end_loc + this.Match_MaxBits);
+      }
+      if (text1 == text2) {
+        // Perfect match, just shove the replacement text in.
+        text = text.substring(0, start_loc) +
+               this.diff_text2(patches[x].diffs) +
+               text.substring(start_loc + text1.length);
+      } else {
+        // Imperfect match.  Run a diff to get a framework of equivalent
+        // indices.
+        var diffs = this.diff_main(text1, text2, false);
+        if (text1.length > this.Match_MaxBits &&
+            this.diff_levenshtein(diffs) / text1.length >
+            this.Patch_DeleteThreshold) {
+          // The end points match, but the content is unacceptably bad.
+          results[x] = false;
+        } else {
+          this.diff_cleanupSemanticLossless(diffs);
+          var index1 = 0;
+          var index2;
+          for (var y = 0; y < patches[x].diffs.length; y++) {
+            var mod = patches[x].diffs[y];
+            if (mod[0] !== DIFF_EQUAL) {
+              index2 = this.diff_xIndex(diffs, index1);
+            }
+            if (mod[0] === DIFF_INSERT) {  // Insertion
+              text = text.substring(0, start_loc + index2) + mod[1] +
+                     text.substring(start_loc + index2);
+            } else if (mod[0] === DIFF_DELETE) {  // Deletion
+              text = text.substring(0, start_loc + index2) +
+                     text.substring(start_loc + this.diff_xIndex(diffs,
+                         index1 + mod[1].length));
+            }
+            if (mod[0] !== DIFF_DELETE) {
+              index1 += mod[1].length;
+            }
+          }
+        }
+      }
+    }
+  }
+  // Strip the padding off.
+  text = text.substring(nullPadding.length, text.length - nullPadding.length);
+  return [text, results];
+};
+
+/**
+ * Merge a set of patches onto the text.  Return a patched text, as well
+ * as a list of true/false values indicating which patches were applied.
+ * @param {Array.<patch_obj>} patches Array of patch objects.
+ * @param {string} text Old text.
+ * @return {Array.<string|Array.<boolean>>} Two element Array, containing the
+ *      new text and an array of boolean values.
+ */
+diff_match_patch.prototype.patch_apply_reverse = function(patches, text) {
+  if (patches.length == 0) {
+    return [text, []];
+  }
+
+  // Deep copy the patches so that no changes are made to originals.
+  patches = this.patch_deepCopy(patches);
+
+  var nullPadding = this.patch_addPadding(patches);
+  text = nullPadding + text + nullPadding;
+
+  this.patch_splitMax(patches);
+  // delta keeps track of the offset between the expected and actual location
+  // of the previous patch.  If there are patches expected at positions 10 and
+  // 20, but the first patch was found at 12, delta is 2 and the second patch
+  // has an effective expected position of 22.
+  var delta = 0;
+  var results = [];
+  for (var x = 0; x < patches.length; x++) {
+    var expected_loc = patches[x].start2 + delta;
+    var text1 = this.diff_text1(patches[x].diffs);
+    var start_loc;
+    var end_loc = -1;
+    if (text1.length > this.Match_MaxBits) {
+      // patch_splitMax will only provide an oversized pattern in the case of
+      // a monster delete.
+      start_loc = this.match_main(text, text1.substring(0, this.Match_MaxBits),
+                                  expected_loc);
+      if (start_loc != -1) {
+        end_loc = this.match_main(text,
+            text1.substring(text1.length - this.Match_MaxBits),
+            expected_loc + text1.length - this.Match_MaxBits);
+        if (end_loc == -1 || start_loc >= end_loc) {
+          // Can't find valid trailing context.  Drop this patch.
+          start_loc = -1;
+        }
+      }
+    } else {
+      start_loc = this.match_main(text, text1, expected_loc);
+    }
+    if (start_loc == -1) {
+      // No match found.  :(
+      results[x] = false;
+      // Subtract the delta for this failed patch from subsequent patches.
+      delta -= patches[x].length2 - patches[x].length1;
+    } else {
+      // Found a match.  :)
+      results[x] = true;
+      delta = start_loc - expected_loc;
+      var text2;
+      if (end_loc == -1) {
+        text2 = text.substring(start_loc, start_loc + text1.length);
+      } else {
+        text2 = text.substring(start_loc, end_loc + this.Match_MaxBits);
+      }
+      if (text1 == text2) {
+        // Perfect match, just shove the replacement text in.
+        text = text.substring(0, start_loc) +
+               this.diff_text2(patches[x].diffs) +
+               text.substring(start_loc + text1.length);
+      } else {
+        // Imperfect match.  Run a diff to get a framework of equivalent
+        // indices.
+        var diffs = this.diff_main(text1, text2, false);
+        if (text1.length > this.Match_MaxBits &&
+            this.diff_levenshtein(diffs) / text1.length >
+            this.Patch_DeleteThreshold) {
+          // The end points match, but the content is unacceptably bad.
+          results[x] = false;
+        } else {
+          this.diff_cleanupSemanticLossless(diffs);
+          var index1 = 0;
+          var index2;
+          for (var y = 0; y < patches[x].diffs.length; y++) {
+            var mod = patches[x].diffs[y];
+            if (mod[0] !== DIFF_EQUAL) {
+              index2 = this.diff_xIndex(diffs, index1);
+            }
+            if (mod[0] === DIFF_DELETE) {  // Deletion
+              text = text.substring(0, start_loc + index2) + mod[1] +
+                     text.substring(start_loc + index2);
+            } else if (mod[0] === DIFF_INSERT) {  // Insertion
+              text = text.substring(0, start_loc + index2) +
+                     text.substring(start_loc + this.diff_xIndex(diffs,
+                         index1 + mod[1].length));
+            }
+            if (mod[0] !== DIFF_INSERT) {
+              index1 += mod[1].length;
+            }
+          }
+        }
+      }
+    }
+  }
+  // Strip the padding off.
+  text = text.substring(nullPadding.length, text.length - nullPadding.length);
+  return [text, results];
+};
+
+
+/**
+ * Add some padding on text start and end so that edges can match something.
+ * Intended to be called only from within patch_apply.
+ * @param {!Array.<!patch_obj>} patches Array of patch objects.
+ * @return {string} The padding string added to each side.
+ */
+diff_match_patch.prototype.patch_addPadding = function(patches) {
+  var paddingLength = this.Patch_Margin;
+  var nullPadding = '';
+  for (var x = 1; x <= paddingLength; x++) {
+    nullPadding += String.fromCharCode(x);
+  }
+
+  // Bump all the patches forward.
+  for (var x = 0; x < patches.length; x++) {
+    patches[x].start1 += paddingLength;
+    patches[x].start2 += paddingLength;
+  }
+
+  // Add some padding on start of first diff.
+  var patch = patches[0];
+  var diffs = patch.diffs;
+  if (diffs.length == 0 || diffs[0][0] != DIFF_EQUAL) {
+    // Add nullPadding equality.
+    diffs.unshift([DIFF_EQUAL, nullPadding]);
+    patch.start1 -= paddingLength;  // Should be 0.
+    patch.start2 -= paddingLength;  // Should be 0.
+    patch.length1 += paddingLength;
+    patch.length2 += paddingLength;
+  } else if (paddingLength > diffs[0][1].length) {
+    // Grow first equality.
+    var extraLength = paddingLength - diffs[0][1].length;
+    diffs[0][1] = nullPadding.substring(diffs[0][1].length) + diffs[0][1];
+    patch.start1 -= extraLength;
+    patch.start2 -= extraLength;
+    patch.length1 += extraLength;
+    patch.length2 += extraLength;
+  }
+
+  // Add some padding on end of last diff.
+  patch = patches[patches.length - 1];
+  diffs = patch.diffs;
+  if (diffs.length == 0 || diffs[diffs.length - 1][0] != DIFF_EQUAL) {
+    // Add nullPadding equality.
+    diffs.push([DIFF_EQUAL, nullPadding]);
+    patch.length1 += paddingLength;
+    patch.length2 += paddingLength;
+  } else if (paddingLength > diffs[diffs.length - 1][1].length) {
+    // Grow last equality.
+    var extraLength = paddingLength - diffs[diffs.length - 1][1].length;
+    diffs[diffs.length - 1][1] += nullPadding.substring(0, extraLength);
+    patch.length1 += extraLength;
+    patch.length2 += extraLength;
+  }
+
+  return nullPadding;
+};
+
+
+/**
+ * Look through the patches and break up any which are longer than the maximum
+ * limit of the match algorithm.
+ * Intended to be called only from within patch_apply.
+ * @param {!Array.<!patch_obj>} patches Array of patch objects.
+ */
+diff_match_patch.prototype.patch_splitMax = function(patches) {
+  var patch_size = this.Match_MaxBits;
+  for (var x = 0; x < patches.length; x++) {
+    if (patches[x].length1 > patch_size) {
+      var bigpatch = patches[x];
+      // Remove the big old patch.
+      patches.splice(x--, 1);
+      var start1 = bigpatch.start1;
+      var start2 = bigpatch.start2;
+      var precontext = '';
+      while (bigpatch.diffs.length !== 0) {
+        // Create one of several smaller patches.
+        var patch = new patch_obj();
+        var empty = true;
+        patch.start1 = start1 - precontext.length;
+        patch.start2 = start2 - precontext.length;
+        if (precontext !== '') {
+          patch.length1 = patch.length2 = precontext.length;
+          patch.diffs.push([DIFF_EQUAL, precontext]);
+        }
+        while (bigpatch.diffs.length !== 0 &&
+               patch.length1 < patch_size - this.Patch_Margin) {
+          var diff_type = bigpatch.diffs[0][0];
+          var diff_text = bigpatch.diffs[0][1];
+          if (diff_type === DIFF_INSERT) {
+            // Insertions are harmless.
+            patch.length2 += diff_text.length;
+            start2 += diff_text.length;
+            patch.diffs.push(bigpatch.diffs.shift());
+            empty = false;
+          } else if (diff_type === DIFF_DELETE && patch.diffs.length == 1 &&
+                     patch.diffs[0][0] == DIFF_EQUAL &&
+                     diff_text.length > 2 * patch_size) {
+            // This is a large deletion.  Let it pass in one chunk.
+            patch.length1 += diff_text.length;
+            start1 += diff_text.length;
+            empty = false;
+            patch.diffs.push([diff_type, diff_text]);
+            bigpatch.diffs.shift();
+          } else {
+            // Deletion or equality.  Only take as much as we can stomach.
+            diff_text = diff_text.substring(0,
+                patch_size - patch.length1 - this.Patch_Margin);
+            patch.length1 += diff_text.length;
+            start1 += diff_text.length;
+            if (diff_type === DIFF_EQUAL) {
+              patch.length2 += diff_text.length;
+              start2 += diff_text.length;
+            } else {
+              empty = false;
+            }
+            patch.diffs.push([diff_type, diff_text]);
+            if (diff_text == bigpatch.diffs[0][1]) {
+              bigpatch.diffs.shift();
+            } else {
+              bigpatch.diffs[0][1] =
+                  bigpatch.diffs[0][1].substring(diff_text.length);
+            }
+          }
+        }
+        // Compute the head context for the next patch.
+        precontext = this.diff_text2(patch.diffs);
+        precontext =
+            precontext.substring(precontext.length - this.Patch_Margin);
+        // Append the end context for this patch.
+        var postcontext = this.diff_text1(bigpatch.diffs)
+                              .substring(0, this.Patch_Margin);
+        if (postcontext !== '') {
+          patch.length1 += postcontext.length;
+          patch.length2 += postcontext.length;
+          if (patch.diffs.length !== 0 &&
+              patch.diffs[patch.diffs.length - 1][0] === DIFF_EQUAL) {
+            patch.diffs[patch.diffs.length - 1][1] += postcontext;
+          } else {
+            patch.diffs.push([DIFF_EQUAL, postcontext]);
+          }
+        }
+        if (!empty) {
+          patches.splice(++x, 0, patch);
+        }
+      }
+    }
+  }
+};
+
+
+/**
+ * Take a list of patches and return a textual representation.
+ * @param {!Array.<!patch_obj>} patches Array of patch objects.
+ * @return {string} Text representation of patches.
+ */
+diff_match_patch.prototype.patch_toText = function(patches) {
+  var text = [];
+  for (var x = 0; x < patches.length; x++) {
+    text[x] = patches[x];
+  }
+  return text.join('');
+};
+
+
+/**
+ * Parse a textual representation of patches and return a list of patch objects.
+ * @param {string} textline Text representation of patches.
+ * @return {!Array.<!patch_obj>} Array of patch objects.
+ * @throws {!Error} If invalid input.
+ */
+diff_match_patch.prototype.patch_fromText = function(textline) {
+  var patches = [];
+  if (!textline) {
+    return patches;
+  }
+  var text = textline.split('\n');
+  var textPointer = 0;
+  var patchHeader = /^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;
+  while (textPointer < text.length) {
+    var m = text[textPointer].match(patchHeader);
+    if (!m) {
+      throw new Error('Invalid patch string: ' + text[textPointer]);
+    }
+    var patch = new patch_obj();
+    patches.push(patch);
+    patch.start1 = parseInt(m[1], 10);
+    if (m[2] === '') {
+      patch.start1--;
+      patch.length1 = 1;
+    } else if (m[2] == '0') {
+      patch.length1 = 0;
+    } else {
+      patch.start1--;
+      patch.length1 = parseInt(m[2], 10);
+    }
+
+    patch.start2 = parseInt(m[3], 10);
+    if (m[4] === '') {
+      patch.start2--;
+      patch.length2 = 1;
+    } else if (m[4] == '0') {
+      patch.length2 = 0;
+    } else {
+      patch.start2--;
+      patch.length2 = parseInt(m[4], 10);
+    }
+    textPointer++;
+
+    while (textPointer < text.length) {
+      var sign = text[textPointer].charAt(0);
+      try {
+        var line = decodeURI(text[textPointer].substring(1));
+      } catch (ex) {
+        // Malformed URI sequence.
+        throw new Error('Illegal escape in patch_fromText: ' + line);
+      }
+      if (sign == '-') {
+        // Deletion.
+        patch.diffs.push([DIFF_DELETE, line]);
+      } else if (sign == '+') {
+        // Insertion.
+        patch.diffs.push([DIFF_INSERT, line]);
+      } else if (sign == ' ') {
+        // Minor equality.
+        patch.diffs.push([DIFF_EQUAL, line]);
+      } else if (sign == '@') {
+        // Start of next patch.
+        break;
+      } else if (sign === '') {
+        // Blank line?  Whatever.
+      } else {
+        // WTF?
+        throw new Error('Invalid patch mode "' + sign + '" in: ' + line);
+      }
+      textPointer++;
+    }
+  }
+  return patches;
+};
+
+
+/**
+ * Class representing one patch operation.
+ * @constructor
+ */
+function patch_obj() {
+  /** @type {!Array.<!diff_match_patch.Diff>} */
+  this.diffs = [];
+  /** @type {?number} */
+  this.start1 = null;
+  /** @type {?number} */
+  this.start2 = null;
+  /** @type {number} */
+  this.length1 = 0;
+  /** @type {number} */
+  this.length2 = 0;
+}
+
+
+/**
+ * Emmulate GNU diff's format.
+ * Header: @@ -382,8 +481,9 @@
+ * Indicies are printed as 1-based, not 0-based.
+ * @return {string} The GNU diff string.
+ */
+patch_obj.prototype.toString = function() {
+  var coords1, coords2;
+  if (this.length1 === 0) {
+    coords1 = this.start1 + ',0';
+  } else if (this.length1 == 1) {
+    coords1 = this.start1 + 1;
+  } else {
+    coords1 = (this.start1 + 1) + ',' + this.length1;
+  }
+  if (this.length2 === 0) {
+    coords2 = this.start2 + ',0';
+  } else if (this.length2 == 1) {
+    coords2 = this.start2 + 1;
+  } else {
+    coords2 = (this.start2 + 1) + ',' + this.length2;
+  }
+  var text = ['@@ -' + coords1 + ' +' + coords2 + ' @@\n'];
+  var op;
+  // Escape the body of the patch with %xx notation.
+  for (var x = 0; x < this.diffs.length; x++) {
+    switch (this.diffs[x][0]) {
+      case DIFF_INSERT:
+        op = '+';
+        break;
+      case DIFF_DELETE:
+        op = '-';
+        break;
+      case DIFF_EQUAL:
+        op = ' ';
+        break;
+    }
+    text[x + 1] = op + encodeURI(this.diffs[x][1]) + '\n';
+  }
+  return text.join('').replace(/%20/g, ' ');
+};
+
+
+// Export these global variables so that they survive Google's JS compiler.
+// In a browser, 'this' will be 'window'.
+// In node.js 'this' will be a global object.
+this['diff_match_patch'] = diff_match_patch;
+this['patch_obj'] = patch_obj;
+this['DIFF_DELETE'] = DIFF_DELETE;
+this['DIFF_INSERT'] = DIFF_INSERT;
+this['DIFF_EQUAL'] = DIFF_EQUAL;
+
diff --git a/bigbluebutton-client/resources/prod/lib/shared_notes.js b/bigbluebutton-client/resources/prod/lib/shared_notes.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e6df8e52bd30cb4e2c9317ca87abe013d7a34d1
--- /dev/null
+++ b/bigbluebutton-client/resources/prod/lib/shared_notes.js
@@ -0,0 +1,304 @@
+/*
+    This file is part of BBB-Notes.
+
+    Copyright (c) Islam El-Ashi. All rights reserved.
+
+    BBB-Notes is free software: you can redistribute it and/or modify
+    it under the terms of the Lesser GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    any later version.
+
+    BBB-Notes is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    Lesser GNU General Public License for more details.
+
+    You should have received a copy of the Lesser GNU General Public License
+    along with BBB-Notes.  If not, see <http://www.gnu.org/licenses/>.
+
+    Author: Islam El-Ashi <ielashi@gmail.com>, <http://www.ielashi.com>
+*/
+var dmp = new diff_match_patch();
+var debug = false;
+
+function diff(text1, text2) {
+	return dmp.patch_toText(dmp.patch_make(dmp.diff_main(unescape(text1),unescape(text2))));
+}
+
+function patch(patch, text) {
+	return dmp.patch_apply(dmp.patch_fromText(patch), unescape(text))[0];
+}
+
+function unpatch(patch, text) {
+	return dmp.patch_apply_reverse(dmp.patch_fromText(patch), unescape(text))[0];
+}
+
+
+/**
+ * Helper Methods
+ */
+
+/**
+ * MobWrite - Real-time Synchronization and Collaboration Service
+ *
+ * Copyright 2006 Google Inc.
+ * http://code.google.com/p/google-mobwrite/
+ *
+ * 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.
+ */
+
+/**
+ * Modify the user's plaintext by applying a series of patches against it.
+ * @param {Array.<patch_obj>} patches Array of Patch objects.
+ * @param {String} client text
+ */
+function patchClientText(patches, text, selectionStart, selectionEnd) {
+  text = unescape(text)
+  // Set some constants which tweak the matching behaviour.
+  // Maximum distance to search from expected location.
+  dmp.Match_Distance = 1000;
+  // At what point is no match declared (0.0 = perfection, 1.0 = very loose)
+  dmp.Match_Threshold = 0.6;
+
+  var oldClientText = text
+  var cursor = captureCursor_(oldClientText, selectionStart, selectionEnd);
+  // Pack the cursor offsets into an array to be adjusted.
+  // See http://neil.fraser.name/writing/cursor/
+  var offsets = [];
+  if (cursor) {
+	offsets[0] = cursor.startOffset;
+	if ('endOffset' in cursor) {
+	  offsets[1] = cursor.endOffset;
+	}
+  }
+  var newClientText = patch_apply_(patches, oldClientText, offsets);
+  // Set the new text only if there is a change to be made.
+  if (oldClientText != newClientText) {
+	//this.setClientText(newClientText);
+	if (cursor) {
+	  // Unpack the offset array.
+	  cursor.startOffset = offsets[0];
+	  if (offsets.length > 1) {
+		cursor.endOffset = offsets[1];
+		if (cursor.startOffset >= cursor.endOffset) {
+		  cursor.collapsed = true;
+		}
+	  }
+	  return [restoreCursor_(cursor, newClientText), newClientText];
+	//  this.restoreCursor_(cursor);
+	}
+  }
+  // no change in client text
+  return [[selectionStart, selectionEnd], newClientText];
+}
+
+/**
+ * Merge a set of patches onto the text.  Return a patched text.
+ * @param {Array.<patch_obj>} patches Array of patch objects.
+ * @param {string} text Old text.
+ * @param {Array.<number>} offsets Offset indices to adjust.
+ * @return {string} New text.
+ */
+function patch_apply_(patchText, text, offsets) {
+  var patches = dmp.patch_fromText(patchText);
+  if (patches.length == 0) {
+	return text;
+  }
+
+  // Deep copy the patches so that no changes are made to originals.
+  patches = dmp.patch_deepCopy(patches);
+  var nullPadding = dmp.patch_addPadding(patches);
+  text = nullPadding + text + nullPadding;
+
+  dmp.patch_splitMax(patches);
+  // delta keeps track of the offset between the expected and actual location
+  // of the previous patch.  If there are patches expected at positions 10 and
+  // 20, but the first patch was found at 12, delta is 2 and the second patch
+  // has an effective expected position of 22.
+  var delta = 0;
+  for (var x = 0; x < patches.length; x++) {
+	var expected_loc = patches[x].start2 + delta;
+	var text1 = dmp.diff_text1(patches[x].diffs);
+	var start_loc;
+	var end_loc = -1;
+	if (text1.length > dmp.Match_MaxBits) {
+	  // patch_splitMax will only provide an oversized pattern in the case of
+	  // a monster delete.
+	  start_loc = dmp.match_main(text, text1.substring(0, dmp.Match_MaxBits), expected_loc);
+	  if (start_loc != -1) {
+		end_loc = dmp.match_main(text, text1.substring(text1.length - dmp.Match_MaxBits),
+			expected_loc + text1.length - dmp.Match_MaxBits);
+		if (end_loc == -1 || start_loc >= end_loc) {
+		  // Can't find valid trailing context.  Drop this patch.
+		  start_loc = -1;
+		}
+	  }
+	} else {
+	  start_loc = dmp.match_main(text, text1, expected_loc);
+	}
+	if (start_loc == -1) {
+	  // No match found.  :(
+	  if (debug) {
+		window.console.warn('Patch failed: ' + patches[x]);
+	  }
+	  // Subtract the delta for this failed patch from subsequent patches.
+	  delta -= patches[x].length2 - patches[x].length1;
+	} else {
+	  // Found a match.  :)
+	  if (debug) {
+		window.console.info('Patch OK.');
+	  }
+	  delta = start_loc - expected_loc;
+	  var text2;
+	  if (end_loc == -1) {
+		text2 = text.substring(start_loc, start_loc + text1.length);
+	  } else {
+		text2 = text.substring(start_loc, end_loc + dmp.Match_MaxBits);
+	  }
+	  // Run a diff to get a framework of equivalent indices.
+	  var diffs = dmp.diff_main(text1, text2, false);
+	  if (text1.length > dmp.Match_MaxBits &&
+		  dmp.diff_levenshtein(diffs) / text1.length >
+		  dmp.Patch_DeleteThreshold) {
+		// The end points match, but the content is unacceptably bad.
+		if (debug) {
+		  window.console.warn('Patch contents mismatch: ' + patches[x]);
+		}
+	  } else {
+		var index1 = 0;
+		var index2;
+		for (var y = 0; y < patches[x].diffs.length; y++) {
+		  var mod = patches[x].diffs[y];
+		  if (mod[0] !== DIFF_EQUAL) {
+			index2 = dmp.diff_xIndex(diffs, index1);
+		  }
+		  if (mod[0] === DIFF_INSERT) {  // Insertion
+			text = text.substring(0, start_loc + index2) + mod[1] +
+				   text.substring(start_loc + index2);
+			for (var i = 0; i < offsets.length; i++) {
+			  if (offsets[i] + nullPadding.length > start_loc + index2) {
+				offsets[i] += mod[1].length;
+			  }
+			}
+		  } else if (mod[0] === DIFF_DELETE) {  // Deletion
+			var del_start = start_loc + index2;
+			var del_end = start_loc + dmp.diff_xIndex(diffs,
+				index1 + mod[1].length);
+			text = text.substring(0, del_start) + text.substring(del_end);
+			for (var i = 0; i < offsets.length; i++) {
+			  if (offsets[i] + nullPadding.length > del_start) {
+				if (offsets[i] + nullPadding.length < del_end) {
+				  offsets[i] = del_start - nullPadding.length;
+				} else {
+				  offsets[i] -= del_end - del_start;
+				}
+			  }
+			}
+		  }
+		  if (mod[0] !== DIFF_DELETE) {
+			index1 += mod[1].length;
+		  }
+		}
+	  }
+	}
+  }
+  // Strip the padding off.
+  text = text.substring(nullPadding.length, text.length - nullPadding.length);
+  return text;
+}
+
+
+/**
+ * Record information regarding the current cursor.
+ * @return {Object?} Context information of the cursor.
+ * @private
+ */
+function captureCursor_(text, selectionStart, selectionEnd) {
+	var padLength = dmp.Match_MaxBits / 2;  // Normally 16.
+	var cursor = {};
+
+	cursor.startPrefix = text.substring(selectionStart - padLength, selectionStart);
+	cursor.startSuffix = text.substring(selectionStart, selectionStart + padLength);
+	cursor.startOffset = selectionStart;
+	cursor.collapsed = (selectionStart == selectionEnd);
+	if (!cursor.collapsed) {
+	  cursor.endPrefix = text.substring(selectionEnd - padLength, selectionEnd);
+	  cursor.endSuffix = text.substring(selectionEnd, selectionEnd + padLength);
+	  cursor.endOffset = selectionEnd;
+	}
+
+	return cursor;
+}
+
+/**
+ * Attempt to restore the cursor's location.
+ * @param {Object} cursor Context information of the cursor.
+ * @private
+ */
+function restoreCursor_(cursor, text) {
+  // Set some constants which tweak the matching behaviour.
+  // Maximum distance to search from expected location.
+  dmp.Match_Distance = 1000;
+  // At what point is no match declared (0.0 = perfection, 1.0 = very loose)
+  dmp.Match_Threshold = 0.9;
+
+  var padLength = dmp.Match_MaxBits / 2;  // Normally 16.
+  var newText = text;
+
+  // Find the start of the selection in the new text.
+  var pattern1 = cursor.startPrefix + cursor.startSuffix;
+  var pattern2, diff;
+  var cursorStartPoint = dmp.match_main(newText, pattern1,
+      cursor.startOffset - padLength);
+  if (cursorStartPoint !== null) {
+    pattern2 = newText.substring(cursorStartPoint,
+                                 cursorStartPoint + pattern1.length);
+    //alert(pattern1 + '\nvs\n' + pattern2);
+    // Run a diff to get a framework of equivalent indicies.
+    diff = dmp.diff_main(pattern1, pattern2, false);
+    cursorStartPoint += dmp.diff_xIndex(diff, cursor.startPrefix.length);
+  }
+
+  var cursorEndPoint = null;
+  if (!cursor.collapsed) {
+    // Find the end of the selection in the new text.
+    pattern1 = cursor.endPrefix + cursor.endSuffix;
+    cursorEndPoint = dmp.match_main(newText, pattern1,
+        cursor.endOffset - padLength);
+    if (cursorEndPoint !== null) {
+      pattern2 = newText.substring(cursorEndPoint,
+                                   cursorEndPoint + pattern1.length);
+      //alert(pattern1 + '\nvs\n' + pattern2);
+      // Run a diff to get a framework of equivalent indicies.
+      diff = dmp.diff_main(pattern1, pattern2, false);
+      cursorEndPoint += dmp.diff_xIndex(diff, cursor.endPrefix.length);
+    }
+  }
+
+  // Deal with loose ends
+  if (cursorStartPoint === null && cursorEndPoint !== null) {
+    // Lost the start point of the selection, but we have the end point.
+    // Collapse to end point.
+    cursorStartPoint = cursorEndPoint;
+  } else if (cursorStartPoint === null && cursorEndPoint === null) {
+    // Lost both start and end points.
+    // Jump to the offset of start.
+    cursorStartPoint = cursor.startOffset;
+  }
+  if (cursorEndPoint === null) {
+    // End not known, collapse to start.
+    cursorEndPoint = cursorStartPoint;
+  }
+
+  return [cursorStartPoint, cursorEndPoint];
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/magnifier.png b/bigbluebutton-client/resources/prod/logo.png
similarity index 60%
rename from bigbluebutton-client/src/org/bigbluebutton/common/assets/images/magnifier.png
rename to bigbluebutton-client/resources/prod/logo.png
index 415b81f589a7ac65ab9e29a9d22b362c8ca0a262..ced2cc1c9ecee0cf720c7060833cf2f3962e593f 100644
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/magnifier.png and b/bigbluebutton-client/resources/prod/logo.png differ
diff --git a/bigbluebutton-client/src/BigBlueButton.mxml b/bigbluebutton-client/src/BigBlueButton.mxml
index 37f0a82bfdbc611e42dd361536427c38549829db..fc78140f56b7f5a1045fcbd9898e703680a1cfbf 100755
--- a/bigbluebutton-client/src/BigBlueButton.mxml
+++ b/bigbluebutton-client/src/BigBlueButton.mxml
@@ -21,7 +21,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 -->
 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                 xmlns:views="*"
-                pageTitle="BigBlueButton" 
+                pageTitle="Mconf-Live"
                 layout="absolute"
 				preinitialize="LogUtil.initLogging(true)"
                 preloader="org.bigbluebutton.main.model.BigBlueButtonPreloader">
diff --git a/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml b/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml
index 99881b885f9814d3c45fa796015e886467dbbccc..9435f2bd03d4ad36a1ce0196cdcadc6a0f126319 100755
--- a/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml
+++ b/bigbluebutton-client/src/BigBlueButtonMainContainer.mxml
@@ -26,6 +26,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   xmlns:coreMap="org.bigbluebutton.core.controllers.maps.*"
   xmlns:mate="http://mate.asfusion.com/"
   width="100%" height="100%"
+  backgroundColor="white"
   horizontalScrollPolicy="off"
   verticalScrollPolicy="off"
   creationComplete="init()"
diff --git a/bigbluebutton-client/src/SharedNotesModule.mxml b/bigbluebutton-client/src/SharedNotesModule.mxml
index 625370678de5a7f75651737e202652cf9f88deba..fb84e306717f01f8587a296833028e23ee233ecf 100755
--- a/bigbluebutton-client/src/SharedNotesModule.mxml
+++ b/bigbluebutton-client/src/SharedNotesModule.mxml
@@ -20,25 +20,35 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 <mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" 
 		   layout="absolute" 
 		   implements="org.bigbluebutton.common.IBigBlueButtonModule" 
-		   creationComplete="onCreationComplete()" >
+		   creationComplete="onCreationComplete()"
+		   xmlns:maps="org.bigbluebutton.modules.sharednotes.maps.*"
+		   xmlns:mate="http://mate.asfusion.com/" >
+
+	<maps:SharedNotesEventMap id="sharedNotesEventMap"/>
+
 	<mx:Script>
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
 			
-			import org.bigbluebutton.common.IBigBlueButtonModule;
+			import org.as3commons.logging.api.ILogger;
+			import org.as3commons.logging.api.getClassLogger;
+			import org.bigbluebutton.common.IBbbModuleWindow;
+			import org.bigbluebutton.common.events.CloseWindowEvent;
+			import org.bigbluebutton.common.events.OpenWindowEvent;
 			import org.bigbluebutton.common.events.ToolbarButtonEvent;
-			import org.bigbluebutton.modules.sharednotes.SharedNotesWindow;
-			import org.bigbluebutton.modules.sharednotes.ToolbarButton;
-			import org.bigbluebutton.modules.sharednotes.infrastructure.HTTPServerConnection;
+			import org.bigbluebutton.modules.sharednotes.events.StartSharedNotesModuleEvent;
+			import org.bigbluebutton.modules.sharednotes.events.StopSharedNotesModuleEvent;
 			
-			private var _moduleName:String = "Notes Module";			
+			private static const LOGGER:ILogger = getClassLogger(SharedNotesModule);
+
+			private var _moduleName:String = "Notes Module";
 			private var _attributes:Object;
 			
-			private var globalDispatcher:Dispatcher = new Dispatcher();
+			private var _globalDispatcher:Dispatcher = new Dispatcher();
 			
 			private function onCreationComplete():void {
-				LogUtil.debug("NotesModule Initialized");	
-				globalDispatcher = new Dispatcher();
+				LOGGER.debug("NotesModule Initialized");
+				_globalDispatcher = new Dispatcher();
 			}
 			
 			public function get moduleName():String {
@@ -60,14 +70,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			public function get mode():String {
 				if (_attributes.mode == null) {					
 					_attributes.mode = "LIVE"
-					LogUtil.debug('Setting NotesModule mode: ' + _attributes.mode);
+					LOGGER.debug('Setting NotesModule mode: ' + _attributes.mode);
 				}
-				LogUtil.debug('NotesModule mode: ' + _attributes.mode);
+				LOGGER.debug('NotesModule mode: ' + _attributes.mode);
 				return _attributes.mode;
 			}
 			
 			public function get userid():Number {
-				return _attributes.userid as Number;
+				return _attributes.userid;
 			}
 			
 			public function get role():String {
@@ -75,23 +85,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
 			
 			public function start(attributes:Object):void {	
-				LogUtil.debug("notes attr: " + attributes.username);
-				_attributes = attributes;
-				SharedNotesWindow.document = _attributes.room;
-				// The following line has been removed, as the uri should be in 
-				// the URI property in the config.xml file of the client
-					HTTPServerConnection.syncURL = (_attributes.uri as String).replace("RTMP", "http") + "/notes/notes.jsp";
-				addToolbarButton();
+				var event:StartSharedNotesModuleEvent = new StartSharedNotesModuleEvent();
+				event.attributes = attributes;
+				_globalDispatcher.dispatchEvent(event);
 			}
 			
-			public function addToolbarButton():void{
-				var button:ToolbarButton = new ToolbarButton();	   	
-				var event:ToolbarButtonEvent = new ToolbarButtonEvent(ToolbarButtonEvent.ADD);
-				event.button = button;
-				globalDispatcher.dispatchEvent(event);
+			public function stop():void {
+				var event:StopSharedNotesModuleEvent = new StopSharedNotesModuleEvent(StopSharedNotesModuleEvent.STOP_SHAREDNOTES_MODULE_EVENT);
+				_globalDispatcher.dispatchEvent(event);
 			}
-			
-			public function stop():void {}
 		]]>
 	</mx:Script>
 </mx:Module>
diff --git a/bigbluebutton-client/src/assets/images/elipse.png b/bigbluebutton-client/src/assets/images/elipse.png
deleted file mode 100755
index 3252b6aa957f272a4c0ae8ea14213464681cba7d..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/assets/images/elipse.png and /dev/null differ
diff --git a/bigbluebutton-client/src/assets/images/fit-to-screen.png b/bigbluebutton-client/src/assets/images/fit-to-screen.png
deleted file mode 100755
index 0f83d20bedc8a35bced16f37b0e6cd2f6277d81f..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/assets/images/fit-to-screen.png and /dev/null differ
diff --git a/bigbluebutton-client/src/assets/images/fit-to-width.png b/bigbluebutton-client/src/assets/images/fit-to-width.png
deleted file mode 100755
index 12b052798435720aca6d0c94e43073e4eac5a1d4..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/assets/images/fit-to-width.png and /dev/null differ
diff --git a/bigbluebutton-client/src/assets/images/left_arrow.png b/bigbluebutton-client/src/assets/images/left_arrow.png
deleted file mode 100755
index e6abeb60d45d8a2a2b0f85b741f1af14683a4c4c..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/assets/images/left_arrow.png and /dev/null differ
diff --git a/bigbluebutton-client/src/assets/images/right_arrow.png b/bigbluebutton-client/src/assets/images/right_arrow.png
deleted file mode 100755
index 6eab9f047a5ecd05d65ac1dae3f226b80009347d..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/assets/images/right_arrow.png and /dev/null differ
diff --git a/bigbluebutton-client/src/assets/images/upload.png b/bigbluebutton-client/src/assets/images/upload.png
deleted file mode 100755
index 724a094ae6974c1fd6e451ed492a06955e538ed2..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/assets/images/upload.png and /dev/null differ
diff --git a/bigbluebutton-client/src/branding/css/assets/img/mconf-logo.png b/bigbluebutton-client/src/branding/css/assets/img/mconf-logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..184cce468d90bf0be4bc4bb9320c0f8ae35e4e29
Binary files /dev/null and b/bigbluebutton-client/src/branding/css/assets/img/mconf-logo.png differ
diff --git a/bigbluebutton-client/src/branding/css/mconf.css b/bigbluebutton-client/src/branding/css/mconf.css
new file mode 100755
index 0000000000000000000000000000000000000000..10667831b49186528ac1c62c16f3de86c8612aca
--- /dev/null
+++ b/bigbluebutton-client/src/branding/css/mconf.css
@@ -0,0 +1,265 @@
+/*
+ * TODO: LoggedOutWindow has scrollbars
+ *
+ * Other:
+ * light green: 1f7385
+ * darker green: 27535C
+ * grey-ish light green: 637d7f
+ * navbar dark: #183338
+ * navbar light: #27535C
+ * bootstrap blue: #0E90D2
+ * bootstrap green: #468847
+ * bootstrap green light: #DFF0D8
+ * bootstrap green medium: #D6E9C6
+ * Flex 3 css properties: http://www.loscavio.com/downloads/blog/flex3_css_list/flex3_css_list.htm#ComboBox
+*/
+
+/* To make something bizarre
+  backgroundAlpha: 1;
+  backgroundColor: #800000;
+  borderStyle: solid;
+  borderColor: #008000;
+  borderAlpha: 1;
+  borderThickness: 5;
+  cornerRadius: 10;
+  dropShadowEnabled: false;
+*/
+
+/* green to blue
+#468847 -> #0E90D2
+#d6e9ff -> #d6e9ff
+#DFF0D8 -> #d6e9ff
+#569556 -> #468ce6
+*/
+
+
+Application
+{
+  /* top, bottom */
+  backgroundGradientColors: #27535C,#183338;  /*#27535C,#27535C; /* #637d7f; /*#444, #666;*/
+  /* main color used everywhere: selections, button borders?, ... */
+  themeColor: #468847; /*#1f7385;*/
+  /* top alpha, bottom alpha */
+  backgroundGradientAlphas: 0.8, 0.5;
+
+  fontFamily: Verdana;
+  fontSize: 10;
+  color: #111111;
+  fontWeight: normal;
+}
+
+/*The image for your logo is 200x200 pixels. No other size is currently supported so resize your logo accordingly. The logo will always appear in the lower right corner. */
+BrandingLogo
+{
+  backgroundImage: Embed(source="assets/img/mconf-logo.png");
+  backgroundSize: "100%";
+}
+
+/* Borders around the application so the windows don't touch the edges.
+   Will affect MicSettings too :( */
+VBox
+{
+  paddingBottom: 0;
+  paddingTop: 0;
+  paddingRight: 5;
+  paddingLeft: 5;
+}
+
+Text
+{
+  borderStyle: solid;
+  borderColor: #800000;
+  borderAlpha: 1;
+  borderThickness: 1;
+}
+
+/* the big area where all internal windows are */
+MDICanvas
+{
+}
+
+Button
+{
+  /* default color: border, hovers, etc. */
+  themeColor: #468847; /*#27535C;*/
+  /* normal all, smoothness? */
+  highlightAlphas: 1, 0.15;/*1, 0.33;*/
+  /* bottom normal?,  bottom normal?, hover, hover (border?) */
+  fillAlphas: 0.8, 0.6, 0.6, 0.8;/*1, 0.16, 0.18, 1;*/
+  /* disabled top and middle normal (weak), bottom all, middle hover (weak), bottom hover. top normal always #fff? */
+  fillColors: #dddddd, #ffffff, #dddddd, #cccccc;
+
+  borderStyle: solid;
+  borderColor: #aaaaaa;
+  borderAlpha: 1;
+  borderThickness: 2;
+}
+
+ComboBox, Button, TextArea, TextInput
+{
+  cornerRadius: 3;
+}
+
+ComboBox /*, LinkButton */
+{
+  selectionColor: #D6E9C6; /*#1f7385;*/
+  rollOverColor: #dddddd;
+  textSelectedColor: #000000; /*#ffffff;*/
+}
+
+DataGrid
+{
+  selectionColor: #DFF0D8;/*#a3c0c7;*/
+  rollOverColor: #dddddd;
+  /*textSelectedColor: #ffffff; TODO: how? */
+}
+
+/* Container that holds the entire app but also container that holds the control
+   buttons in every window title bar */
+LayoutContainer
+{
+  horizontalGap: 10; /* space between window controls (close, min) */
+  verticalGap: 0;
+}
+
+/* Both the top control bar and the control bar in the bottom of PresentModule */
+ApplicationControlBar
+{
+  backgroundAlpha: 0.01;
+  backgroundColor: #000000;/*#27535C;*/
+  borderStyle: solid;
+  /*borderColor: #27535C;*/
+  borderAlpha: 0;
+  borderThickness: 0;
+  cornerRadius: 0;
+  dropShadowEnabled: false;
+}
+/* doesn't work :( */
+/*ApplicationControlBar Button
+{
+  backgroundAlpha: 0.1;
+  backgroundColor: #000000;
+  borderThickness: 10;
+  cornerRadius: 1;
+  dropShadowEnabled: false;
+  themeColor: #800000;
+}*/
+
+/* Space around modal windows and aroung the control bars in the bottom of
+   almost all modules. Apparently doesn't work if TitleWindow is also
+   defined. */
+Panel
+{
+  /* To change the modal windows e.g. audio controls */
+  /*borderStyle: solid;
+  borderColor: #ffffff;
+  borderAlpha: 0.8;
+  borderThickness: 2;
+  cornerRadius: 2;
+  dropShadowEnabled: true;*/
+
+  /* this style will match the bottom control bars that exist in almost all
+     modules, like the place with the chat input text control and btn */
+  /*controlBarStyleName: "panelControlBar";*/
+}
+
+/* Internals of modal windows */
+TitleWindow
+{
+  backgroundAlpha: 1;
+  backgroundColor: #eeeeee;
+  borderStyle: solid;
+  borderColor: #ffffff;
+  borderAlpha: 0.9;
+  borderThickness: 4;
+  cornerRadius: 2;
+  dropShadowEnabled: true;
+  shadowDirection: right;
+}
+
+ProgressBar
+{
+  borderStyle: solid;
+  borderColor: #cccccc;
+  borderAlpha: 0.9;
+  borderThickness: 0;
+  cornerRadius: 1;
+  barColor: #569556;
+  color: #222; /*ffffff;*/
+}
+
+/* matches the tab component in ChatModule */
+/*TabNavigator
+{
+}*/
+
+/* List of participants */
+DataGridColumn
+{
+  backgroundAlpha: 1;
+  backgroundColor: #800000;
+  borderStyle: solid;
+  borderColor: #008000;
+  borderAlpha: 1;
+  borderThickness: 5;
+  cornerRadius: 10;
+  dropShadowEnabled: false;
+}
+
+/* Internal windows with focus */
+.mdiWindowFocus
+{
+  headerHeight: 22;
+  backgroundAlpha: 1;
+  backgroundColor: #dddddd; /*#637d7f;*/
+  borderStyle: solid;
+  borderColor: #ffffff; /*#27535C;*/
+  borderAlpha: 0.9;
+  borderThickness: 1;
+  cornerRadius: 1;
+  dropShadowEnabled: false;
+  titleStyleName: "mypanelTitleFocused";
+}
+.mypanelTitleFocused
+{
+  fontFamily: Verdana;
+  fontSize: 10;
+  fontWeight: bold;
+  color: #111111;
+}
+
+/* Internal windows without focus */
+.mdiWindowNoFocus
+{
+  headerHeight: 22;
+  backgroundAlpha: 0.95;
+  backgroundColor: #dddddd; /*#637d7f;*/
+  borderStyle: solid;
+  borderColor: #eeeeee;
+  borderAlpha: 0.9;
+  borderThickness: 1;
+  cornerRadius: 1;
+  dropShadowEnabled: false;
+  titleStyleName: "mypanelTitle";
+}
+.mypanelTitle
+{
+  fontFamily: Verdana;
+  fontSize: 10;
+  fontWeight: bold;
+  color: #111111;
+}
+
+HSlider
+{
+  showTrackHighlight: true;
+}
+
+ToolTip {
+   cornerRadius: 2;
+   paddingLeft: 3;
+   paddingRight: 3;
+   backgroundColor: #94bbbe;
+   color: #222222;
+   textAlign: center;
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/Images.as b/bigbluebutton-client/src/org/bigbluebutton/common/Images.as
index 0334acfb0cf0d1e846d585943164b6fb5c68c312..cc24fd43f0dbfb98d2f986eadce75ffb5cca055d 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/common/Images.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/common/Images.as
@@ -22,9 +22,6 @@ package org.bigbluebutton.common
 	public class Images
 	{
 
-    [Embed(source="assets/images/page_link.png")]
-    public var page_link:Class;
-
 	[Embed(source="assets/images/users_settings.png")]
 	public var users_settings:Class;
 
@@ -43,126 +40,27 @@ package org.bigbluebutton.common
 	[Embed(source="assets/images/audio_20.png")]
 	public var audio_20:Class;
 
-	[Embed(source="assets/images/webcam_new.png")]
-	public var webcam_new:Class;
-
     [Embed(source="assets/images/webcam_new_20.png")]
     public var webcam_new_20:Class;
 
 	[Embed(source="assets/images/sound_new.png")]
 	public var sound_new:Class;
 
-	[Embed(source="assets/images/moderator.png")]
+	[Embed(source="assets/images/moderator_20db.png")]
 	public var moderator:Class;
 
-	[Embed(source="assets/images/presenter_new.png")]
+	[Embed(source="assets/images/presenter_new_20db.png")]
 	public var presenter_new:Class;
 
-    [Embed(source="assets/images/webcam_kickuser.png")]
-    public var webcam_kickuser:Class;
-
-    [Embed(source="assets/images/webcam_make_presenter.png")]
-    public var webcam_make_presenter:Class;
-
     [Embed(source="assets/images/webcam_mute.png")]
     public var webcam_mute:Class;
 
-    [Embed(source="assets/images/webcam_private_chat.png")]
-    public var webcam_private_chat:Class;
-
-    [Embed(source="assets/images/webcam_unmute.png")]
-    public var webcam_unmute:Class;
-
-    [Embed(source="assets/images/vdoc_bg.jpg")]
-    public var video_dock_bg:Class;
-
-    [Embed(source="assets/images/bandwidth.png")]
-    public var bandwidth:Class;
-
-    [Embed(source="assets/images/statistics.png")]
-    public var stats:Class;
-
-    [Embed(source="assets/images/avatar.png")]
-    public var avatar:Class;
-
-    [Embed(source="assets/images/sign-out.png")]
-    public var signOutIcon:Class;
-
-    [Embed(source="assets/images/chat.png")]
-    public var chatIcon:Class;
-
-		[Embed(source="assets/images/webcam_close.png")]
-		public var webcamClose:Class;
-
-		[Embed(source="assets/images/deskshare_close.png")]
-		public var deskshareClose:Class;
-
-		[Embed(source="assets/images/fit-to-page.png")]
-		public var fitToPage:Class;
-
-		[Embed(source="assets/images/fit-to-width.png")]
-		public var fitToWidth:Class;
-
-		[Embed(source="assets/images/green-circle.png")]
-		public var greenCircle:Class;
-
-		[Embed(source="assets/images/blank-circle.png")]
-		public var blankCircle:Class;
-
-		[Embed(source="assets/images/red-circle.png")]
-		public var redCircle:Class;
-
-        [Embed(source="assets/images/user_gray.png")]
-        public var user_gray:Class;
-
-        [Embed(source="assets/images/user_green.png")]
-        public var user_green:Class;
-
-		[Embed(source="assets/images/Cursor.png")]
-		public var cursorIcon:Class;
-
-		[Embed(source="assets/images/magnifier_reset.png")]
-		public var mag_reset:Class;
-
-        [Embed(source="assets/images/user_orange.png")]
-        public var user_orange:Class;
-
-        [Embed(source="assets/images/user_red.png")]
-        public var user_red:Class;
-
-        [Embed(source="assets/images/user.png")]
-        public var user:Class;		
-
-        [Embed(source="assets/images/administrator.gif")]
-        public var admin:Class;
-
-        [Embed(source="assets/images/participant.gif")]
-        public var participant:Class;
-
-        [Embed(source="assets/images/participant-mute.png")]
-        public var participant_mute:Class;
-
-        [Embed(source="assets/images/mic_muted.png")]
-        public var sound_mute:Class;
-
-        [Embed(source="assets/images/mic_unmuted.png")]
-        public var sound_none:Class;
-
-        [Embed(source="assets/images/sound.png")]
+        [Embed(source="assets/images/ic_hearing_grey_20dp.png")]
         public var sound:Class;
 
         [Embed(source="assets/images/cancel.png")]
         public var cancel:Class;
 
-        [Embed(source="assets/images/user_go.png")]
-        public var eject_user:Class;
-
-        [Embed(source="assets/images/webcam.png")]
-        public var webcam:Class;
-
-	[Embed(source="assets/images/webcam_on.png")]
-        public var webcamOn:Class;
-
         [Embed(source="assets/images/pencil.png")]
         public var pencil_icon:Class;
 
@@ -184,18 +82,15 @@ package org.bigbluebutton.common
         [Embed(source="assets/images/ellipse.png")]
         public var circle_icon:Class;
 
-        [Embed(source="assets/images/arrow_out.png")]
+        [Embed(source="assets/images/ic_fullscreen_16px.png")]
         public var full_screen:Class;
 
+        [Embed(source="assets/images/ic_fullscreen_exit_16px.png")]
+        public var exit_full_screen:Class;
+
         [Embed(source="assets/images/BBBlogo.png")]
         public var bbb_logo:Class;
 
-        [Embed(source="assets/images/deskshare_icon.png")]
-        public var deskShareIcon:Class;
-
-	[Embed(source="assets/images/deskshare_on.png")]
-        public var deskShareIconOn:Class;
-
         [Embed(source="assets/images/control_play_blue.png")]
         public var control_play:Class;
 
@@ -208,67 +103,29 @@ package org.bigbluebutton.common
 		[Embed(source="assets/images/trash.png")]
 		public var delete_icon:Class;
 
-        [Embed(source="assets/images/arrow_right.png")]
-        public var forward:Class;
-
-        [Embed(source="assets/images/arrow_left.png")]
-        public var backward:Class;
-
-        [Embed(source="assets/images/magnifier.png")]
-        public var magnifier:Class;
-
         [Embed(source="assets/images/add.png")]
         public var add:Class;
 
         [Embed(source="assets/images/bullet_go.png")]
         public var bulletGo:Class;
 
-        [Embed(source="assets/images/upload.png")]
-        public var upload:Class;
-
-		[Embed(source="assets/images/annotation.png")]
-		public var whiteboard:Class;
-
 		[Embed(source="assets/images/whiteboard_thick.png")]
 		public var whiteboard_thick:Class;
 
 		[Embed(source="assets/images/whiteboard_thin.png")]
 		public var whiteboard_thin:Class;
 
-		[Embed(source="assets/images/lock.png")]
-		public var locked:Class;
-
-		[Embed(source="assets/images/unlock.png")]
-		public var unlocked:Class;
-
 		[Embed(source="assets/images/lock_20.png")]
 		public var locked_20:Class;
 
 		[Embed(source="assets/images/unlock_20.png")]
 		public var unlocked_20:Class;
 
-		[Embed(source="assets/images/presenter.png")]
-		public var presenter:Class;
-
 		[Embed(source="assets/images/lock_open.png")]
 		public var lock_open:Class;
 
-		[Embed(source="assets/images/lock_close.png")]
-		public var lock_close:Class;
-
-		[Embed(source="assets/images/arrow_in.png")]
-		public var arrow_in:Class;
-
-		[Embed(source="assets/images/shape_handles.png")]
-		public var shape_handles:Class;
-	[Embed(source="assets/images/poll_icon.png")]
-	public var pollIcon:Class;
-
-		[Embed(source="assets/images/disk.png")]
-		public var disk:Class;
-
-		[Embed(source="assets/images/folder.png")]
-		public var folder:Class;
+		[Embed(source="assets/images/disk_grayscale.png")]
+		public var disk_grayscale:Class;
 
 		// PLACE CUSTOM IMAGES BELOW
 		[Embed(source="assets/images/line.png")]
@@ -301,29 +158,14 @@ package org.bigbluebutton.common
 		[Embed(source="assets/images/grid_icon.png")]
 		public var grid_icon:Class;
 
+		[Embed(source="assets/images/ic_refresh_16px.png")]
+		public var refreshSmall:Class;
+
 		[Embed(source="assets/images/moderator_white.png")]
 		public var moderator_white:Class;
 
 		[Embed(source="assets/images/presenter_white.png")]
 		public var presenter_white:Class;
-
-		[Embed(source="assets/images/emoji_raiseHand.png")]
-		public var emoji_raiseHand:Class;
-
-		[Embed(source="assets/images/emoji_happy.png")]
-		public var emoji_happy:Class;
-
-		[Embed(source="assets/images/emoji_sad.png")]
-		public var emoji_sad:Class;
-
-		[Embed(source="assets/images/emoji_neutral.png")]
-		public var emoji_neutral:Class;
-
-		[Embed(source="assets/images/emoji_away.png")]
-		public var emoji_away:Class;
-
-		[Embed(source="assets/images/emoji_confused.png")]
-		public var emoji_confused:Class;
 		
 		[Embed(source="assets/images/transfer.png")]
 		public var transfer:Class;
@@ -342,5 +184,50 @@ package org.bigbluebutton.common
 
 		[Embed(source="assets/images/emoji_applause.png")]
 		public var emoji_applause:Class;
+
+		[Embed(source="assets/images/user_add.png")]
+		public var user_add:Class;
+
+		[Embed(source="assets/images/user_delete.png")]
+		public var user_delete:Class;
+
+		[Embed(source="assets/images/status/ic_mood_grey_20dp.png")]
+		public var mood:Class;
+
+		[Embed(source="assets/images/status/ic_clear_grey_20dp.png")]
+		public var mood_clear:Class;
+
+		[Embed(source="assets/images/status/icon-3-grey-high-five.png")]
+		public var mood_raiseHand:Class;
+
+		[Embed(source="assets/images/status/icon-6-grey-thumb-up.png")]
+		public var mood_agree:Class;
+
+		[Embed(source="assets/images/status/icon-7-grey-thumb-down.png")]
+		public var mood_disagree:Class;
+
+		[Embed(source="assets/images/status/ic_fast_forward_grey_20dp.png")]
+		public var mood_speakFaster:Class;
+
+		[Embed(source="assets/images/status/ic_fast_rewind_grey_20dp.png")]
+		public var mood_speakSlower:Class;
+
+		[Embed(source="assets/images/status/ic_volume_up_grey_20dp.png")]
+		public var mood_speakLouder:Class;
+
+		[Embed(source="assets/images/status/ic_volume_down_grey_20dp.png")]
+		public var mood_speakSofter:Class;
+
+		[Embed(source="assets/images/status/ic_access_time_grey_20dp.png")]
+		public var mood_beRightBack:Class;
+
+		[Embed(source="assets/images/status/icon-6-grey-smiling-face.png")]
+		public var mood_happy:Class;
+
+		[Embed(source="assets/images/status/icon-7-grey-sad-face.png")]
+		public var mood_sad:Class;
+
+		[Embed(source="assets/images/status/applause-20.png")]
+		public var mood_applause:Class;
 	}
 }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/Cursor.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/Cursor.png
deleted file mode 100755
index 6e29c43729b8711191d7120348e15bbcfa236dd0..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/Cursor.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/administrator.gif b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/administrator.gif
deleted file mode 100755
index 608d2d165cc57f36680e07fab2e93bfa807b1448..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/administrator.gif and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/annotation.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/annotation.png
deleted file mode 100755
index fb7cb8e9e749505cb926978acd0a4c5e3a531064..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/annotation.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/application_put.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/application_put.png
deleted file mode 100644
index c30cf59894473550b70d2ab97e2244af64c2ecd0..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/application_put.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_in.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_in.png
deleted file mode 100755
index 745c65134db478a64016d63a7104e585452f2b9f..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_in.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_left.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_left.png
deleted file mode 100644
index 56ee138d14b6276fabb20d8f4a0001c284915667..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_left.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_out.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_out.png
deleted file mode 100644
index 2e9bc42bec16e3077a9680e7af0f90395bfeb60c..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_out.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_right.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_right.png
deleted file mode 100644
index f455031232ff01b4eadc4a995091b8c7d80d5c4c..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_right.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_undo.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_undo.png
deleted file mode 100644
index e0f8038cff94cd994c8356cdb543b3aa849bb288..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/arrow_undo.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/avatar.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/avatar.png
deleted file mode 100644
index 2e9f8151f4083aece663009ae40d9271104dbb41..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/avatar.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/bandwidth.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/bandwidth.png
deleted file mode 100755
index adb979ce5aa24832549312d1291605e4dfcc4cae..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/bandwidth.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/blank-circle.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/blank-circle.png
deleted file mode 100755
index f3b2a1360a0a4dcfe3824294e268cad6918ea240..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/blank-circle.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/chat.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/chat.png
deleted file mode 100755
index 15ce4659becbb786d104c863aec789ce78c487be..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/chat.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/circle.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/circle.png
deleted file mode 100644
index 06e7ffa98614ec3ad0f62671581cbd0bcf6e74c7..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/circle.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/deskshare_close.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/deskshare_close.png
deleted file mode 100755
index 2c68797e1e5ec4ecde6df2e3ffc0ad1cc4c91302..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/deskshare_close.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/deskshare_on.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/deskshare_on.png
deleted file mode 100644
index ab036b1766e4284d2603518848309a1ad3a5f842..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/deskshare_on.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/disk.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/disk.png
deleted file mode 100644
index 99d532e8b1750115952f97302a92d713c0486f97..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/disk.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/disk_grayscale.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/disk_grayscale.png
new file mode 100644
index 0000000000000000000000000000000000000000..30056e2734a4077a030755f5de3d9db5c6804276
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/disk_grayscale.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_away.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_away.png
deleted file mode 100644
index c2042f1d8b21f16533efdb858119daaa0a716942..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_away.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_confused.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_confused.png
deleted file mode 100644
index d7774ba6c620bc836c1c45ed1067c027fd0c099b..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_confused.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_happy.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_happy.png
deleted file mode 100644
index c1e579d3ae58090650ccfab6b99c9b76535d7d0b..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_happy.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_neutral.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_neutral.png
deleted file mode 100644
index 90337ef36e9df667485ec99670da54670e844c35..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_neutral.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_raiseHand.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_raiseHand.png
deleted file mode 100755
index 4c5c4836d1a4a55a34ed332a7b2b05800febe97a..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_raiseHand.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_sad.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_sad.png
deleted file mode 100644
index e8d820ccab4945d2e74f22a62c30406c91bc0a14..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/emoji_sad.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/fit-to-page.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/fit-to-page.png
deleted file mode 100755
index 47277b6aacc1f97b155fe640dfe56a191fb5476d..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/fit-to-page.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/fit-to-screen.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/fit-to-screen.png
deleted file mode 100755
index fe28c01d240b2ba38bc005ec4fc8af97f3248d62..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/fit-to-screen.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/fit-to-width.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/fit-to-width.png
deleted file mode 100755
index f991166ed66ce39733208574c3a1bc7931d812be..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/fit-to-width.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/folder.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/folder.png
deleted file mode 100644
index 784e8fa48234f4f64b6922a6758f254ee0ca08ec..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/folder.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/forward_blue.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/forward_blue.png
deleted file mode 100644
index 4a2f9d4e4a81857f509d85bbe46936c99709cd6f..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/forward_blue.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/green-circle.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/green-circle.png
deleted file mode 100755
index 08f8b8c25a23734b28abe4b90f809d770d592600..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/green-circle.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/hand_icon.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/hand_icon.png
deleted file mode 100755
index 9613b05b115c820fa93ef5ce38ac181407a3d465..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/hand_icon.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_fullscreen_16px.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_fullscreen_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..685700f137f2e62b1c8f727d3fbb122438ec6300
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_fullscreen_16px.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_fullscreen_exit_16px.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_fullscreen_exit_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..e6c25681015ba7367447ec565750bd530359f7a2
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_fullscreen_exit_16px.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_hearing_grey_20dp.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_hearing_grey_20dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..2be75cab8dea9c36da7411ac429d2fe2a938e0b7
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_hearing_grey_20dp.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_refresh_16px.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_refresh_16px.png
new file mode 100644
index 0000000000000000000000000000000000000000..02a2d81f6f291371599e4bec81442a796a4d295b
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/ic_refresh_16px.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/left_arrow.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/left_arrow.png
deleted file mode 100755
index 3117136c1fda27fb27a057d835deb05a0a888e23..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/left_arrow.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/lock.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/lock.png
deleted file mode 100755
index 08f0bf613f5e25dababa85e2a9e645f27ef9aec4..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/lock.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/lock_close.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/lock_close.png
deleted file mode 100755
index 2ebc4f6f9663e32cad77d67ef93ab8843dfea3c0..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/lock_close.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/magnifier_reset.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/magnifier_reset.png
deleted file mode 100755
index 7f9d1f10fe789afffe142dfc6b3375565c649d91..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/magnifier_reset.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/mic_muted.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/mic_muted.png
deleted file mode 100755
index 34e813655006205fa661dbda05b852a91663cddc..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/mic_muted.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/mic_unmuted.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/mic_unmuted.png
deleted file mode 100755
index d5b65fc7efc1702fcb6fcf34bb7d51c59ae16235..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/mic_unmuted.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/moderator.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/moderator.png
deleted file mode 100644
index 36213a78668b1dca782629208ea25c0680a5216f..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/moderator.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/moderator_20db.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/moderator_20db.png
new file mode 100644
index 0000000000000000000000000000000000000000..e14349d5cef9f7b2a1b1a24c70e03839ccd5c272
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/moderator_20db.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/page_link.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/page_link.png
deleted file mode 100644
index 319e27b1925e4f135f1f82873478452403516db9..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/page_link.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/participant-mute.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/participant-mute.png
deleted file mode 100644
index 57b6320479d61cab97575cbef09157da017fb3b6..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/participant-mute.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/participant.gif b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/participant.gif
deleted file mode 100755
index d307b20068a20cd09497a6366201a93ff1487778..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/participant.gif and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/pointer_delete_icon.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/pointer_delete_icon.png
deleted file mode 100644
index 58843f630372ea8ffc69424b0ec1fa58e287b5f3..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/pointer_delete_icon.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/poll_icon.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/poll_icon.png
deleted file mode 100644
index 1747b00c1767ecb5ef1bf822eded15c8a67b25c5..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/poll_icon.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/presenter.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/presenter.png
deleted file mode 100644
index c1974cda745278a404b9e29fa91e0503a84accb1..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/presenter.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/presenter_new.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/presenter_new.png
deleted file mode 100644
index b9d40bb75b3df779443e7f96c808f193d82bee63..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/presenter_new.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/presenter_new_20db.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/presenter_new_20db.png
new file mode 100644
index 0000000000000000000000000000000000000000..4ada04086f217489af85d1cc6c36b43429930d2e
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/presenter_new_20db.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/red-circle.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/red-circle.png
deleted file mode 100755
index 1c500ba34e6e023796bf329bb335390d9649c3d6..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/red-circle.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/righ-arrow.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/righ-arrow.png
deleted file mode 100755
index f00775a7eab38053a23d662ed228e66cb25f4b56..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/righ-arrow.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/scribble_icon.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/scribble_icon.png
deleted file mode 100755
index 60c8b028e28b9b3daf788df737f6a56b2608add4..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/scribble_icon.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/shape_handles.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/shape_handles.png
deleted file mode 100755
index ce27fe3a0345e03e919b54ca3b6a8498743b2ee9..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/shape_handles.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/sign-out.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/sign-out.png
deleted file mode 100755
index 5f99debfcad533d31a79852b2422cf9bd4130cd8..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/sign-out.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/statistics.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/statistics.png
deleted file mode 100755
index d4779d9d69e71375594045eeb070e9793fb897a6..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/statistics.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/applause-20.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/applause-20.png
new file mode 100644
index 0000000000000000000000000000000000000000..8f39c4618c55666ed738407dd6e423b4ee5a2f12
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/applause-20.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_access_time_grey_20dp.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_access_time_grey_20dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..00e5112469ea4416e53d6164f5110c60c11c3369
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_access_time_grey_20dp.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_clear_grey_20dp.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_clear_grey_20dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..8e6d3ce19bfe2a8223c3161c411592a25d769a69
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_clear_grey_20dp.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_fast_forward_grey_20dp.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_fast_forward_grey_20dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..2416aaefdc638f7656ccfd714a7a7c920dfcfcd0
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_fast_forward_grey_20dp.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_fast_rewind_grey_20dp.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_fast_rewind_grey_20dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..e9d507243f66c59bb5b737530310d73a3415d363
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_fast_rewind_grey_20dp.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_mood_grey_20dp.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_mood_grey_20dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..60604dbb3cc459b7c7627cadf2bb7c7861a73b8c
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_mood_grey_20dp.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_volume_down_grey_20dp.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_volume_down_grey_20dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..c068c151f6dab4f7f4565c5c1a0cac812bcd4fd7
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_volume_down_grey_20dp.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_volume_up_grey_20dp.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_volume_up_grey_20dp.png
new file mode 100644
index 0000000000000000000000000000000000000000..d625a3f7c72215d767c4a361bea225f3b4bd0766
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/ic_volume_up_grey_20dp.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-3-grey-high-five.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-3-grey-high-five.png
new file mode 100644
index 0000000000000000000000000000000000000000..08577497f29344b4833c7f040dcb1ebb214f425c
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-3-grey-high-five.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-6-grey-smiling-face.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-6-grey-smiling-face.png
new file mode 100644
index 0000000000000000000000000000000000000000..9d10ce0c7492c7270989be4e2cabfb0147fcb2a3
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-6-grey-smiling-face.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-6-grey-thumb-up.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-6-grey-thumb-up.png
new file mode 100644
index 0000000000000000000000000000000000000000..0c78bea9d46b6605f76eb02f9e6400daa43ac7b3
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-6-grey-thumb-up.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-7-grey-sad-face.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-7-grey-sad-face.png
new file mode 100644
index 0000000000000000000000000000000000000000..5b938878a6083702a51a45649baeb566cf501377
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-7-grey-sad-face.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-7-grey-thumb-down.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-7-grey-thumb-down.png
new file mode 100644
index 0000000000000000000000000000000000000000..f9d48bd5d8c32dffec647c312aef106513569738
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/status/icon-7-grey-thumb-down.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/triangle_icon.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/triangle_icon.png
deleted file mode 100644
index eca80815db2747df0f97b6c54531dcb450e8a404..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/triangle_icon.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/unlock.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/unlock.png
deleted file mode 100755
index d09050420eb92a7060454f1053d8a72352413178..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/unlock.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/upload.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/upload.png
deleted file mode 100755
index 030cc3e82aab53ff29cbc0dc4fbe30ee067177be..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/upload.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_add.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_add.png
new file mode 100644
index 0000000000000000000000000000000000000000..deae99bcff9815d8530a920e754d743700ddd5fb
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_add.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_delete.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_delete.png
new file mode 100644
index 0000000000000000000000000000000000000000..acbb5630e51a12a1cd30ea799d659b309e7041cd
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_delete.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_go.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_go.png
deleted file mode 100644
index 0468cf08f3760dc13e44aed69f4f15cedc93b503..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_go.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_gray.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_gray.png
deleted file mode 100644
index 8fd539e9cb04111e950ac9b0cce82676f12f67d4..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_gray.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_green.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_green.png
deleted file mode 100644
index 30383c2de517fd22945a87b0528d2821ec4d49ce..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_green.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_orange.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_orange.png
deleted file mode 100644
index b818127df6d064b71838c377063c2c61517ffa01..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_orange.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_red.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_red.png
deleted file mode 100644
index c6f66e8b300750826b214e38e7cf3365fa637878..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/user_red.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/vdoc_bg.jpg b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/vdoc_bg.jpg
deleted file mode 100755
index 0dfda438df84be7d57567944ff3a89f1f540900a..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/vdoc_bg.jpg and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam.png
deleted file mode 100755
index af71c30610862c76f07e948d8c28433c7d338f9a..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_close.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_close.png
deleted file mode 100755
index 5265a7305e18196d51edcf9db18789c935bb9e9e..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_close.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_kickuser.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_kickuser.png
deleted file mode 100755
index 561edc8d9b00d9c97c9acd82b4bf121bc3a77426..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_kickuser.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_make_presenter.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_make_presenter.png
deleted file mode 100755
index e7cfff5e97381b5a88d0b96b35508e52e850960e..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_make_presenter.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_new.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_new.png
deleted file mode 100644
index ae305c167a690281fa8f741e2d096605f5b94f99..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_new.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_on.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_on.png
deleted file mode 100644
index 6c491aa4b5b75f6e3aeed6f3b75f04f74eff9143..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_on.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_private_chat.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_private_chat.png
deleted file mode 100755
index 9fdff988a3cfa2f6ef81f0a2d0de135dd199371e..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_private_chat.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_unmute.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_unmute.png
deleted file mode 100755
index 32a685732f0073772bb782662fe37e30a83d5220..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/webcam_unmute.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/whiteboard_icon.png b/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/whiteboard_icon.png
deleted file mode 100755
index aee99fc0c74ce104ee94ef5116badb9dc6e2eb38..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/whiteboard_icon.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/events/SettingsComponentEvent.as b/bigbluebutton-client/src/org/bigbluebutton/common/events/SettingsComponentEvent.as
new file mode 100755
index 0000000000000000000000000000000000000000..1063ae9dba43f9619cacdea1c53711345df859a8
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/common/events/SettingsComponentEvent.as
@@ -0,0 +1,39 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*
+*/
+
+package org.bigbluebutton.common.events
+{
+	import flash.events.Event;
+
+	import mx.core.UIComponent;
+
+	public class SettingsComponentEvent extends Event
+	{
+		public static const ADD:String = "Add Component Event";
+		public static const REMOVE:String = "Remove Component Event";
+
+		public var component:UIComponent;
+
+		public function SettingsComponentEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/UsersUtil.as b/bigbluebutton-client/src/org/bigbluebutton/core/UsersUtil.as
index 8887e7ab68b50e8b39c1f8987e3e0f9aae4073b6..8efcff5597bc38667542567d67d52a1a2fa0e1b3 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/core/UsersUtil.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/UsersUtil.as
@@ -140,6 +140,10 @@ package org.bigbluebutton.core
     public static function amIPresenter():Boolean {
       return UserManager.getInstance().getConference().amIPresenter;
     }
+
+    public static function amIWaitingForAcceptance():Boolean {
+      return UserManager.getInstance().getConference().amIWaitingForAcceptance();
+    }
         
     public static function hasUser(userID:String):Boolean {
       return UserManager.getInstance().getConference().hasUser(userID);
@@ -148,6 +152,10 @@ package org.bigbluebutton.core
     public static function getUser(userID:String):BBBUser {
       return UserManager.getInstance().getConference().getUser(userID);
     }
+
+    public static function getMyself():BBBUser {
+      return UserManager.getInstance().getConference().getMyself();
+    }
     
     public static function isMe(userID:String):Boolean {
       return UserManager.getInstance().getConference().amIThisUser(userID);
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConnectionManager.as b/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConnectionManager.as
index 47313b50325f10d692014d27f30358ed84079f7d..5523c1879869c480585c7bee7643bb17014ab8d4 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConnectionManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/managers/ConnectionManager.as
@@ -63,6 +63,10 @@ package org.bigbluebutton.core.managers
     public function forceClose():void {
       connDelegate.forceClose(); 
     }
+
+    public function guestDisconnect():void {
+      connDelegate.guestDisconnect();
+    }
             
 	}
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/model/Config.as b/bigbluebutton-client/src/org/bigbluebutton/core/model/Config.as
index 0df4af0d4f4896f156f106d844261934b4108b82..043cd471c756797eaeb54ce7b327cafef3736f82 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/core/model/Config.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/model/Config.as
@@ -99,6 +99,16 @@ package org.bigbluebutton.core.model
 	      return new XML(config.layout.toXMLString());
 	    }
     	
+		public function get branding():Object{
+			var a:Object = new Object();
+			a.copyright = config.branding.@copyright;
+			a.logo = config.branding.@logo;
+			a.background = config.branding.@background;
+			a.toolbarColor = config.branding.@toolbarColor;
+			a.toolbarColorAlphas = config.branding.@toolbarColorAlphas;
+			return a
+		}
+
 		public function get meeting():XML {
 			return new XML(config.meeting.toXMLString());
 		}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/model/MeBuilder.as b/bigbluebutton-client/src/org/bigbluebutton/core/model/MeBuilder.as
index 50a77f661e4afc87140bb0e23330d5a3d71b6984..b69d15ac8715fb72e3f86e9e14bb441996653f93 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/core/model/MeBuilder.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/model/MeBuilder.as
@@ -12,6 +12,7 @@ package org.bigbluebutton.core.model
     internal var logoutURL:String;
     internal var dialNumber:String;
     internal var role:String;
+    internal var guest:Boolean;
     internal var customData:Object;
     
     public function MeBuilder(id: String, name: String) {
@@ -58,6 +59,11 @@ package org.bigbluebutton.core.model
       role = value;
       return this;
     }
+
+    public function withGuest(value: Boolean):MeBuilder {
+      guest = value;
+      return this;
+    }
     
     public function withCustomData(value: Object):MeBuilder {
       customData = value;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/model/Meeting.as b/bigbluebutton-client/src/org/bigbluebutton/core/model/Meeting.as
index 96faa4557e9b30f6abcee2dc67623962dd6b0c8c..0e7332cfb226464f1c28857c423d2faaea4355a5 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/core/model/Meeting.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/model/Meeting.as
@@ -14,6 +14,7 @@ package org.bigbluebutton.core.model
     private var _welcomeMessage:String;
     private var _modOnlyMessage:String;
     private var _allowStartStopRecording:Boolean;
+    private var _metadata:Object = null;
     
     public var isRecording: Boolean = false;
     
@@ -31,6 +32,7 @@ package org.bigbluebutton.core.model
       _welcomeMessage = build.welcomeMessage;
       _modOnlyMessage = build.modOnlyMessage;
       _allowStartStopRecording = build.allowStartStopRecording;
+      _metadata = build.metadata;
     }
     
     public function get name():String {
@@ -68,5 +70,16 @@ package org.bigbluebutton.core.model
     public function get allowStartStopRecording():Boolean {
       return _allowStartStopRecording;
     }
+
+    public function get metadata():Object {
+      return _metadata;
+    }
+
+    public function isMetadata(key: String):Boolean {
+      if (_metadata != null) {
+        return _metadata.hasOwnProperty(key);
+      }
+      return false;
+    }
   }
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/model/MeetingBuilder.as b/bigbluebutton-client/src/org/bigbluebutton/core/model/MeetingBuilder.as
index ba33d0a34f31388b8c3fbd799856fac718fd9019..5abdfc8d765221b2fe04b902113828740438399b 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/core/model/MeetingBuilder.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/model/MeetingBuilder.as
@@ -14,6 +14,7 @@ package org.bigbluebutton.core.model
     internal var welcomeMessage:String;
     internal var modOnlyMessage:String;
     internal var allowStartStopRecording: Boolean;
+    internal var metadata: Object;
     
     public function MeetingBuilder(id: String, name: String) {
       this.id = id;
@@ -70,6 +71,11 @@ package org.bigbluebutton.core.model
       return this;
     }    
     
+    public function withMetadata(value: Object):MeetingBuilder {
+      metadata = value;
+      return this;
+    }
+
     public function build():Meeting {
       return new Meeting(this);
     }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/model/users/UserBuilder.as b/bigbluebutton-client/src/org/bigbluebutton/core/model/users/UserBuilder.as
index 5bb1c9ed70c6c2175952d9eaa01cb430a8f7fc93..41a5db2f8bbe4601842503872476e126b2ab9833 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/core/model/users/UserBuilder.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/model/users/UserBuilder.as
@@ -43,6 +43,10 @@ package org.bigbluebutton.core.model.users
     public function withRole(value: String):UserBuilder {
       return this;  
     }
+
+    public function withGuest(value: Boolean):UserBuilder {
+      return this;
+    }
     
     public function withCustomData(value: String):UserBuilder {
       return this;  
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/services/BandwidthMonitor.as b/bigbluebutton-client/src/org/bigbluebutton/core/services/BandwidthMonitor.as
index 79a667b1ebec660fa74e1d85ff372477321e0604..a9b330ef3174b282cd93fbc757703c2269091c10 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/core/services/BandwidthMonitor.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/services/BandwidthMonitor.as
@@ -19,10 +19,9 @@
 package org.bigbluebutton.core.services
 {
   import flash.events.AsyncErrorEvent;
+  import flash.events.IOErrorEvent;
   import flash.events.NetStatusEvent;
-  import flash.events.TimerEvent;
   import flash.net.NetConnection;
-  import flash.utils.Timer;
   
   import org.as3commons.logging.api.ILogger;
   import org.as3commons.logging.api.getClassLogger;
@@ -32,26 +31,69 @@ package org.bigbluebutton.core.services
   import org.red5.flash.bwcheck.events.BandwidthDetectEvent;
 
   public class BandwidthMonitor {
-	private static const LOGGER:ILogger = getClassLogger(BandwidthMonitor);
-	
+    private static const LOGGER:ILogger = getClassLogger(BandwidthMonitor);
+    public static const INTERVAL_BETWEEN_CHECKS:int = 30000; // in ms
+
+    private static var _instance:BandwidthMonitor = null;
     private var _serverURL:String = "localhost";
     private var _serverApplication:String = "video";
     private var _clientServerService:String = "checkBandwidthUp";
     private var _serverClientService:String = "checkBandwidth";
-    private var nc:NetConnection;
+    private var _pendingClientToServer:Boolean;
+    private var _pendingServerToClient:Boolean;
+    private var _lastClientToServerCheck:Date;
+    private var _lastServerToClientCheck:Date;
+    private var _runningMeasurement:Boolean;
+    private var _connecting:Boolean;
+    private var _nc:NetConnection;
     
-    private var bwTestTimer:Timer;
+    /**
+     * This class is a singleton. Please initialize it using the getInstance() method.
+     */
+    public function BandwidthMonitor(enforcer:SingletonEnforcer) {
+        if (enforcer == null) {
+            throw new Error("There can only be one instance of this class");
+        }
+        initialize();
+    }
     
-    public function BandwidthMonitor() {
-      
+    private function initialize():void {
+        _pendingClientToServer = false;
+        _pendingServerToClient = false;
+        _runningMeasurement = false;
+        _connecting = false;
+        _lastClientToServerCheck = null;
+        _lastServerToClientCheck = null;
+
+        _nc = new NetConnection();
+        _nc.proxyType = "best";
+        _nc.objectEncoding = flash.net.ObjectEncoding.AMF0;
+        _nc.client = this;
+        _nc.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
+        _nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
+        _nc.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
     }
     
+    /**
+     * Return the single instance of this class
+     */
+    public static function getInstance():BandwidthMonitor {
+        if (_instance == null) {
+            _instance = new BandwidthMonitor(new SingletonEnforcer());
+        }
+        return _instance;
+    }
+
     public function set serverURL(url:String):void {
-      _serverURL = url;
+        if (_nc.connected)
+            _nc.close();
+        _serverURL = url;
     }
     
     public function set serverApplication(app:String):void {
-      _serverApplication = app;
+        if (_nc.connected)
+            _nc.close();
+        _serverApplication = app;
     }
 
     public function start():void {
@@ -59,18 +101,73 @@ package org.bigbluebutton.core.services
     }
        
     private function connect():void {
-      nc = new NetConnection();
-      nc.objectEncoding = flash.net.ObjectEncoding.AMF0;
-      nc.proxyType = "best";
-      nc.client = this;
-      nc.addEventListener(NetStatusEvent.NET_STATUS, onStatus);	
-      nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);	
-      nc.connect("rtmp://" + _serverURL + "/" + _serverApplication);
+        if (!_nc.connected && !_connecting) {
+            _nc.connect("rtmp://" + _serverURL + "/" + _serverApplication);
+            _connecting = true;
+        }
     }
-    
-    private function onAsyncError(event:AsyncErrorEvent):void
-    {
-      LOGGER.debug(event.error.toString());
+
+    public function checkClientToServer():void {
+        if (_lastClientToServerCheck != null && _lastClientToServerCheck.getTime() + INTERVAL_BETWEEN_CHECKS > new Date().getTime())
+            return;
+
+        if (!_nc.connected) {
+            _pendingClientToServer = true;
+            connect();
+        } if (_runningMeasurement) {
+            _pendingClientToServer = true;
+        } else {
+            _pendingClientToServer = false;
+            _runningMeasurement = true;
+            _lastClientToServerCheck = new Date();
+
+            LOGGER.debug("Start client-server bandwidth detection");
+            var clientServer:ClientServerBandwidth  = new ClientServerBandwidth();
+            clientServer.connection = _nc;
+            clientServer.service = _clientServerService;
+            clientServer.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onClientServerComplete);
+            clientServer.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onClientServerStatus);
+            clientServer.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed);
+            clientServer.start();
+        }
+    }
+
+    public function checkServerToClient():void {
+        if (_lastServerToClientCheck != null && _lastServerToClientCheck.getTime() + INTERVAL_BETWEEN_CHECKS > new Date().getTime())
+            return;
+
+        if (!_nc.connected) {
+            _pendingServerToClient = true;
+            connect();
+        } if (_runningMeasurement) {
+            _pendingServerToClient = true;
+        } else {
+            _pendingServerToClient = false;
+            _runningMeasurement = true;
+            _lastServerToClientCheck = new Date();
+
+            LOGGER.debug("Start server-client bandwidth detection");
+            var serverClient:ServerClientBandwidth = new ServerClientBandwidth();
+            serverClient.connection = _nc;
+            serverClient.service = _serverClientService;
+            serverClient.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onServerClientComplete);
+            serverClient.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onServerClientStatus);
+            serverClient.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed);
+            serverClient.start();
+        }
+    }
+
+    private function checkPendingOperations():void {
+      if (_pendingClientToServer) checkClientToServer();
+      if (_pendingServerToClient) checkServerToClient();
+    }
+
+    private function onAsyncError(event:AsyncErrorEvent):void {
+        LOGGER.debug(event.error.toString());
+    }
+
+    private function onIOError(event:IOErrorEvent):void {
+        LOGGER.debug(event.text);
     }
     
     private function onStatus(event:NetStatusEvent):void
@@ -78,87 +175,49 @@ package org.bigbluebutton.core.services
       switch (event.info.code)
       {
         case "NetConnection.Connect.Success":
-			LOGGER.debug("Starting to monitor bandwidth between client and server");
- //         monitor();
+          LOGGER.debug("Starting to monitor bandwidth between client and server");
           break;
         default:
-		  LOGGER.debug("Cannot establish the connection to measure bandwidth");
+          LOGGER.debug("Cannot establish the connection to measure bandwidth");
           break;
       }      
+      _connecting = false;
+      checkPendingOperations();
     }
     
-    private function monitor():void {
-	  LOGGER.debug("Starting to monitor bandwidth");
-      bwTestTimer =  new Timer(30000);
-      bwTestTimer.addEventListener(TimerEvent.TIMER, rtmptRetryTimerHandler);
-      bwTestTimer.start();
-    }
-    
-    private function rtmptRetryTimerHandler(event:TimerEvent):void {
-	  LOGGER.debug("Starting to detect bandwidth from server to client");
-      ServerClient();
-    }
-    
-    public function ClientServer():void
-    {
-      var clientServer:ClientServerBandwidth  = new ClientServerBandwidth();
-      //connect();
-      clientServer.connection = nc;
-      clientServer.service = _clientServerService;
-      clientServer.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onClientServerComplete);
-      clientServer.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onClientServerStatus);
-      clientServer.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed);
-      clientServer.start();
-    }
-    
-    public function ServerClient():void
-    {
-      var serverClient:ServerClientBandwidth = new ServerClientBandwidth();
-      //connect();
-      serverClient.connection = nc;
-      serverClient.service = _serverClientService;
-      serverClient.addEventListener(BandwidthDetectEvent.DETECT_COMPLETE,onServerClientComplete);
-      serverClient.addEventListener(BandwidthDetectEvent.DETECT_STATUS,onServerClientStatus);
-      serverClient.addEventListener(BandwidthDetectEvent.DETECT_FAILED,onDetectFailed);
-      serverClient.start();
+    public function onDetectFailed(event:BandwidthDetectEvent):void {
+      LOGGER.debug("Detection failed with error: " + event.info.application + " " + event.info.description);
+      _runningMeasurement = false;
     }
     
-    public function onDetectFailed(event:BandwidthDetectEvent):void
-    {
-	  LOGGER.debug("Detection failed with error: {0} {1}", [event.info.application, event.info.description]);
-    }
-    
-    public function onClientServerComplete(event:BandwidthDetectEvent):void
-    {
-//      LogUtil.debug("Client-slient bandwidth detect complete");
-      
-//      LogUtil.debug(ObjectUtil.toString(event.info));
+    public function onClientServerComplete(event:BandwidthDetectEvent):void {
+      LOGGER.debug("Client-server bandwidth detection complete");
+//      LOGGER.debug(ObjectUtil.toString(event.info));
       NetworkStatsData.getInstance().setUploadMeasuredBW(event.info);
+      _runningMeasurement = false;
+      checkPendingOperations();
     }
     
-    public function onClientServerStatus(event:BandwidthDetectEvent):void
-    {
+    public function onClientServerStatus(event:BandwidthDetectEvent):void {
       if (event.info) {
-//        LogUtil.debug("\n count: "+event.info.count+ " sent: "+event.info.sent+" timePassed: "+event.info.timePassed+" latency: "+event.info.latency+" overhead:  "+event.info.overhead+" packet interval: " + event.info.pakInterval + " cumLatency: " + event.info.cumLatency);
+//        LOGGER.debug("\n count: "+event.info.count+ " sent: "+event.info.sent+" timePassed: "+event.info.timePassed+" latency: "+event.info.latency+" overhead:  "+event.info.overhead+" packet interval: " + event.info.pakInterval + " cumLatency: " + event.info.cumLatency);
       }
     }
     
-    public function onServerClientComplete(event:BandwidthDetectEvent):void
-    {
-//      LogUtil.debug("Server-client bandwidth detect complete");
-      
-//      LogUtil.debug(ObjectUtil.toString(event.info));
+    public function onServerClientComplete(event:BandwidthDetectEvent):void {
+      LOGGER.debug("Server-client bandwidth detection complete");
+//      LOGGER.debug(ObjectUtil.toString(event.info));
       NetworkStatsData.getInstance().setDownloadMeasuredBW(event.info);
-
-//      LogUtil.debug("Detecting Client Server Bandwidth");
-      ClientServer();
+      _runningMeasurement = false;
+      checkPendingOperations();
     }
     
-    public function onServerClientStatus(event:BandwidthDetectEvent):void
-    {	
+    public function onServerClientStatus(event:BandwidthDetectEvent):void {
       if (event.info) {
-//        LogUtil.debug("\n count: "+event.info.count+ " sent: "+event.info.sent+" timePassed: "+event.info.timePassed+" latency: "+event.info.latency+" cumLatency: " + event.info.cumLatency);
+//        LOGGER.debug("\n count: "+event.info.count+ " sent: "+event.info.sent+" timePassed: "+event.info.timePassed+" latency: "+event.info.latency+" cumLatency: " + event.info.cumLatency);
       }
     }
   }
 }
+
+class SingletonEnforcer{}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/services/StreamMonitor.as b/bigbluebutton-client/src/org/bigbluebutton/core/services/StreamMonitor.as
index 892b712ff579542414d07a3f3371ae9035bf8303..c91a4ae2fd2f454088eaee9718d893be6081130b 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/core/services/StreamMonitor.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/services/StreamMonitor.as
@@ -131,6 +131,9 @@ package org.bigbluebutton.core.services
 
 			var download:Dictionary = new Dictionary();
 			var upload:Dictionary = new Dictionary();
+
+			download["byteCount"] = upload["byteCount"]
+					= download["currentBytesPerSecond"] = upload["currentBytesPerSecond"] = 0;
 			 
 			for (var i:int = 0; i < streams.length; i++) {
 				if (streams[i] == null || streams[i].info == null) {
@@ -144,7 +147,7 @@ package org.bigbluebutton.core.services
 				var ref:Dictionary = (remote? download: upload);
 
 				if (streams[i].info.uri == null) {
-					log("Stream URI is null, returning");
+					//log("Stream URI is null, returning");
 					continue;
 				}
 				var uri:String = streams[i].info.uri.toLowerCase();
@@ -175,7 +178,7 @@ package org.bigbluebutton.core.services
 						var property:String = s.@name;
 						var num:Number = 0;
 						if (ref.hasOwnProperty(property))
-							num = ref[property] as Number;
+							num = (ref[property] as Number);
 						num += (streams[i].info[property] as Number);
 						ref[property] = num;
 					}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/vo/Config.as b/bigbluebutton-client/src/org/bigbluebutton/core/vo/Config.as
index d005b462285c4cb1d8b7f492b3fe9ee2e5eebdfb..ff85cb799a064403b441b2a70799697b9a56c9bd 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/core/vo/Config.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/vo/Config.as
@@ -30,6 +30,11 @@ package org.bigbluebutton.core.vo {
 		private var _shortcutKeysShowButton:Boolean;
 		private var _skinning:String = "";
 		private var _showDebug:Boolean = false;
+		private var _copyright:String;
+		private var _logo:String;
+		private var _background:String;
+		private var _toolbarColor:String;
+		private var _toolbarColorAlphas:String;
 		
 		public function Config(builder:ConfigBuilder) {
 			_version = builder.version;
@@ -44,6 +49,11 @@ package org.bigbluebutton.core.vo {
 			_shortcutKeysShowButton = builder.shortcutKeysShowButton;
 			_skinning = builder.skinning;
 			_showDebug = builder.showDebug;
+			_copyright = builder.copyright;
+			_logo = builder.logo;
+			_background = builder.background;
+			_toolbarColor = builder.toolbarColor;
+			_toolbarColorAlphas = builder.toolbarColorAlphas;
 		}
 		
 		public function get version():String {
@@ -93,5 +103,21 @@ package org.bigbluebutton.core.vo {
 		public function get showDebug():Boolean {
 			return _showDebug;
 		} 
+
+		public function get copyright():String {
+			return _copyright;
+		}
+
+		public function get logo():String {
+			return _logo;
+		}
+
+		public function get toolbarColor():String {
+			return _toolbarColor;
+		}
+
+		public function get toolbarColorAlphas():String {
+			return _toolbarColorAlphas;
+		}
 	}
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/core/vo/ConfigBuilder.as b/bigbluebutton-client/src/org/bigbluebutton/core/vo/ConfigBuilder.as
index 6e8f0ed2ed121efb0a3c7552090e7155ddb50d0a..81cbae97864f4d7abc429d900cbe6feb92f0cccc 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/core/vo/ConfigBuilder.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/core/vo/ConfigBuilder.as
@@ -30,6 +30,11 @@ package org.bigbluebutton.core.vo {
 		internal var shortcutKeysShowButton:Boolean;
 		internal var skinning:String = "";
 		internal var showDebug:Boolean = false;
+		internal var copyright:String;
+		internal var logo:String;
+		internal var background:String;
+		internal var toolbarColor:String;
+		internal var toolbarColorAlphas:String;
 		
 		public function ConfigBuilder(version:String, localVersion:String){
 			this.version = version;
@@ -85,6 +90,31 @@ package org.bigbluebutton.core.vo {
 			this.showDebug = showDebug;
 			return this;
 		}
+
+		public function withCopyright(copyright:String):ConfigBuilder {
+			this.copyright = copyright;
+			return this;
+		}
+
+		public function withLogo(logo:String):ConfigBuilder {
+			this.logo = logo;
+			return this;
+		}
+
+		public function withBackground(background:String):ConfigBuilder {
+			this.background = background;
+			return this;
+		}
+
+		public function withToolbarColor(toolbarColor:String):ConfigBuilder {
+			this.toolbarColor = toolbarColor;
+			return this;
+		}
+
+		public function withToolbarColorAlphas(toolbarColorAlphas:String):ConfigBuilder {
+			this.toolbarColorAlphas = toolbarColorAlphas;
+			return this;
+		}
 		
    		public function build():Config {
 			return new Config(this);
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/BBBEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/BBBEvent.as
index b4bf6048b027686aa29e7ee3b7c9479fe74fd9cf..96294c36ea391ce356a1f728be16237a0b604ade 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/events/BBBEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/BBBEvent.as
@@ -22,6 +22,11 @@ package org.bigbluebutton.main.events {
 	public class BBBEvent extends Event {    
     
 		public static const END_MEETING_EVENT:String = 'END_MEETING_EVENT';
+		public static const LOGOUT_END_MEETING_EVENT:String = 'LOGOUT_END_MEETING_EVENT';
+		public static const CONFIRM_LOGOUT_END_MEETING_EVENT:String = 'CONFIRM_LOGOUT_END_MEETING_EVENT';
+		public static const INACTIVITY_WARNING_EVENT:String = 'INACTIVITY_WARNING_EVENT';
+		public static const ACTIVITY_RESPONSE_EVENT:String = 'ACTIVITY_RESPONSE_EVENT';
+		public static const MEETING_IS_ACTIVE_EVENT:String = 'MEETING_IS_ACTIVE_EVENT';
 		public static const LOGIN_EVENT:String = 'loginEvent';
 		public static const RECEIVED_PUBLIC_CHAT_MESSAGE_EVENT:String = 'RECEIVED_PUBLIC_CHAT_MESSAGE_EVENT';
 		public static const SEND_PUBLIC_CHAT_MESSAGE_EVENT:String = 'SEND_PUBLIC_CHAT_MESSAGE_EVENT';
@@ -43,6 +48,18 @@ package org.bigbluebutton.main.events {
 	public static const CAM_SETTINGS_CLOSED:String = "CAM_SETTINGS_CLOSED";
 	public static const JOIN_VOICE_FOCUS_HEAD:String = "JOIN_VOICE_FOCUS_HEAD";
 	public static const CHANGE_RECORDING_STATUS:String = "CHANGE_RECORDING_STATUS";
+
+		public static const SETTINGS_CONFIRMED:String = "BBB_SETTINGS_CONFIRMED";
+		public static const SETTINGS_CANCELLED:String = "BBB_SETTINGS_CANCELLED";
+
+		public static const ACCEPT_ALL_WAITING_GUESTS:String = "BBB_ACCEPT_ALL_WAITING_GUESTS";
+		public static const DENY_ALL_WAITING_GUESTS:String = "BBB_DENY_ALL_WAITING_GUESTS";
+		public static const BROADCAST_GUEST_POLICY:String = "BBB_BROADCAST_GUEST_POLICY";
+		public static const RETRIEVE_GUEST_POLICY:String = "BBB_RETRIEVE_GUEST_POLICY";
+		public static const MODERATOR_ALLOWED_ME_TO_JOIN:String = "MODERATOR_ALLOWED_ME_TO_JOIN";
+		public static const WAITING_FOR_MODERATOR_ACCEPTANCE:String = "WAITING_FOR_MODERATOR_ACCEPTANCE";
+		public static const ADD_GUEST_TO_LIST:String = "ADD_GUEST_TO_LIST";
+		public static const REMOVE_GUEST_FROM_LIST:String = "REMOVE_GUEST_FROM_LIST";
    
 		public static const RECONNECT_DISCONNECTED_EVENT:String = "RECONNECT_ON_DISCONNECTED_EVENT";
 		public static const RECONNECT_CONNECTION_ATTEMPT_FAILED_EVENT:String = "RECONNECT_CONNECTION_ATTEMPT_FAILED_EVENT";
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/LogoutEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/LogoutEvent.as
index fb99b50209129e567e291dc70ea8958af25bea80..a8504044c4c92bee56524e0728c86c4ad1243b55 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/events/LogoutEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/LogoutEvent.as
@@ -25,6 +25,7 @@ package org.bigbluebutton.main.events
 		public static const USER_LOGGED_OUT:String = "USER_LOGGED_OUT";
 		public static const DISCONNECT_TEST:String = "disconnect_test";
 		public static const USER_KICKED_OUT:String = "USER_KICKED_OUT";
+		public static const MODERATOR_DENIED_ME:String = "MODERATOR_DENIED_ME";
 		public static const CONFIRM_LOGOUT:String = "CONFIRM_LOGOUT";
 		public static const REFOCUS_CONFIRM:String = "REFOCUS_CONFIRM";
 		
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/NetworkStatsEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/NetworkStatsEvent.as
index 665a6b5a37f682052c9c66f9afad6b5170e045d7..2c44df973371d82d3f2f585628687967afc63b18 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/events/NetworkStatsEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/NetworkStatsEvent.as
@@ -24,13 +24,14 @@ package org.bigbluebutton.main.events
 	public class NetworkStatsEvent extends Event
 	{
 		public static const NETWORK_STATS_EVENTS:String = "NETWORK_STATS_EVENTS";
+		public static const OPEN_NETSTATS_WIN:String = "OPEN_NETWORK_WIN";
 		
 		public var downloadStats:Dictionary;
 		public var uploadStats:Dictionary;
 		
-		public function NetworkStatsEvent(bubbles:Boolean=true, cancelable:Boolean=false)
+		public function NetworkStatsEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
 		{
-			super(NETWORK_STATS_EVENTS, bubbles, cancelable);
+			super(type, bubbles, cancelable);
 		}
 		
 	}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/PresenterStatusEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/PresenterStatusEvent.as
index 691e753b695985452f8e78f9cc1f2311ea175c28..b6139dc226eb3d5f4e981093662a710235c6d0a4 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/events/PresenterStatusEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/PresenterStatusEvent.as
@@ -25,10 +25,12 @@ package org.bigbluebutton.main.events
 		public static const PRESENTER_NAME_CHANGE:String = "PRESENTER_NAME_CHANGE";
 		public static const SWITCH_TO_VIEWER_MODE:String = "VIEWER_MODE";
 		public static const SWITCH_TO_PRESENTER_MODE:String = "PRESENTER_MODE";
+		public static const ANNOTATIONS_PERMISSION_CHANGE:String = "ANNOTATIONS_PERMISSION_CHANGE";
 		
 		public var presenterName:String;
 		public var assignerBy:Number;
 		public var userID:String;
+		public var enableAnnotations:Boolean;
 		
 		public function PresenterStatusEvent(type:String)
 		{
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/RefreshGuestEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/RefreshGuestEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..cca1d2cdd47761fd75613cf6fe10dd5a685653c7
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/RefreshGuestEvent.as
@@ -0,0 +1,34 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.main.events
+{
+	import flash.events.Event;
+
+	public class RefreshGuestEvent extends Event
+	{
+		public static const REFRESH_GUEST_VIEW:String = "RefreshGuestView";
+
+		public var listOfGuests:Object;
+
+		public function RefreshGuestEvent(type:String = REFRESH_GUEST_VIEW)
+		{
+			super(type, true, false);
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/RemoveGuestEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/RemoveGuestEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..825d37cf2bc0cebe0703c525cb79bd7e0ae72bc3
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/RemoveGuestEvent.as
@@ -0,0 +1,35 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.main.events
+{
+	import flash.events.Event;
+
+	public class RemoveGuestEvent extends Event
+	{
+		public static const REMOVE_GUEST:String = "RemoveGuest";
+		public static const REMOVE_ALL:String = "RemoveAllGuests";
+
+		public var userid:String;
+
+		public function RemoveGuestEvent(type:String = REMOVE_GUEST)
+		{
+			super(type, true, false);
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/RemoveGuestFromViewEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/RemoveGuestFromViewEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..a12cc04249d3ed07bc1fcb4b12e17ea19599bfc0
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/RemoveGuestFromViewEvent.as
@@ -0,0 +1,34 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.main.events
+{
+	import flash.events.Event;
+
+	public class RemoveGuestFromViewEvent extends Event
+	{
+		public static const REMOVE_GUEST:String = "RemoveGuest";
+
+		public var userid:String;
+
+		public function RemoveGuestFromViewEvent(type:String = REMOVE_GUEST)
+		{
+			super(type, true, false);
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/events/ResponseModeratorEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/events/ResponseModeratorEvent.as
new file mode 100755
index 0000000000000000000000000000000000000000..f10d2a30d45c45e7ecac5e4d718af8a80a439ac0
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/events/ResponseModeratorEvent.as
@@ -0,0 +1,40 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.main.events
+{
+	import flash.events.Event;
+
+	import org.bigbluebutton.main.model.ConferenceParameters;
+	import org.bigbluebutton.main.model.users.BBBUser;
+	import org.bigbluebutton.main.model.ConferenceParameters;
+
+	public class ResponseModeratorEvent extends Event
+	{
+		public static const RESPONSE:String = "Response";
+		public static const RESPONSE_ALL:String	= "RESPONSE_ALL";
+
+		public var userid:String;
+		public var resp:Boolean;
+
+		public function ResponseModeratorEvent(type:String)
+		{
+			super(type, true, false);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml
index 2f4399ed84b5a80e3b667627cbca19b54673d70e..349dd326be1ff7468850a57bbfd650b9d96a952b 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/maps/ApplicationEventMap.mxml
@@ -31,10 +31,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<ObjectBuilder generator="{ModulesProxy}" cache="global" />
 		<ObjectBuilder generator="{ConfigManager}" cache="global" />
 		<ObjectBuilder generator="{ReconnectionManager}" cache="global" />
-		<!--
-		Disabling temporarily the stream monitor
-		-->
-		<!--ObjectBuilder generator="{StreamMonitor}" cache="global" /-->
+		<ObjectBuilder generator="{StreamMonitor}" cache="global" />
 	</EventHandlers>
 	
 	<EventHandlers type="{LoadConfigCommand.LOAD_CONFIG_COMMAND}" >
@@ -78,6 +75,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     <MethodInvoker generator="{ModulesProxy}" method="startAllModules" />
   </EventHandlers>
 
+  <EventHandlers type="{LogoutEvent.MODERATOR_DENIED_ME}" >
+    <MethodInvoker generator="{ModulesProxy}" method="handleLogout" />
+  </EventHandlers>
+
   <EventHandlers type="{BBBEvent.RECONNECT_DISCONNECTED_EVENT}">
     <MethodInvoker generator="{ReconnectionManager}" method="onDisconnected" arguments="{[event.payload.type, event.payload.callback, event.payload.callbackParameters]}"/>
   </EventHandlers>
@@ -103,6 +104,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		import org.bigbluebutton.core.managers.ConfigManager;
 		import org.bigbluebutton.core.managers.ReconnectionManager;
 		import org.bigbluebutton.core.services.SkinningService;
+		import org.bigbluebutton.core.services.StreamMonitor;
 		import org.bigbluebutton.main.events.BBBEvent;
 		import org.bigbluebutton.main.events.ConfigLoadedEvent;
 		import org.bigbluebutton.main.events.LoadConfigCommand;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/ConferenceParameters.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/ConferenceParameters.as
index d94bb513fa1b4f006804df0cb668c6e6ed83069f..be3fe0d947601c7c65052b72d83d07f50b5c5087 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/ConferenceParameters.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/ConferenceParameters.as
@@ -63,6 +63,11 @@ package org.bigbluebutton.main.model {
 		 * Voice conference bridge that external SIP clients use. Usually the same as webvoiceconf
 		 */
 		public var voicebridge:String;
+
+		/**
+		 * Flag used to enter as a guest
+		 */
+		public var guest:Boolean;
 		
 		/**
 		 *  The welcome string, as passed in through the API /create call.
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/ConfigParameters.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/ConfigParameters.as
index b8ac7b46593de0a365e11a9e7e674b3fa4fcf997..4cef61efb5ce181b13ac153be12e5c33236062cc 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/ConfigParameters.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/ConfigParameters.as
@@ -58,6 +58,11 @@ package org.bigbluebutton.main.model
 		public var shortcutKeysShowButton:Boolean;
 		public var skinning:String = "";
 		public var showDebug:Boolean = false;
+		public var copyright:String = "";
+		public var logo:String = "";
+		public var background:String = "";
+		public var toolbarColor:String = "";
+		public var toolbarColorAlphas:String = "";
 		
 		private var loadedListener:Function;
 		private var dispatcher:Dispatcher = new Dispatcher();
@@ -130,6 +135,12 @@ package org.bigbluebutton.main.model
 			if (xml.skinning.@enabled == "true") skinning = xml.skinning.@url;
 
 			if (xml.debug.@showDebugWindow == "true") showDebug = true;
+
+			copyright = xml.branding.@copyright;
+			logo = xml.branding.@logo;
+			background = xml.branding.@background;
+			toolbarColor = xml.branding.@toolbarColor;
+			toolbarColorAlphas = xml.branding.@toolbarColorAlphas;
 		}
 		
 		public function getModulesXML():XMLList{
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/Guest.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/Guest.as
new file mode 100644
index 0000000000000000000000000000000000000000..dee9650051f0cdfa25b771ed001843feb96b9993
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/Guest.as
@@ -0,0 +1,57 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2013 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+* author:
+*/
+package org.bigbluebutton.main.model
+{
+
+	public class Guest
+	{
+		private var listOfGuests:Object = new Object();
+		private var numberOfGuests:Number = 0;
+
+		public function hasGuest():Boolean {
+			return numberOfGuests > 0;
+		}
+
+		public function getNumberOfGuests():Number {
+			return numberOfGuests;
+		}
+
+		public function addGuest(userid:String, username:String):void {
+			listOfGuests[userid] = username;
+			numberOfGuests++;
+		}
+
+		public function getGuests():Object {
+			return this.listOfGuests;
+		}
+
+		public function removeAllGuests():void {
+			listOfGuests = new Object();
+			numberOfGuests = 0;
+		}
+
+		public function remove(userid:String):void {
+			if (listOfGuests[userid] != null) {
+				numberOfGuests--;
+				delete listOfGuests[userid];
+			}
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/GuestManager.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/GuestManager.as
new file mode 100644
index 0000000000000000000000000000000000000000..74308ccbe36a45016f75b8a39c2d05b16af83a89
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/GuestManager.as
@@ -0,0 +1,66 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2013 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+* author:
+*/
+package org.bigbluebutton.main.model
+{
+
+	import com.asfusion.mate.events.Dispatcher;
+	import org.bigbluebutton.main.events.BBBEvent;
+	import org.bigbluebutton.main.events.RefreshGuestEvent;
+	import org.bigbluebutton.main.events.RemoveGuestFromViewEvent;
+
+	public class GuestManager
+	{
+		private var guest:Guest;
+		private var dispatcher:Dispatcher;
+
+		function GuestManager() {
+			this.dispatcher = new Dispatcher();
+			this.guest = new Guest();
+		}
+
+		public function addGuest(evt:BBBEvent):void {
+			guest.addGuest(evt.payload.userId, evt.payload.name);
+			refreshGuestView();
+		}
+
+		public function refreshGuestView():void {
+			if (guest.hasGuest()) {
+				var refreshGuestEvent:RefreshGuestEvent = new RefreshGuestEvent();
+				refreshGuestEvent.listOfGuests = guest.getGuests();
+				dispatcher.dispatchEvent(refreshGuestEvent);
+			}
+		}
+
+		public function removeAllGuests():void {
+			guest.removeAllGuests();
+		}
+
+		private function removeGuestFromView(userid:String):void {
+			var removeGuestFromViewEvent:RemoveGuestFromViewEvent = new RemoveGuestFromViewEvent();
+			removeGuestFromViewEvent.userid = userid;
+			dispatcher.dispatchEvent(removeGuestFromViewEvent);
+		}
+
+		public function removeGuest(userid:String):void {
+			guest.remove(userid);
+			removeGuestFromView(userid);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/ImageLoader.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/ImageLoader.as
new file mode 100644
index 0000000000000000000000000000000000000000..ede756753cd085bdc6335e0f5eee416847920571
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/ImageLoader.as
@@ -0,0 +1,91 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.main.model
+{
+  import flash.display.Bitmap;
+  import flash.display.Loader;
+  import flash.events.Event;
+  import flash.events.IOErrorEvent;
+  import flash.net.URLLoader;
+  import flash.net.URLRequest;
+  import flash.system.LoaderContext;
+
+  import mx.controls.Image;
+  import mx.events.FlexEvent;
+  import mx.utils.ObjectUtil;
+
+  public class ImageLoader
+  {
+    private static const LOG:String = "Main::ImageLoader - ";
+
+    private var _src:String;
+    private var _callback:Function;
+
+    public function load(src:String, onSuccessCallback:Function):void {
+      _src = src;
+      _callback = onSuccessCallback;
+
+      loadBitmap();
+    }
+
+    private function loadBitmap():void {
+      trace(LOG + "loadBitmap");
+      var backgroundLoader:Loader = new Loader();
+      backgroundLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onBitmapLoaded, false, 0, true);
+      backgroundLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onBitmapIoError);
+      var context:LoaderContext = new LoaderContext();
+      context.checkPolicyFile = true;
+      var request:URLRequest = new URLRequest(_src);
+      backgroundLoader.load(request , context);
+    }
+
+    private function onBitmapIoError(e:IOErrorEvent):void {
+      trace(LOG + "onBitmapIoError: " + e.toString());
+    }
+
+    private function onBitmapLoaded(e:Event):void {
+      trace(LOG + "onBitmapLoaded");
+      try {
+        var backgroundBitmap:Bitmap = Bitmap(e.target.content);
+        backgroundBitmap.smoothing = true;
+        _callback(backgroundBitmap, backgroundBitmap.width, backgroundBitmap.height);
+      } catch(error:Error) {
+        trace(LOG + "onBitmapLoaded error: " + error.toString());
+        loadImage();
+      }
+    }
+
+    private function loadImage():void {
+      trace(LOG + "loadImage");
+      var image:Image = new Image();
+      image.addEventListener(Event.COMPLETE, onImageLoaded);
+      image.addEventListener(IOErrorEvent.IO_ERROR, onImageIoError);
+      image.load(_src);
+    }
+
+    private function onImageLoaded(e:Event):void {
+      trace(LOG + "onImageLoaded");
+      _callback(e.currentTarget, e.currentTarget.contentWidth, e.currentTarget.contentHeight);
+    }
+
+    private function onImageIoError(e:IOErrorEvent):void {
+      trace(LOG + "onImageIoError: " + e.toString());
+    }
+  }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/LayoutOptions.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/LayoutOptions.as
old mode 100755
new mode 100644
index 0839c996574957f439c856c1ff92eba0964a524d..7e17bfcabace0767157c92825ff85d8b2371b390
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/LayoutOptions.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/LayoutOptions.as
@@ -54,7 +54,9 @@ package org.bigbluebutton.main.model {
 		[Bindable]
 		public var logoutOnStopRecording:Boolean = false;
 		
-		
+		[Bindable]
+		public var showNetworkMonitor:Boolean = true;
+
 		public var defaultLayout:String = "Default";
 		
 		public function parseOptions():void {
@@ -107,6 +109,10 @@ package org.bigbluebutton.main.model {
 				if (vxml.@logoutOnStopRecording != undefined) {
 					logoutOnStopRecording = (vxml.@logoutOnStopRecording.toString().toUpperCase() == "TRUE") ? true : false;
 				}
+
+				if(vxml.@showNetworkMonitor != undefined){
+					showNetworkMonitor = (vxml.@showNetworkMonitor.toString().toUpperCase() == "TRUE") ? true : false;
+				}
 			}
 		}
 	
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/NetworkStatsData.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/NetworkStatsData.as
index bf6516041e875e78dd0eebc809f20b5324d7d51f..bb75c51c08d9e0547cf506f21cc970533635c8de 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/NetworkStatsData.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/NetworkStatsData.as
@@ -19,6 +19,13 @@
 package org.bigbluebutton.main.model
 {
 	
+	import com.asfusion.mate.events.Dispatcher;
+
+	import mx.formatters.NumberFormatter;
+
+	import org.bigbluebutton.common.LogUtil;
+	import org.bigbluebutton.main.events.NetworkStatsEvent;
+
 	import flash.events.EventDispatcher;
 	
 	public class NetworkStatsData extends EventDispatcher
@@ -26,12 +33,15 @@ package org.bigbluebutton.main.model
 		private static var _instance:NetworkStatsData = null;
 		private var _currentConsumedDownBW:Number = 0; // Kb
 		private var _currentConsumedUpBW:Number = 0; // Kb
-		private var _totalConsumedDownBW:Number = 0; // MB
-		private var _totalConsumedUpBW:Number = 0; // MB
-		private var _measuredDownBW:int = 0; // Mb
+		private var _totalConsumedDownBW:Number = 0; // KB
+		private var _totalConsumedUpBW:Number = 0; // KB
+		private var _measuredDownBWCheck:Boolean = false;
+		private var _measuredDownBW:Number = 0; // Kb
 		private var _measuredDownLatency:int = 0; // ms
-		private var _measuredUpBW:int = 0; // Mb
+		private var _measuredUpBWCheck:Boolean = false;
+		private var _measuredUpBW:Number = 0; // Kb
 		private var _measuredUpLatency:int = 0; // ms
+		private var _numberFormatter:NumberFormatter = new NumberFormatter();
 		
 		/**
 		 * This class is a singleton. Please initialize it using the getInstance() method.
@@ -44,6 +54,8 @@ package org.bigbluebutton.main.model
 		}
 		
 		private function initialize():void {
+			_numberFormatter.precision = 1;
+			_numberFormatter.useThousandsSeparator = true;
 		}
 		
 		/**
@@ -58,10 +70,10 @@ package org.bigbluebutton.main.model
 		
 		// all the numbers are in bytes
 		public function updateConsumedBW(down:Number, up:Number, downTotal:Number, upTotal:Number):void {
-			_currentConsumedDownBW = (down * 8)/1024;
-			_currentConsumedUpBW = (up * 8)/1024;
-			_totalConsumedDownBW = downTotal / 1048576;
-			_totalConsumedUpBW = upTotal / 1048576;
+			_currentConsumedDownBW = (down * 8) / 1024;
+			_currentConsumedUpBW = (up * 8) / 1024;
+			_totalConsumedDownBW = downTotal / 1024;
+			_totalConsumedUpBW = upTotal / 1024;
 		}
 		
 		/*
@@ -72,7 +84,8 @@ package org.bigbluebutton.main.model
 			  [latency] 10
 		*/
 		public function setDownloadMeasuredBW(info:Object):void {
-			_measuredDownBW = info["kbitDown"] / 1000;
+			_measuredDownBWCheck = true;
+			_measuredDownBW = info["kbitDown"];
 			_measuredDownLatency = info["latency"];
   		}
 		
@@ -85,40 +98,83 @@ package org.bigbluebutton.main.model
 			  latency = 11
 		*/
 		public function setUploadMeasuredBW(info:Object):void {
-			_measuredUpBW = info.kbitUp / 1000;
+			_measuredUpBWCheck = true;
+			_measuredUpBW = info.kbitUp;
 			_measuredUpLatency = info.latency;
 		}
 		
-		public function get currentConsumedDownBW():Number {
-			return _currentConsumedDownBW;
+		private function format_KB(n:Number):String {
+			var unit:String = "KB";
+			if (n >= 1073741824) {
+				unit = "TB";
+				n /= 1073741824;
+			} else if (n >= 1048576) {
+				unit = "GB";
+				n /= 1048576;
+			} else if (n >= 1024) {
+				unit = "MB";
+				n /= 1024;
+			}
+			return _numberFormatter.format(n) + " " + unit;
+		}
+
+		private function format_Kbps(n:Number):String {
+			var unit:String = "Kbps";
+			if (n >= 1000000000) {
+				unit = "Tbps";
+				n /= 1000000000;
+			} else if (n >= 1000000) {
+				unit = "Gbps";
+				n /= 1000000;
+			} else if (n >= 1000) {
+				unit = "Mbps";
+				n /= 1000;
+			}
+			return _numberFormatter.format(n) + " " + unit;
+		}
+
+		public function get formattedCurrentConsumedDownBW():String {
+			return format_Kbps(_currentConsumedDownBW);
 		}
 
-		public function get currentConsumedUpBW():Number {
-			return _currentConsumedUpBW;
+		public function get formattedCurrentConsumedUpBW():String {
+			return format_Kbps(_currentConsumedUpBW);
 		}
 
-		public function get totalConsumedDownBW():Number {
-			return _totalConsumedDownBW;
+		public function get formattedTotalConsumedDownBW():String {
+			return format_KB(_totalConsumedDownBW);
 		}
 
-		public function get totalConsumedUpBW():Number {
-			return _totalConsumedUpBW;
+		public function get formattedTotalConsumedUpBW():String {
+			return format_KB(_totalConsumedUpBW);
 		}
 
-		public function get measuredDownBW():int {
-			return _measuredDownBW;
+		public function get formattedMeasuredDownBW():String {
+			if (_measuredDownBWCheck)
+				return format_Kbps(_measuredDownBW);
+			else
+				return "-";
 		}
 
-		public function get measuredDownLatency():int {
-			return _measuredDownLatency;
+		public function get formattedMeasuredDownLatency():String {
+			if (_measuredDownBWCheck)
+				return _measuredDownLatency + " ms";
+			else
+				return "-";
 		}
 
-		public function get measuredUpBW():int {
-			return _measuredUpBW;
+		public function get formattedMeasuredUpBW():String {
+			if (_measuredUpBWCheck)
+				return format_Kbps(_measuredUpBW);
+			else
+				return "-";
 		}
 
-		public function get measuredUpLatency():int {
-			return _measuredUpLatency;
+		public function get formattedMeasuredUpLatency():String {
+			if (_measuredUpBWCheck)
+				return _measuredUpLatency + " ms";
+			else
+				return "-";
 		}
 	}
 }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/User.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/User.as
index b6f5679f620b2bdc5f4f3d2c5fb4948ad7dd231e..b7f6d7f67cd347b322effe77915c348b48b294a6 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/User.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/User.as
@@ -28,5 +28,6 @@ package org.bigbluebutton.main.model
 		public var role:String;
 		public var isPresenter:Boolean;
 		public var authToken:String;
+		public var guest:Boolean;
 	}
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as
index 4eeeb8a8fd0900bd66da3b4476b5f07137000104..a657869b687ab3bcbfac24cf6829804b9bd55352 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/modules/ModulesDispatcher.as
@@ -157,6 +157,11 @@ package org.bigbluebutton.main.model.modules
         .withPortTestHost(c.portTestHost)
         .withShowDebug(c.showDebug)
         .withSkinning(c.skinning)
+        .withCopyright(c.copyright)
+        .withLogo(c.logo)
+        .withBackground(c.background)
+        .withToolbarColor(c.toolbarColor)
+        .withToolbarColorAlphas(c.toolbarColorAlphas)
         .build()
       event.config = config;
       dispatcher.dispatchEvent(event);
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as
index 6f1a8e7dfd23d1f267fa8ad461e958fe59b1d97d..2fee949f0fb742a2f490005d54353ba4d8630604 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/BBBUser.as
@@ -60,6 +60,9 @@ package org.bigbluebutton.main.model.users
     	[Bindable] public var lockedLayout:Boolean = false;
 		[Bindable] public var avatarURL:String="";
     
+		[Bindable] public var guest:Boolean = false;
+		[Bindable] public var waitingForAcceptance:Boolean = false;
+
 		[Bindable]
 		public function get hasStream():Boolean {
 			return streamNames.length > 0;
@@ -216,6 +219,10 @@ package org.bigbluebutton.main.model.users
 				_userStatus = ResourceUtil.getInstance().getString('bbb.users.usersGrid.statusItemRenderer.viewer');
 		}
 		
+		public function amIGuest():Boolean {
+			return guest;
+		}
+
 		/*
 		* This variable is for accessibility for the Users Window. It can't be manually set
 		* and only changes when one of the relevant media variables changes. Use the verifyMedia
@@ -383,6 +390,7 @@ package org.bigbluebutton.main.model.users
 			n.disableMyPrivateChat = user.disableMyPrivateChat;
 			n.disableMyPublicChat = user.disableMyPublicChat;
 			n.breakoutRooms = user.breakoutRooms.concat(); // concatenate an array with nothing to deliver a new array.
+			n.guest = user.guest;
 			return n;		
 		}
 		
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as
index c6b8a1202250a839c72ab9e469503aca87a9e3c9..48266c8afdb8d8193d9c1c851e960f3274c77957 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/Conference.as
@@ -53,6 +53,9 @@ package org.bigbluebutton.main.model.users {
 		[Bindable]
 		public var record:Boolean;
 		
+		[Bindable]
+		public var numAdditionalSharedNotes:Number = 0;
+
 		private static const LOGGER:ILogger = getClassLogger(Conference);
 		
 		private var lockSettings:LockSettingsVO;
@@ -360,6 +363,10 @@ package org.bigbluebutton.main.model.users {
 			return me.userID;
 		}
 		
+		public function getMyself():BBBUser {
+			return me;
+		}
+
 		public function setMyUserid(userID:String):void {
 			me.userID = userID;
 		}
@@ -382,6 +389,19 @@ package org.bigbluebutton.main.model.users {
 		
 		public function setMyRole(role:String):void {
 			me.role = role;
+			applyLockSettings();
+		}
+
+		public function amIGuest():Boolean {
+			return me.guest;
+		}
+
+		public function amIWaitingForAcceptance():Boolean {
+			return me.waitingForAcceptance;
+		}
+
+		public function setGuest(guest:Boolean):void {
+			me.guest = guest;
 		}
 		
 		public function setMyRoom(room:String):void {
@@ -440,6 +460,15 @@ package org.bigbluebutton.main.model.users {
 				var s:Status = new Status(status, value);
 				aUser.changeStatus(s);
 			}
+
+			users.refresh();
+		}
+
+		public function newUserRole(userID:String, role:String):void {
+			var aUser:BBBUser = getUser(userID);
+			if (aUser != null) {
+				aUser.role = role;
+			}
 			users.refresh();
 		}
 		
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/JoinService.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/JoinService.as
index 2e4b15c1983b12d150fb547090f3b4da5e4ed1d3..61621e1f91131312a815f0fddc22c2701191e633 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/JoinService.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/JoinService.as
@@ -89,6 +89,20 @@ package org.bigbluebutton.main.model.users
 			var dispatcher:Dispatcher = new Dispatcher();
 			dispatcher.dispatchEvent(e);
 		}
+
+		private function extractMetadata(metadata:Object):Object {
+			var response:Object = new Object();
+			if (metadata) {
+				var data:Array = metadata as Array;
+				for each (var item:Object in data) {
+					for (var id:String in item) {
+						var value:String = item[id] as String;
+						response[id] = value;
+					}
+				}
+			}
+			return response;
+		}
 		
 		private function handleComplete(e:Event):void {			
             var result:Object = JSON.parse(e.target.data);
@@ -118,6 +132,7 @@ package org.bigbluebutton.main.model.users
                 response.externUserID = result.response.externUserID;
                 response.internalUserId = result.response.internalUserID;
                 response.role = result.response.role;
+                response.guest = result.response.guest;
                 response.room = result.response.room;
                 response.authToken = result.response.authToken;
                 response.record = result.response.record;
@@ -149,11 +164,13 @@ package org.bigbluebutton.main.model.users
                 
             }
 				        
+            response.metadata = extractMetadata(result.response.metadata);
+
         UsersModel.getInstance().me = new MeBuilder(response.internalUserId, response.username).withAvatar(response.avatarURL)
                                              .withExternalId(response.externUserID).withToken(response.authToken)
                                              .withLayout(response.defaultLayout).withWelcome(response.welcome)
                                              .withDialNumber(response.dialnumber).withRole(response.role)
-                                             .withCustomData(response.customData).build();
+                                             .withCustomData(response.customData).withGuest(response.guest.toUpperCase() == "TRUE").build();
                 
         MeetingModel.getInstance().meeting = new MeetingBuilder(response.conference, response.conferenceName)
                                              .withDefaultLayout(response.defaultLayout).withVoiceConf(response.voiceBridge)
@@ -161,7 +178,7 @@ package org.bigbluebutton.main.model.users
                                              .withDefaultAvatarUrl(response.avatarURL).withDialNumber(response.dialNumber)
                                              .withWelcomeMessage(response.welcome).withModOnlyMessage(response.modOnlyMessage)
                                              .withAllowStartStopRecording(response.allowStartStopRecording).withBreakout(response.isBreakout)
-                                             .build();
+                                             .withMetadata(response.metadata).build();
 
 				if (_resultListener != null) _resultListener(true, response);
 			}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as
index ba6043e0d05df3c7c619d928bed8829031f91b86..ca3aca706aa969dc1278865f9122d1e8a68d9d60 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/NetConnectionDelegate.as
@@ -53,6 +53,7 @@ package org.bigbluebutton.main.model.users
         private var _messageListeners:Array = new Array();
         private var authenticated: Boolean = false;
         private var reconnecting:Boolean = false;
+        private var guestKickedOutCommand:Boolean = false;
         
         private var maxConnectAttempt:int = 2;
         private var connectAttemptCount:int = 0;
@@ -262,6 +263,8 @@ package org.bigbluebutton.main.model.users
                 var appURL:String = BBB.getConfigManager().config.application.uri;
                 var pattern:RegExp = /(?P<protocol>.+):\/\/(?P<server>.+)\/(?P<app>.+)/;
                 var result:Array = pattern.exec(appURL);
+
+                BandwidthMonitor.getInstance().serverURL = result.server;
             
                 var protocol:String = "rtmp";
                 var uri:String = appURL + "/" + confParams.room;
@@ -287,7 +290,8 @@ package org.bigbluebutton.main.model.users
                 _netConnection.connect(bbbAppsUrl, confParams.username, confParams.role,
                                         confParams.room, confParams.voicebridge, 
                                         confParams.record, confParams.externUserID,
-                                        confParams.internalUserID, confParams.muteOnStart, confParams.lockSettings);
+                                        confParams.internalUserID, confParams.muteOnStart,
+                                        confParams.lockSettings, confParams.guest);
                    
             } catch(e:ArgumentError) {
                 // Invalid parameters.
@@ -324,6 +328,11 @@ package org.bigbluebutton.main.model.users
             _netConnection.close();
         }
         
+        public function guestDisconnect() : void {
+            this.guestKickedOutCommand = true;
+            _netConnection.close();
+        }
+
         public function forceClose():void {
           _netConnection.close();
         }
@@ -426,7 +435,13 @@ package org.bigbluebutton.main.model.users
             var logData:Object = UsersUtil.initLogData();
             logData.tags = ["apps", "connection"];
 
-            if (this.logoutOnUserCommand) {
+            if (this.guestKickedOutCommand) {
+                logData.reason = "Guest kicked out.";
+                logData.message = "User disconnected from BBB App.";
+                LOGGER.info(JSON.stringify(logData));
+
+                sendGuestUserKickedOutEvent();
+            } else if (this.logoutOnUserCommand) {
                 logData.reason = "User requested.";
                 logData.message = "User logged out from BBB App.";
                 LOGGER.info(JSON.stringify(logData));
@@ -474,6 +489,11 @@ package org.bigbluebutton.main.model.users
             dispatcher.dispatchEvent(e);
         }
 
+        private function sendGuestUserKickedOutEvent():void {
+            var e:ConnectionFailedEvent = new ConnectionFailedEvent(ConnectionFailedEvent.MODERATOR_DENIED_ME);
+            dispatcher.dispatchEvent(e);
+        }
+
         public function onBWCheck(... rest):Number { 
             return 0; 
         } 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as
index 82111fe31fae1ef423de5f32f6b38972f118517a..6a914d1df0bd6c68a22d5c0988aa9fdec3345b10 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/UserService.as
@@ -34,11 +34,14 @@ package org.bigbluebutton.main.model.users
 	import org.bigbluebutton.core.model.Config;
 	import org.bigbluebutton.main.events.BBBEvent;
 	import org.bigbluebutton.main.events.BreakoutRoomEvent;
+	import org.bigbluebutton.main.events.LogoutEvent;
+	import org.bigbluebutton.main.events.ResponseModeratorEvent;
 	import org.bigbluebutton.main.events.SuccessfulLoginEvent;
 	import org.bigbluebutton.main.events.UserServicesEvent;
 	import org.bigbluebutton.main.model.ConferenceParameters;
 	import org.bigbluebutton.main.model.users.events.BroadcastStartedEvent;
 	import org.bigbluebutton.main.model.users.events.BroadcastStoppedEvent;
+	import org.bigbluebutton.main.model.users.events.ChangeRoleEvent;
 	import org.bigbluebutton.main.model.users.events.ConferenceCreatedEvent;
 	import org.bigbluebutton.main.model.users.events.EmojiStatusEvent;
 	import org.bigbluebutton.main.model.users.events.KickUserEvent;
@@ -56,6 +59,7 @@ package org.bigbluebutton.main.model.users
 		private var hostURI:String;		
 		private var connection:NetConnection;
 		private var dispatcher:Dispatcher;
+		private var reconnecting:Boolean = false;
 		
     private var _connectionManager:ConnectionManager;
     private var msgReceiver:MessageReceiver = new MessageReceiver();
@@ -63,6 +67,23 @@ package org.bigbluebutton.main.model.users
     
 		public function UserService() {
 			dispatcher = new Dispatcher();
+			msgReceiver.onAllowedToJoin = function():void {
+				onAllowedToJoin();
+			}
+		}
+
+		private function onAllowedToJoin():void {
+			sender.queryForParticipants();
+			sender.queryForRecordingStatus();
+			sender.queryForGuestPolicy();
+
+			if (!_conferenceParameters.isBreakout) {
+				sender.queryForBreakoutRooms(_conferenceParameters.meetingID);
+			}
+
+			var loadCommand:SuccessfulLoginEvent = new SuccessfulLoginEvent(SuccessfulLoginEvent.USER_LOGGED_IN);
+			loadCommand.conferenceParameters = _conferenceParameters;
+			dispatcher.dispatchEvent(loadCommand);
 		}
 		
 		public function startService(e:UserServicesEvent):void {      
@@ -78,6 +99,7 @@ package org.bigbluebutton.main.model.users
 				UserManager.getInstance().getConference().setMyName(result.username);
 				UserManager.getInstance().getConference().setMyRole(result.role);
 				UserManager.getInstance().getConference().setMyRoom(result.room);
+				UserManager.getInstance().getConference().setGuest(result.guest == "true");
 				UserManager.getInstance().getConference().setMyAuthToken(result.authToken);
 				UserManager.getInstance().getConference().setMyCustomData(result.customdata);
 				UserManager.getInstance().getConference().setDefaultLayout(result.defaultLayout);
@@ -102,6 +124,7 @@ package org.bigbluebutton.main.model.users
 				_conferenceParameters.isBreakout = result.isBreakout;
 				_conferenceParameters.conference = result.conference;
 				_conferenceParameters.username = result.username;
+				_conferenceParameters.guest = (result.guest.toUpperCase() == "TRUE");
 				_conferenceParameters.role = result.role;
 				_conferenceParameters.room = result.room;
         _conferenceParameters.authToken = result.authToken;
@@ -111,7 +134,7 @@ package org.bigbluebutton.main.model.users
 				_conferenceParameters.meetingID = result.meetingID;
 				_conferenceParameters.externUserID = result.externUserID;
 				_conferenceParameters.internalUserID = result.internalUserId;
-				_conferenceParameters.logoutUrl = result.logoutUrl;
+				_conferenceParameters.logoutUrl = processLogoutUrl(result);
 				_conferenceParameters.record = (result.record != "false");
 				
 				var muteOnStart:Boolean;
@@ -139,12 +162,35 @@ package org.bigbluebutton.main.model.users
 				connect();
 			}
 		}
+
+		private function processLogoutUrl(confInfo:Object):String {
+			var logoutUrl:String = confInfo.logoutUrl;
+			var rules:Object = {
+				"%%FULLNAME%%": confInfo.username,
+				"%%CONFNAME%%": confInfo.conferenceName,
+				"%%DIALNUM%%": confInfo.dialnumber,
+				"%%CONFNUM%%": confInfo.voicebridge
+			}
+
+			for (var attr:String in rules) {
+				logoutUrl = logoutUrl.replace(new RegExp(attr, "g"), rules[attr]);
+			}
+
+			return logoutUrl;
+		}
 		
     private function connect():void{
       _connectionManager = BBB.initConnectionManager();
       _connectionManager.connect();
     }
 	
+	public function logoutEndMeeting():void{
+		if (this.isModerator()) {
+			var myUserId: String = UserManager.getInstance().getConference().getMyUserId();
+			sender.logoutEndMeeting(myUserId);
+		}
+	}
+
     public function logoutUser():void {
       disconnect(true);
     }
@@ -152,6 +198,10 @@ package org.bigbluebutton.main.model.users
     public function disconnect(onUserAction:Boolean):void {
       _connectionManager.disconnect(onUserAction);
 		}
+
+		public function activityResponse():void {
+			sender.activityResponse();
+		}
 		
 		private function queryForRecordingStatus():void {
 			sender.queryForRecordingStatus();
@@ -167,14 +217,30 @@ package org.bigbluebutton.main.model.users
 		public function userLoggedIn(e:UsersConnectionEvent):void {
 			UserManager.getInstance().getConference().setMyUserid(e.userid);
 			_conferenceParameters.userid = e.userid;
-			sender.queryForParticipants();
-			sender.queryForRecordingStatus();
-			if (!_conferenceParameters.isBreakout) {
-				sender.queryForBreakoutRooms(_conferenceParameters.meetingID);
+
+			var waitingForAcceptance:Boolean = true;
+			if (UserManager.getInstance().getConference().hasUser(e.userid)) {
+				LOGGER.debug("userLoggedIn - conference has this user");
+				waitingForAcceptance = UserManager.getInstance().getConference().getUser(e.userid).waitingForAcceptance;
 			}
-			var loadCommand:SuccessfulLoginEvent = new SuccessfulLoginEvent(SuccessfulLoginEvent.USER_LOGGED_IN);
-			loadCommand.conferenceParameters = _conferenceParameters;
-			dispatcher.dispatchEvent(loadCommand);
+
+			if (reconnecting && !waitingForAcceptance) {
+				LOGGER.debug("userLoggedIn - reconnecting and allowed to join");
+				onAllowedToJoin();
+				reconnecting = false;
+			}
+		}
+
+		public function denyGuest():void {
+			dispatcher.dispatchEvent(new LogoutEvent(LogoutEvent.MODERATOR_DENIED_ME));
+		}
+
+		public function setGuestPolicy(event:BBBEvent):void {
+			sender.setGuestPolicy(event.payload['guestPolicy']);
+		}
+
+		public function guestDisconnect():void {
+			_connectionManager.guestDisconnect();
 		}
 
 		public function isModerator():Boolean {
@@ -201,6 +267,10 @@ package org.bigbluebutton.main.model.users
 		public function createBreakoutRooms(e:BreakoutRoomEvent):void{
 			sender.createBreakoutRooms(_conferenceParameters.meetingID, e.rooms, e.durationInMinutes, e.record);
 		}
+
+		public function responseToGuest(e:ResponseModeratorEvent):void {
+			sender.responseToGuest(e.userid, e.resp);
+		}
 		
 		public function requestBreakoutJoinUrl(e:BreakoutRoomEvent):void{
 			sender.requestBreakoutJoinUrl(_conferenceParameters.meetingID, e.breakoutMeetingId, e.userId);
@@ -222,6 +292,17 @@ package org.bigbluebutton.main.model.users
 		public function kickUser(e:KickUserEvent):void{
 			if (this.isModerator()) sender.kickUser(e.userid);
 		}
+
+		public function changeRole(e:ChangeRoleEvent):void {
+			if (this.isModerator()) sender.changeRole(e.userid, e.role);
+		}
+
+		public function onReconnecting(e:BBBEvent):void {
+			if (e.payload.type == "BIGBLUEBUTTON_CONNECTION") {
+				LOGGER.debug("onReconnecting");
+				reconnecting = true;
+			}
+		}
 		
 		/**
 		 * Assign a new presenter 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/ChangeMyRole.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/ChangeMyRole.as
new file mode 100644
index 0000000000000000000000000000000000000000..47666e267cc615ad80715996ffc1c82ec94cbb32
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/ChangeMyRole.as
@@ -0,0 +1,35 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.main.model.users.events
+{
+	import flash.events.Event;
+
+	public class ChangeMyRole extends Event
+	{
+		public static const CHANGE_MY_ROLE_EVENT:String = "CHANGE_MY_ROLE_EVENT";
+
+		public var role:String;
+
+		public function ChangeMyRole(role:String)
+		{
+			this.role = role;
+			super(CHANGE_MY_ROLE_EVENT, true, false);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/ChangeRoleEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/ChangeRoleEvent.as
new file mode 100755
index 0000000000000000000000000000000000000000..7a9784797694187ef143197b2883f3d667676bf4
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/ChangeRoleEvent.as
@@ -0,0 +1,37 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.main.model.users.events
+{
+	import flash.events.Event;
+
+	public class ChangeRoleEvent extends Event
+	{
+		public static const CHANGE_ROLE_EVENT:String = "CHANGE_ROLE_EVENT";
+
+		public var userid:String;
+		public var role:String;
+
+		public function ChangeRoleEvent(userid:String, role:String)
+		{
+			this.userid = userid;
+			this.role = role;
+			super(CHANGE_ROLE_EVENT, true, false);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/ConnectionFailedEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/ConnectionFailedEvent.as
index f6b8530e5a99d5138daeff5fc225127aadf836be..2162ee3925c23c8ddcf002c37dc39518807afb62 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/ConnectionFailedEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/ConnectionFailedEvent.as
@@ -31,6 +31,7 @@ package org.bigbluebutton.main.model.users.events
         public static const ASYNC_ERROR:String = "asyncError";
         public static const USER_LOGGED_OUT:String = "userHasLoggedOut";
         public static const USER_EJECTED_FROM_MEETING:String = "userHasBeenEjectFromMeeting";
+        public static const MODERATOR_DENIED_ME:String = "moderatorDeniedMe";
 
         public function ConnectionFailedEvent(type:String) {
             super(type, true, false);
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/GuestConnectionEvent.as b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/GuestConnectionEvent.as
new file mode 100755
index 0000000000000000000000000000000000000000..12856f61bfb225dfee5ae4fd84fd2203b533d389
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/model/users/events/GuestConnectionEvent.as
@@ -0,0 +1,36 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.main.model.users.events
+{
+	import flash.events.Event;
+	import flash.net.NetConnection;
+
+	public class GuestConnectionEvent extends Event
+	{
+		public static const GUEST_CONNECTION:String = "guestConnection";
+
+		public var connection:NetConnection;
+		public var userid:Number;
+
+		public function UsersConnectionEvent(type:String)
+		{
+			super(type, true, false);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/BBBSettings.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/BBBSettings.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..eacd2a708edbd462b8ce6ea09d931ac67a972241
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/BBBSettings.mxml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
+		showCloseButton="false"
+		xmlns:mate="http://mate.asfusion.com/"
+		minWidth="250"
+		creationComplete="init()"
+		title="{ResourceUtil.getInstance().getString('bbb.settings.title')}" >
+
+	<mx:Script>
+		<![CDATA[
+			import mx.events.ItemClickEvent;
+			import mx.managers.PopUpManager;
+			import mx.core.UIComponent;
+
+			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.common.LogUtil;
+			import org.bigbluebutton.main.events.BBBEvent;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+			import org.bigbluebutton.common.events.SettingsComponentEvent;
+
+			private function init():void {
+				this.x = (this.parent.width - this.width) / 2;
+				this.y = (this.parent.height - this.height) / 2;
+			}
+
+			public function pushComponents(components:Array):void {
+				for (var i:int = 0; i < components.length; ++i) {
+					addedComponents.addChildAt(components[i] as UIComponent, 0);
+				}
+			}
+
+			private function onCancelClicked():void {
+				var event:BBBEvent = new BBBEvent(BBBEvent.SETTINGS_CANCELLED);
+				dispatchEvent(event);
+				close();
+			}
+
+			private function onOkClicked():void {
+				var event:BBBEvent = new BBBEvent(BBBEvent.SETTINGS_CONFIRMED);
+				dispatchEvent(event);
+				close();
+			}
+
+			private function close():void {
+				PopUpManager.removePopUp(this);
+			}
+
+		]]>
+	</mx:Script>
+	<mx:VBox id="addedComponents" height="100%" />
+
+	<mx:ControlBar width="100%" horizontalAlign="center">
+		<mx:Button id="okBtn" label="{ResourceUtil.getInstance().getString('bbb.settings.ok')}" width="100" click="onOkClicked()"/>
+		<mx:Spacer width="10"/>
+		<mx:Button id="cancelBtn" label="{ResourceUtil.getInstance().getString('bbb.settings.cancel')}" width="100" click="onCancelClicked()"/>
+	</mx:ControlBar>
+</mx:TitleWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/CameraDisplaySettings.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/CameraDisplaySettings.mxml
index 790fec496ec004a329d68b31dfc35a4ef78381d7..c1476c1c128e7a810655ac9a5cc121c75fbf972b 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/CameraDisplaySettings.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/CameraDisplaySettings.mxml
@@ -220,8 +220,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   <common:TabIndexer startIndex="1" tabIndices="{[textArea, cmbCameraSelector, cmbVideoProfile, btnStartPublish, btnClosePublish]}"/>
   
   <mx:VBox id="webcamDisplay" width="100%" height="100%" paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5" styleName="cameraDisplaySettingsWindowBackground">
-    <mx:TextArea width="100%" borderSkin="{null}" editable="false" text="{ResourceUtil.getInstance().getString('bbb.users.settings.webcamSettings')}" 
+    <mx:HBox width="100%" horizontalAlign="left">
+      <mx:TextArea width="100%" wordWrap="false" borderSkin="{null}" editable="false" text="{ResourceUtil.getInstance().getString('bbb.users.settings.webcamSettings')}"
                    styleName="webcamSettingsWindowTitleStyle" id="textArea"/>
+    </mx:HBox>
+
     <mx:HRule width="100%"/>
     <mx:Spacer height="1"/>
     
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/FirefoxMicPermissionImage.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/FirefoxMicPermissionImage.mxml
index a528a89b454529ad1de35dff1976e9a21efbf54d..10da75f3189ba57e860066c0944fe4680d921924 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/FirefoxMicPermissionImage.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/FirefoxMicPermissionImage.mxml
@@ -30,8 +30,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     borderThicknessLeft="0" 
     borderThicknessRight="0"
     borderThicknessTop="0"
-    x="20"
-    y="-20">
+    headerHeight="0"
+    paddingTop="0"
+    paddingBottom="0"
+    paddingRight="0"
+    paddingLeft="0"
+    width="384"
+    height="254">
   
 	<mate:Listener type="{WebRTCMediaEvent.WEBRTC_MEDIA_SUCCESS}" method="handleWebRTCMediaSuccessEvent" />
 	<mate:Listener type="{WebRTCMediaEvent.WEBRTC_MEDIA_FAIL}" method="handleWebRTCMediaFailEvent" />
@@ -60,23 +65,27 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		]]>
 	</mx:Script>
   
-  <mx:VBox width="100%" height="100%"  paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5">
-     <mx:TextArea borderSkin="{null}"
-                  editable="false"
-                  text="{ResourceUtil.getInstance().getString('bbb.micPermissions.firefox.title')}"
-                  styleName="micSettingsWindowTitleStyle"
-                  width="440" height="100%" verticalScrollPolicy="off"
-                  left="0"/>
-    <mx:HBox width="100%">      
-      <mx:Text width="100%" text="{ResourceUtil.getInstance().getString('bbb.micPermissions.firefox.message1')}"
-               styleName="micSettingsWindowSpeakIntoMicLabelStyle" />		
-      <mx:Image source="@Embed('assets/ff-share-mic.png')"/>	
+  <mx:VBox id="externalBox" width="100%" height="100%" verticalGap="0" horizontalGap="0">
+    <mx:HBox width="100%" height="126" backgroundColor="#0150ab">
+      <mx:HBox width="100%" height="100%">
+        <mx:VBox paddingLeft="10" paddingTop="15">
+          <mx:Image source="@Embed('assets/ff-arrow-2.png')"/>
+        </mx:VBox>
+        <mx:VBox width="100%" height="100%" paddingLeft="25" paddingRight="10" verticalAlign="middle">
+          <mx:Text width="100%" textAlign="right"
+                text="{ResourceUtil.getInstance().getString('bbb.micPermissions.firefox.message2')}"
+                styleName="micSettingsWindowOpenDialogLabelStyle"
+                selectable="false"/>
+        </mx:VBox>
+      </mx:HBox>
     </mx:HBox>
-    <mx:HBox width="100%">
-      <mx:Text width="100%" text="{ResourceUtil.getInstance().getString('bbb.micPermissions.firefox.message2')}"
-               styleName="micSettingsWindowHearFromHeadsetLabelStyle"/>	
-      <mx:Image source="@Embed('assets/ff-show-mic.png')"/>
+    <mx:HBox width="100%" height="100%" paddingLeft="10" paddingTop="10" paddingRight="10" paddingBottom="10" verticalAlign="bottom" backgroundColor="white">
+      <mx:Text width="100%" text="{ResourceUtil.getInstance().getString('bbb.micPermissions.firefox.message1')}"
+              styleName="micSettingsWindowShareMicrophoneLabelStyle"
+              textAlign="left"
+              paddingRight="25"
+              selectable="false"/>
+      <mx:Image source="@Embed('assets/ff-arrow-1.png')"/>
     </mx:HBox>
-  </mx:VBox>		
-
+  </mx:VBox>
 </mx:TitleWindow> 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/GuestItem.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/GuestItem.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..9f89c6219209ced2c3aab84ca14e7ece7004a726
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/GuestItem.mxml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org
+
+  Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+
+  BigBlueButton is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Lesser General Public License as published by the Free Software
+  Foundation; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+  PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License along
+  with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  $Id: $
+-->
+
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
+    verticalAlign="middle" width="100%" >
+
+    <mx:Script>
+        <![CDATA[
+            import mx.core.FlexGlobals;
+            import mx.managers.PopUpManager;
+            import com.asfusion.mate.events.Dispatcher;
+            import org.bigbluebutton.common.Images;
+            import org.bigbluebutton.core.BBB;
+            import org.bigbluebutton.core.managers.UserManager;
+            import org.bigbluebutton.main.events.ResponseModeratorEvent;
+            import org.bigbluebutton.main.events.ModuleLoadEvent;
+            import org.bigbluebutton.util.i18n.ResourceUtil;
+            import mx.containers.HBox;
+            import mx.controls.Button;
+            import mx.controls.Spacer;
+            import org.bigbluebutton.main.events.BBBEvent;
+
+            private var dispatcher:Dispatcher = new Dispatcher();
+
+            [Bindable] private var username:String = "";
+            private var userid:String;
+
+            public function setUser(username:String, userid:String):void {
+                this.username = username;
+                this.userid = userid;
+            }
+
+            private function onRejectUserBtnClick():void {
+                sendResponseToServer(false);
+            }
+
+            private function onAcceptUserBtnClick():void {
+                sendResponseToServer(true);
+            }
+
+            private function sendResponseToServer(accept:Boolean):void {
+                var respCommand:ResponseModeratorEvent = new ResponseModeratorEvent(ResponseModeratorEvent.RESPONSE);
+                respCommand.userid = userid;
+                respCommand.resp = accept;
+                dispatcher.dispatchEvent(respCommand);
+            }
+
+        ]]>
+    </mx:Script>
+
+    <mx:Label text="{username}" maxWidth="150" />
+    <mx:Spacer width="100%" />
+    <mx:Button styleName="denyButtonStyle" toolTip="{ResourceUtil.getInstance().getString('bbb.guests.denyBtn.toolTip')}" click="onRejectUserBtnClick()" />
+    <mx:Button styleName="acceptButtonStyle" toolTip="{ResourceUtil.getInstance().getString('bbb.guests.allowBtn.toolTip')}" click="onAcceptUserBtnClick()" />
+
+</mx:HBox>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/GuestManagement.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/GuestManagement.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..f8ab06436b5d8e9fced5c2c5629fa62436c15c9a
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/GuestManagement.mxml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
+		xmlns:mate="http://mate.asfusion.com/"
+		width="400" >
+
+		<mate:Listener type="{BBBEvent.RETRIEVE_GUEST_POLICY}" method="refreshGuestPolicy"/>
+		<mate:Listener type="{BBBEvent.SETTINGS_CONFIRMED}" method="onOkClicked"/>
+		<mate:Listener type="{BBBEvent.SETTINGS_CANCELLED}" method="onCancelClicked"/>
+
+	<mx:Script>
+		<![CDATA[
+			import mx.events.ItemClickEvent;
+			import mx.managers.PopUpManager;
+
+			import org.as3commons.logging.api.ILogger;
+			import org.as3commons.logging.api.getClassLogger;
+
+			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.main.events.BBBEvent;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+			import org.bigbluebutton.common.events.SettingsComponentEvent;
+			import com.asfusion.mate.events.Dispatcher;
+
+			private static const LOGGER:ILogger = getClassLogger(GuestManagement);
+
+			private var option:Number = 0;
+			private var guestPolicy:String;
+
+			private function refreshGuestPolicy(event:BBBEvent):void {
+				setGuestPolicy(event.payload.guestPolicy);
+			}
+
+			public function setGuestPolicy(guestPolicy:String):void {
+				this.guestPolicy = guestPolicy;
+
+				if(guestPolicy == "ASK_MODERATOR") {
+					guestManagement.selectedValue = 0;
+					option = 0;
+				} else if(guestPolicy == "ALWAYS_ACCEPT") {
+					guestManagement.selectedValue = 1;
+					option = 1;
+				} else {
+					guestManagement.selectedValue = 2;
+					option = 2;
+				}
+			}
+
+			public function addToSettings():void {
+				var addGuestManagement:SettingsComponentEvent = new SettingsComponentEvent(SettingsComponentEvent.ADD);
+				addGuestManagement.component = this;
+				var dispatcher:Dispatcher = new Dispatcher();
+				dispatcher.dispatchEvent(addGuestManagement);
+			}
+
+			private function onCancelClicked(e:Event = null):void {
+				setGuestPolicy(guestPolicy);
+			}
+
+			private function handleGuestClick(event:ItemClickEvent):void {
+				option = event.currentTarget.selectedValue;
+			}
+
+			private function onOkClicked(e:Event = null):void {
+				var event:BBBEvent = new BBBEvent(BBBEvent.BROADCAST_GUEST_POLICY);
+				if(option == 0) {
+					event.payload['guestPolicy'] = "ASK_MODERATOR";
+					dispatchEvent(event);
+				}
+				else if(option == 1) {
+					event.payload['guestPolicy'] = "ALWAYS_ACCEPT";
+					dispatchEvent(event);
+					dispatchEvent(new BBBEvent(BBBEvent.ACCEPT_ALL_WAITING_GUESTS));
+				}
+				else {
+					event.payload['guestPolicy'] = "ALWAYS_DENY";
+					dispatchEvent(event);
+					dispatchEvent(new BBBEvent(BBBEvent.DENY_ALL_WAITING_GUESTS));
+				}
+				LOGGER.debug("SENDING TO SERVER POLICY");
+			}
+		]]>
+	</mx:Script>
+	<mx:VBox width="30%">
+		<mx:Label text="{ResourceUtil.getInstance().getString('bbb.guests.Management')}"/>
+	</mx:VBox>
+	<mx:Spacer width="30" />
+	<mx:VBox width="70%">
+		<mx:RadioButtonGroup id="guestManagement" itemClick="handleGuestClick(event);"/>
+		<mx:RadioButton groupName="guestManagement"
+				id="askModerator"
+				label="{ResourceUtil.getInstance().getString('bbb.guests.askModerator')}"
+				value="0"
+				/>
+		<mx:RadioButton groupName="guestManagement"
+				id="alwaysAccept"
+				label="{ResourceUtil.getInstance().getString('bbb.guests.alwaysAccept')}"
+				value="1"
+				/>
+		<mx:RadioButton groupName="guestManagement"
+				id="AlwaysDeny"
+				label="{ResourceUtil.getInstance().getString('bbb.guests.alwaysDeny')}"
+				value="2"
+				/>
+	</mx:VBox>
+</mx:HBox>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/GuestWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/GuestWindow.mxml
new file mode 100755
index 0000000000000000000000000000000000000000..2f360dae4aa0c68728f41704d8c873063e0c8921
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/GuestWindow.mxml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org
+
+  Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+
+  BigBlueButton is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Lesser General Public License as published by the Free Software
+  Foundation; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+  PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License along
+  with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  $Id: $
+-->
+
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
+	title="{ResourceUtil.getInstance().getString('bbb.guests.title')}" showCloseButton="false" creationComplete="init()"
+	x="0" y="0" layout="vertical" width="320" horizontalAlign="center"
+	xmlns:mate="http://mate.asfusion.com/" >
+
+	<mate:Listener type="{BBBEvent.ACCEPT_ALL_WAITING_GUESTS}" method="acceptAllWaitingGuests" />
+	<mate:Listener type="{BBBEvent.DENY_ALL_WAITING_GUESTS}" method="denyAllWaitingGuests" />
+	<mate:Listener type="{RemoveGuestFromViewEvent.REMOVE_GUEST}" receive="{remove(event.userid)}" />
+
+	<mx:Script>
+		<![CDATA[
+			import mx.core.FlexGlobals;
+			import mx.managers.PopUpManager;
+			import com.asfusion.mate.events.Dispatcher;
+			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.core.BBB;
+			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.main.events.ModuleLoadEvent;
+			import org.bigbluebutton.main.events.RemoveGuestEvent;
+			import org.bigbluebutton.main.events.ResponseModeratorEvent;
+			import org.bigbluebutton.main.events.RemoveGuestFromViewEvent;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+			import mx.containers.HBox;
+			import mx.controls.Button;
+			import mx.controls.Spacer;
+			import mx.events.CloseEvent;
+			import org.bigbluebutton.main.events.BBBEvent;
+
+			private var guestButtons:Object = new Object();
+			[Bindable] private var numberOfGuests:Number = 0;
+			private var dispatcher:Dispatcher = new Dispatcher();
+
+			public function init():void {
+				//Uncomment this line to make titlewindow undraggable
+				//this.isPopUp = false;
+			}
+
+			public function refreshGuestView(listOfGuests:Object):void {
+				for (var userid:String in listOfGuests) {
+					if(guestButtons[userid] == null) {
+						var guestItem:GuestItem = new GuestItem();
+						guestItem.setUser(listOfGuests[userid], userid);
+						guestListBox.addChild(guestItem);
+						guestButtons[userid] = guestItem;
+						numberOfGuests++;
+					}
+				}
+				this.visible = true;
+			}
+
+			public function sendResponseToAllGuests(resp:Boolean):void {
+				removeAllGuests();
+				var respCommand:ResponseModeratorEvent = new ResponseModeratorEvent(ResponseModeratorEvent.RESPONSE_ALL);
+				respCommand.resp = resp;
+				dispatcher.dispatchEvent(respCommand);
+			}
+
+			public function sendResponseToAllGuestsCheckBox(resp:Boolean):void {
+				if(rememberCheckBox.selected) {
+					var event:BBBEvent = new BBBEvent(BBBEvent.BROADCAST_GUEST_POLICY);
+					if (resp) {
+						event.payload['guestPolicy'] = "ALWAYS_ACCEPT";
+					} else {
+						event.payload['guestPolicy'] = "ALWAYS_DENY";
+					}
+					dispatcher.dispatchEvent(event);
+				}
+				sendResponseToAllGuests(resp);
+			}
+
+			public function acceptAllWaitingGuests(event:BBBEvent):void {
+				sendResponseToAllGuests(true);
+			}
+
+			public function denyAllWaitingGuests(event:BBBEvent):void {
+				sendResponseToAllGuests(false);
+			}
+
+			public function removeAllGuests():void {
+				var removeGuestEvent:RemoveGuestEvent = new RemoveGuestEvent(RemoveGuestEvent.REMOVE_ALL);
+				dispatcher.dispatchEvent(removeGuestEvent);
+
+				closeWindow();
+			}
+
+			public function remove(userid:String):void {
+				if (guestButtons[userid] != null) {
+					numberOfGuests = numberOfGuests  - 1;
+					guestListBox.removeChild(guestButtons[userid]);
+					delete guestButtons[userid];
+
+					var removeGuestEvent:RemoveGuestEvent = new RemoveGuestEvent();
+					removeGuestEvent.userid = userid;
+					dispatcher.dispatchEvent(removeGuestEvent);
+
+					if (!hasGuest()) {
+						closeWindow();
+					}
+				}
+			}
+
+			public function hasGuest():Boolean {
+				return numberOfGuests > 0;
+			}
+
+			public function closeWindow():void {
+				this.visible = false;
+				PopUpManager.removePopUp(this);
+				dispatchEvent(new CloseEvent(CloseEvent.CLOSE));
+			}
+
+		]]>
+	</mx:Script>
+	<mx:Label text="{numberOfGuests > 1? ResourceUtil.getInstance().getString('bbb.guests.message.plural', [String(numberOfGuests)]): ResourceUtil.getInstance().getString('bbb.guests.message.singular', [String(numberOfGuests)])}"/>
+	<mx:HRule width="100%"/>
+	<mx:Button id="allowEveryoneBtn" label="{ResourceUtil.getInstance().getString('bbb.guests.allowEveryoneBtn.text')}" width="70%" click="sendResponseToAllGuestsCheckBox(true)" toolTip="{allowEveryoneBtn.label}"/>
+	<mx:Button id="denyEveryoneBtn" label="{ResourceUtil.getInstance().getString('bbb.guests.denyEveryoneBtn.text')}" width="70%" click="sendResponseToAllGuestsCheckBox(false)" toolTip="{denyEveryoneBtn.label}"/>
+	<mx:CheckBox id="rememberCheckBox" label="{ResourceUtil.getInstance().getString('bbb.guests.rememberAction.text')}"/>
+	<mx:HRule width="100%"/>
+	<mx:VBox id="guestListBox" width="100%" height="100%" maxHeight="200" paddingLeft="10" paddingRight="10" paddingBottom="2" />
+
+</mx:TitleWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/InactivityWarningWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/InactivityWarningWindow.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..537f9641f50418ac122a513109a656a23afcc6dd
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/InactivityWarningWindow.mxml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+-->
+
+<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml"
+		xmlns:mate="http://mate.asfusion.com/"
+		verticalScrollPolicy="off"
+		horizontalScrollPolicy="off"
+		horizontalAlign="center"
+		width="500"
+		height="120"
+		styleName="inactivityWarningTextStyle"
+		title="{ResourceUtil.getInstance().getString('bbb.inactivityWarning.title')}"
+		creationComplete="onCreationComplete()">
+
+	<mate:Listener type="{BBBEvent.MEETING_IS_ACTIVE_EVENT}" method="meetingIsActiveFeedback"/>
+
+	<mx:Script>
+	<![CDATA[
+		import com.asfusion.mate.events.Dispatcher;
+
+		import mx.managers.PopUpManager;
+
+		import org.as3commons.logging.api.ILogger;
+		import org.as3commons.logging.api.getClassLogger;
+
+		import org.bigbluebutton.util.i18n.ResourceUtil;
+		import org.bigbluebutton.main.events.BBBEvent;
+
+		private static const LOGGER:ILogger = getClassLogger(InactivityWarningWindow);
+
+		public var duration:Number = 0;
+		private var tickTimer:Timer;
+
+		[Bindable]
+		private var cancelButtonLabel:String = ResourceUtil.getInstance().getString('bbb.inactivityWarning.cancel');
+
+		private function onCreationComplete():void {
+			tickTimer = new Timer(1000, 0);
+			tickTimer.addEventListener(TimerEvent.TIMER, tick);
+
+			cancelButton.width = cancelButton.measureText(genCancelButtonLabel(duration)).width
+					+ cancelButton.getStyle("paddingRight")
+					+ cancelButton.getStyle("paddingLeft")
+					+ 8; // 8 is magic number
+
+			tickTimer.start();
+			cancelButton.visible = true;
+		}
+
+		private function tick(e:TimerEvent):void {
+			if (duration > 0) {
+				cancelButton.label = genCancelButtonLabel(duration);
+				duration--;
+			} else {
+				tickTimer.stop();
+				cancelButton.visible = false;
+				cancelButton.includeInLayout = false;
+				warningMessage.text = ResourceUtil.getInstance().getString('bbb.shuttingDown.message');
+			}
+		}
+
+		private function genCancelButtonLabel(timeLeft:Number):String {
+			return cancelButtonLabel + " (" + timeLeft.toString() + ")";
+		}
+
+		private function meetingIsActiveFeedback(e:BBBEvent):void {
+			tickTimer.stop();
+			PopUpManager.removePopUp(this);
+		}
+
+		private function cancelButtonClicked():void {
+			var dispatcher:Dispatcher = new Dispatcher();
+			var bbbEvent:BBBEvent = new BBBEvent(BBBEvent.ACTIVITY_RESPONSE_EVENT);
+			dispatcher.dispatchEvent(bbbEvent);
+		}
+	]]>
+	</mx:Script>
+	<mx:VBox width="100%" height="100%"  paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5" horizontalAlign="center" verticalAlign="middle">
+		<mx:Text id="warningMessage" selectable="false" text="{ResourceUtil.getInstance().getString('bbb.inactivityWarning.message')}" styleName="inactivityWarningTextStyle"/>
+		<mx:Button id="cancelButton" click="cancelButtonClicked()" visible="false" styleName="inactivityWarningWindowCancelButtonStyle"/>
+	</mx:VBox>
+</mx:Panel>
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/LanguageSelector.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/LanguageSelector.mxml
index 3b7652b872a3c686585ea6aafb92cbeb8f690148..0a572a5fafc4bab2a2b1df5c736d679abdd5d379 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/LanguageSelector.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/LanguageSelector.mxml
@@ -21,48 +21,25 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 -->
 
 <mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml" 
-		dataProvider="{ResourceUtil.getInstance().localeNames}" 
-		selectedIndex="{ResourceUtil.getInstance().localeIndex}"
-		change="changeLanguage()" rowCount="15" width="120" height="22">
-
-	<mx:itemRenderer >
-		<mx:Component >
-			<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml"
-					mouseOver="highlightItem()" 
-					mouseOut="removeHighlightItem()"
-					enabled="true"
-					width="100%"
-					paddingLeft="0" paddingRight="0" paddingTop="0" paddingBottom="0"
-					horizontalScrollPolicy="off">
-				<mx:Script>
-					<![CDATA[
-						import org.bigbluebutton.util.i18n.ResourceUtil;
-						
-						private function highlightItem():void {
-							boxCont.setStyle("backgroundColor", "0xB2E1FF");
-						}
-						private function removeHighlightItem():void {
-							if(data == ResourceUtil.getInstance().getPreferredLocaleName())
-								boxCont.setStyle("backgroundColor", "0x7FCEFF");
-							else
-								boxCont.setStyle("backgroundColor", "0xFFFFFF");
-						}
-					]]>
-				</mx:Script>
-				<mx:Box paddingLeft="0" paddingRight="0" paddingTop="0" paddingBottom="0" id="boxCont" width="100%" horizontalScrollPolicy="off" backgroundColor="{data == ResourceUtil.getInstance().getPreferredLocaleName() ? 0x7FCEFF : 0xFFFFFF}">
-					<mx:Label paddingLeft="0" paddingRight="0" paddingTop="0" paddingBottom="0" text="{data}" width="150"/>
-				</mx:Box>
-			</mx:Box>
-		</mx:Component>
-	</mx:itemRenderer>
+		xmlns:mate="http://mate.asfusion.com/"
+		dataProvider="{ResourceUtil.getInstance().locales}"
+		change="changeLanguage()"
+		labelField="name"
+		rowCount="15" width="120" height="22">
 
+	<mate:Listener type="{LocaleChangeEvent.LOCALE_CHANGED}" method="localeChanged" />
 
 	<mx:Script>
 		<![CDATA[
 			import org.bigbluebutton.util.i18n.ResourceUtil;
+			import org.bigbluebutton.common.events.LocaleChangeEvent;
+
+			private function localeChanged(e:LocaleChangeEvent):void {
+				selectedIndex = ResourceUtil.getInstance().getCurrentLanguageIndex();
+			}
 
 			private function changeLanguage():void {
-				ResourceUtil.getInstance().setPreferredLocale(ResourceUtil.getInstance().getLocaleCodeForIndex(selectedIndex));
+				ResourceUtil.getInstance().setPreferredLocale(selectedItem.code);
 			}
 		]]>
 	</mx:Script>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/LoadingBar.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/LoadingBar.mxml
index 41bf6d1f761e6ae80e51147148a4d1af8133bb3d..83a3ab08928d2f59c51d293d20090baafd2476bc 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/LoadingBar.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/LoadingBar.mxml
@@ -20,7 +20,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 -->
 
-<mx:ProgressBar xmlns:mate="http://mate.asfusion.com/" xmlns:mx="http://www.adobe.com/2006/mxml" labelPlacement="bottom" minimum="0" maximum="100" mode="manual" >
+<mx:ProgressBar xmlns:mate="http://mate.asfusion.com/" xmlns:mx="http://www.adobe.com/2006/mxml" labelPlacement="bottom" minimum="0" maximum="100" mode="manual" barColor="black" >
 	
 	<mate:Listener type="{ModuleLoadEvent.MODULE_LOADING_STARTED}" method="moduleLoadingStarted" />
 	<mate:Listener type="{ModuleLoadEvent.MODULE_LOAD_PROGRESS}" method="moduleLoadProgress" />
@@ -47,6 +47,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       private function moduleLoadingStarted(e:ModuleLoadEvent):void{
 		  numModules = BBB.getConfigManager().config.numberOfModules();
         this.label = ResourceUtil.getInstance().getString('bbb.mainshell.statusProgress.loading', [numModules]);
+        this.visible = true;
       }
 			
       private function moduleLoadProgress(e:ModuleLoadEvent):void{
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/LogoutWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/LogoutWindow.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..45a3d5825e7f1c3af7a3758cbb387301a24df0c2
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/LogoutWindow.mxml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+-->
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
+          xmlns:mate="http://mate.asfusion.com/"
+          verticalScrollPolicy="off"
+          horizontalScrollPolicy="off"
+          horizontalAlign="center"
+          showCloseButton="false"
+          creationComplete="onCreationComplete()"
+          styleName="logoutWindowStyle"
+          height="108"
+          width="350"
+          title="{ResourceUtil.getInstance().getString('bbb.logout.confirm.title')}">
+
+  <mx:Script>
+    <![CDATA[
+      import com.asfusion.mate.events.Dispatcher;
+
+      import mx.controls.Alert;
+      import mx.events.CloseEvent;
+      import mx.managers.PopUpManager;
+      import org.bigbluebutton.common.Images;
+      import org.bigbluebutton.common.LogUtil;
+      import org.bigbluebutton.core.UsersUtil;
+      import org.bigbluebutton.util.i18n.ResourceUtil;
+      import org.bigbluebutton.modules.layout.events.LayoutEvent;
+      import org.bigbluebutton.main.events.BBBEvent;
+      import org.bigbluebutton.main.events.LogoutEvent;
+
+      private var globalDispatcher:Dispatcher = new Dispatcher();;
+
+      private function onCreationComplete():void {
+        cancelButton.setFocus();
+        endMeetingButton.visible = endMeetingButton.includeInLayout = UsersUtil.amIModerator();
+      }
+
+      private function endMeetingClickHandler():void {
+        globalDispatcher.dispatchEvent(new BBBEvent(BBBEvent.CONFIRM_LOGOUT_END_MEETING_EVENT));
+
+        close();
+      }
+
+      private function confirmButtonClickHandler():void {
+        globalDispatcher.dispatchEvent(new LogoutEvent(LogoutEvent.USER_LOGGED_OUT));
+
+        close();
+      }
+
+      private function cancelButtonClickHandler():void {
+        close();
+      }
+
+      private function close():void {
+        PopUpManager.removePopUp(this);
+      }
+    ]]>
+  </mx:Script>
+
+  <mx:VBox width="100%" height="100%">
+    <mx:Box width="100%" height="100%" horizontalAlign="center" verticalAlign="middle">
+      <mx:Text text="{ResourceUtil.getInstance().getString('bbb.logout.confirm.message')}" />
+    </mx:Box>
+    <mx:HBox width="100%" horizontalAlign="center">
+      <mx:Button id="confimButton" height="22" label="{ResourceUtil.getInstance().getString('bbb.logout.confirm.yes')}" click="confirmButtonClickHandler()" />
+      <mx:Button id="cancelButton" height="22" label="{ResourceUtil.getInstance().getString('bbb.logout.confirm.no')}" click="cancelButtonClickHandler()" />
+      <mx:Button id="endMeetingButton" height="22" label="{ResourceUtil.getInstance().getString('bbb.logout.confirm.endMeeting')}" click="endMeetingClickHandler()" />
+   </mx:HBox>
+  </mx:VBox>
+</mx:TitleWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
index f0a90158456fa05ffe1b75d8eb8d111d0dfe9598..de53cbc627ccbbfa496e1656c0fe96fc9e7ae787 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainApplicationShell.mxml
@@ -31,7 +31,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		xmlns:common="org.bigbluebutton.common.*"
 		width="100%" height="{parentApplication.height - 1}"
 		horizontalScrollPolicy="off" verticalScrollPolicy="off"
-		creationComplete="initializeShell()">
+		backgroundColor="white" styleName="mainVBox"
+		creationComplete="initializeShell()"
+		verticalGap="0">
 
 	<!--
 	height="{parentApplication.height - 1}" : The container height is set to fix height because the percentHeight
@@ -64,9 +66,19 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<mate:Listener type="{ToolbarButtonEvent.REMOVE}" method="handleRemoveToolbarComponent"/>
 	<mate:Listener type="{ShortcutEvent.OPEN_SHORTCUT_WIN}" method="openShortcutHelpWindow" />
 	<mate:Listener type="{BBBEvent.OPEN_WEBCAM_PREVIEW}" method="openVideoPreviewWindow" />
+	<mate:Listener type="{BBBEvent.INACTIVITY_WARNING_EVENT}" method="handleInactivityWarningEvent" />
 	<mate:Listener type="{LockControlEvent.OPEN_LOCK_SETTINGS}" method="openLockSettingsWindow" />
 	<mate:Listener type="{BreakoutRoomEvent.OPEN_BREAKOUT_ROOMS_PANEL}" method="openBreakoutRoomsWindow" />
 	<mate:Listener type="{InvalidAuthTokenEvent.INVALID_AUTH_TOKEN}" method="handleInvalidAuthToken" />
+
+	<mate:Listener type="{NetworkStatsEvent.OPEN_NETSTATS_WIN}" method="openNetworkStatsWindow" />
+	<mate:Listener type="{BBBEvent.RETRIEVE_GUEST_POLICY}" method="setGuestPolicy"/>
+	<mate:Listener type="{ConnectionFailedEvent.MODERATOR_DENIED_ME}" method="handleLogout" />
+	<mate:Listener type="{BBBEvent.MODERATOR_ALLOWED_ME_TO_JOIN}" method="guestAllowed" />
+	<mate:Listener type="{RefreshGuestEvent.REFRESH_GUEST_VIEW}" method="refreshGuestView" />
+	<mate:Listener type="{BBBEvent.REMOVE_GUEST_FROM_LIST}" method="removeGuestWindow" />
+	<mate:Listener type="{BBBEvent.WAITING_FOR_MODERATOR_ACCEPTANCE}" method="openWaitWindow" />
+	<mate:Listener type="{BBBEvent.RECONNECT_DISCONNECTED_EVENT}" method="closeWaitWindow"/>
 	  
 	<mx:Script>
 		<![CDATA[
@@ -97,6 +109,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.common.events.OpenWindowEvent;
 			import org.bigbluebutton.common.events.ToolbarButtonEvent;
 			import org.bigbluebutton.core.BBB;
+			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.core.events.LockControlEvent;
 			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.core.vo.LockSettingsVO;
@@ -108,10 +121,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.main.events.InvalidAuthTokenEvent;
 			import org.bigbluebutton.main.events.MeetingNotFoundEvent;
 			import org.bigbluebutton.main.events.ModuleLoadEvent;
+			import org.bigbluebutton.main.events.NetworkStatsEvent;
+			import org.bigbluebutton.main.events.RefreshGuestEvent;
 			import org.bigbluebutton.main.events.ShortcutEvent;
+			import org.bigbluebutton.main.model.Guest;
+			import org.bigbluebutton.main.model.ImageLoader;
 			import org.bigbluebutton.main.model.LayoutOptions;
 			import org.bigbluebutton.main.model.users.Conference;
 			import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
+			import org.bigbluebutton.modules.phone.PhoneOptions;
 			import org.bigbluebutton.modules.phone.events.AudioSelectionWindowEvent;
 			import org.bigbluebutton.modules.phone.events.FlashMicSettingsEvent;
 			import org.bigbluebutton.modules.phone.events.WebRTCCallEvent;
@@ -129,6 +147,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private var images:Images = new Images();
 			private var stoppedModules:ArrayCollection;			
 			private var logWindow:LogWindow;
+			private var waitWindow:WaitingWindow = null;
+			private var guestWindow:GuestWindow = null;
 			private var scWindow:ShortcutHelpWindow;
 			private var logoutWindow:LoggedOutWindow;
 			private var connectionLostWindow:ConnectionLostWindow;
@@ -142,11 +162,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			[Bindable] private var fullscreen_icon:Class = images.full_screen;
 			[Bindable] private var logs_icon:Class = images.table;
 			[Bindable] private var reset_layout_icon:Class = images.layout;
-			[Bindable] private var statsIcon:Class = images.bandwidth;
       
 			private var receivedConfigLocaleVer:Boolean = false;
 			private var receivedResourceLocaleVer:Boolean = false;
 			
+			[Bindable] private var copyrightText:String;
+
+			private var _hideToolbarsTimer:Timer;
+
 			public function get mode():String {
 				return _mode;
 			}
@@ -154,16 +177,27 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			[Bindable] private var layoutOptions:LayoutOptions;
 			
 			[Bindable] private var showToolbarOpt:Boolean = true;
-			[Bindable] private var toolbarHeight:Number = 32;
-			[Bindable] private var toolbarPaddingTop:Number = 4;
+			[Bindable] private var _showToolbar:Boolean = true;
+			private const DEFAULT_TOOLBAR_HEIGHT:Number = 32;
+			[Bindable] private var toolbarHeight:Number = DEFAULT_TOOLBAR_HEIGHT;
+			[Bindable] private var toolbarPaddingTop:Number = 2;
 			[Bindable] private var showFooterOpt:Boolean = true;
+			[Bindable] private var _showFooter:Boolean = true;
 			[Bindable] private var footerHeight:Number = 24;
 			
 			[Bindable] private var isTunneling:Boolean = false;
 			
+			private var guestManagement:GuestManagement = null;
+			private var guest:Guest = new Guest();
+			private var guestPolicy:String = "ASK_MODERATOR";
+
 			private var confirmingLogout:Boolean = false;
 			private var chromeBrowser:ChromeWebcamPermissionImage = null;
 			
+			private const THRESHOLD_AREA_SHOW_TOOLBARS:int = 5;
+			private const HIDE_TOOLBARS_EFFECT_DURATION:int = 500;
+			private const HIDE_TOOLBARS_DELAY:int = 1000;
+
 			public function getLogWindow() : LogWindow
 			{
 				if (logWindow == null){
@@ -173,6 +207,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
       
 			public function initOptions(e:Event):void {
+				updateCopyrightText();
+				loadBackground();
+
 				UserManager.getInstance().getConference().configLockSettings();
 				layoutOptions = new LayoutOptions();
 				layoutOptions.parseOptions();
@@ -190,27 +227,155 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				
 				if (!showFooterOpt) {
 					footerHeight = 0;
-					controlBar.visible = false;
+					controlBar.visible = controlBar.includeInLayout = false;
 					calculateCanvasHeight();
 				}
 			}
 		
+			private function updateCopyrightText():void {
+				if (BBB.getConfigManager().config.branding.copyright == undefined) {
+					copyrightText = ResourceUtil.getInstance().getString('bbb.mainshell.copyrightLabel2',[appVersion]);
+				} else {
+					copyrightText = String(BBB.getConfigManager().config.branding.copyright).replace("{0}", appVersion);
+				}
+			}
+
 			protected function initializeShell():void {	
 				globalDispatcher = new Dispatcher();
 				
+				_hideToolbarsTimer = new Timer(HIDE_TOOLBARS_DELAY, 1);
+				_hideToolbarsTimer.addEventListener(TimerEvent.TIMER, onHideToolbarsTimerComplete);
+
+				if (stage == null) {
+					addEventListener(Event.ADDED_TO_STAGE, initFullScreen);
+				} else {
+					initFullScreen();
+				}
+
 				systemManager.addEventListener(Event.RESIZE, handleApplicationResizeEvent);
+				copyrightLabel2.addEventListener(FlexEvent.UPDATE_COMPLETE, updateCopyrightLabelDimensions);
+				handleApplicationResizeEvent();
+			}
+
+			private function handleApplicationResizeEvent(e:Event = null):void {
 				calculateCanvasHeight();
+				updateCopyrightLabelDimensions();
 			}
 			
-			private function handleApplicationResizeEvent(e:Event):void {
+			private function setGuestPolicy(event:BBBEvent):void {
+				guestPolicy = event.payload.guestPolicy;
+				if(guestManagement == null) {
+					LOGGER.debug("ADD Guest Event");
+					guestManagement = new GuestManagement();
+					guestManagement.setGuestPolicy(guestPolicy);
+					guestManagement.addToSettings();
+				}
+			}
+
+			private function isFullScreen():Boolean {
+				return stage.displayState == StageDisplayState.FULL_SCREEN ||
+						stage.displayState == StageDisplayState.FULL_SCREEN_INTERACTIVE;
+			}
+
+			private function mouseMoveHandler(e:MouseEvent):void {
+				if (isFullScreen()) {
+					if (e.stageY <= THRESHOLD_AREA_SHOW_TOOLBARS || e.stageY > this.height - THRESHOLD_AREA_SHOW_TOOLBARS) {
+						showToolbars();
+					} else if (e.stageY >= toolbar.height && e.stageY <= this.height - controlBar.height) {
+						hideToolbars();
+					}
+				} else {
+					showToolbars();
+				}
+			}
+
+			private function set showToolbar(visible:Boolean):void {
+				if (!showToolbarOpt) return;
+
+				if (visible) {
+					if (enlargeToolbar.isPlaying) return;
+					if (shrinkToolbar.isPlaying) shrinkToolbar.end();
+
+					enlargeToolbar.heightFrom = toolbar.height;
+					if (enlargeToolbar.heightFrom != enlargeToolbar.heightTo) {
+						_showToolbar = true;
+						enlargeToolbar.play([toolbar]);
+					}
+				} else {
+					if (shrinkToolbar.isPlaying) return;
+					if (enlargeToolbar.isPlaying) enlargeToolbar.end();
+
+					shrinkToolbar.heightFrom = toolbar.height;
+					if (shrinkToolbar.heightFrom != shrinkToolbar.heightTo) {
+						_showToolbar = true;
+						shrinkToolbar.play([toolbar]);
+					}
+				}
+			}
+
+
+			private function onToolbarEffectEnd():void {
+				_showToolbar = showToolbarOpt && (toolbar.height > 0);
 				calculateCanvasHeight();
 			}
+
+			private function set showFooter(visible:Boolean):void {
+				if (!showFooterOpt) return;
+
+				if (visible) {
+					if (enlargeControlBar.isPlaying) return;
+					if (shrinkControlBar.isPlaying) shrinkControlBar.end();
+
+					enlargeControlBar.heightFrom = controlBar.height;
+					if (enlargeControlBar.heightFrom != enlargeControlBar.heightTo) {
+						_showFooter = true;
+						enlargeControlBar.play([controlBar]);
+					}
+				} else {
+					if (shrinkControlBar.isPlaying) return;
+					if (enlargeControlBar.isPlaying) enlargeControlBar.end();
+
+					shrinkControlBar.heightFrom = controlBar.height;
+					if (shrinkControlBar.heightFrom != shrinkControlBar.heightTo) {
+						_showFooter = true;
+						shrinkControlBar.play([controlBar]);
+					}
+				}
+			}
+
+			private function onControlBarEffectEnd():void {
+				_showFooter = showFooterOpt && (controlBar.height > 0);
+				calculateCanvasHeight();
+			}
+
+			private function onHideToolbarsTimerComplete(event:TimerEvent):void {
+				showToolbar = showFooter = false;
+			}
+
+			private function hideToolbars():void {
+				_hideToolbarsTimer.reset();
+				_hideToolbarsTimer.start();
+			}
+
+			private function showToolbars():void {
+				_hideToolbarsTimer.reset();
+				showToolbar = showFooter = true;
+			}
+
+			private function updateCopyrightLabelDimensions(e:Event = null):void {
+				var screenRect:Rectangle = systemManager.screen;
+
+				if (spacer.width == 0) {
+					copyrightLabel2.width += (screenRect.width - controlBar.width);
+				} else {
+					copyrightLabel2.width += Math.min(spacer.width, copyrightLabel2.measuredWidth - copyrightLabel2.width);
+				}
+			}
 		
-			protected function initFullScreen():void {				
-				/* Set up full screen handler. */
+			protected function initFullScreen(e:Event = null):void {
 				stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenHandler);
-				dispState = stage.displayState;
-			}					
+				stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
+			}
 			
 			private var sendStartModulesEvent:Boolean = true;
 			
@@ -220,7 +385,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			//             https://github.com/bigbluebutton/bigbluebutton/issues/2437
 			private function calculateCanvasHeight():void {
 				var screenRect:Rectangle = systemManager.screen;
-				mdiCanvas.height = screenRect.height - footerHeight - toolbarHeight - 12;
+				mdiCanvas.height = screenRect.height - (_showFooter? footerHeight: 0) - (_showToolbar? toolbarHeight: 0);
+				updateCanvasBackgroundDimensions();
 			}
 			
 			private function handleApplicationVersionEvent(event:AppVersionEvent):void {
@@ -262,15 +428,72 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				dispatcher.dispatchEvent(new ModuleLoadEvent(ModuleLoadEvent.START_ALL_MODULES));	
 			}
 			
+			public function guestAllowed(evt:BBBEvent):void {
+				progressBar.visible = true;
+				if (waitWindow != null) {
+					PopUpManager.removePopUp(waitWindow);
+					waitWindow = null;
+				}
+			}
+
 			private function fullScreenHandler(evt:FullScreenEvent):void {
 				dispState = stage.displayState + " (fullScreen=" + evt.fullScreen.toString() + ")";
 				if (evt.fullScreen) {
-					/* Do something specific here if we switched to full screen mode. */
-				
+					LOGGER.debug("Switching to full screen");
+					fullscreen_icon = images.exit_full_screen;
+					hideToolbars();
 				} else {
-					/* Do something specific here if we switched to normal mode. */
+					LOGGER.debug("Switching to normal screen");
+					fullscreen_icon = images.full_screen;
+					showToolbars();
 				}
 			}			
+
+			private function closeGuestWindow(e:Event = null):void {
+				if(guestWindow != null) {
+					guestWindow.closeWindow();
+					guestWindow = null;
+				}
+			}
+
+			private function refreshGuestView(evt:RefreshGuestEvent):void {
+				// do not show the guest window if the user isn't moderator or if he's waiting for acceptance
+				if (!UsersUtil.amIModerator() || UsersUtil.amIWaitingForAcceptance()) {
+					closeGuestWindow();
+					return;
+				}
+
+				if (guestWindow == null) {
+					guestWindow = PopUpManager.createPopUp( mdiCanvas, GuestWindow, false) as GuestWindow;
+					guestWindow.addEventListener(Event.CLOSE, closeGuestWindow);
+
+					guestWindow.x = systemManager.screen.width - guestWindow.width - 20;
+					guestWindow.y = 20;
+				}
+				guestWindow.refreshGuestView(evt.listOfGuests);
+			}
+
+			public function removeGuestWindow(evt:BBBEvent):void {
+				if (guestWindow != null) {
+					guestWindow.remove(evt.payload.userId);
+				}
+			}
+
+			private function closeWaitWindow(e:BBBEvent):void {
+				if(waitWindow != null && e.payload.type == "BIGBLUEBUTTON_CONNECTION") {
+					LOGGER.debug("closeWaitWindow");
+					waitWindow.removeWindow();
+				}
+			}
+
+			private function openWaitWindow(evt:BBBEvent):void {
+				progressBar.visible = false;
+				waitWindow = PopUpManager.createPopUp( mdiCanvas, WaitingWindow, false) as WaitingWindow;
+
+				// Calculate position of TitleWindow in Application's coordinates.
+				waitWindow.x = (systemManager.screen.width - waitWindow.width) / 2;
+				waitWindow.y = (systemManager.screen.height - waitWindow.height) / 2;
+			}
 			
 			private function openLogWindow():void {
 				mdiCanvas.windowManager.add(getLogWindow());
@@ -282,6 +505,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			public function openShortcutHelpWindow(e:Event = null):void{
 				if (scWindow == null) {
 					scWindow = new ShortcutHelpWindow();
+					scWindow.width = 300;
+					scWindow.height = 300;
 				}
 				
 				if (scWindow.minimized)
@@ -291,21 +516,25 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					scWindow.restore();
 				
 				mdiCanvas.windowManager.add(scWindow);
-				mdiCanvas.windowManager.absPos(scWindow, mdiCanvas.width/2 - scWindow.width/2, mdiCanvas.height/2 - scWindow.height/2);
+				mdiCanvas.windowManager.absPos(scWindow, mdiCanvas.width/2 - 150, mdiCanvas.height/2 - 150);
 				
 				scWindow.focusHead();
 			}
 			
 			private function toggleFullScreen():void{
+				LOGGER.debug("Toggling fullscreen, current mode: " + stage.displayState);
 	   			try {
 					switch (stage.displayState) {
 						case StageDisplayState.FULL_SCREEN:
+						case StageDisplayState.FULL_SCREEN_INTERACTIVE:
+							LOGGER.debug("Full screen mode, switching to normal screen mode");
 							// If already in full screen mode, switch to normal mode.
 							stage.displayState = StageDisplayState.NORMAL;
 							break;
 						default:
+							LOGGER.debug("Normal screen mode, switching to full screen mode");
 							// If not in full screen mode, switch to full screen mode.
-							stage.displayState = StageDisplayState.FULL_SCREEN;
+							stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
 							break;
 					}
 				} catch (err:SecurityError) {
@@ -424,6 +653,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					});
 				});
 			}
+
+			private function handleInactivityWarningEvent(e:BBBEvent):void {
+				var inactivityWarning:InactivityWarningWindow = PopUpManager.createPopUp(mdiCanvas, InactivityWarningWindow, true) as InactivityWarningWindow;
+				inactivityWarning.duration = e.payload.duration;
+				PopUpManager.centerPopUp(inactivityWarning);
+			}
 			
       private function openVideoPreviewWindow(event:BBBEvent):void {
         var camSettings:CameraDisplaySettings = CameraDisplaySettings(PopUpManager.createPopUp(mdiCanvas, CameraDisplaySettings, true));		
@@ -457,13 +692,22 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	  }
           
       private function handleWebRTCMediaRequestEvent(event:WebRTCMediaEvent):void {
+        var options:PhoneOptions = new PhoneOptions();
+        if (!options.showMicrophoneHint) {
+          return;
+        }
+
         var browser:String = ExternalInterface.call("determineBrowser")[0];
         if (browser == "Firefox") {
-          var ffBrowser:FirefoxMicPermissionImage = PopUpManager.createPopUp(mdiCanvas, FirefoxMicPermissionImage, true) as FirefoxMicPermissionImage;
+          var ffBrowser:FirefoxMicPermissionImage = new FirefoxMicPermissionImage();
+          // we want to increase the contrast between the modal and the rest of the UI
+          ffBrowser.setStyle("modalTransparency", 0.75);
+          ffBrowser.setStyle("modalTransparencyColor", 0x000000);
           ffBrowser.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
-            ffBrowser.x = 100;
-            ffBrowser.y = 150;
-          }); 
+            ffBrowser.x = 54;
+            ffBrowser.y = 0;
+          });
+          PopUpManager.addPopUp(ffBrowser, mdiCanvas, true);
         } else if (browser == "Chrome") {
           var chromeBrowser:ChromeMicPermissionImage = PopUpManager.createPopUp(mdiCanvas, ChromeMicPermissionImage, true) as ChromeMicPermissionImage;
           chromeBrowser.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:Event):void {
@@ -602,24 +846,58 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					addedBtns.removeChild(event.button as UIComponent);
 			}
 
-			private var networkStatsWindow:NetworkStatsWindow = new NetworkStatsWindow();
+			private var networkStatsWindow:NetworkStatsWindow = null;
 
 			private function openNetworkStatsWindow(e:Event = null):void {
-				/*var btnPosition:Point = new Point(btnNetwork.x, btnNetwork.y);
-				var btnPositionOnGlobal:Point = btnNetwork.localToGlobal(btnPosition);
-				var windowPosition:Point = networkStatsWindow.globalToLocal(btnPositionOnGlobal);
+				if (networkStatsWindow == null) {
+					networkStatsWindow = new NetworkStatsWindow();
+				}
 				
-				windowPosition.x += btnNetwork.width + 10;
-				windowPosition.y -= networkStatsWindow.height - 10;
+				mdiCanvas.windowManager.add(networkStatsWindow);
+				mdiCanvas.windowManager.absPos(networkStatsWindow, mdiCanvas.width - networkStatsWindow.width, 0);
+				mdiCanvas.windowManager.bringToFront(networkStatsWindow);
+			}
 
-				networkStatsWindow.x = windowPosition.x;
-				networkStatsWindow.y = windowPosition.y;*/
+			private function updateToolbarHeight():void {
+				if (toolbarHeight != 0) {
+					toolbarHeight = Math.max(DEFAULT_TOOLBAR_HEIGHT, toolbar.logo.height + 10);
+				}
+				calculateCanvasHeight();
+			}
 
-				networkStatsWindow.appear();
+			private function updateCanvasBackgroundDimensions():void {
+				if (canvasBackground == null) {
+					return;
 			}
 			
-			private function closeNetworkStatsWindow(e:Event = null):void {
-				networkStatsWindow.disappear();
+				var canvasAspectRatio:Number = mdiCanvas.width / mdiCanvas.height;
+
+				// this is the case when the image is a banner that should be positioned in the top, and
+				// be shown entirely
+				if (canvasBackgroundAspectRatio > 2 || canvasAspectRatio >= canvasBackgroundAspectRatio) {
+					canvasBackground.width = mdiCanvas.width;
+					canvasBackground.height = Math.ceil(mdiCanvas.width / canvasBackgroundAspectRatio);
+				} else {
+					canvasBackground.height = mdiCanvas.height;
+					canvasBackground.width = Math.ceil(mdiCanvas.height * canvasBackgroundAspectRatio);
+				}
+			}
+
+			private var canvasBackground:DisplayObject = null;
+			private var canvasBackgroundAspectRatio:Number = NaN;
+
+			private function loadBackground():void {
+				var backgroundCandidate:String = BBB.getConfigManager().config.branding.background;
+				if (backgroundCandidate != "") {
+					var imageLoader:ImageLoader = new ImageLoader();
+					imageLoader.load(backgroundCandidate, function(obj:DisplayObject, width:Number, height:Number):void {
+						canvasBackground = obj;
+						canvasBackgroundAspectRatio = width / height;
+						backgroundPlaceHolder.rawChildren.addChild(canvasBackground);
+						backgroundPlaceHolder.invalidateDisplayList();
+						updateCanvasBackgroundDimensions();
+					});
+				}
 			}
 			
 			private function openLockSettingsWindow(event:LockControlEvent):void {
@@ -656,6 +934,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
 		]]>
 	</mx:Script>
+
+	<mx:Resize id="shrinkControlBar" duration="{HIDE_TOOLBARS_EFFECT_DURATION}" heightFrom="{footerHeight}" heightTo="0" effectEnd="onControlBarEffectEnd()" />
+	<mx:Resize id="enlargeControlBar" duration="{HIDE_TOOLBARS_EFFECT_DURATION}" heightFrom="0" heightTo="{footerHeight}" effectEnd="onControlBarEffectEnd()" />
+	<mx:Resize id="shrinkToolbar" target="{toolbar}" duration="{HIDE_TOOLBARS_EFFECT_DURATION}" heightFrom="{toolbarHeight}" heightTo="0" effectEnd="onToolbarEffectEnd()" />
+	<mx:Resize id="enlargeToolbar" duration="{HIDE_TOOLBARS_EFFECT_DURATION}" heightFrom="0" heightTo="{toolbarHeight}" effectEnd="onToolbarEffectEnd()" />
 	
 	<common:TabIndexer id="tabIndexer" startIndex="100000"
 					   tabIndices="{[langSelector, logBtn]}"/>
@@ -664,28 +947,31 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					   dock="true" 
 					   width="100%" 
 					   height="{toolbarHeight}" 
-					   visible="{showToolbarOpt}" 
+					   visible="{_showToolbar}"
+					   includeInLayout="{showToolbarOpt}"
 					   verticalAlign="middle" 
 					   toolbarOptions="{layoutOptions}" 
-					   paddingTop="{toolbarPaddingTop}"/>
+					   paddingTop="{toolbarPaddingTop}"
+					   updateComplete="updateToolbarHeight()"
+					   paddingBottom="0" />
 					   
 	<views:MainCanvas id="mdiCanvas" 
 					  horizontalScrollPolicy="off" 
 					  verticalScrollPolicy="off" 
 					  effectsLib="{flexlib.mdi.effects.effectsLib.MDIVistaEffects}" 
 					  width="100%" >
+		<mx:Canvas id="backgroundPlaceHolder" width="100%" height="100%" />
 		<views:LoadingBar id="progressBar" horizontalCenter="0" verticalCenter="0" width="50%" />
 		<views:BrandingLogo x="{this.width - 300}" y="{this.height - 300}" />
 	</views:MainCanvas>	
 	
-	<mx:ControlBar width="100%" height="{footerHeight}" paddingTop="0" id="controlBar">
+	<mx:ControlBar width="100%" height="{footerHeight}" id="controlBar" paddingTop="2" paddingBottom="2" verticalAlign="middle" visible="{_showFooter}" includeInLayout="{showFooterOpt}" >
 		<mx:Label
-				htmlText="{ResourceUtil.getInstance().getString('bbb.mainshell.copyrightLabel2',[appVersion])}"
+				htmlText="{copyrightText}"
 				link="onFooterLinkClicked(event)"
 				id="copyrightLabel2" truncateToFit="true"
-				width="100%" minWidth="1"
 				selectable="true" paddingRight="10"/>
-		
+		<mx:Spacer width="100%" id="spacer" />
 		<mx:Label 
 				id="lblWebRTC"
 				text="{'[ '+ResourceUtil.getInstance().getString('bbb.mainshell.notification.webrtc')+' ]'}"
@@ -715,5 +1001,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				icon="{logs_icon}"
 				click="openLogWindow()"/>
 		<mx:HBox id="addedBtns" />
+		<mx:Button width="20" height="20" toolTip="{ResourceUtil.getInstance().getString('bbb.mainshell.fullscreenBtn.toolTip')}" id="fullScreen" icon="{fullscreen_icon}" click="toggleFullScreen()" />
 	</mx:ControlBar>
 </mx:VBox>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
index f73c205eb38f9be439a7efa1612abfbb035c3bc6..b284a10e462369cda25282b5da710675569b5092 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MainToolbar.mxml
@@ -31,35 +31,54 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<mate:Listener type="{BBBEvent.END_MEETING_EVENT}" method="handleEndMeetingEvent"/>
 	<mate:Listener type="{ConnectionFailedEvent.USER_LOGGED_OUT}" method="hideToolbar" />
 	<mate:Listener type="{ConnectionFailedEvent.CONNECTION_CLOSED}" method="hideToolbar" />
-	<mate:Listener type="{ConfigEvent.CONFIG_EVENT}" method="gotConfigParameters" />
+	<mate:Listener type="{ConfigLoadedEvent.CONFIG_LOADED_EVENT}" method="handleConfigLoadedEvent" />
 	<mate:Listener type="{SettingsEvent.SETTINGS_MODULE_LOADED}" method="showSettingsButton" />
 	<mate:Listener type="{ShortcutEvent.REMOTE_OPEN_SHORTCUT_WIN}" method="remoteShortcutClick" />
 	<mate:Listener type="{ShortcutEvent.LOGOUT}" method="remoteLogout" />
 	<mate:Listener type="{ShortcutEvent.FOCUS_SHORTCUT_BUTTON}" method="focusShortcutButton" />
 	<mate:Listener type="{ShortcutEvent.FOCUS_LOGOUT_BUTTON}" method="focusLogoutButton" />
 	<mate:Listener type="{ConferenceCreatedEvent.CONFERENCE_CREATED_EVENT}" method="retrieveMeetingName" />
+	<mate:Listener type="{ConnectionFailedEvent.MODERATOR_DENIED_ME}" method="hideToolbar" />
+	<mate:Listener type="{SettingsComponentEvent.ADD}" method="addSettingsComponent" />
+	<mate:Listener type="{SettingsComponentEvent.REMOVE}" method="removeSettingsComponent"/>
   <mate:Listener type="{BBBEvent.CHANGE_RECORDING_STATUS}" method="onRecordingStatusChanged" />
+	<mate:Listener type="{SuccessfulLoginEvent.USER_LOGGED_IN}" method="refreshModeratorButtonsVisibility" />
+	<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
+	<mate:Listener type="{BBBEvent.CONFIRM_LOGOUT_END_MEETING_EVENT}" method="confirmEndSession" />
   
 	<mx:Script>
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
 			
+			import mx.binding.utils.BindingUtils;
 			import mx.controls.Alert;
+			import mx.core.IToolTip;
 			import mx.core.UIComponent;
 			import mx.events.CloseEvent;
 			
+			import mx.events.ToolTipEvent;
+			import mx.managers.PopUpManager;
+			import mx.core.FlexGlobals;
+
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
 			import org.bigbluebutton.common.IBbbToolbarComponent;
+			import org.bigbluebutton.common.events.SettingsComponentEvent;
 			import org.bigbluebutton.common.events.ToolbarButtonEvent;
 			import org.bigbluebutton.core.BBB;
 			import org.bigbluebutton.core.UsersUtil;
+			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.core.model.Config;
 			import org.bigbluebutton.main.events.BBBEvent;
-			import org.bigbluebutton.main.events.ConfigEvent;
+			import org.bigbluebutton.main.events.ConfigLoadedEvent;
 			import org.bigbluebutton.main.events.LogoutEvent;
+			import org.bigbluebutton.main.events.NetworkStatsEvent;
 			import org.bigbluebutton.main.events.SettingsEvent;
 			import org.bigbluebutton.main.events.ShortcutEvent;
+			import org.bigbluebutton.main.events.SuccessfulLoginEvent;
 			import org.bigbluebutton.main.model.LayoutOptions;
+			import org.bigbluebutton.main.model.NetworkStatsData;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
 			import org.bigbluebutton.main.model.users.events.ConferenceCreatedEvent;
 			import org.bigbluebutton.main.model.users.events.ConnectionFailedEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
@@ -73,9 +92,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			[Bindable] private var showHelpBtn:Boolean = false;
 			[Bindable] private var showToolbar:Boolean = false;
+			[Bindable] private var showGuestSettingsButton:Boolean = false;
+			[Bindable] private var showRecordButton:Boolean = false;
 			[Bindable] public var toolbarOptions:LayoutOptions = new LayoutOptions();		
 			[Bindable] private var numButtons:int;
       
+			[Bindable] private var _bandwidthConsumedUp:String = "-";
+			[Bindable] private var _bandwidthConsumedDown:String = "-";
+			private var _updateBandwidthTimer:Timer = new Timer(1000);
+			private var _bandwidthToolTip:IToolTip;
+
 			/*
 			 * Because of the de-centralized way buttons are added to the toolbar, there is a large gap between the tab indexes of the main buttons
 			 * on the left and the tab indexes of the "other" items on the right (shortcut glossary, language slector, etc). This will make it more
@@ -85,6 +111,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			 */
 			
 			private var xml:XML;
+			private var settingsComponents:Array = new Array();
+			private var settingsPopup:BBBSettings = null;
 			
 			private function init():void{
 				numButtons = 0;
@@ -94,6 +122,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                 timer.addEventListener(TimerEvent.TIMER, checkAccessiblity);
                 timer.start();
 
+				BindingUtils.bindSetter(refreshModeratorButtonsVisibility, UserManager.getInstance().getConference(), "record");
 			}
       
       private function onCreationComplete():void {
@@ -138,6 +167,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				} else {
 					showHelpBtn = false;
 				}
+				if(toolbarOptions.showNetworkMonitor) {
+					initBandwidthToolTip();
+				}
 			}
 			
       private function retrieveMeetingName(e:ConferenceCreatedEvent):void {
@@ -151,6 +183,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
           logFlashPlayerCapabilities();
       }
 
+      private function refreshModeratorButtonsVisibility(e:*):void {
+          var userLoaded:Boolean = UserManager.getInstance().getConference().getMyUser() != null
+                  && ! UserManager.getInstance().getConference().getMyUser().waitingForAcceptance;
+
+          showGuestSettingsButton = userLoaded && UsersUtil.amIModerator();
+
+          showRecordButton = userLoaded;
+      }
+
       private function getFlashPlayerCapabilities():Object {
           var caps:Object = new Object();
           caps.avHardwareDisable = Capabilities.avHardwareDisable;
@@ -218,18 +259,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			
 			private function confirmLogout():void {
-				if (toolbarOptions.confirmLogout){
-					// Confirm logout using built-in alert
-					var alert:Alert = Alert.show(ResourceUtil.getInstance().getString('bbb.logout.confirm.message'), ResourceUtil.getInstance().getString('bbb.logout.confirm.title'), Alert.YES | Alert.NO, this, alertLogout, null, Alert.YES);
-					
-          var newX:Number = btnLogout.x + btnLogout.width - alert.width;
+				if (toolbarOptions.confirmLogout) {
+					var logoutWindow:LogoutWindow;
+					logoutWindow = LogoutWindow(PopUpManager.createPopUp(FlexGlobals.topLevelApplication as DisplayObject, LogoutWindow, true));
+
+					var newX:Number = btnLogout.x + btnLogout.width - logoutWindow.width;
 					var newY:Number = btnLogout.y + btnLogout.height + 5;
-												
-					alert.validateNow();
-					alert.move(newX, newY);
-					//Accessibility.updateProperties();
-				}
-				else{
+
+					PopUpManager.centerPopUp(logoutWindow);
+
+					logoutWindow.x = newX;
+					logoutWindow.y = newY;
+				} else {
 					doLogout();
 				}
 			}
@@ -252,6 +293,23 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private function doLogout():void {
 				dispatchEvent(new LogoutEvent(LogoutEvent.USER_LOGGED_OUT));
 			}
+
+			private function confirmEndSession(event:BBBEvent):void {
+				var alert:Alert = Alert.show(ResourceUtil.getInstance().getString('bbb.endSession.confirm.message'), ResourceUtil.getInstance().getString('bbb.endSession.confirm.title'), Alert.YES | Alert.NO, null, onConfirmEndSessionAlertClosed, null, Alert.YES);
+				// we need to set transparency duration to avoid the blur effect when two alerts are displayed sequentially
+				alert.setStyle("modalTransparencyDuration", 250);
+			}
+
+			private function onConfirmEndSessionAlertClosed(e:CloseEvent):void {
+				// Check to see if the YES button was pressed.
+				if (e.detail == Alert.YES) {
+					endSession();
+				}
+			}
+
+			private function endSession():void {
+				dispatchEvent(new BBBEvent(BBBEvent.LOGOUT_END_MEETING_EVENT));
+			}
 			
 			private function hideToolbar(e:ConnectionFailedEvent):void{
 				if (toolbarOptions.showToolbar) {
@@ -313,9 +371,23 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				}
 			}
 						
-			private function gotConfigParameters(e:ConfigEvent):void{
-				shortcutKeysBtn.includeInLayout = shortcutKeysBtn.visible = e.config.shortcutKeysShowButton; 
-				DEFAULT_HELP_URL = e.config.helpURL;
+			private function handleConfigLoadedEvent(e:ConfigLoadedEvent):void{
+				var config:Config = BBB.getConfigManager().config;
+				shortcutKeysBtn.includeInLayout = shortcutKeysBtn.visible = config.shortcutKeys.showButton;
+
+				if (config.branding.logo == "") {
+					hideLogo();
+				} else {
+					logo.source = config.branding.logo;
+				}
+
+				if (config.branding.toolbarColor != "") {
+					setStyle("backgroundColor", config.branding.toolbarColor);
+				}
+
+				if (config.branding.toolbarColorAlphas != "") {
+					setStyle("highlightAlphas", config.branding.toolbarColorAlphas.split(","));
+				}
 			}
 			
 			private function onDisconnectTest():void{
@@ -373,6 +445,61 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         }
       }
 
+			private function onNetStatsButtonClick(e:Event = null):void {
+				var d:Dispatcher = new Dispatcher();
+				d.dispatchEvent(new NetworkStatsEvent(NetworkStatsEvent.OPEN_NETSTATS_WIN));
+			}
+
+			private function initBandwidthToolTip():void {
+				_updateBandwidthTimer.addEventListener(TimerEvent.TIMER, updateBandwidthTimerHandler);
+				_updateBandwidthTimer.start();
+				btnNetwork.addEventListener(ToolTipEvent.TOOL_TIP_SHOW, bwToolTipShowHandler);
+				btnNetwork.addEventListener(ToolTipEvent.TOOL_TIP_END, bwToolTipEndHandler);
+			}
+
+			private function bwToolTipShowHandler(e:ToolTipEvent):void {
+				// The ToolTip must be stored so it's text can be updated
+				_bandwidthToolTip = e.toolTip;
+				updateBwToolTip();
+			}
+
+			private function bwToolTipEndHandler(e:ToolTipEvent):void {
+				_bandwidthToolTip = null;
+			}
+
+			private function updateBandwidthTimerHandler(e:TimerEvent):void {
+				_bandwidthConsumedDown = NetworkStatsData.getInstance().formattedCurrentConsumedDownBW;
+				_bandwidthConsumedUp = NetworkStatsData.getInstance().formattedCurrentConsumedUpBW;
+				updateBwToolTip();
+			}
+
+			private function updateBwToolTip():void {
+				if(_bandwidthToolTip) {
+					_bandwidthToolTip.text = ResourceUtil.getInstance().getString('bbb.bwmonitor.upload.short') + ": " + _bandwidthConsumedUp +
+						" | " + ResourceUtil.getInstance().getString('bbb.bwmonitor.download.short')+": "+_bandwidthConsumedDown;
+				}
+			}
+
+			private function hideLogo():void {
+				logoHolder.visible = logoHolder.includeInLayout = false;
+			}
+
+			private function addSettingsComponent(e:SettingsComponentEvent = null):void {
+				settingsComponents.push(e.component);
+			}
+
+			private function removeSettingsComponent(e:SettingsComponentEvent = null):void {
+				throw("Not implemented");
+			}
+
+			private function onSettingsButtonClick():void {
+				settingsPopup = BBBSettings(PopUpManager.createPopUp(this.parent, BBBSettings, true));
+				settingsPopup.pushComponents(settingsComponents);
+			}
+
+			private function refreshRole(e:ChangeMyRole):void {
+				refreshModeratorButtonsVisibility(null);
+			}
 		]]>
 	</mx:Script>
 	
@@ -381,6 +508,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					   tabIndices="{[recordBtn, muteMeBtn, shortcutKeysBtn, helpBtn, btnLogout]}"/>
 
     
+    <mx:HBox id="logoHolder" paddingRight="12" >
+        <mx:Image id="logo" ioError="hideLogo()" />
+    </mx:HBox>
     <mx:HBox id="quickLinks" width="1" includeInLayout="false">
         <mx:LinkButton id="usersLinkBtn" click="onQuickLinkClicked('users')" label="{ResourceUtil.getInstance().getString('bbb.users.quickLink.label')}"
                        accessibilityDescription="{usersLinkBtn.label}" toolTip="{usersLinkBtn.label}"
@@ -396,14 +526,29 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                        height="22" styleName="quickWindowLinkStyle" />
     </mx:HBox>
 	<mx:HBox id="addedBtns"/>
-	<views:RecordButton id="recordBtn"/>
+	<views:RecordButton id="recordBtn" visible="{showRecordButton}" includeInLayout="{showRecordButton}"/>
 	<mx:VRule strokeWidth="2" height="100%" visible="{muteMeBtn.visible}" includeInLayout="{muteMeBtn.includeInLayout}"/>
 	<views:MuteMeButton id="muteMeBtn"  height="20"/>
 	<mx:Label id="meetingNameLbl" width="100%" minWidth="1" styleName="meetingNameLabelStyle" />
 
+	<mx:Button
+			id="bbbSettings"
+			visible="{showGuestSettingsButton}"
+			includeInLayout="{showGuestSettingsButton}"
+			toolTip="{ResourceUtil.getInstance().getString('bbb.settings.btn.toolTip')}"
+			click="onSettingsButtonClick()"
+			styleName="settingsButtonStyle"
+			height="22"
+	/>
 <!--
   <mx:Button label="DISCONNECT!" click="BBB.initConnectionManager().forceClose()" height="22" toolTip="Click to simulate disconnection" />
 -->
+	<mx:Button
+			id="btnNetwork"
+			styleName="bandwidthButtonStyle"
+			toolTip="dummy text"
+			click="onNetStatsButtonClick()"
+			visible="{toolbarOptions.showNetworkMonitor}" />
 	<mx:Button id="shortcutKeysBtn" label="{ResourceUtil.getInstance().getString('bbb.mainToolbar.shortcutBtn')}" styleName="shortcutButtonStyle"
              click="onShortcutButtonClick()" height="22" 
              toolTip="{ResourceUtil.getInstance().getString('bbb.mainToolbar.shortcutBtn.toolTip')}"/>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/MuteMeButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/MuteMeButton.mxml
index dd614f4535be062883d019a8e973bbdba147160d..10fa677bc8f99e872712c2687d5998c2e7b8a241 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/MuteMeButton.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/MuteMeButton.mxml
@@ -38,6 +38,7 @@ $Id: $
 	<mate:Listener type="{ShortcutEvent.MUTE_ME_EVENT}" method="toggleMuteMeState" />
 	<mate:Listener type="{EventConstants.USER_TALKING}" method="handleUserTalking" />
 	<mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
+	<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
   <mate:Listener type="{BBBEvent.USER_VOICE_JOINED}" method="handleJoinedVoiceConferenceEvent" />
   <mate:Listener type="{BBBEvent.USER_VOICE_LEFT}" method="handleLeftVoiceConferenceEvent" />
   <mate:Listener type="{BBBEvent.USER_VOICE_MUTED}" method="handleVoiceMutedEvent" />
@@ -60,6 +61,7 @@ $Id: $
 			import org.bigbluebutton.main.events.ShortcutEvent;
 			import org.bigbluebutton.main.model.users.BBBUser;
 			import org.bigbluebutton.main.model.users.Conference;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
       
 			private static const LOGGER:ILogger = getClassLogger(MuteMeButton);      
@@ -86,6 +88,10 @@ $Id: $
 			private function localeChanged(e:Event):void {
 				updateMuteMeBtn();
 			}
+
+			private function refreshRole(e:ChangeMyRole):void {
+				updateMuteMeBtn();
+			}
 			
 			private function lockSettingsChanged(e:Event):void {
         if (UsersUtil.amIModerator()  || UsersUtil.amIPresenter()){
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml
index d77f47554eaf003ecaf1ca25d65763cd147ace44..03f869bc2b88955d05e9a0fa163a9e4367f9c20a 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/NetworkStatsWindow.mxml
@@ -20,15 +20,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 -->
 
-<CustomMdiWindow xmlns="org.bigbluebutton.common.*" 
-		xmlns:mx="http://www.adobe.com/2006/mxml" 
+<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
+		xmlns:mx="http://www.adobe.com/2006/mxml"
 		xmlns:mate="http://mate.asfusion.com/"
-		title="Network monitor" 
+		title="{ResourceUtil.getInstance().getString('bbb.bwmonitor.title')}"
 		creationComplete="onCreationComplete()"
 		resizable="false"
-		showCloseButton="false"
+		showCloseButton="true"
 		implements="org.bigbluebutton.common.IBbbModuleWindow"
-		width="210" height="261" minHeight="0" minWidth="0"
+		width="210" minWidth="0"
 		resize="onResize()">
 
 	<mx:Script>
@@ -37,105 +37,78 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			import flash.utils.Timer;
 			
+			import mx.core.IFlexDisplayObject;
 			import mx.effects.Fade;
 			import mx.events.EffectEvent;
-			import mx.formatters.NumberFormatter;
+			import mx.managers.PopUpManager;
 			
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
-			import org.bigbluebutton.common.IBbbModuleWindow;
+			import org.bigbluebutton.common.Images;
 			import org.bigbluebutton.common.events.CloseWindowEvent;
 			import org.bigbluebutton.common.events.OpenWindowEvent;
+			import org.bigbluebutton.core.services.BandwidthMonitor;
 			import org.bigbluebutton.main.model.NetworkStatsData;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
 
-			private static const LOGGER:ILogger = getClassLogger(NetworkStatsWindow);      
+			private static const LOGGER:ILogger = getClassLogger(NetworkStatsWindow);
 
 			private var _globalDispatcher:Dispatcher = new Dispatcher();
 			private var _updateTimer:Timer = new Timer(1000);
-			private var _numberFormatter:NumberFormatter = new NumberFormatter();
-		
+
+			private var _images:Images = new Images();
+			[Bindable] private var _refreshIcon:Class = _images.refreshSmall;
+
 			private function onCreationComplete():void {
 				this.windowControls.maximizeRestoreBtn.visible = false;
 				this.windowControls.minimizeBtn.visible = false;
 				
-				this.x = parent.width - this.width;
-				this.y = parent.height - this.height;
-				
-				_numberFormatter.precision = 2;
-				_numberFormatter.useThousandsSeparator = true;
-
 				_updateTimer.addEventListener(TimerEvent.TIMER, timerHandler);
 				_updateTimer.start();
+
+				height = panel.measuredHeight + borderMetrics.top + borderMetrics.bottom;
+				runBandwidthMeasurement();
 			}
 			
-	        private function timerHandler(e:TimerEvent):void {
-				labelCurrentDownload.text = _numberFormatter.format(NetworkStatsData.getInstance().currentConsumedDownBW);
-			 	labelTotalDownload.text   = _numberFormatter.format(NetworkStatsData.getInstance().totalConsumedDownBW);
-			 	labelAvailableDownload.text   = _numberFormatter.format(NetworkStatsData.getInstance().measuredDownBW);
-			 	labelDownloadLatency.text   = String(NetworkStatsData.getInstance().measuredDownLatency);
-
-			 	labelCurrentUpload.text   = _numberFormatter.format(NetworkStatsData.getInstance().currentConsumedUpBW);
-			 	labelTotalUpload.text     = _numberFormatter.format(NetworkStatsData.getInstance().totalConsumedUpBW);
-			 	labelAvailableUpload.text   = _numberFormatter.format(NetworkStatsData.getInstance().measuredUpBW);
-			 	labelUploadLatency.text   = String(NetworkStatsData.getInstance().measuredUpLatency);
-	        }
-        			
+			private function timerHandler(e:TimerEvent):void {
+				labelCurrentDownload.text = NetworkStatsData.getInstance().formattedCurrentConsumedDownBW;
+				labelTotalDownload.text = NetworkStatsData.getInstance().formattedTotalConsumedDownBW;
+				labelAvailableDownload.text = NetworkStatsData.getInstance().formattedMeasuredDownBW;
+				labelDownloadLatency.text = NetworkStatsData.getInstance().formattedMeasuredDownLatency;
+
+				labelCurrentUpload.text = NetworkStatsData.getInstance().formattedCurrentConsumedUpBW;
+				labelTotalUpload.text = NetworkStatsData.getInstance().formattedTotalConsumedUpBW;
+				labelAvailableUpload.text = NetworkStatsData.getInstance().formattedMeasuredUpBW;
+				labelUploadLatency.text = NetworkStatsData.getInstance().formattedMeasuredUpLatency;
+			}
+
 			public function getPrefferedPosition():String {
 				return MainCanvas.ABSOLUTE;
 			}
-			
-			private function onResize():void {
-				LOGGER.debug("width={0} height={1}", [width, height]);
-			}
-			
-			public function appear():void {
-				var fader:Fade = new Fade();
-				fader.alphaFrom = 0;
-				fader.alphaTo = 1;
-				fader.duration = 500;
-				fader.target = this;
-//				fader.addEventListener(EffectEvent.EFFECT_START, function(e:EffectEvent):void {
-//					var windowEvent:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
-//					windowEvent.window = e.currentTarget as IBbbModuleWindow;
-//					_globalDispatcher.dispatchEvent(windowEvent);
-//				});
-				fader.play();
-				var windowEvent:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
-				windowEvent.window = this;
-				_globalDispatcher.dispatchEvent(windowEvent);
-				this.windowManager.bringToFront(this);
-			}
-			
-			public function disappear():void {
-				var fader:Fade = new Fade();
-				fader.alphaFrom = 1;
-				fader.alphaTo = 0;
-				fader.duration = 500;
-				fader.target = this;
-				fader.addEventListener(EffectEvent.EFFECT_END, function(e:EffectEvent):void {
-					var windowEvent:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
-					windowEvent.window = e.target as IBbbModuleWindow;
-					_globalDispatcher.dispatchEvent(windowEvent);
-				});
-				fader.play();
+
+			private function onResize():void {}
+
+			private function runBandwidthMeasurement():void {
+				BandwidthMonitor.getInstance().checkClientToServer();
+				BandwidthMonitor.getInstance().checkServerToClient();
 			}
+
 		]]>
 	</mx:Script>
-	
-	
-	<mx:Panel width="100%" height="100%"
-	 paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10" headerHeight="10">
+
+	<mx:Panel id="panel" width="100%" paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10" headerHeight="10">
 		<mx:VBox verticalGap="0" width="100%" height="100%">
-			<mx:HBox backgroundColor="haloOrange" width="100%" horizontalAlign="center"><mx:Label fontWeight="bold" text="Upload"/></mx:HBox>
-			<mx:HBox horizontalGap="0"><mx:Label text="Total: "/><mx:Label id="labelTotalUpload" fontWeight="bold" text="-"/><mx:Label text="MB"/></mx:HBox>
-			<mx:HBox horizontalGap="0"><mx:Label text="Current: "/><mx:Label id="labelCurrentUpload" fontWeight="bold" text="-"/><mx:Label text="Kb/s"/></mx:HBox>
-			<mx:HBox horizontalGap="0"><mx:Label text="Available: "/><mx:Label id="labelAvailableUpload" fontWeight="bold" text="-"/><mx:Label text="Mb/s"/></mx:HBox>
-			<mx:HBox horizontalGap="0"><mx:Label text="Latency: "/><mx:Label id="labelUploadLatency" fontWeight="bold" text="-"/><mx:Label text="ms"/></mx:HBox>
-			<mx:HBox backgroundColor="haloOrange" width="100%" horizontalAlign="center"><mx:Label fontWeight="bold" text="Download"/></mx:HBox>
-			<mx:HBox horizontalGap="0"><mx:Label text="Total: "/><mx:Label id="labelTotalDownload" fontWeight="bold" text="-"/><mx:Label text="MB"/></mx:HBox>
-			<mx:HBox horizontalGap="0"><mx:Label text="Current: "/><mx:Label id="labelCurrentDownload" fontWeight="bold" text="-"/><mx:Label text="Kb/s"/></mx:HBox>
-			<mx:HBox horizontalGap="0"><mx:Label text="Available: "/><mx:Label id="labelAvailableDownload" fontWeight="bold" text="-"/><mx:Label text="Mb/s"/></mx:HBox>
-			<mx:HBox horizontalGap="0"><mx:Label text="Latency: "/><mx:Label id="labelDownloadLatency" fontWeight="bold" text="-"/><mx:Label text="ms"/></mx:HBox>
+			<mx:HBox backgroundColor="haloOrange" width="100%" horizontalAlign="center"><mx:Label fontWeight="bold" text="{ResourceUtil.getInstance().getString('bbb.bwmonitor.upload')}"/></mx:HBox>
+			<mx:HBox visible="false" includeInLayout="false" horizontalGap="0"><mx:Label text="{ResourceUtil.getInstance().getString('bbb.bwmonitor.total')}: "/><mx:Label id="labelTotalUpload" fontWeight="bold" text="-"/></mx:HBox>
+			<mx:HBox horizontalGap="0"><mx:Label text="{ResourceUtil.getInstance().getString('bbb.bwmonitor.current')}: "/><mx:Label id="labelCurrentUpload" fontWeight="bold" text="-"/></mx:HBox>
+			<mx:HBox visible="false" includeInLayout="false" horizontalGap="0"><mx:Label text="{ResourceUtil.getInstance().getString('bbb.bwmonitor.available')}: "/><mx:Label id="labelAvailableUpload" fontWeight="bold" text="-"/></mx:HBox>
+			<mx:HBox horizontalGap="0"><mx:Label text="{ResourceUtil.getInstance().getString('bbb.bwmonitor.latency')}: "/><mx:Label id="labelUploadLatency" fontWeight="bold" text="-"/></mx:HBox>
+			<mx:HBox backgroundColor="haloOrange" width="100%" horizontalAlign="center"><mx:Label fontWeight="bold" text="{ResourceUtil.getInstance().getString('bbb.bwmonitor.download')}"/></mx:HBox>
+			<mx:HBox visible="false" includeInLayout="false" horizontalGap="0"><mx:Label text="{ResourceUtil.getInstance().getString('bbb.bwmonitor.total')}: "/><mx:Label id="labelTotalDownload" fontWeight="bold" text="-"/></mx:HBox>
+			<mx:HBox horizontalGap="0"><mx:Label text="{ResourceUtil.getInstance().getString('bbb.bwmonitor.current')}: "/><mx:Label id="labelCurrentDownload" fontWeight="bold" text="-"/></mx:HBox>
+			<mx:HBox visible="false" includeInLayout="false" horizontalGap="0"><mx:Label text="{ResourceUtil.getInstance().getString('bbb.bwmonitor.available')}: "/><mx:Label id="labelAvailableDownload" fontWeight="bold" text="-"/></mx:HBox>
+			<mx:HBox horizontalGap="0"><mx:Label text="{ResourceUtil.getInstance().getString('bbb.bwmonitor.latency')}: "/><mx:Label id="labelDownloadLatency" fontWeight="bold" text="-"/></mx:HBox>
+			<mx:HBox horizontalGap="0" width="100%" ><mx:Spacer width="100%"/><mx:Button id="labelRefresh" icon="{_refreshIcon}" width="16" height="16" click="runBandwidthMeasurement()" /></mx:HBox>
 		</mx:VBox>
 	</mx:Panel>
 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/RecordButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/RecordButton.mxml
index c4833766b2536d723fd16c16bceef09fce21e330..d7da1d0ee4201a3fe563901087e23b17ce6c2266 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/RecordButton.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/RecordButton.mxml
@@ -26,19 +26,17 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	styleName="recordButtonStyleNormal"
 	click="confirmChangeRecordingStatus()"
 	height="24"
-	toolTip="{UserManager.getInstance().getConference().amIModerator() 
-              ? ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.start')
-              : ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.notRecording')}"
 	enabled="false"
 	creationComplete="onCreationComplete()"
-	visible="{UserManager.getInstance().getConference().record}"
-	includeInLayout="{UserManager.getInstance().getConference().record}" 
+	visible="true"
+	includeInLayout="true"
 	mouseOver="onRecordButtonMouseOver(event)"
 	mouseOut="onRecordButtonMouseOut(event)" >
 
 	<mate:Listener type="{BBBEvent.CHANGE_RECORDING_STATUS}" method="onRecordingStatusChanged" />
 	<mate:Listener type="{FlashJoinedVoiceConferenceEvent.JOINED_VOICE_CONFERENCE}" method="handleFlashJoinedVoiceConference" />
 	<mate:Listener type="{WebRTCCallEvent.WEBRTC_CALL_STARTED}" method="handleWebRTCCallStarted" />
+	<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
 	<mx:Script>
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
@@ -47,6 +45,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			import mx.controls.Alert;
 			import mx.events.CloseEvent;
+			import mx.managers.PopUpManager;
 			
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
@@ -55,6 +54,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.core.model.MeetingModel;
 			import org.bigbluebutton.main.events.BBBEvent;
 			import org.bigbluebutton.main.model.LayoutOptions;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
 			import org.bigbluebutton.modules.phone.events.FlashJoinedVoiceConferenceEvent;
 			import org.bigbluebutton.modules.phone.events.WebRTCCallEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
@@ -64,6 +64,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private var recordingFlag:Boolean;
 			private var firstAudioJoin:Boolean = true;
 			private var layoutOptions:LayoutOptions = null;
+			private var _confirmationAlert:Alert = null;
 			
 			[Embed(source="/org/bigbluebutton/common/assets/images/record.png")]
 			private var recordReminderIcon:Class;
@@ -72,26 +73,42 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				ResourceUtil.getInstance().addEventListener(Event.CHANGE, localeChanged); // Listen for locale changing
 			}
 
-			private function confirmChangeRecordingStatus():void {
-        		LOGGER.debug("Confirming recording status change!!!!");
-        
-				// need to save the flag in case of any remote update on the recording status
-				recordingFlag = !this.selected;
+			private function hideConfirmationAlert():void {
+				if (_confirmationAlert != null) {
+					if (_confirmationAlert.visible) {
+						PopUpManager.removePopUp(_confirmationAlert);
+					}
+					_confirmationAlert = null;
+				}
+			}
+
+			private function showConfirmationAlert():void {
+				hideConfirmationAlert();
 
 				var message:String = recordingFlag? ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.confirm.message.start'): ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.confirm.message.stop');
 
 				// Confirm logout using built-in alert
-				var alert:Alert = Alert.show(message, ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.confirm.title'), Alert.YES | Alert.NO, this, alertChangeRecordingStatus, null, Alert.YES);
+				_confirmationAlert = Alert.show(message, ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.confirm.title'), Alert.YES | Alert.NO, this, onCloseConfirmationDialog, null, Alert.YES);
 
 				var newX:Number = this.x;
 				var newY:Number = this.y + this.height + 5;
 
-				alert.validateNow();
-				alert.move(newX, newY);
+				_confirmationAlert.validateNow();
+				_confirmationAlert.move(newX, newY);
 				//Accessibility.updateProperties();
 			}
 
-			private function alertChangeRecordingStatus(e:CloseEvent):void {
+			private function confirmChangeRecordingStatus():void {
+				LOGGER.debug("Confirming recording status change!!!!");
+
+				// need to save the flag in case of any remote update on the recording status
+				recordingFlag = !this.selected;
+
+				showConfirmationAlert();
+			}
+
+			private function onCloseConfirmationDialog(e:CloseEvent):void {
+				hideConfirmationAlert();
 				// check to see if the YES button was pressed
 				if (e.detail==Alert.YES) {
 					 doChangeRecordingStatus();
@@ -121,15 +138,23 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				}
 			}
 
-			private function onRecordingStatusChanged(event:BBBEvent):void {
-				if (event.payload.remote) {
-					this.selected = event.payload.recording;
+			private function updateButton(recording:Boolean):void {
+				this.selected = recording;
 
-					resourcesChanged();
+				resourcesChanged();
 
-					if (UserManager.getInstance().getConference().amIModerator() && MeetingModel.getInstance().meeting.allowStartStopRecording) {
-						this.enabled = true;
-					}
+				if (UserManager.getInstance().getConference().record) {
+					this.enabled = UserManager.getInstance().getConference().amIModerator() && MeetingModel.getInstance().meeting.allowStartStopRecording;
+				}
+
+				if (! this.enabled) {
+					hideConfirmationAlert();
+				}
+			}
+
+			private function onRecordingStatusChanged(event:BBBEvent):void {
+				if (event.payload.remote) {
+					updateButton(event.payload.recording);
 
 					LOGGER.debug("RecordButton:onRecordingStatusChanged changing record status to {0}", [event.payload.recording]);
 				}
@@ -149,6 +174,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 						&& UserManager.getInstance().getConference().amIModerator()
 						&& MeetingModel.getInstance().meeting.allowStartStopRecording) {
 					var alert:Alert = Alert.show(ResourceUtil.getInstance().getString("bbb.mainToolbar.recordBtn..notification.message1") + "\n\n" + ResourceUtil.getInstance().getString("bbb.mainToolbar.recordBtn..notification.message2"), ResourceUtil.getInstance().getString("bbb.mainToolbar.recordBtn..notification.title"), Alert.OK, this);
+					// we need to set transparency duration to avoid the blur effect when two alerts are displayed sequentially
+					alert.setStyle("modalTransparencyDuration", 250);
 					alert.titleIcon = recordReminderIcon;
 					
 					var newX:Number = this.x;
@@ -170,40 +197,64 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
 			
 			private function onRecordButtonMouseOver(event:MouseEvent):void {
-				if (UserManager.getInstance().getConference().amIModerator()) {
+				if (UserManager.getInstance().getConference().amIModerator() && UserManager.getInstance().getConference().record) {
 					this.styleName = this.selected? "recordButtonStyleStop": "recordButtonStyleStart";
 				}
 			}
 
 			private function onRecordButtonMouseOut(event:MouseEvent):void {
-				if (UserManager.getInstance().getConference().amIModerator()) {
+				if (UserManager.getInstance().getConference().amIModerator() && UserManager.getInstance().getConference().record) {
 					this.styleName = this.selected? "recordButtonStyleStart": "recordButtonStyleNormal";
 				}
 			}
 
-			override protected function resourcesChanged():void{
-				super.resourcesChanged();
-
-				this.styleName = this.selected? "recordButtonStyleStart": "recordButtonStyleNormal";
-
-				if (UserManager.getInstance().getConference().amIModerator() && MeetingModel.getInstance().meeting.allowStartStopRecording) {
-					if (this.selected) {
-						this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.stop');
+			private function updateToolTip():void {
+				if (UserManager.getInstance().getConference().record) {
+					if (UserManager.getInstance().getConference().amIModerator()) {
+						if (MeetingModel.getInstance().meeting.allowStartStopRecording) {
+							if (this.selected) {
+								this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.stop');
+							} else {
+								this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.start');
+							}
+						} else {
+							this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.wontInterrupt');
+						}
 					} else {
-						this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.start');
+						if (this.selected) {
+							this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.recording');
+						} else {
+							this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.onlyModerators');
+						}
 					}
 				} else {
-					if (this.selected) {
-						this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.recording');
+					if (UserManager.getInstance().getConference().amIModerator()) {
+						if (MeetingModel.getInstance().meeting.isMetadata("mconf-live-wont-record-message")) {
+							this.toolTip = MeetingModel.getInstance().meeting.metadata["mconf-live-wont-record-message"];
+						} else {
+							this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.wontRecord');
+						}
 					} else {
-						this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.notRecording');
+						this.toolTip = ResourceUtil.getInstance().getString('bbb.mainToolbar.recordBtn.toolTip.wontRecord');
 					}
 				}
 			}
 
+			override protected function resourcesChanged():void{
+				super.resourcesChanged();
+
+				this.styleName = this.selected? "recordButtonStyleStart": "recordButtonStyleNormal";
+
+				updateToolTip();
+			}
+
 			private function localeChanged(e:Event):void{
 				resourcesChanged();
 			}
+
+			private function refreshRole(e:ChangeMyRole):void {
+				updateButton(this.selected);
+			}
 		]]>
 	</mx:Script>
 </mx:Button>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/VideoWithWarnings.as b/bigbluebutton-client/src/org/bigbluebutton/main/views/VideoWithWarnings.as
index cf49081bfe4a505b1808e2370024e073d0bb4db4..d8bfb4b94f2657556f150dbbd334f05f1c3a9de9 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/VideoWithWarnings.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/VideoWithWarnings.as
@@ -148,8 +148,10 @@ package org.bigbluebutton.main.views
                 _camera.addEventListener(StatusEvent.STATUS, onStatusEvent);
 
                 if (_camera.muted) {
-                    if (_cameraAccessDenied) {
+                    if (_cameraAccessDenied && !_chromePermissionDenied) {
                         Security.showSettings(SecurityPanel.PRIVACY)
+                    } else if (_chromePermissionDenied) {
+                        showWarning('bbb.video.publish.hint.cameraDenied');
                     } else {
                         onFailCallback('bbb.video.publish.hint.waitingApproval');
                     }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/VideoWithWarningsBase.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/VideoWithWarningsBase.mxml
index f69c63b223fa79dba50ee5ac88ec0b80615b48bd..44ba12cb73af89df8e38f132c718791613fbc0a6 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/VideoWithWarningsBase.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/VideoWithWarningsBase.mxml
@@ -48,6 +48,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                 includeInLayout="{_text.visible}"
                 hideEffect="{dissolveOut}" showEffect="{dissolveIn}" >
             <mx:Box
+                    id="_textBackground"
                     width="100%"
                     styleName="videoMessageBackgroundStyle" >
                 <mx:Text
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/WaitingWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/WaitingWindow.mxml
new file mode 100755
index 0000000000000000000000000000000000000000..b822fbe1dfce7bd75c14dc081c8e0b0c7514beaf
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/WaitingWindow.mxml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org
+
+  Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+
+  BigBlueButton is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Lesser General Public License as published by the Free Software
+  Foundation; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+  PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License along
+  with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+  $Id: $
+-->
+
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
+		title="{ResourceUtil.getInstance().getString('bbb.waitWindow.waitMessage.title')}" showCloseButton="false"
+		layout="vertical" width="350" horizontalAlign="center">
+
+	<mx:Script>
+		<![CDATA[
+			import mx.managers.PopUpManager;
+
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+
+			public function removeWindow():void {
+				PopUpManager.removePopUp(this);
+			}
+		]]>
+	</mx:Script>
+	<mx:Text text="{ResourceUtil.getInstance().getString('bbb.waitWindow.waitMessage.message')}" width="100%" textAlign="center" />
+</mx:TitleWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/WebRTCEchoTest.mxml b/bigbluebutton-client/src/org/bigbluebutton/main/views/WebRTCEchoTest.mxml
index 4435fe9a5c53eebddd1b23951e7b7edfcc416c0c..34425dfdd8875dd6939286c1903e73de051396cd 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/main/views/WebRTCEchoTest.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/WebRTCEchoTest.mxml
@@ -58,8 +58,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       
 			private static const LOGGER:ILogger = getClassLogger(WebRTCEchoTest);      
 			private static var DEFAULT_HELP_URL:String = "http://www.bigbluebutton.org/content/videos";
+
+			private static const TIMEOUT:Number = 60;
+			private static const CANCEL_BUTTON:Number = 55;
 			
 			private var dotTimer:Timer;
+
+			private var cancelTimer:Timer;
+			private var countdown:Number;
+
+			[Bindable]
+			private var cancelButtonLabel:String = ResourceUtil.getInstance().getString('bbb.micSettings.cancel');
+
 			private var userClosed:Boolean = false;
 			
 			override public function move(x:Number, y:Number):void {
@@ -68,7 +78,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			private function onCancelClicked():void {
 
-				if (dotTimer) dotTimer.stop();
+				stopTimers();
 				PopUpManager.removePopUp(this);
 			}
 			
@@ -81,13 +91,51 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				lblConnectMessage.text = lblConnectMessageMock.text = ResourceUtil.getInstance().getString('bbb.micSettings.webrtc.connecting');
 				dotTimer = new Timer(200, 0);
 				dotTimer.addEventListener(TimerEvent.TIMER, dotAnimate);
-				dotTimer.start();
+
+				cancelTimer = new Timer(1000, 0);
+				cancelTimer.addEventListener(TimerEvent.TIMER, timeout);
+
+				startTimers();
+
+				cancelButton.width = cancelButton.measureText(genCancelButtonLabel(TIMEOUT)).width
+						+ cancelButton.getStyle("paddingRight")
+						+ cancelButton.getStyle("paddingLeft")
+						+ 8; // 8 is magic number
         
         var testState:String = PhoneModel.getInstance().webRTCModel.state;
         if (testState == Constants.DO_ECHO_TEST) {
           webRTCEchoTestStarted();
         }
 			}
+
+			private function startTimers():void {
+				cancelButton.visible = false;
+				if (!dotTimer.running) dotTimer.start();
+				if (!cancelTimer.running) {
+					countdown = TIMEOUT;
+					cancelTimer.start();
+				}
+			}
+
+			private function stopTimers():void {
+				if (dotTimer.running) dotTimer.stop();
+				if (cancelTimer.running) cancelTimer.stop();
+			}
+
+			private function genCancelButtonLabel(countdown:Number):String {
+				return cancelButtonLabel + " (" + countdown.toString() + ")";
+			}
+
+			private function timeout(e:TimerEvent):void {
+				if (countdown > 0) {
+					if (!cancelButton.visible && countdown < CANCEL_BUTTON)
+						cancelButton.visible = true;
+					cancelButton.label = genCancelButtonLabel(countdown);
+					countdown--;
+				} else {
+					noButtonClicked();
+				}
+			}
 			
 			private function dotAnimate(e:TimerEvent):void {
 				if (lblConnectDots.text.length > 5) {
@@ -134,7 +182,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
       private function webRTCEchoTestStarted():void {
         setCurrentState("started");
-        dotTimer.stop();        
+        stopTimers();
       }
       
 			private function handleWebRTCEchoTestEndedEvent(e:WebRTCEchoTestEvent):void {
@@ -144,7 +192,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       private function webRTCEchoTestEnded():void {
         setCurrentState("connecting");
         lblConnectMessage.text = lblConnectMessageMock.text = ResourceUtil.getInstance().getString('bbb.micSettings.webrtc.endedecho');
-        if (!dotTimer.running) dotTimer.start();
         
         if (!userClosed) {
           onCancelClicked();
@@ -160,19 +207,19 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private function handleWebRTCEchoTestWaitingForICEEvent(e:WebRTCEchoTestEvent):void {
 				setCurrentState("connecting");
 				lblConnectMessage.text = lblConnectMessageMock.text = ResourceUtil.getInstance().getString('bbb.micSettings.webrtc.waitingforice');
-				if (!dotTimer.running) dotTimer.start();
+				startTimers();
 			}
 			
 			private function handleWebRTCEchoTestTransferringEvent(e:WebRTCEchoTestEvent):void {
 				setCurrentState("connecting");
 				lblConnectMessage.text = lblConnectMessageMock.text = ResourceUtil.getInstance().getString('bbb.micSettings.webrtc.transferring');
-				if (!dotTimer.running) dotTimer.start();
+				startTimers();
 			}
 			
 			private function handleWebRTCCallConnectingEvent(e:WebRTCCallEvent):void {
 				setCurrentState("connecting");
 				lblConnectMessage.text = lblConnectMessageMock.text = ResourceUtil.getInstance().getString('bbb.micSettings.webrtc.connecting');
-				if (!dotTimer.running) dotTimer.start();
+				startTimers();
 			}
 			
 			private function handleWebRTCCallFailedEvent(e:WebRTCCallEvent):void {
@@ -182,7 +229,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private function handleWebRTCCallWaitingForICEEvent(e:WebRTCCallEvent):void {
 				setCurrentState("connecting");
 				lblConnectMessage.text = lblConnectMessageMock.text = ResourceUtil.getInstance().getString('bbb.micSettings.webrtc.waitingforice');
-				if (!dotTimer.running) dotTimer.start();
+				startTimers();
 			}
       
       private function webRTCCallStarted():void {
@@ -230,13 +277,32 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<mx:states>
 		<mx:State name="connecting">
 			<mx:AddChild relativeTo="cnvTitle" position="after">
-				<mx:HBox width="100%" height="100%" verticalAlign="middle" horizontalAlign="center">
-					<mx:TextArea id="lblConnectMessage" editable="false" textAlign="right" borderSkin="{null}"
-								 width="{lblConnectMessageMock.width + 4}" height="{lblConnectDots.height}"
-								 styleName="micSettingsWindowSpeakIntoMicLabelStyle" />
-					<mx:Text id="lblConnectMessageMock" visible="false" includeInLayout="false" styleName="micSettingsWindowSpeakIntoMicLabelStyle" />
-					<mx:Label id="lblConnectDots" width="20" textAlign="left" styleName="micSettingsWindowSpeakIntoMicLabelStyle" text="" />
-				</mx:HBox>
+				<mx:VBox width="100%" height="100%" verticalAlign="middle">
+					<mx:HBox width="100%" height="100%" verticalAlign="middle" horizontalAlign="center">
+						<mx:TextArea id="lblConnectMessage"
+								editable="false"
+								textAlign="right"
+								borderSkin="{null}"
+								width="{lblConnectMessageMock.width + 10}"
+								height="{lblConnectDots.height}"
+								styleName="micSettingsWindowSpeakIntoMicLabelStyle"/>
+						<mx:Text id="lblConnectMessageMock"
+								visible="false"
+								includeInLayout="false"/>
+						<mx:Label id="lblConnectDots"
+								width="20"
+								textAlign="left"
+								styleName="micSettingsWindowSpeakIntoMicLabelStyle"
+								text=""/>
+					</mx:HBox>
+					<mx:HBox width="100%" verticalAlign="bottom" horizontalAlign="right">
+						<mx:Button id="cancelButton"
+								label="{cancelButtonLabel}"
+								styleName="micSettingsWindowPlaySoundButtonStyle"
+								click="noButtonClicked()"
+								toolTip=""/>
+					</mx:HBox>
+				</mx:VBox>
 			</mx:AddChild>
 		</mx:State>
 		
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/WellPositionedMenu.as b/bigbluebutton-client/src/org/bigbluebutton/main/views/WellPositionedMenu.as
new file mode 100644
index 0000000000000000000000000000000000000000..a0577ea0185196ef263b82ce0a4d5417446862f7
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/main/views/WellPositionedMenu.as
@@ -0,0 +1,47 @@
+package org.bigbluebutton.main.views
+{
+    import flash.display.DisplayObject;
+    import flash.display.DisplayObjectContainer;
+    import flash.geom.Point;
+
+    import mx.controls.Menu;
+    import mx.events.ResizeEvent;
+
+    public class WellPositionedMenu {
+        private static function posOutOfStage(menu:Menu, pos:Point):Boolean {
+            return pos.x < 0
+            || pos.y < 0
+            || pos.y + menu.height > menu.stage.stageHeight
+            || pos.x + menu.width > menu.stage.stageWidth;
+        }
+
+        private static function onFirstResize(object:DisplayObject):Function {
+            return function(e:ResizeEvent):void {
+                var menu:Menu = e.currentTarget as Menu;
+
+                var possiblePos:Array = [
+                    object.localToGlobal(new Point(0, object.height + 1)), // bottom-right
+                    object.localToGlobal(new Point(object.width + 1, 0)), // right
+                    object.localToGlobal(new Point(object.width - menu.width, object.height + 1)), // bottom-left
+                    object.localToGlobal(new Point(0, -(menu.height + 1))), // top-right
+                    object.localToGlobal(new Point(object.width - menu.width, -(menu.height + 1))) // top-left
+                ]
+
+                var pos:Point = possiblePos[0];
+                for (var i:int = 0; i < possiblePos.length; ++i) {
+                    if (! posOutOfStage(menu, possiblePos[i])) {
+                        pos = possiblePos[i];
+                        break;
+                    }
+                }
+                menu.move(pos.x, pos.y);
+            };
+        }
+
+        public static function createMenu(parent:DisplayObjectContainer, mdp:Object, displayNextTo:DisplayObject, showRoot:Boolean = true):Menu {
+            var menu:Menu = Menu.createMenu(parent, mdp, showRoot);
+            menu.addEventListener(ResizeEvent.RESIZE, onFirstResize(displayNextTo));
+            return menu;
+        }
+    }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-change-mic-2.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-change-mic-2.png
deleted file mode 100755
index cd664085f71681dbf632285794848847a80aa353..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-change-mic-2.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-change-mic.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-change-mic.png
deleted file mode 100755
index 30e999e61ea2ac47a1493349b022c27d6fc30a10..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-change-mic.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-mic-permission.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-mic-permission.png
deleted file mode 100755
index 4a05fa0f01592400ecd96cc6756985214d940b06..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-mic-permission.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-mic-switch-done.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-mic-switch-done.png
deleted file mode 100755
index b750a983459be7faf4e2363b104680201dfb64ae..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-mic-switch-done.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-reload-page.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-reload-page.png
deleted file mode 100755
index 8057c9369280bd3859509312d02638dc8a9a02c2..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-reload-page.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-show-mics.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-show-mics.png
deleted file mode 100755
index 75024779a60ca57ccef3b335e3f1b58d86f27b1d..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-show-mics.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-switch-mic.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-switch-mic.png
deleted file mode 100755
index 0a544b233cc99e0f27cfb04cdd9cf904d4ae1554..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome-switch-mic.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome_allow.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome_allow.png
deleted file mode 100644
index f5bccc25aefea3ef7dcd80436aff7d4599806fb2..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/chrome_allow.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-arrow-1.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-arrow-1.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3274a818f90ca99fb742affce86003b4f6271bc
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-arrow-1.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-arrow-2.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-arrow-2.png
new file mode 100644
index 0000000000000000000000000000000000000000..515ac0ed9d1ddb7b15763c2c55a7a17aff41f05f
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-arrow-2.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-mic-permission.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-mic-permission.png
deleted file mode 100755
index fc76db6bbf29582c680f31fa6b0c2c36dd1462ed..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-mic-permission.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-share-mic.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-share-mic.png
deleted file mode 100755
index caea95541b37d6a4e57a506b6cb65518d29f033d..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-share-mic.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-show-mic.png b/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-show-mic.png
deleted file mode 100755
index 2a048b28d011d72f9ebcc1163caa6faa9e093f09..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/main/views/assets/ff-show-mic.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml
index b4568e8f6803307e0084b425e4a9f6367a0b2c8b..7c1ef23e4e23ea07d3fe2196f41d593e933421de 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/caption/views/CaptionWindow.mxml
@@ -107,11 +107,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				if (UserManager.getInstance().getConference().amIModerator()) {
 					transcriptsCollection = new ArrayCollection();
 					
-					var names:Array = ResourceUtil.getInstance().localeNames;
-					var codes:Array = ResourceUtil.getInstance().localeCodes;
+					var locales:Array = ResourceUtil.getInstance().locales;
 					
-					for (var i:int=0; i<names.length; i++) {
-						transcriptsCollection.addItem({locale: names[i], localeCode: codes[i]});
+					for each(var item:* in locales) {
+						transcriptsCollection.addItem({locale: item.name, localeCode: item.code});
 					}
 				} else {
 					transcriptsCollection = t.transcriptCollection;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatCopyEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatCopyEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..be0906e8a96fd2b9cd5a674ee44e95ed045a3f29
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatCopyEvent.as
@@ -0,0 +1,17 @@
+package org.bigbluebutton.modules.chat.events
+{
+	import flash.events.Event;
+	import org.bigbluebutton.modules.chat.model.ChatConversation;
+
+	public class ChatCopyEvent extends Event
+	{
+		public static const COPY_CHAT_EVENT:String = 'COPY_CHAT_EVENT';
+
+		public var chatMessages:ChatConversation;
+
+		public function ChatCopyEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatEvent.as
index 5f6787c914370b3c7ac1a6f1a2d4232cf1f9d7a5..580ed3ebff62d0c68525f26a2ef638ba506532bd 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatEvent.as
@@ -26,6 +26,7 @@ package org.bigbluebutton.modules.chat.events
 		public static const CHAT_EVENT:String = 'CHAT_EVENT';
 		public static const NEW_CHAT_MESSAGE_EVENT:String = 'NEW_CHAT_MESSAGE_EVENT';
 		public static const PRIVATE_CHAT_MESSAGE_EVENT:String = 'PRIVATE_CHAT_MESSAGE_EVENT';
+		public static const RESIZE_CHAT_TOOLBAR:String = 'RESIZE_CHAT_TOOLBAR';
 		
 		public function ChatEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
 		{
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatSaveEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatSaveEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..30cf4f3684eaec5f2be59e56615c90cf65325f78
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatSaveEvent.as
@@ -0,0 +1,18 @@
+package org.bigbluebutton.modules.chat.events
+{
+	import flash.events.Event;
+	import org.bigbluebutton.modules.chat.model.ChatConversation;
+
+	public class ChatSaveEvent extends Event
+	{
+		public static const SAVE_CHAT_EVENT:String = 'SAVE_CHAT_EVENT';
+
+		public var chatMessages:ChatConversation;
+		public var filename:String;
+
+		public function ChatSaveEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatToolbarButtonEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatToolbarButtonEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..c380fbad1f8585e1c37d8e29203a6067f108a42b
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ChatToolbarButtonEvent.as
@@ -0,0 +1,16 @@
+package org.bigbluebutton.modules.chat.events
+{
+	import flash.events.Event;
+
+	public class ChatToolbarButtonEvent extends Event
+	{
+		public static const SAVE_CHAT_TOOLBAR_EVENT:String = "SAVE_CHAT_TOOLBAR_EVENT";
+		public static const COPY_CHAT_TOOLBAR_EVENT:String = "COPY_CHAT_TOOLBAR_EVENT";
+		public static const CLEAR_PUBLIC_CHAT_TOOLBAR_EVENT:String = "CLEAR_PUBLIC_CHAT_TOOLBAR_EVENT";
+
+		public function ChatToolbarButtonEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ClearPublicChatEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ClearPublicChatEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..9e16a56ba6d5b6ca3150ee8b796419afaa5f7ba2
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/events/ClearPublicChatEvent.as
@@ -0,0 +1,32 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.modules.chat.events
+{
+	import flash.events.Event;
+
+	public class ClearPublicChatEvent extends Event
+	{
+		public static const CLEAR_PUBLIC_CHAT_EVENT:String = 'CLEAR_PUBLIC_CHAT_EVENT';
+
+		public function ClearPublicChatEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml
index 8188f1ab01b83bf2535c06dd8056844347d19231..c3d620d00da49cdab696bbd6b58481b54de0bcc3 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/maps/ChatEventMap.mxml
@@ -30,7 +30,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       import org.bigbluebutton.core.EventConstants;
       import org.bigbluebutton.main.events.BBBEvent;
       import org.bigbluebutton.main.events.ModuleStartedEvent;
+      import org.bigbluebutton.modules.chat.events.ChatCopyEvent;
       import org.bigbluebutton.modules.chat.events.ChatEvent;
+      import org.bigbluebutton.modules.chat.events.ChatSaveEvent;
+      import org.bigbluebutton.modules.chat.events.ChatToolbarButtonEvent;
       import org.bigbluebutton.modules.chat.events.SendPrivateChatMessageEvent;
       import org.bigbluebutton.modules.chat.events.SendPublicChatMessageEvent;
       import org.bigbluebutton.modules.chat.events.StartChatModuleEvent;
@@ -39,6 +42,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       import org.bigbluebutton.modules.chat.services.ChatMessageService;
       import org.bigbluebutton.modules.chat.services.MessageReceiver;
       import org.bigbluebutton.modules.chat.services.MessageSender;
+      import org.bigbluebutton.modules.chat.services.ChatCopy;
+      import org.bigbluebutton.modules.chat.services.ChatSaver;
       import org.bigbluebutton.modules.chat.views.ChatView;
       import org.bigbluebutton.modules.chat.views.ChatWindow;
 		]]>
@@ -85,6 +90,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     <EventAnnouncer generator="{TranscriptEvent}" type="{TranscriptEvent.LOAD_TRANSCRIPT}"/>
   </EventHandlers>
   
+  <EventHandlers type="{ChatSaveEvent.SAVE_CHAT_EVENT}">
+    <MethodInvoker generator="{ChatSaver}" method="saveChatToFile" arguments="{event}"/>
+  </EventHandlers>
+
+  <EventHandlers type="{ChatCopyEvent.COPY_CHAT_EVENT}">
+    <MethodInvoker generator="{ChatCopy}" method="copyAllText" arguments="{event}"/>
+  </EventHandlers>
+
+  <EventHandlers type="{ChatToolbarButtonEvent.CLEAR_PUBLIC_CHAT_TOOLBAR_EVENT}">
+    <MethodInvoker generator="{ChatMessageService}" method="clearPublicChatMessages"/>
+  </EventHandlers>
+
   <Injectors target="{ChatMessageService}">
     <PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/>
     <PropertyInjector targetKey="receiver" source="{MessageReceiver}"/>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/model/ChatConversation.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/model/ChatConversation.as
index 5098e6fc932a8222ef5a9493feb216716f3e61bd..49ce915729328cff6235cac2a45e60b2433e60d7 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/model/ChatConversation.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/model/ChatConversation.as
@@ -18,15 +18,24 @@
  */
 package org.bigbluebutton.modules.chat.model
 {
+  import com.adobe.utils.StringUtil;
+
   import flash.system.Capabilities;
   
   import mx.collections.ArrayCollection;
   
+  import com.asfusion.mate.events.Dispatcher;
+
   import org.bigbluebutton.modules.chat.ChatUtil;
+  import org.bigbluebutton.util.i18n.ResourceUtil;
   import org.bigbluebutton.modules.chat.vo.ChatMessageVO;
+  import org.bigbluebutton.modules.chat.events.TranscriptEvent;
 
   public class ChatConversation
   { 
+
+    private var _dispatcher:Dispatcher = new Dispatcher();
+
     [Bindable]
     public var messages:ArrayCollection = new ArrayCollection();
     
@@ -51,22 +60,28 @@ package org.bigbluebutton.modules.chat.model
       cm.name = msg.fromUsername;
       cm.senderColor = uint(msg.fromColor);
       
-      cm.fromTime = msg.fromTime;		
-      cm.fromTimezoneOffset = msg.fromTimezoneOffset;
-      
-      var sentTime:Date = new Date();
-      sentTime.setTime(cm.fromTime);
-      cm.time = ChatUtil.getHours(sentTime) + ":" + ChatUtil.getMinutes(sentTime);
+      // Welcome message will skip time
+      if (msg.fromTime != -1) {
+        cm.fromTime = msg.fromTime;
+        cm.fromTimezoneOffset = msg.fromTimezoneOffset;
+        var sentTime:Date = new Date();
+        sentTime.setTime(cm.fromTime);
+        cm.time = ChatUtil.getHours(sentTime) + ":" + ChatUtil.getMinutes(sentTime);
+      }
       
       messages.addItem(cm); 
     }
     
     public function getAllMessageAsString():String{
       var allText:String = "";
-      var returnStr:String = (Capabilities.os.indexOf("Windows") >= 0 ? "\r\n" : "\r");
+      var returnStr:String = (Capabilities.os.indexOf("Windows") >= 0 ? "\r\n" : "\n");
       for (var i:int = 0; i < messages.length; i++){
         var item:ChatMessage = messages.getItemAt(i) as ChatMessage;
-        allText += item.name + " - " + item.time + " : " + item.text + returnStr;
+        allText += "[" + item.time + "] ";
+        if (StringUtil.trim(item.name) != "") {
+          allText += item.name + ": ";
+        }
+        allText += item.text + returnStr;
       }
       return allText;
     }
@@ -81,5 +96,18 @@ package org.bigbluebutton.modules.chat.model
       return msg.time;
     }
             
+    public function clearPublicChat():void {
+      var cm:ChatMessage = new ChatMessage();
+      cm.time = getLastTime();
+      cm.text = "<b><i>"+ResourceUtil.getInstance().getString('bbb.chat.clearBtn.chatMessage')+"</b></i>";
+      cm.name = "";
+      cm.senderColor = uint(0x000000);
+
+      messages.removeAll();
+      messages.addItem(cm);
+
+      var welcomeEvent:TranscriptEvent = new TranscriptEvent(TranscriptEvent.TRANSCRIPT_EVENT);
+      _dispatcher.dispatchEvent(welcomeEvent);
+    }
   }
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/ChatCopy.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/ChatCopy.as
new file mode 100644
index 0000000000000000000000000000000000000000..e1a074718984602b56796e3c7c388ff56befa26b
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/ChatCopy.as
@@ -0,0 +1,19 @@
+package org.bigbluebutton.modules.chat.services
+{
+  import flash.system.System;
+
+  import mx.controls.Alert;
+
+  import org.bigbluebutton.modules.chat.model.ChatConversation;
+  import org.bigbluebutton.modules.chat.events.ChatCopyEvent;
+  import org.bigbluebutton.util.i18n.ResourceUtil;
+
+  public class ChatCopy
+  {
+    public function copyAllText(e:ChatCopyEvent):void {
+      var chat:ChatConversation = e.chatMessages;
+      System.setClipboard(chat.getAllMessageAsString());
+      Alert.show(ResourceUtil.getInstance().getString('bbb.chat.copy.complete'), "", Alert.OK);
+    }
+  }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/ChatMessageService.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/ChatMessageService.as
index 6dc2108168f54bde07a80a2cee2ae9a18aa27607..72c4d26424c67092a0a13e888c462747465b0ed2 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/ChatMessageService.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/ChatMessageService.as
@@ -86,6 +86,10 @@ package org.bigbluebutton.modules.chat.services
     public function getPublicChatMessages():void {
       sender.getPublicChatMessages();
     }
+
+    public function clearPublicChatMessages():void {
+      sender.clearPublicChatMessages();
+    }
     
     private static const SPACE:String = " ";
     
@@ -98,7 +102,7 @@ package org.bigbluebutton.modules.chat.services
         welcomeMsg.fromUserID = SPACE;
         welcomeMsg.fromUsername = SPACE;
         welcomeMsg.fromColor = "86187";
-        welcomeMsg.fromTime = new Date().getTime();
+        welcomeMsg.fromTime = -1;
         welcomeMsg.fromTimezoneOffset = new Date().getTimezoneOffset();
         welcomeMsg.toUserID = SPACE;
         welcomeMsg.toUsername = SPACE;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/ChatSaver.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/ChatSaver.as
new file mode 100644
index 0000000000000000000000000000000000000000..44a5c78e80b13734ab094fe24406f959c257c681
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/ChatSaver.as
@@ -0,0 +1,37 @@
+package org.bigbluebutton.modules.chat.services
+{
+	import flash.events.Event;
+	import mx.controls.Alert;
+	import flash.net.FileReference;
+	import org.bigbluebutton.modules.chat.model.ChatConversation;
+	import org.bigbluebutton.modules.chat.events.ChatSaveEvent;
+	import org.bigbluebutton.util.i18n.ResourceUtil;
+
+	public class ChatSaver
+	{
+		public function ChatSaver(){}
+
+		public function saveChatToFile(e:ChatSaveEvent):void{
+			var chat:ChatConversation = e.chatMessages;
+			var filename:String = e.filename;
+
+			var textToExport:String = chat.getAllMessageAsString();
+			var fileRef:FileReference = new FileReference();
+
+			fileRef.addEventListener(Event.COMPLETE, function(evt:Event):void {
+				Alert.show(ResourceUtil.getInstance().getString('bbb.chat.save.complete'), "", Alert.OK);
+			});
+
+			var cr:String = String.fromCharCode(13);
+			var lf:String = String.fromCharCode(10);
+			var crlf:String = String.fromCharCode(13, 10);
+
+			textToExport = textToExport.replace(new RegExp(crlf, "g"), '\n');
+			textToExport = textToExport.replace(new RegExp(cr, "g"), '\n');
+			textToExport = textToExport.replace(new RegExp(lf, "g"), '\n');
+			textToExport = textToExport.replace(new RegExp('\n', "g"), crlf);
+
+			fileRef.save(textToExport, filename + ".txt");
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/MessageReceiver.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/MessageReceiver.as
index efb0c79f334aa885b9d1da4946015ed9c96477e0..2a12acca009e50db00fba0dbfd30a546839b875f 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/MessageReceiver.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/MessageReceiver.as
@@ -29,6 +29,7 @@ package org.bigbluebutton.modules.chat.services
   import org.bigbluebutton.modules.chat.events.PrivateChatMessageEvent;
   import org.bigbluebutton.modules.chat.events.PublicChatMessageEvent;
   import org.bigbluebutton.modules.chat.events.TranscriptEvent;
+  import org.bigbluebutton.modules.chat.events.ClearPublicChatEvent;
   import org.bigbluebutton.modules.chat.vo.ChatMessageVO;
   
   public class MessageReceiver implements IMessageListener
@@ -57,6 +58,9 @@ package org.bigbluebutton.modules.chat.services
         case "ChatRequestMessageHistoryReply":
           handleChatRequestMessageHistoryReply(message);
           break;	
+        case "ChatClearPublicMessageCommand":
+          handleChatClearPublicMessageCommand(message);
+          break;
         default:
           //   LogUtil.warn("Cannot handle message [" + messageName + "]");
       }
@@ -123,5 +127,12 @@ package org.bigbluebutton.modules.chat.services
       pcCoreEvent.message = message;
       dispatcher.dispatchEvent(pcCoreEvent);      
     }
+
+    private function handleChatClearPublicMessageCommand(message:Object):void {
+      LOGGER.debug("Handling clear chat history message");
+
+      var clearChatEvent:ClearPublicChatEvent = new ClearPublicChatEvent(ClearPublicChatEvent.CLEAR_PUBLIC_CHAT_EVENT);
+      dispatcher.dispatchEvent(clearChatEvent);
+    }
   }
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/MessageSender.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/MessageSender.as
index 6ad463e8e91c8d339e42ae99e06cfe23620d31bb..5871879fcb9331a2ec71d368daac603be30108d9 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/MessageSender.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/services/MessageSender.as
@@ -76,5 +76,19 @@ package org.bigbluebutton.modules.chat.services
         message.toObj()
       );
     }
+
+    public function clearPublicChatMessages():void
+    {
+      LOGGER.debug("Sending [chat.clearPublicChatMessages] to server.");
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage("chat.clearPublicChatMessages",
+        function(result:String):void { // On successful result
+          LOGGER.debug(result);
+        },
+        function(status:String):void { // status - On error occurred
+          LOGGER.error(status);
+        }
+      );
+    }
   }
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml
index f28eecad77a95201d274ca3bee3d2ed98a2d391f..2a57c64a939ef58a19060b32c3ef51e661c9f5e1 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AddChatTabBox.mxml
@@ -27,6 +27,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
          creationComplete="onCreationComplete()">
   
   <mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
+  <mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
   
     <mx:Script>
         <![CDATA[
@@ -43,6 +44,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.main.model.users.BBBUser;
 			import org.bigbluebutton.main.model.users.Conference;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
 			import org.bigbluebutton.modules.chat.events.ChatNoiseEnabledEvent;
 			import org.bigbluebutton.modules.chat.events.ChatOptionsEvent;
 			import org.bigbluebutton.modules.chat.model.ChatOptions;
@@ -52,7 +54,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
             [Bindable] public var users:ArrayCollection;
             [Bindable] public var chatView:ChatView;
-            [Bindable] private var fontSizes:Array = ['10', '12', '14', '16', '20', '24'];
+            [Bindable] private var fontSizes:Array = ['8', '10', '12', '14', '16', '18'];
             
             [Bindable] public var chatOptions:ChatOptions = new ChatOptions();		
             
@@ -126,6 +128,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
             }
           
           private function lockSettingsChanged(e:Event = null):void {
+              refreshListStatus();
+          }
+
+          private function refreshRole(e:ChangeMyRole):void {
+              refreshListStatus();
+          }
+
+          private function refreshListStatus():void {
             
             if (UsersUtil.amIModerator() || UsersUtil.amIPresenter()) return; // Settings only affect viewers.
             
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AdvancedList.as b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AdvancedList.as
index d6c6a4f2138dffe63c77bc0fe79bf71629181b72..50bebba45c598b68fa595878ee72a08e3cd4c32b 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AdvancedList.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/AdvancedList.as
@@ -19,6 +19,7 @@
 package org.bigbluebutton.modules.chat.views
 {
   import mx.controls.List;
+  import org.bigbluebutton.modules.chat.events.ChatEvent;
   
   import org.as3commons.logging.api.ILogger;
   import org.as3commons.logging.api.getClassLogger;
@@ -37,6 +38,8 @@ package org.bigbluebutton.modules.chat.views
       super.measure();
       //sovled on forum by Flex HarUI
       measuredHeight = measureHeightOfItems() + viewMetrics.top + viewMetrics.bottom;
+
+      dispatchEvent(new ChatEvent(ChatEvent.RESIZE_CHAT_TOOLBAR));
     }
     
     public function scrollToBottom():void {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatBox.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatBox.mxml
index 152718c8e43b9dcf35a33d2844ba3615c064ab4b..0e69e70f12b968e0d5927139b686140deb57fcb9 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatBox.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatBox.mxml
@@ -56,6 +56,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<mate:Listener type="{ShortcutEvent.GOREAD_MESSAGE}" method="goToLatestReadMessage" />
   <mate:Listener type="{PrivateChatMessageEvent.PRIVATE_CHAT_MESSAGE_EVENT}" method="handlePrivateChatMessageEvent"/>
   <mate:Listener type="{PublicChatMessageEvent.PUBLIC_CHAT_MESSAGE_EVENT}" method="handlePublicChatMessageEvent"/>
+  <mate:Listener type="{ClearPublicChatEvent.CLEAR_PUBLIC_CHAT_EVENT}" method="handleClearPublicChatBoxMessages"/>
   <mate:Listener type="{ShortcutEvent.FOCUS_CHAT_INPUT}" method="focusChatInput" />
   <mate:Listener type="{UserLeftEvent.LEFT}" method="handleUserLeftEvent"/>
   <mate:Listener type="{UserJoinedEvent.JOINED}" method="handleUserJoinedEvent"/>
@@ -66,6 +67,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   <mate:Listener type="{BBBEvent.RECONNECT_DISCONNECTED_EVENT}" receive="refreshChat(event)"/>
 	
 	<mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
+	<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
 
 	<mx:Script>
 		<![CDATA[
@@ -90,14 +92,17 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.main.events.UserLeftEvent;
 			import org.bigbluebutton.main.model.users.BBBUser;
 			import org.bigbluebutton.main.model.users.Conference;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
 			import org.bigbluebutton.modules.chat.ChatConstants;
 			import org.bigbluebutton.modules.chat.ChatUtil;
+			import org.bigbluebutton.modules.chat.events.ChatEvent;
 			import org.bigbluebutton.modules.chat.events.ChatOptionsEvent;
 			import org.bigbluebutton.modules.chat.events.PrivateChatMessageEvent;
 			import org.bigbluebutton.modules.chat.events.PublicChatMessageEvent;
 			import org.bigbluebutton.modules.chat.events.SendPrivateChatMessageEvent;
 			import org.bigbluebutton.modules.chat.events.SendPublicChatMessageEvent;
 			import org.bigbluebutton.modules.chat.events.TranscriptEvent;
+			import org.bigbluebutton.modules.chat.events.ClearPublicChatEvent;
 			import org.bigbluebutton.modules.chat.model.ChatConversation;
 			import org.bigbluebutton.modules.chat.model.ChatOptions;
 			import org.bigbluebutton.modules.chat.vo.ChatMessageVO;
@@ -147,8 +152,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 		      [Bindable]
 		      private var chatListHeight:Number = 100;
+
+			[Bindable]
+			private var chatToolbarHeight:Number = 80;
 			
 			[Bindable] public var chatOptions:ChatOptions = new ChatOptions();	
+
+			private var shiftPressed:Boolean = false;
+			private var ctrlPressed:Boolean = false;
       
 			private function onCreationComplete():void {    
 				bindToHeightToDetermineHeightOfMessageList();
@@ -171,6 +182,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				txtMsgArea.addEventListener(TextEvent.TEXT_INPUT, handleTextInput);
 				txtMsgArea.addEventListener(KeyboardEvent.KEY_DOWN, handleMsgAreaKeyDown);
 				
+				// Listen for the navigable keys to avoid moving and resizing the chat box while text selection
+				txtMsgArea.addEventListener(KeyboardEvent.KEY_DOWN, checkNavigableButtonDown);
+				txtMsgArea.addEventListener(KeyboardEvent.KEY_UP, checkNavigableButtonUp);
+				chatMessagesList.addEventListener(KeyboardEvent.KEY_DOWN, checkNavigableButtonDown);
+				chatMessagesList.addEventListener(KeyboardEvent.KEY_UP, checkNavigableButtonUp);
+
+				this.addEventListener(FocusEvent.FOCUS_OUT, releaseNavigableButton);
+
 				queryForChatHistory();
 				
 				if(chatMessagesList.accessibilityProperties == null)
@@ -191,12 +210,49 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				
 				LOGGER.debug(" onCreationComplete. Apply lock settings");
 				applyLockSettings();
+
+				chatToolbar.registerListeners(chatMessagesList);
+
+				chatMessagesList.addEventListener(ChatEvent.RESIZE_CHAT_TOOLBAR, adjustToolbarWidthAccordingToScrollBar);
 			}
 
 			private function handleRemaininTimeBreakout(e:BreakoutRoomEvent):void {
 				TimerUtil.setCountDownTimer(timerLabel, e.durationInMinutes);
 			}
 
+			private function checkNavigableButtonDown(e:KeyboardEvent):void {
+				if (e.shiftKey && !shiftPressed) {
+					shiftPressed = true;
+					parentDocument.handleDraggableStatus(false);
+				}
+				if (e.ctrlKey && !ctrlPressed) {
+					ctrlPressed = true;
+					parentDocument.handleResizableStatus(false);
+				}
+			}
+
+			private function checkNavigableButtonUp(e:KeyboardEvent):void {
+				if (!e.shiftKey && shiftPressed) {
+					shiftPressed = false;
+					parentDocument.handleDraggableStatus(true);
+				}
+				if (!e.ctrlKey && ctrlPressed) {
+					ctrlPressed = false;
+					parentDocument.handleResizableStatus(true);
+				}
+			}
+
+			private function releaseNavigableButton(focus:FocusEvent):void {
+				if (shiftPressed) {
+					shiftPressed = false;
+					parentDocument.handleDraggableStatus(true);
+				}
+				if (ctrlPressed) {
+					ctrlPressed = false;
+					parentDocument.handleResizableStatus(true);
+				}
+			}
+
 			private function focusChatBox(e:ShortcutEvent):void{
 				focusManager.setFocus(chatMessagesList);
 			}
@@ -307,6 +363,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
           }
         }
       }
+
+      private function adjustToolbarWidthAccordingToScrollBar(e:ChatEvent):void{
+        invalidateDisplayList();
+        validateNow();
+      }
       
       private function handlePrivateChatMessageEvent(event:PrivateChatMessageEvent):void {
         var message:ChatMessageVO = event.message;
@@ -382,6 +443,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private function changeFontSize(e:ChatOptionsEvent):void {
 				this.setStyle("fontSize", e.fontSize);
 			}
+
+			private function copyAllText():void{
+				System.setClipboard(chatMessages.getAllMessageAsString());
+			}
+
+			public function getChatMessages():ChatConversation {
+				return chatMessages;
+			}
 			
 			private function addContextMenuItems():void {
 				var contextMenu:ContextMenu = new ContextMenu();
@@ -755,6 +824,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
 		}
 		
+		private function refreshRole(e:ChangeMyRole):void {
+			applyLockSettings();
+		}
+
 		private function get messageCanBeSent() : Boolean {
 			return StringUtils.trim(txtMsgArea.text).length <= chatOptions.maxMessageLength;
 		}
@@ -768,6 +841,36 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				hideMessageTooLong();
 			}
 		}
+
+		private function handleClearPublicChatBoxMessages(event:ClearPublicChatEvent):void {
+			if(publicChat){
+				chatMessages.clearPublicChat();
+				invalidateDisplayList();
+				validateNow();
+			}
+		}
+
+		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
+			super.updateDisplayList(unscaledWidth, unscaledHeight);
+
+			// Force validation before evaluation of toolbar width
+			validateNow();
+
+			const paddingHeight:int = 5;
+			const paddingWidth:int = 5;
+
+			chatToolbar.width = 45;
+			chatToolbar.x = (chatMessagesCanvas.width - chatToolbar.width) - 10;
+			chatToolbar.y = 10;
+
+			if (!publicChat) {
+				chatToolbar.publicChat = false;
+			}
+
+			if(chatMessagesList.mx_internal::scroll_verticalScrollBar != null && chatMessagesList.mx_internal::scroll_verticalScrollBar.visible){
+				chatToolbar.width -= chatMessagesList.mx_internal::scroll_verticalScrollBar.width;
+			}
+		}
 		]]>
 		
 	</mx:Script>
@@ -775,10 +878,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<common:TabIndexer id="tabIndexer" tabIndices="{[chatMessagesList, txtMsgArea, sendBtn, cmpColorPicker]}"/>
 
 	<mx:VBox width="100%" height="{chatListHeight}" verticalScrollPolicy="off">
-		<chat:AdvancedList width="100%" height="{chatListHeight - timerBox.height}" id="chatMessagesList" selectable="false" variableRowHeight="true" 
+		<mx:Canvas id="chatMessagesCanvas" width="100%" height="{chatListHeight}" horizontalScrollPolicy="off" verticalScrollPolicy="off" >
+			<chat:AdvancedList width="100%" height="{chatListHeight - timerBox.height}" id="chatMessagesList" selectable="false" variableRowHeight="true" paddingTop="0" paddingBottom="0"
 						   itemRenderer="org.bigbluebutton.modules.chat.views.ChatMessageRenderer" verticalScrollPolicy="on" horizontalScrollPolicy="off" wordWrap="true"
 						   dataProvider="{chatMessages.messages}"
 						   accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.messageList')}" />
+			<chat:ChatToolbar id="chatToolbar" />
+		</mx:Canvas>
 		<mx:HBox id="timerBox" styleName="breakoutRoomTimerBox"
 				 includeInLayout="false" visible="false"
 				 width="100%" height="0">
@@ -789,7 +895,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<mx:HBox id="chatCtrlBar" width="100%" height="60" styleName="chatControlBarStyle" verticalScrollPolicy="off"
 			 paddingLeft="5" paddingRight="5">	
 		<mx:VBox width="100%" height="100%">
-			<mx:TextArea id="txtMsgArea" width="100%" height="100%"
+			<!-- There is a restrict in this textArea to avoid a known issue where a \u007F, which is the delete character, would be seen written in some browsers as an invalid character -->
+			<mx:TextArea id="txtMsgArea" width="100%" height="100%" restrict="^\u007F"
 						 styleName="chatControlBarTextMsgStyle"
 						 change="txtMsgAreaChangeHandler(event)"
 						 toolTip="{ResourceUtil.getInstance().getString('bbb.accessibility.chat.chatwindow.input')}"
@@ -797,11 +904,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			<mx:Label id="msgTooLongLabel" width="100%" height="100%" includeInLayout="false" visible="false"/>
 		</mx:VBox>
 		<mx:VBox verticalScrollPolicy="off" verticalAlign="middle" height="100%" >
-			<mx:Button label="{ResourceUtil.getInstance().getString('bbb.chat.sendBtn')}" id="sendBtn"
+			<mx:HBox horizontalGap="0">
+				<mx:Button label="{ResourceUtil.getInstance().getString('bbb.chat.sendBtn')}" id="sendBtn"
 					   styleName="chatControlBarSendButtonStyle"
 					   toolTip="{ResourceUtil.getInstance().getString('bbb.chat.sendBtn.toolTip')}" 
 					   click="sendMessages()"
-					   accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.sendBtn.accessibilityName')}"/>  
+					   accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.sendBtn.accessibilityName')}" height="100%"/>
+			</mx:HBox>
 			<mx:ColorPicker id="cmpColorPicker" showTextField="false" width="100%" visible="{chatOptions.colorPickerIsVisible}"
 							includeInLayout="{chatOptions.colorPickerIsVisible}" 
 							toolTip="{ResourceUtil.getInstance().getString('bbb.chat.cmpColorPicker.toolTip')}" 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatMessageRenderer.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatMessageRenderer.mxml
index 9085ba45d402233daa0b47463d0843d2239e89c1..450ab76e26c283977226b65388bbecb8d841a2c0 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatMessageRenderer.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatMessageRenderer.mxml
@@ -62,9 +62,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				//remove the header if not needed to save space
 				hbHeader.includeInLayout = hbHeader.visible = lblName.visible || lblTime.visible;
 				
-				// adjust the name width so that "..." are added if it's too long
-				lblName.width = this.width - lblTime.width - 22;
-				
 				// If you remove this some of the chat messages will fail to render
 				validateNow();
 			}
@@ -79,7 +76,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	</mx:Script>
 	
   <mx:Canvas width="100%" id="hbHeader" verticalScrollPolicy="off" horizontalScrollPolicy="off">
-    <mx:Label id="lblName" text="{data.name}" visible="true" color="gray" textAlign="left" left="0"/>
+    <mx:Label id="lblName" text="{data.name}" visible="true" color="gray" textAlign="left" left="0" width="{this.width - lblTime.width - 22}"/>
     <mx:Text id="lblTime" htmlText="{data.time}" textAlign="right"
              visible="true" 
              color="gray" right="4" />
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatToolbar.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatToolbar.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..8eb19eed8c20733a2227d699c506d72ed10b81c1
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatToolbar.mxml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<mx:VBox xmlns="flexlib.containers.*"
+		initialize="init()"
+		xmlns:mx="http://www.adobe.com/2006/mxml"
+		xmlns:mate="http://mate.asfusion.com/"
+		xmlns:common="org.bigbluebutton.common.*"
+		creationComplete="onCreationComplete()"
+		visible="{toolbarVisible}"
+		styleName="chatToolbarStyle"
+		horizontalAlign="center"
+		hideEffect="{fadeOut}" showEffect="{fadeIn}"
+		backgroundColor="{bgColor}">
+
+	<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="onChangeMyRole" />
+
+	<mx:Script>
+		<![CDATA[
+			import mx.core.UIComponent;
+			import com.asfusion.mate.events.Dispatcher;
+
+			import org.bigbluebutton.core.UsersUtil;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
+			import org.bigbluebutton.modules.chat.events.ChatToolbarButtonEvent;
+			import org.bigbluebutton.modules.chat.model.ChatOptions;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+
+			import mx.controls.Alert;
+			import mx.core.UIComponent;
+			import mx.events.CloseEvent;
+
+			[Bindable] public var chatOptions:ChatOptions;
+			[Bindable] private var baseIndex:int;
+			[Bindable] private var toolbarVisible:Boolean = false;
+			[Bindable] private var bgColor:Number = 0xCCCCCC;
+			[Bindable] private var clrBtnVisible:Boolean = false;
+
+			private var mousedOver:Boolean = false;
+			private var globalDispatcher:Dispatcher;
+			private var _toolbarHideTimer:Timer;
+
+			[Bindable] public var publicChat:Boolean = true;
+
+			public function init():void{
+				chatOptions = new ChatOptions();
+				baseIndex = chatOptions.baseTabIndex;
+
+				_toolbarHideTimer = new Timer(500, 1);
+				_toolbarHideTimer.addEventListener(TimerEvent.TIMER, closeToolbar);
+				clrBtnVisible = UsersUtil.amIModerator() && publicChat;
+			}
+
+			private function onCreationComplete():void {
+				globalDispatcher = new Dispatcher();
+				this.addEventListener(MouseEvent.ROLL_OVER, handleMouseIn);
+				this.addEventListener(MouseEvent.ROLL_OUT, handleMouseOut);
+			}
+
+			private function checkVisibility():void {
+				toolbarVisible = (toolbarAllowed() && mousedOver);
+			}
+
+			public function closeToolbar(e:TimerEvent = null):void {
+				mousedOver = false;
+				checkVisibility();
+			}
+
+			private function handleMouseIn(e:MouseEvent = null):void {
+				_toolbarHideTimer.reset();
+				mousedOver = true;
+				checkVisibility();
+			}
+
+			private function handleMouseOut(e:MouseEvent = null):void {
+				_toolbarHideTimer.reset();
+				_toolbarHideTimer.start();
+			}
+
+			private function toolbarAllowed():Boolean {
+				// Created to make possible to create rules to allow or not the toolbar
+				return true;
+			}
+
+			public function sendSaveEvent():void{
+				var saveEvent:ChatToolbarButtonEvent = new ChatToolbarButtonEvent(ChatToolbarButtonEvent.SAVE_CHAT_TOOLBAR_EVENT);
+				globalDispatcher.dispatchEvent(saveEvent);
+			}
+
+			public function sendCopyEvent():void{
+				var copyEvent:ChatToolbarButtonEvent = new ChatToolbarButtonEvent(ChatToolbarButtonEvent.COPY_CHAT_TOOLBAR_EVENT);
+				globalDispatcher.dispatchEvent(copyEvent);
+			}
+
+			public function sendClearEvent():void{
+				var clearChatHistoryAlert:Alert = Alert.show(ResourceUtil.getInstance().getString('bbb.chat.clearBtn.alert.text'),
+					ResourceUtil.getInstance().getString('bbb.chat.clearBtn.alert.title'),
+					Alert.YES | Alert.NO, null, handleClearChatHistoryAlert, null, Alert.YES);
+			}
+
+			private function handleClearChatHistoryAlert(e:CloseEvent):void {
+				if (e.detail == Alert.YES) {
+					var clearEvent:ChatToolbarButtonEvent = new ChatToolbarButtonEvent(ChatToolbarButtonEvent.CLEAR_PUBLIC_CHAT_TOOLBAR_EVENT);
+					globalDispatcher.dispatchEvent(clearEvent);
+				}
+			}
+
+			public function onChangeMyRole(e:ChangeMyRole):void{
+				clearBtn.visible = clearBtn.enabled = clearBtn.includeInLayout = clrBtnVisible = UsersUtil.amIModerator() && publicChat;
+			}
+
+			public function registerListeners(component:UIComponent):void {
+				component.addEventListener(MouseEvent.ROLL_OVER, handleMouseIn);
+				component.addEventListener(MouseEvent.ROLL_OUT, handleMouseOut);
+			}
+		]]>
+	</mx:Script>
+
+	<common:TabIndexer id="tabIndexer" tabIndices="{[saveBtn, copyBtn, clearBtn]}"/>
+
+	<mx:Fade id="fadeOut" duration="200" alphaFrom="1.0" alphaTo="0.0"/>
+	<mx:Fade id="fadeIn" duration="200" alphaFrom="0.0" alphaTo="1.0"/>
+
+	<mx:Button id="saveBtn"
+			styleName="chatSaveButtonStyle"
+			width="22"
+			height="22"
+			toolTip="{ResourceUtil.getInstance().getString('bbb.chat.saveBtn.toolTip')}"
+			click="sendSaveEvent()"
+			accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.saveBtn.accessibilityName')}"/>
+
+	<mx:Button id="copyBtn"
+			styleName="chatCopyButtonStyle"
+			width="22"
+			height="22"
+			toolTip="{ResourceUtil.getInstance().getString('bbb.chat.copyBtn.toolTip')}"
+			click="sendCopyEvent()"
+			accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.copyBtn.accessibilityName')}"/>
+
+	<mx:Button id="clearBtn"
+			styleName="chatClearButtonStyle"
+			width="22"
+			height="22"
+			visible = "{clrBtnVisible}"
+			enabled = "{clrBtnVisible}"
+			includeInLayout = "{clrBtnVisible}"
+			toolTip="{ResourceUtil.getInstance().getString('bbb.chat.clearBtn.toolTip')}"
+			click="sendClearEvent()"
+			accessibilityName="{ResourceUtil.getInstance().getString('bbb.chat.clearBtn.accessibilityName')}"/>
+</mx:VBox>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml
index b651a037cf41cf77917a043d8a16a742f8521c0a..f15f3bc952d9712499bff303973de4ef57b6954d 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatView.mxml
@@ -32,6 +32,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   <mate:Listener type="{PublicChatMessageEvent.PUBLIC_CHAT_MESSAGE_EVENT}" method="handlePublicChatMessageEvent"/>
   <mate:Listener type="{EventConstants.START_PRIVATE_CHAT}" method="handleStartPrivateChatMessageEvent"/>
   <mate:Listener type="{ShortcutEvent.FOCUS_CHAT_TABS}" method="focusChatTabs" />
+  <mate:Listener type="{ChatToolbarButtonEvent.SAVE_CHAT_TOOLBAR_EVENT}" method="dispatchSaveChatEvent" />
+  <mate:Listener type="{ChatToolbarButtonEvent.COPY_CHAT_TOOLBAR_EVENT}" method="dispatchCopyChatEvent" />
   <mate:Listener type="{ShortcutEvent.CLOSE_PRIVATE}" method="remoteClosePrivate" />
   
 	<mx:Script>
@@ -54,12 +56,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.core.events.CoreEvent;
 			import org.bigbluebutton.main.events.ShortcutEvent;
+			import org.bigbluebutton.modules.chat.events.ChatCopyEvent;
 			import org.bigbluebutton.modules.chat.events.ChatNoiseEnabledEvent;
+			import org.bigbluebutton.modules.chat.events.ChatSaveEvent;
 			import org.bigbluebutton.modules.chat.events.PrivateChatMessageEvent;
 			import org.bigbluebutton.modules.chat.events.PublicChatMessageEvent;
 			import org.bigbluebutton.modules.chat.model.ChatOptions;
 			import org.bigbluebutton.util.i18n.ResourceUtil;			
 					
+			import org.bigbluebutton.modules.chat.events.ChatToolbarButtonEvent;
+
 	    private static const PUBLIC_CHAT_USERID:String = 'public_chat_userid';
 	    private var PUBLIC_CHAT_USERNAME:String = ResourceUtil.getInstance().getString("bbb.chat.publicChatUsername");
 	    private var OPTION_TAB_ID:String = ResourceUtil.getInstance().getString("bbb.chat.optionsTabName");
@@ -107,6 +113,33 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				systemManager.stage.addEventListener(Event.ACTIVATE, activate);
 				systemManager.stage.addEventListener(Event.DEACTIVATE, deactivate);
 			}       
+
+			private function getVisibleChatBox():ChatBox {
+				var chatBox:ChatBox = chatTabs.getChildAt(chatTabs.selectedIndex) as ChatBox;
+				return chatBox;
+			}
+
+			private function dispatchSaveChatEvent(e:Event):void {
+				var chatBox:ChatBox = getVisibleChatBox();
+				var saveEvent:ChatSaveEvent = new ChatSaveEvent(ChatSaveEvent.SAVE_CHAT_EVENT);
+
+				if (chatBox.chatWithUsername == null || chatBox.chatWithUsername == "") {
+					saveEvent.filename = ResourceUtil.getInstance().getString('bbb.chat.save.filename');
+				} else {
+					saveEvent.filename = chatBox.chatWithUsername;
+				}
+
+				saveEvent.chatMessages = chatBox.getChatMessages();
+				globalDispatcher.dispatchEvent(saveEvent);
+			}
+
+			private function dispatchCopyChatEvent(e:Event):void {
+				var chatBox:ChatBox = getVisibleChatBox();
+				var copyEvent:ChatCopyEvent = new ChatCopyEvent(ChatCopyEvent.COPY_CHAT_EVENT);
+
+				copyEvent.chatMessages = chatBox.getChatMessages();
+				globalDispatcher.dispatchEvent(copyEvent);
+			}
 			
 			private function focusChatTabs(e:ShortcutEvent):void{
 				focusManager.setFocus(chatTabs);
@@ -366,6 +399,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					chatTabs.removeChild(selectedTab as DisplayObject);
 				}
 			}
+
+			// This message comes from the chat box and must get to the chat window
+			public function handleDraggableStatus(value:Boolean):void {
+				parentDocument.handleDraggableStatus(value);
+			}
+
+			// This message comes from the chat box and must get to the chat window
+			public function handleResizableStatus(value:Boolean):void {
+				parentDocument.handleResizableStatus(value);
+			}
 			
 		]]>
 	</mx:Script>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatWindow.mxml
index 4be28c107ce20ca33f36e8f0da72e38f30e0ebeb..681270b2f484af9b6f99e2100ce575ee19a54cc1 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/chat/views/ChatWindow.mxml
@@ -175,6 +175,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			override protected function showAllChildren():void {
 				chatView.includeInLayout=true;
 			}
+
+			public function handleDraggableStatus(value:Boolean):void {
+				this.draggable = value;
+			}
+
+			public function handleResizableStatus(value:Boolean):void {
+				this.resizable = value;
+			}
 			
 		]]>
 	</mx:Script>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutEvent.as
old mode 100755
new mode 100644
index 7f95201e26a76d2eb9331cab62eed675d4487b8b..d04dfcc515d344797befab916d2edf14d6087e6e
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutEvent.as
@@ -22,17 +22,24 @@ package org.bigbluebutton.modules.layout.events
 
   public class LayoutEvent extends Event
   {
+    public static const SYNC_LAYOUT_EVENT:String = 'SYNC_LAYOUT_EVENT';
     public static const BROADCAST_LAYOUT_EVENT:String = 'BROADCAST_LAYOUT_EVENT';
+    public static const LOCK_LAYOUT_EVENT:String = 'LOCK_LAYOUT_EVENT';
+    public static const UNLOCK_LAYOUT_EVENT:String = 'UNLOCK_LAYOUT_EVENT';
     public static const STOP_LAYOUT_MODULE_EVENT:String = 'STOP_LAYOUT_MODULE_EVENT';
     public static const VIEW_INITIALIZED_EVENT:String = 'VIEW_INITIALIZED_EVENT';
 
     public static const SAVE_LAYOUTS_EVENT:String = 'SAVE_LAYOUTS_EVENT';
+    public static const SAVE_LAYOUTS_WINDOW_EVENT:String = 'SAVE_LAYOUTS_WINDOW_EVENT';
     public static const LOAD_LAYOUTS_EVENT:String = 'LOAD_LAYOUTS_EVENT';
     public static const ADD_CURRENT_LAYOUT_EVENT:String = 'ADD_CURRENT_LAYOUT_EVENT';
     public static const FILE_LOADED_SUCCESSFULLY_EVENT:String = 'FILE_LOADED_SUCCESSFULLY_EVENT';
     public static const APPLY_DEFAULT_LAYOUT_EVENT:String = 'APPLY_DEFAULT_LAYOUT_EVENT';
     public static const INVALIDATE_LAYOUT_EVENT:String = 'INVALIDATE_LAYOUT_EVENT';
 
+    public var layoutName:String = "";
+    public var overwrite:Boolean = false;
+
     public function LayoutEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
     {
       super(type, bubbles, cancelable);
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutNameInUseEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutNameInUseEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..b2610b99d18f8326cea79005fd648a9005d38036
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/events/LayoutNameInUseEvent.as
@@ -0,0 +1,35 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.modules.layout.events
+{
+	import flash.events.Event;
+	import org.bigbluebutton.modules.layout.model.LayoutDefinitionFile;
+
+	public class LayoutNameInUseEvent extends Event
+	{
+		public static const LAYOUT_NAME_IN_USE_EVENT:String = "LAYOUT_NAME_IN_USE_EVENT";
+
+		public var inUse:Boolean = false;
+
+		public function LayoutNameInUseEvent(type:String = LAYOUT_NAME_IN_USE_EVENT)
+		{
+			super(type,true,false);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/LayoutManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/LayoutManager.as
old mode 100644
new mode 100755
index 65889d7e5cc56564d3a9251cfce31f5ca8b10a53..c432b075798d1826eb1b98f43d0d03f9e6044a03
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/LayoutManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/managers/LayoutManager.as
@@ -20,14 +20,24 @@ package org.bigbluebutton.modules.layout.managers
 {
   import com.asfusion.mate.events.Dispatcher;
   
+  import flash.display.DisplayObject;
+  import mx.core.FlexGlobals;
+  import mx.core.IFlexDisplayObject;
+  import mx.managers.PopUpManager;
+  import org.bigbluebutton.util.i18n.ResourceUtil;
   import flash.events.Event;
   import flash.events.EventDispatcher;
   import flash.events.TimerEvent;
   import flash.net.FileReference;
+  import flash.net.URLLoader;
+  import flash.net.URLRequest;
+  import flash.utils.Dictionary;
   import flash.utils.Timer;
   
   import mx.controls.Alert;
   import mx.events.ResizeEvent;
+  import mx.events.EffectEvent;
+  import mx.events.CloseEvent;
   
   import flexlib.mdi.containers.MDICanvas;
   import flexlib.mdi.containers.MDIWindow;
@@ -36,21 +46,29 @@ package org.bigbluebutton.modules.layout.managers
   import org.as3commons.logging.api.ILogger;
   import org.as3commons.logging.api.getClassLogger;
   import org.bigbluebutton.common.CustomMdiWindow;
+  import org.bigbluebutton.core.EventBroadcaster;
   import org.bigbluebutton.core.UsersUtil;
   import org.bigbluebutton.core.events.SwitchedLayoutEvent;
   import org.bigbluebutton.core.managers.UserManager;
+  import org.bigbluebutton.core.model.Config;
+  import org.bigbluebutton.main.events.ModuleLoadEvent;
   import org.bigbluebutton.main.model.LayoutOptions;
   import org.bigbluebutton.modules.layout.events.LayoutFromRemoteEvent;
   import org.bigbluebutton.main.model.users.BBBUser;
+  import org.bigbluebutton.modules.layout.events.LayoutEvent;
   import org.bigbluebutton.modules.layout.events.LayoutLockedEvent;
   import org.bigbluebutton.modules.layout.events.LayoutsLoadedEvent;
   import org.bigbluebutton.modules.layout.events.LayoutsReadyEvent;
   import org.bigbluebutton.modules.layout.events.LockLayoutEvent;
   import org.bigbluebutton.modules.layout.events.RemoteSyncLayoutEvent;
+  import org.bigbluebutton.modules.layout.events.LayoutNameInUseEvent;
   import org.bigbluebutton.modules.layout.events.SyncLayoutEvent;
   import org.bigbluebutton.modules.layout.model.LayoutDefinition;
+  import org.bigbluebutton.modules.layout.model.LayoutDefinitionFile;
   import org.bigbluebutton.modules.layout.model.LayoutLoader;
   import org.bigbluebutton.modules.layout.model.LayoutModel;
+  import org.bigbluebutton.modules.layout.model.WindowLayout;
+  import org.bigbluebutton.modules.layout.views.CustomLayoutNameWindow;
   import org.bigbluebutton.util.i18n.ResourceUtil;
 
 	public class LayoutManager extends EventDispatcher {
@@ -60,29 +78,23 @@ package org.bigbluebutton.modules.layout.managers
 		private var _globalDispatcher:Dispatcher = new Dispatcher();
 		private var _locked:Boolean = false;
 		private var _currentLayout:LayoutDefinition = null;
-		private var _detectContainerChange:Boolean = true;
-		private var _containerDeactivated:Boolean = false;
 		private var _customLayoutsCount:int = 0;
 		private var _serverLayoutsLoaded:Boolean = false;
-    private var _sendCurrentLayoutUpdateTimer:Timer = new Timer(500,1);
-    private var _applyCurrentLayoutTimer:Timer = new Timer(150,1);
+		private var _applyCurrentLayoutTimer:Timer = new Timer(150,1);
+		private var _applyingLayoutCounter:int = 0;
+		private var _temporaryLayoutName:String = "";
     
     private var _layoutModel:LayoutModel = LayoutModel.getInstance();
     
-		private var _eventsToDelay:Array = new Array(MDIManagerEvent.WINDOW_RESTORE,
-				MDIManagerEvent.WINDOW_MINIMIZE,
-				MDIManagerEvent.WINDOW_MAXIMIZE);
-		
+    /**
+    * If we sync automatically with other users while the action (move, resize) is done on the
+    * window.
+    */
+    private var _autoSync:Boolean = false;
 
     public function LayoutManager() {
       _applyCurrentLayoutTimer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void {
-        //trace(LOG + " timerEvent layout [" + _currentLayout.name +  "]");
-        applyLayout(_currentLayout);
-        //trace(LOG + "Applied layout after user resized browser");
-      });
-      _sendCurrentLayoutUpdateTimer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void {
-        //trace(LOG + "Applying layout due to window resize");
-        updateCurrentLayout(null);
+        applyLayout(currentLayout);
       });
     }
     
@@ -117,21 +129,104 @@ package org.bigbluebutton.modules.layout.managers
     }
 		
 		public function saveLayoutsToFile():void {
+			if (!_currentLayout.currentLayout) {
+				var alertSaveCurrentLayToFile:Alert = Alert.show(ResourceUtil.getInstance().getString('bbb.layout.addCurrentToFileWindow.text'),
+					ResourceUtil.getInstance().getString('bbb.layout.addCurrentToFileWindow.title'),
+					Alert.YES | Alert.NO, _canvas, alertSaveCurrentLayoutFile, null, Alert.YES);
+			} else {
+				saveLayoutsWindow();
+			}
+		}
+
+		public function alertSaveCurrentLayoutFile(e:CloseEvent):void {
+				// Check to see if the YES button was pressed.
+				if (e.detail==Alert.YES) {
+					var layoutNameWindow:CustomLayoutNameWindow = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as DisplayObject, CustomLayoutNameWindow, true) as CustomLayoutNameWindow;
+					layoutNameWindow.savingForFileDownload = true;
+					PopUpManager.centerPopUp(layoutNameWindow);
+				} else if (e.detail==Alert.NO){
+					saveLayoutsWindow();
+				}
+			}
+
+		public function saveLayoutsWindow():void{
 			var _fileRef:FileReference = new FileReference();
 			_fileRef.addEventListener(Event.COMPLETE, function(e:Event):void {
 				Alert.show(ResourceUtil.getInstance().getString('bbb.layout.save.complete'), "", Alert.OK, _canvas);
 			});
 			_fileRef.save(_layoutModel.toString(), "layouts.xml");
 		}
-				
-		public function addCurrentLayoutToList():void {
-				_layoutModel.addLayout(_currentLayout);
-        
+
+		public function loadLayoutsFromFile():void {
+			var loader:LayoutLoader = new LayoutLoader();
+			loader.addEventListener(LayoutsLoadedEvent.LAYOUTS_LOADED_EVENT, function(e:LayoutsLoadedEvent):void {
+				if (e.success) {
+					_layoutModel.addLayouts(e.layouts);
+					applyLayout(_layoutModel.getDefaultLayout());
+					broadcastLayouts();
+					Alert.show(ResourceUtil.getInstance().getString('bbb.layout.load.complete'), "", Alert.OK, _canvas);
+				} else
+					Alert.show(ResourceUtil.getInstance().getString('bbb.layout.load.failed'), "", Alert.OK, _canvas);
+			});
+			loader.loadFromLocalFile();
+		}
+
+		public function alertOverwriteLayoutName(event:CloseEvent):void {
+				// Check to see if the YES button was pressed.
+				if (event.detail==Alert.YES) {
+					var e:LayoutEvent = new LayoutEvent(LayoutEvent.ADD_CURRENT_LAYOUT_EVENT);
+					e.overwrite = true;
+					e.layoutName = _temporaryLayoutName;
+					addCurrentLayoutToList(e);
+				} else if (event.detail==Alert.NO){
+					return;
+				}
+			}
+
+		public function addCurrentLayoutToList(e:LayoutEvent):void {
+				// Layout Name Window Popup calls this function
+				var newLayout:LayoutDefinition;
+				var layoutName:LayoutNameInUseEvent = new LayoutNameInUseEvent();
+				_temporaryLayoutName = e.layoutName;
+				if (e.layoutName != "") {
+					newLayout = LayoutDefinition.getLayout(_canvas, e.layoutName);
+					// This is true when the name given is already in use
+					if (_layoutModel.hasLayout(e.layoutName)) {
+
+						if (!e.overwrite) {
+							layoutName.inUse = true;
+							_globalDispatcher.dispatchEvent(layoutName);
+
+							var alertOverwriteLayName:Alert = Alert.show(ResourceUtil.getInstance().getString('bbb.layout.overwriteLayoutName.text'),
+							ResourceUtil.getInstance().getString('bbb.layout.overwriteLayoutName.title'),
+							Alert.YES | Alert.NO, _canvas, alertOverwriteLayoutName, null, Alert.NO);
+
+							return; //to stop the creation of a new layout with the same name
+						} else {
+							_layoutModel.removeLayout(newLayout);
+						}
+					}
+				} else {
+					// if the user does not change the "Custom Layout" name that is default when the windows is shown
+					// the name will be "Custom Layout #", incrementing number # to avoid overwrite
+					newLayout = LayoutDefinition.getLayout(_canvas, ResourceUtil.getInstance().getString('bbb.layout.combo.customName'));
+					newLayout.name += " " + (++_customLayoutsCount);
+				}
+
+				_layoutModel.addLayout(newLayout);
+				updateCurrentLayout(newLayout);
+				broadcastLayouts();
+
 				var redefineLayout:LayoutFromRemoteEvent = new LayoutFromRemoteEvent();
-				redefineLayout.layout = _currentLayout;
+				redefineLayout.layout = newLayout;
 				// this is to force LayoutCombo to update the current label
 				redefineLayout.remote = true;
 				_globalDispatcher.dispatchEvent(redefineLayout);
+
+				layoutName.inUse = false;
+				_temporaryLayoutName = "";
+
+				_globalDispatcher.dispatchEvent(layoutName);
 		}
 		
 		public function setCanvas(canvas:MDICanvas):void {
@@ -139,18 +234,30 @@ package org.bigbluebutton.modules.layout.managers
 
 			// this is to detect changes on the container
 			_canvas.windowManager.container.addEventListener(ResizeEvent.RESIZE, onContainerResized);
-//	        _canvas.windowManager.container.addEventListener(Event.ACTIVATE, onContainerActivated);
-//	        _canvas.windowManager.container.addEventListener(Event.DEACTIVATE, onContainerDeactivated);
-
-			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_RESIZE_END, onActionOverWindowFinished);
-			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_DRAG_END, onActionOverWindowFinished);
-			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_MINIMIZE, onActionOverWindowFinished);
-			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_MAXIMIZE, onActionOverWindowFinished);
-			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_RESTORE, onActionOverWindowFinished);
+			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_RESIZE_END, onMDIManagerEvent);
+			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_DRAG_END, onMDIManagerEvent);
+			_canvas.windowManager.addEventListener(EffectEvent.EFFECT_END, function(e:EffectEvent):void {
+				var obj:Object = (e as Object);
+				if (obj.mdiEventType == "windowAdd") {
+					LOGGER.debug("Ignoring windowAdd");
+					return;
+				}
+				var windows:Array = obj.windows;
+				if (windows != null) {
+					for each (window in windows) {
+						LOGGER.debug(e.type + "/" + obj.mdiEventType + " on window " + WindowLayout.getType(window));
+						onActionOverWindowFinished(window);
+					}
+				} else {
+					LOGGER.debug(e.type + "/" + obj.mdiEventType + " with no window associated");
+				}
+			});
 			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_ADD, function(e:MDIManagerEvent):void {
-				checkPermissionsOverWindow(e.window);
-        //trace(LOG + " setCanvas layout [" + _currentLayout.name +  "]");
-				applyLayout(_currentLayout);
+				e.window.callLater(function():void {
+					checkSingleWindowPermissions(e.window);
+					LOGGER.debug("applying layout to just created window " + WindowLayout.getType(e.window));
+					applyLayout(_currentLayout);
+				});
 			});
 			
 			_canvas.windowManager.addEventListener(MDIManagerEvent.WINDOW_FOCUS_START, function(e:MDIManagerEvent):void {
@@ -200,6 +307,12 @@ package org.bigbluebutton.modules.layout.managers
       layoutEvent.layoutID = layoutID;
       _globalDispatcher.dispatchEvent(layoutEvent);      
     }
+
+    public function syncLayout():void {
+      if (UsersUtil.amIModerator() || UsersUtil.amIPresenter()) {
+        _globalDispatcher.dispatchEvent(new SyncLayoutEvent(_currentLayout));
+      }
+    }
       
 		public function lockLayout():void {
 			_locked = true;
@@ -211,6 +324,8 @@ package org.bigbluebutton.modules.layout.managers
 			//trace(LOG + " layout changed by me. Sync others to this new layout.");
 			var e:SyncLayoutEvent = new SyncLayoutEvent(_currentLayout);
 			_globalDispatcher.dispatchEvent(e);
+
+			Alert.show(ResourceUtil.getInstance().getString('bbb.layout.sync'), "", Alert.OK, _canvas);
 		}
 		
 		private function sendLayoutUpdate(layout:LayoutDefinition):void {
@@ -222,16 +337,36 @@ package org.bigbluebutton.modules.layout.managers
 		}
 		
 		private function applyLayout(layout:LayoutDefinition):void {
-			_detectContainerChange = false;
+			LOGGER.debug("applyLayout");
+			detectContainerChange = false;
+
 			if (layout != null) {
-        layout.applyToCanvas(_canvas);
-        dispatchSwitchedLayoutEvent(layout.name);
-      }
-      //trace(LOG + " applyLayout layout [" + layout.name +  "]");	
+				layout.applyToCanvas(_canvas, function():void {
+					LOGGER.debug("layout applied successfully, resetting detectContainerChange");
+					detectContainerChange = true;
+				});
+				dispatchSwitchedLayoutEvent(layout.name);
+				UserManager.getInstance().getConference().numAdditionalSharedNotes = layout.numAdditionalSharedNotes;
+			} else {
+				detectContainerChange = true;
+			}
 			updateCurrentLayout(layout);
-			_detectContainerChange = true;
 		}
 
+    private function set detectContainerChange(detect:Boolean):void {
+      LOGGER.debug("setting detectContainerChange to " + detect);
+      if (detect) {
+        _applyingLayoutCounter--;
+      } else {
+        _applyingLayoutCounter++;
+      }
+      LOGGER.debug("current value of detectContainerChange: " + detectContainerChange);
+    }
+
+    private function get detectContainerChange():Boolean {
+      return _applyingLayoutCounter == 0;
+    }
+
     public function handleLockLayoutEvent(e: LockLayoutEvent):void {
       
     }
@@ -239,13 +374,13 @@ package org.bigbluebutton.modules.layout.managers
     
     public function handleLayoutLockedEvent(e: LayoutLockedEvent):void {
       _locked = e.locked;
-      checkPermissionsOverWindow();
+      checkWindowsPermissions();
     }
 
     public function lockSettingsChanged():void {
       var myUser:BBBUser = UserManager.getInstance().getConference().getMyUser();
       _locked = myUser.lockedLayout;
-      checkPermissionsOverWindow();
+      checkWindowsPermissions();
     }
     
 		public function applyRemoteLayout(e:LayoutFromRemoteEvent):void {
@@ -257,29 +392,28 @@ package org.bigbluebutton.modules.layout.managers
 		public function remoteLockLayout():void {
 			//trace(LOG + " remote lock received");
 			_locked = true;
-			checkPermissionsOverWindow();
+			checkWindowsPermissions();
 		}
 		
     public function remoteSyncLayout(event:RemoteSyncLayoutEvent):void {
-      //trace(LOG + " remote lock received");
-      
-      checkPermissionsOverWindow();
+      checkWindowsPermissions();
     }
     
 		public function remoteUnlockLayout():void {
 			//trace(LOG + " remote unlock received");
 			_locked = false;
-			checkPermissionsOverWindow();
+			checkWindowsPermissions();
 		}
 		
-		private function checkPermissionsOverWindow(window:MDIWindow=null):void {
-			if (UsersUtil.amIModerator()) return;
-			if (window != null && !LayoutDefinition.ignoreWindow(window)) {
-				(window as CustomMdiWindow).unlocked = !_locked;
-			} else {
-				for each (window in _canvas.windowManager.windowList) {
-					checkPermissionsOverWindow(window);
-				}
+		private function checkWindowsPermissions():void {
+			for each (var window:MDIWindow in _canvas.windowManager.windowList) {
+				checkSingleWindowPermissions(window);
+			}
+		}
+
+		private function checkSingleWindowPermissions(window:MDIWindow):void {
+			if (!LayoutDefinition.ignoreWindow(window)) {
+				(window as CustomMdiWindow).unlocked = !_locked || UsersUtil.amIModerator() || UsersUtil.amIPresenter();
 			}
 		}
 		
@@ -294,35 +428,55 @@ package org.bigbluebutton.modules.layout.managers
       _applyCurrentLayoutTimer.reset();
       _applyCurrentLayoutTimer.start();
 		}
+
+		private function onMDIManagerEvent(e:MDIManagerEvent):void {
+			LOGGER.debug("Window has been modified. Event=[" + e.type + "]");
+			onActionOverWindowFinished(e.window);
+		}
+
+		private function onActionOverWindowFinished(window:MDIWindow):void {
+			if (LayoutDefinition.ignoreWindow(window))
+				return;
 			
-    private function onActionOverWindowFinished(e:MDIManagerEvent):void {
-      if (LayoutDefinition.ignoreWindow(e.window))
-        return;
-      
-      checkPermissionsOverWindow(e.window);
-      //trace(LOG + "Window is being resized. Event=[" + e.type + "]");
-      //updateCurrentLayout(null);
-      /*
-       * 	All events must be delayed because the window doesn't actually 
-	   *    change size until after the animation has finished.
-       */
-      _sendCurrentLayoutUpdateTimer.reset();
-      _sendCurrentLayoutUpdateTimer.start();
-    }
+			checkSingleWindowPermissions(window);
+
+			updateCurrentLayout();
+			if (_autoSync) {
+				sendLayoutUpdate(currentLayout);
+			}
+		}
 		
-		private function updateCurrentLayout(layout:LayoutDefinition):LayoutDefinition {
-      //trace(LOG + "updateCurrentLayout");
+    private function updateCurrentLayout(layout:LayoutDefinition=null):LayoutDefinition {
       if (layout != null) {
         if (_currentLayout) _currentLayout.currentLayout = false;
         _currentLayout = layout;
         //trace(LOG + "updateCurrentLayout - currentLayout = [" + layout.name + "]");
         layout.currentLayout = true;
-      } else {
+      } else if (detectContainerChange) {
+        LOGGER.debug("invalidating layout event");
+        _globalDispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.INVALIDATE_LAYOUT_EVENT));
         _currentLayout = LayoutDefinition.getLayout(_canvas, ResourceUtil.getInstance().getString('bbb.layout.combo.customName'));
         //trace(LOG + "updateCurrentLayout - layout is NULL! Setting currentLayout = [" + _currentLayout.name + "]");
       }
 
 			return _currentLayout;
 		}
+
+		/*
+		 * This is because a unique layout may have multiple definitions depending
+		 * on the role of the participant
+		 */
+		public function presenterChanged():void {
+			if (_canvas != null)
+				applyLayout(_currentLayout);
+		}
+
+		public function set currentLayout(value:LayoutDefinition):void {
+			_currentLayout = value;
+		}
+
+		public function get currentLayout():LayoutDefinition {
+			return _currentLayout;
+		}
 	}
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMap.mxml
old mode 100755
new mode 100644
index 3482f9b7cb66225b63f87952cc2f725e296cf27e..561000995b30b2cb676c08e6e724b3fe66c3859f
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMap.mxml
@@ -25,6 +25,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       
       import org.bigbluebutton.core.EventConstants;
       import org.bigbluebutton.core.events.LockControlEvent;
+      import org.bigbluebutton.main.model.users.events.ChangeMyRole;
       import org.bigbluebutton.main.events.MadePresenterEvent;
       import org.bigbluebutton.modules.layout.events.ChangeLayoutEvent;
       import org.bigbluebutton.modules.layout.events.ComboBoxCreatedEvent;
@@ -64,6 +65,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
    		<MethodInvoker generator="{LayoutEventMapDelegate}" method="stopModule" />
     </EventHandlers>
             
+    <EventHandlers type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}">
+      <MethodInvoker generator="{LayoutEventMapDelegate}" method="refreshRole" arguments="{event}"/>
+    </EventHandlers>
+
     <EventHandlers type="{LayoutEvent.APPLY_DEFAULT_LAYOUT_EVENT}">
    		<MethodInvoker generator="{LayoutManager}" method="applyDefaultLayout" />
     </EventHandlers>
@@ -96,13 +101,25 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     <EventHandlers type="{LayoutFromRemoteEvent.LAYOUT_FROM_REMOTE}">
    		<MethodInvoker generator="{LayoutManager}" method="applyRemoteLayout" arguments="{event}" />
     </EventHandlers>
+
+  <EventHandlers type="{LayoutEvent.SYNC_LAYOUT_EVENT}">
+    <MethodInvoker generator="{LayoutManager}" method="syncLayout" />
+  </EventHandlers>
   
     <EventHandlers type="{LayoutEvent.SAVE_LAYOUTS_EVENT}">
    		<MethodInvoker generator="{LayoutManager}" method="saveLayoutsToFile" />
     </EventHandlers>
 	
+    <EventHandlers type="{LayoutEvent.SAVE_LAYOUTS_WINDOW_EVENT}">
+      <MethodInvoker generator="{LayoutManager}" method="saveLayoutsWindow" />
+    </EventHandlers>
+
+    <EventHandlers type="{LayoutEvent.LOAD_LAYOUTS_EVENT}">
+      <MethodInvoker generator="{LayoutManager}" method="loadLayoutsFromFile" />
+    </EventHandlers>
+
     <EventHandlers type="{LayoutEvent.ADD_CURRENT_LAYOUT_EVENT}">
-   		<MethodInvoker generator="{LayoutManager}" method="addCurrentLayoutToList" />
+      <MethodInvoker generator="{LayoutManager}" method="addCurrentLayoutToList" arguments="{event}"/>
     </EventHandlers>
   
   <EventHandlers type="{EventConstants.SWITCH_LAYOUT_REQ}">
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMapDelegate.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMapDelegate.mxml
index 1bf68677acd20d96f15459a63f3f9ef4b7c33340..8db5397d01279524baca7b45be8aabca2c428b95 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMapDelegate.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/maps/LayoutEventMapDelegate.mxml
@@ -23,13 +23,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
 			
+			import org.bigbluebutton.common.Role;
 			import org.bigbluebutton.common.events.ToolbarButtonEvent;
 			import org.bigbluebutton.main.model.LayoutOptions;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
 			import org.bigbluebutton.modules.layout.views.ToolbarComponent;
 			
 			private var _attributes:Object;
 			private var _globalDispatcher:Dispatcher = new Dispatcher();
 			private var options:LayoutOptions = new LayoutOptions();
+			private var layoutComponent:ToolbarComponent;
 			
 			public function stopModule():void {
 			}
@@ -38,7 +41,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				_attributes = attributes;
 				options.parseOptions();
 				
-				var layoutComponent:ToolbarComponent = new ToolbarComponent();
+				layoutComponent = new ToolbarComponent();
 				
 				// using the negation will keep it enabled if the property is not there
 				layoutComponent.enableEdit = !(_attributes.enableEdit == "false");
@@ -49,6 +52,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				_globalDispatcher.dispatchEvent(event);
 				
 			}
+
+			public function refreshRole(e:ChangeMyRole):void {
+				layoutComponent.enableEdit = !(_attributes.enableEdit == "false");
+				layoutComponent.refreshRole(e.role == Role.MODERATOR);
+			}
 		]]>
 	</mx:Script>
 </EventMap>
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinition.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinition.as
index 57eb6a74c19973bde61a624af421b981f6f85bb9..e92f96ae411fa0d5626432f4686409a625b8734d 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinition.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinition.as
@@ -26,6 +26,7 @@ package org.bigbluebutton.modules.layout.model {
 	import org.as3commons.logging.api.getClassLogger;
 	import org.bigbluebutton.common.Role;
 	import org.bigbluebutton.core.managers.UserManager;
+	import org.bigbluebutton.modules.layout.managers.OrderManager;
 
 	public class LayoutDefinition {
 		
@@ -41,7 +42,7 @@ package org.bigbluebutton.modules.layout.model {
 		
 		static private var _ignoredWindows:Array = new Array("AvatarWindow", "PublishWindow", 
 				"VideoWindow", "DesktopPublishWindow", "DesktopViewWindow",
-				"LogWindow");
+				"LogWindow", "NetworkStatsWindow", "ShortcutHelpWindow");
 		static private var _roles:Array = new Array(Role.VIEWER, Role.MODERATOR, Role.PRESENTER);
 				
 		private function loadLayout(vxml:XML):void {
@@ -130,24 +131,81 @@ package org.bigbluebutton.modules.layout.model {
 			return xml;
 		}
 		
-		public function applyToCanvas(canvas:MDICanvas):void {
-			if (canvas == null)
+		/*
+		 * 0 if there's no order
+		 * 1 if "a" should appears after "b"
+		 * -1 if "a" should appears before "b"
+		 */
+		private function sortWindows(a:Object, b:Object):int {
+			// ignored windows are positioned in front
+			if (a.ignored && b.ignored) return 0;
+			if (a.ignored) return 1;
+			if (b.ignored) return -1;
+			// then comes the windows that has no layout definition
+			if (!a.hasLayoutDefinition && !b.hasLayoutDefinition) return 0;
+			if (!a.hasLayoutDefinition) return 1;
+			if (!b.hasLayoutDefinition) return -1;
+			// then the focus order is used to sort
+			if (a.order == b.order) return 0;
+			if (a.order == -1) return 1;
+			if (b.order == -1) return -1;
+			return (a.order < b.order? 1: -1);
+		}
+
+		private function adjustWindowsOrder(canvas:MDICanvas):void {
+			var orderedList:Array = new Array();
+			var type:String;
+			var order:int;
+			var ignored:Boolean;
+			var hasLayoutDefinition:Boolean;
+
+			for each (var window:MDIWindow in canvas.windowManager.windowList) {
+				type = WindowLayout.getType(window);
+				hasLayoutDefinition = myLayout.hasOwnProperty(type);
+				if (hasLayoutDefinition)
+					order = myLayout[type].order;
+				else
+					order = -1;
+				ignored = ignoreWindowByType(type);
+				var item:Object = { window:window, order:order, type:type, ignored:ignored, hasLayoutDefinition:hasLayoutDefinition };
+				orderedList.push(item);
+			}
+			orderedList.sort(this.sortWindows);
+			for each (var obj:Object in orderedList) {
+				if (!obj.ignored)
+					OrderManager.getInstance().bringToFront(obj.window);
+				canvas.windowManager.bringToFront(obj.window);
+			}
+		}
+
+		public function applyToCanvas(canvas:MDICanvas, onLayoutAppliedCallback:Function):void {
+			if (canvas == null) {
+				onLayoutAppliedCallback();
 				return;
+			}
+
+			adjustWindowsOrder(canvas);
 			
-			var windows:Array = canvas.windowManager.windowList;
-			// LogUtil.traceObject(myLayout);
+			var windows:Array = canvas.windowManager.windowList.filter(function(item:*, index:int, array:Array):Boolean {
+				return !ignoreWindow(item as MDIWindow);
+			});
+
+			if (windows.length == 0) {
+				onLayoutAppliedCallback();
+				return;
+			}
 			var transformedLayout:Dictionary = generateWindowsTransformations(myLayout, windows, canvas.width, canvas.height);
 			
 			var type:String;
+			var count:int = windows.length;
 			for each (var window:MDIWindow in windows) {
 				type = WindowLayout.getType(window);
-				//trace(LOG + "Determine if we need to apply layout [" + name + "] for window [" + type + "]");
-				if (!ignoreWindowByType(type)) {
-					//trace(LOG + "Applying layout [" + name + "] to window [" + type + "]");
-					WindowLayout.setLayout(canvas, window, transformedLayout[type]);
-				} else {
-					//trace(LOG + "Ignoring layout [" + name + "] to window [" + type + "]");
-				}
+				WindowLayout.setLayout(canvas, window, transformedLayout[type], function():void {
+					count--;
+					if (count == 0) {
+						onLayoutAppliedCallback();
+					}
+				});
 			}
 		}
 		
@@ -283,17 +341,7 @@ package org.bigbluebutton.modules.layout.model {
 			
 			return copiedLayout;
 		}
-		
-		private function apply(canvas:MDICanvas, window:MDIWindow, type:String=null):void {
-			if (type == null) {
-				type = WindowLayout.getType(window);
-			}
 
-			if (!ignoreWindowByType(type)) {
-				WindowLayout.setLayout(canvas, window, myLayout[type]);
-			}
-		}
-		
 		static private function ignoreWindowByType(type:String):Boolean {
 			return (_ignoredWindows.indexOf(type) != -1);
 		}
@@ -314,5 +362,15 @@ package org.bigbluebutton.modules.layout.model {
 			}
 			return layoutDefinition;
 		}
+
+		public function get numAdditionalSharedNotes():Number {
+			var sharedNotesCounter:int = 0;
+			for each (var window:WindowLayout in _layoutsPerRole[Role.VIEWER]) {
+				if (window.name.indexOf("AdditionalSharedNotesWindow") != -1) {
+					sharedNotesCounter++;
+				}
+			}
+			return sharedNotesCounter;
+		}
 	}
 }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinitionFile.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinitionFile.as
index 4c299c28ba7901adc6e3030f54a03869acb67946..dc1c575d4b9d4bacb6795098d1cf12432e4f985c 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinitionFile.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutDefinitionFile.as
@@ -18,6 +18,8 @@
 */
 package org.bigbluebutton.modules.layout.model
 {
+	import org.bigbluebutton.util.i18n.ResourceUtil;
+
 	public class LayoutDefinitionFile {
 		private var _layouts:Array = new Array();
 		
@@ -49,7 +51,25 @@ package org.bigbluebutton.modules.layout.model
 		public function push(layoutDefinition:LayoutDefinition):void {
 			_layouts.push(layoutDefinition);
 		}
+
+		public function splice(position:int):void{
+			_layouts.splice(position,1);
+		}
 		
+		public function indexOf(layoutName:String):int{
+			for (var i:Number=0; i < _layouts.length; i++){
+				var translatedName:String = ResourceUtil.getInstance().getString(_layouts[i].name);
+				if (translatedName == "undefined"){
+					if(_layouts[i].name == layoutName){
+						return i;
+					}
+				} else if (translatedName == layoutName){
+					return i;
+				}
+			}
+			return -1;
+		}
+
 		public function getDefault():LayoutDefinition {
 			for each (var value:LayoutDefinition in _layouts) {
 				if (value.defaultLayout)
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutModel.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutModel.as
index ba7d8a2c9cd0906c8580520b02256691e4df5dde..c1a7429d3fc7fbec3769515e3aa3b69a52ae5755 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutModel.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/LayoutModel.as
@@ -2,6 +2,7 @@ package org.bigbluebutton.modules.layout.model
 {
   import org.as3commons.logging.api.ILogger;
   import org.as3commons.logging.api.getClassLogger;
+  import org.bigbluebutton.util.i18n.ResourceUtil;
 
   public class LayoutModel
   {
@@ -34,10 +35,9 @@ package org.bigbluebutton.modules.layout.model
     }
     
     public function hasLayout(name:String):Boolean {
-      var layoutName:LayoutDefinition = _layouts.getLayout(name);
-      
-      if (layoutName != null) return true;
-      
+      if (_layouts.indexOf(name) != -1) {
+        return true;
+      }
       return false;
     }
     
@@ -48,6 +48,10 @@ package org.bigbluebutton.modules.layout.model
     public function addLayout(layout: LayoutDefinition):void {
       _layouts.push(layout);
     }
+
+    public function removeLayout(layout: LayoutDefinition):void {
+      if (layout != null) _layouts.splice(_layouts.indexOf(layout.name));
+    }
     
     public function getLayoutNames():Array {
       if (_layouts == null) return new Array();
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/WindowLayout.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/WindowLayout.as
index 86d1dd9ad095b28f168367513ee180b5603a00e8..374dd19af3d4bca517665075b26564d6379c8f99 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/WindowLayout.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/model/WindowLayout.as
@@ -17,21 +17,29 @@
 *
 */
 package org.bigbluebutton.modules.layout.model {
-	import flash.events.TimerEvent;
-	import flash.utils.Timer;
-	import flash.utils.getQualifiedClassName;
-	
-	import mx.effects.Move;
-	import mx.effects.Parallel;
-	import mx.effects.Resize;
-	
-	import flexlib.mdi.containers.MDICanvas;
-	import flexlib.mdi.containers.MDIWindow;
-	
-	import org.bigbluebutton.modules.layout.managers.OrderManager;
+	import flash.display.DisplayObject;
+	import flash.display.DisplayObjectContainer;
+	import flash.events.TimerEvent;
+	import flash.geom.Rectangle;
+	import flash.utils.Dictionary;
+	import flash.utils.getQualifiedClassName;
+	import flash.utils.Timer;
 
-	public class WindowLayout {
+	import flexlib.mdi.containers.MDICanvas;
+	import flexlib.mdi.containers.MDIWindow;
+
+	import mx.effects.Fade;
+	import mx.effects.Move;
+	import mx.effects.Parallel;
+	import mx.effects.Resize;
+	import mx.events.EffectEvent;
 
+	import org.as3commons.logging.api.ILogger;
+	import org.as3commons.logging.api.getClassLogger;
+	import org.bigbluebutton.modules.layout.managers.OrderManager;
+
+	public class WindowLayout {
+		private static const LOGGER:ILogger = getClassLogger(WindowLayout);
 
 		[Bindable] public var name:String;
 		[Bindable] public var width:Number;
@@ -43,10 +51,7 @@ package org.bigbluebutton.modules.layout.model {
 		[Bindable] public var minimized:Boolean = false;
 		[Bindable] public var maximized:Boolean = false;
 		[Bindable] public var hidden:Boolean = false;
-    [Bindable] public var resizable:Boolean = true;
-    [Bindable] public var draggable:Boolean = true;
 		[Bindable] public var order:int = -1;
-		
 
 		static private var EVENT_DURATION:int = 500;
 
@@ -62,14 +67,11 @@ package org.bigbluebutton.modules.layout.model {
 			cloned.minimized = this.minimized;
 			cloned.maximized = this.maximized;
 			cloned.hidden = this.hidden;
-			cloned.resizable = this.resizable;
-			cloned.draggable = this.draggable;
 			cloned.order = this.order;
 			return cloned;
 		}
 
 		public function load(vxml:XML):void {
-//      trace("Load layout \n" + vxml.toXMLString() + "\n");
 			if (vxml != null) {
 				if (vxml.@name != undefined) {
 					name = vxml.@name.toString();
@@ -89,10 +91,6 @@ package org.bigbluebutton.modules.layout.model {
 				if (vxml.@minWidth != undefined) {
 					minWidth = int(vxml.@minWidth);
 				}
-				// not implemented yet
-				//if (vxml.@minHeight != undefined) {
-				//	minHeight = int(vxml.@minHeight);
-				//}
 				if (vxml.@minimized != undefined) {
 					minimized = (vxml.@minimized.toString().toUpperCase() == "TRUE") ? true : false;
 				}
@@ -102,182 +100,165 @@ package org.bigbluebutton.modules.layout.model {
 				if (vxml.@hidden != undefined) {
 					hidden = (vxml.@hidden.toString().toUpperCase() == "TRUE") ? true : false;
 				}
-        if (vxml.@draggable != undefined) {
-          draggable = (vxml.@draggable.toString().toUpperCase() == "TRUE") ? true : false;
-        }
-        if (vxml.@resizable != undefined) {
-          resizable = (vxml.@resizable.toString().toUpperCase() == "TRUE") ? true : false;
-        }
 				if (vxml.@order != undefined) {
 					order = int(vxml.@order);
 				}
 			}
-      
-//      trace("WindowLayout::load for " + name + " [minimized=" + minimized + ",maximized=" 
-//        + maximized + ",hidden=" + hidden + ",drag=" + draggable + ",resize=" + resizable + "]");
 		}
 		
-		static public function getLayout(canvas:MDICanvas, window:MDIWindow):WindowLayout {
+		private static function getWindowDimensionsAndPosition(window:MDIWindow):Rectangle {
+			if (window.minimized || window.maximized) {
+				return window.savedWindowRect;
+			} else {
+				return new Rectangle(window.x, window.y, window.width, window.height);
+			}
+		}
+
+		public static function getLayout(canvas:MDICanvas, window:MDIWindow):WindowLayout {
 			var layout:WindowLayout = new WindowLayout();
+			var windowRect:Rectangle = getWindowDimensionsAndPosition(window);
 			layout.name = getType(window);
-			layout.width = window.width / canvas.width;
-			layout.height = window.height / canvas.height;
+			layout.width = windowRect.width / canvas.width;
+			layout.height = windowRect.height / canvas.height;
 			layout.minWidth = -1;
-			//layout.minHeight = -1;
-			layout.x = window.x / canvas.width;
-			layout.y = window.y / canvas.height;
+			layout.x = windowRect.x / canvas.width;
+			layout.y = windowRect.y / canvas.height;
 			layout.minimized = window.minimized;
 			layout.maximized = window.maximized;
-      layout.resizable = window.resizable;
-      layout.draggable = window.draggable;
 			layout.hidden = !window.visible;
 			layout.order = OrderManager.getInstance().getOrderByRef(window);
-      
-      //trace("WindowLayout::getLayout for " + layout.name + " [minimized=" + layout.minimized + ",maximized=" + layout.maximized + ",hidden=" + layout.hidden 
-      //  + ",drag=" + layout.draggable + ",resize=" + layout.resizable + "]");
-      
 			return layout;
 		}
 		
-		static public function setLayout(canvas:MDICanvas, window:MDIWindow, layout:WindowLayout):void {
-      //if (window == null) trace("WindowLayout::setLayout - window is NULL!!!");
-      //if (layout == null) trace("WindowLayout::setLayout - layout is NULL!!!");
-      //if (layout.name == null) trace("WindowLayout::setLayout - layout.name is NULL!!!");
-      
-      //trace("WindowLayout::setLayout for " + getType(window) + ",layout=" + layout.name + "]");
-      
+		static public function setLayout(canvas:MDICanvas, window:MDIWindow, layout:WindowLayout, onEffectEndCallback:Function):void {
 			if (layout == null) {
-        return;
-      }
-      
-      //trace("WindowLayout::setLayout [minimized=" + layout.minimized + ",maximized=" + layout.maximized + ",hidden=" + layout.hidden 
-      //  + ",drag=" + layout.draggable + ",resize=" + layout.resizable + "]");
-      
-			layout.applyToWindow(canvas, window);
-		}
-		
-		private var _delayedEffects:Array = new Array();
-		private function delayEffect(canvas:MDICanvas, window:MDIWindow):void {
-			var obj:Object = {canvas:canvas, window:window};
-			_delayedEffects.push(obj);
-			var timer:Timer = new Timer(150,1);
-			timer.addEventListener(TimerEvent.TIMER, onTimerComplete);
-			timer.start();
-		}
-		
-		private function onTimerComplete(event:TimerEvent = null):void {
-//      trace("::onTimerComplete");
-			var obj:Object = _delayedEffects.pop();
-			applyToWindow(obj.canvas, obj.window);
+				onEffectEndCallback();
+				return;
+			}
+
+			layout.applyToWindow(canvas, window, onEffectEndCallback);
 		}
 		
-		private function applyToWindow(canvas:MDICanvas, window:MDIWindow):void {
-//      trace("WindowLayout::applyToWindow for " + window.name + " using layout " + this.name + "]");
-      
-			var effect:Parallel = new Parallel();
-			effect.duration = EVENT_DURATION;
-			effect.target = window;
+		private function applyToWindow(canvas:MDICanvas, window:MDIWindow, onEffectEndCallback:Function):void {
+			var newWidth:int = Math.floor(this.width * canvas.width);
+			var newHeight:int = Math.floor(this.height * canvas.height);
+			var newX:int = Math.floor(this.x * canvas.width);
+			var newY:int = Math.floor(this.y * canvas.height);
+			var newWindowRect:Rectangle = new Rectangle(newX, newY, newWidth, newHeight);
+			var type:String = getType(window);
+
+			window.visible = !this.hidden;
 
-      if (window.visible && this.hidden) {
-        window.visible = false;
-      }
-      
-      if (!this.hidden) {
-        window.visible = true;
-      }
-      
-      // fcecagno 06/06/2013
-      // Fixing the issue https://code.google.com/p/bigbluebutton/issues/detail?id=1520
-      // Issue introduced in this commit https://github.com/bigbluebutton/bigbluebutton/commit/20487a75cbadac046e27ce5bdc124048b4bed1e0
-      // There's an important conceptual problem defining draggable and resizable properties for layouts. The problem
-      // is that, when the moderator locks the layout, the viewers shouldn't be able to drag nor resize the windows. But what if
-      // the layout definition says that the layout is draggable and/or resizable? Then, the lock button is no guarantee that
-      // all users are viewing the same window arrangement. My opinion is that the use case should be very well documented, as
-      // well as the expected behavior of these properties. In case we decide to remove completely this implementation, we should
-      // cleanup most part of the changes done in the above commit.
-      //window.draggable = this.draggable;
-      //window.resizable = this.resizable;
-      
 			if (this.minimized) {
-				if (!window.minimized) window.minimize();
+				if (!window.minimized) {
+					doOnEffectEnd(window, "windowMinimize", function():void {
+						window.savedWindowRect = newWindowRect;
+						onEffectEndCallback();
+					});
+					window.minimize();
+				} else {
+					window.savedWindowRect = newWindowRect;
+					onEffectEndCallback();
+				}
 			} else if (this.maximized) {
-				if (!window.maximized) window.maximize();
-			} else if (window.minimized && !this.minimized && !this.hidden) {
+				if (!window.maximized) {
+					doOnEffectEnd(window, "windowMaximize", function():void {
+						window.savedWindowRect = newWindowRect;
+						onEffectEndCallback();
+					});
+					window.maximize();
+				} else {
+					window.savedWindowRect = newWindowRect;
+					onEffectEndCallback();
+				}
+			} else if (!this.minimized && window.minimized) {
+				doOnEffectEnd(window, "windowRestore", function():void {
+					window.callLater(function():void {
+						applyToWindow(canvas, window, onEffectEndCallback);
+					});
+				});
 				window.unMinimize();
-				delayEffect(canvas, window);
-				return;
-			} else if (window.maximized && !this.maximized && !this.hidden) {
+				window.restore();
+			} else if (!this.maximized && window.maximized) {
+				doOnEffectEnd(window, "windowRestore", function():void {
+					window.callLater(function():void {
+						applyToWindow(canvas, window, onEffectEndCallback);
+					});
+				});
 				window.maximizeRestore();
-				delayEffect(canvas, window);
-				return;
+				window.restore();
 			} else {
-				if (!this.hidden) {
-					var newWidth:int = int(this.width * canvas.width);
-					var newHeight:int = int(this.height * canvas.height);
-					var newX:int = int(this.x * canvas.width);
-					var newY:int = int(this.y * canvas.height);
-					
-					if (newX != window.x || newY != window.y) {
-						var mover:Move = new Move();
-						mover.xTo = newX;
-						mover.yTo = newY;
-						effect.addChild(mover);
-					}
+				var effect:Parallel = new Parallel();
+				effect.duration = EVENT_DURATION;
+				effect.target = window;
+
+				if (newX != window.x || newY != window.y) {
+					var mover:Move = new Move();
+					mover.xTo = newX;
+					mover.yTo = newY;
+					effect.addChild(mover);
+				}
+
+				if (newWidth != window.width || newHeight != window.height) {
+					var resizer:Resize = new Resize();
+					resizer.widthTo = newWidth;
+					resizer.heightTo = newHeight;
+					effect.addChild(resizer);
+				}
+
+				if (effect.children.length > 0) {
+					window.addEventListener(EffectEvent.EFFECT_END, function(e:EffectEvent):void {
+						e.currentTarget.removeEventListener(e.type, arguments.callee);
+						onEffectEndCallback();
+					});
 					
-					if (newWidth != window.width || newHeight != window.height) {
-						var resizer:Resize = new Resize();
-						resizer.widthTo = newWidth;
-						resizer.heightTo = newHeight;
-						effect.addChild(resizer)
-					}
+					effect.play();
+				} else {
+					onEffectEndCallback();
 				}
 			}
-      
-      if (window.visible && this.hidden) {
-        window.visible = false;
-      }
-      
-//      trace("WindowLayout::applyToWindow Layout= [minimized=" + this.minimized + ",maximized=" + this.maximized + ",visible=" + !this.hidden 
-//        + ",drag=" + this.draggable + ",resize=" + this.resizable + "]");
-      
-//      trace("WindowLayout::applyToWindow Window = [minimized=" + window.minimized + ",maximized=" + window.maximized + ",visible=" + window.visible 
-//        + ",drag=" + window.draggable + ",resize=" + window.resizable + "]");
+		}
 		
-			if (effect.children.length > 0) {
-				effect.play();
-      }
+		private function doOnEffectEnd(window:MDIWindow, eventType:String, onEffectEndCallback:Function):void {
+			window.windowManager.addEventListener(EffectEvent.EFFECT_END, function(e:EffectEvent):void {
+				try {
+					var obj:Object = (e as Object);
+					var windows:Array = obj.windows;
+					if (obj.mdiEventType == eventType && windows.indexOf(window) != -1) {
+						e.currentTarget.removeEventListener(e.type, arguments.callee);
+						onEffectEndCallback();
+					}
+				} catch (e:Error) {
+					LOGGER.debug(e.toString());
+				}
+			});
 		}
 		
 		static public function getType(obj:Object):String {
-			var qualifiedClass:String = String(getQualifiedClassName(obj));
-			var pattern:RegExp = /(\w+)::(\w+)/g;
-			if (qualifiedClass.match(pattern)) {
-				return qualifiedClass.split("::")[1];
-			} else { 
-				return String(Object).substr(String(Object).lastIndexOf(".") + 1).match(/[a-zA-Z]+/).join();
+			if (obj.hasOwnProperty("windowName")) {
+				return obj.windowName;
+			} else {
+				var qualifiedClass:String = String(getQualifiedClassName(obj));
+				var pattern:RegExp = /(\w+)::(\w+)/g;
+				if (qualifiedClass.match(pattern)) {
+					return qualifiedClass.split("::")[1];
+				} else {
+					return String(Object).substr(String(Object).lastIndexOf(".") + 1).match(/[a-zA-Z]+/).join();
+				}
 			}
 		}
 		
 		public function toAbsoluteXml(canvas:MDICanvas):XML {
 			var xml:XML = <window/>;
 			xml.@name = name;
-			if (minimized)
-				xml.@minimized = true;
-			else if (maximized)
-				xml.@maximized = true;
-			else if (hidden)
-				xml.@hidden = true;
-			else {
-				xml.@width = int(width * canvas.width);
-				xml.@height = int(height * canvas.height);
-				xml.@minWidth = minWidth;
-				//xml.@minHeight = minHeight;
-				xml.@x = int(x * canvas.width);
-				xml.@y = int(y * canvas.height);
-
-				xml.@draggable = draggable;
-				xml.@resizable = resizable;
-			}
+			xml.@minimized = minimized;
+			xml.@maximized = maximized;
+			xml.@hidden = hidden;
+			xml.@width = int(width * canvas.width);
+			xml.@height = int(height * canvas.height);
+			xml.@minWidth = minWidth;
+			xml.@x = int(x * canvas.width);
+			xml.@y = int(y * canvas.height);
 			xml.@order = order;
 			return xml;
 		}
@@ -285,23 +266,14 @@ package org.bigbluebutton.modules.layout.model {
 		public function toXml():XML {
 			var xml:XML = <window/>;
 			xml.@name = name;
-			if (minimized)
-				xml.@minimized = true;
-			else if (maximized)
-				xml.@maximized = true;
-			else if (hidden)
-				xml.@hidden = true;
-			else {
-				xml.@width = width;
-				xml.@height = height;
-				xml.@minWidth = minWidth;
-				//xml.@minHeight = minHeight;
-				xml.@x = x;
-				xml.@y = y;
-
-				xml.@draggable = draggable;
-				xml.@resizable = resizable;
-			}
+			xml.@minimized = minimized;
+			xml.@maximized = maximized;
+			xml.@hidden = hidden;
+			xml.@width = width;
+			xml.@height = height;
+			xml.@minWidth = minWidth;
+			xml.@x = x;
+			xml.@y = y;
 			xml.@order = order;
 			return xml;			
 		}  
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/services/MessageReceiver.as b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/services/MessageReceiver.as
index 74d2e90a90156d02b917c564a5f59e72c1eafa88..f9cdd0049392559c1e106db6afad51a466734300 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/services/MessageReceiver.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/services/MessageReceiver.as
@@ -63,7 +63,7 @@ package org.bigbluebutton.modules.layout.services
     private function onReceivedFirstLayout(message:Object):void {
       LOGGER.debug("LayoutService: handling the first layout. locked = [{0}] layout = [{1}]", [message.locked, message.layout]);
 	  trace("LayoutService: handling the first layout. locked = [" + message.locked + "] layout = [" + message.layout + "], moderator = [" + UsersUtil.amIModerator() + "]");
-	  if(message.layout == "" || UsersUtil.amIModerator())
+	  if(message.layout == "")
 		  _dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.APPLY_DEFAULT_LAYOUT_EVENT));
 	  else {
       	handleSyncLayout(message);
@@ -81,6 +81,9 @@ package org.bigbluebutton.modules.layout.services
       layoutDefinition.load(new XML(message.layout));
       var translatedName:String = ResourceUtil.getInstance().getString(layoutDefinition.name)
       if (translatedName == "undefined") translatedName = layoutDefinition.name;
+      // remove previously added [Remote] mark
+      var pattern:RegExp = /^\[.*\] /g;
+      translatedName = translatedName.replace(pattern, "");
       layoutDefinition.name = "[" + ResourceUtil.getInstance().getString('bbb.layout.combo.remote') + "] " + translatedName;
       var redefineLayout:LayoutFromRemoteEvent = new LayoutFromRemoteEvent();
       redefineLayout.layout = layoutDefinition;
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/AddButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/AddButton.mxml
index 7ba7d3ed3717b8555660b4da8227d43f4ed3f11f..3d62118d8974e0780d523680c9984c5f146f0ad0 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/AddButton.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/AddButton.mxml
@@ -23,7 +23,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		   xmlns:mate="http://mate.asfusion.com/"
 		   xmlns:views="org.bigbluebutton.modules.layout.views.*"
 		   toolTip="{ResourceUtil.getInstance().getString('bbb.layout.addButton.toolTip')}"
-		   icon="{icon_add}"
+		   styleName="addLayoutButtonStyle"
 		   click="onClick(event)"
 		   enabled="{UserManager.getInstance().getConference().amIModerator()}">
 	
@@ -33,22 +33,26 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			import flash.events.Event;
 			
+			import mx.core.FlexGlobals;
+			import mx.core.IFlexDisplayObject;
+			import mx.managers.PopUpManager;
 			import org.bigbluebutton.common.Images;
 			import org.bigbluebutton.core.managers.UserManager;
-			import org.bigbluebutton.modules.layout.events.LayoutEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
 
 			private var _dispatcher:Dispatcher = new Dispatcher();
-			private var _images:Images = new Images();
-			[Bindable] private var icon_add:Class = _images.add;
 			
 			private function init():void {
 			}
 			
 			private function onClick(e:Event):void {
-				_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.ADD_CURRENT_LAYOUT_EVENT));
+				var layoutNameWindow:IFlexDisplayObject = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as DisplayObject, CustomLayoutNameWindow, true);
+				PopUpManager.centerPopUp(layoutNameWindow);
 			}
 			
+			public function refreshRole(amIModerator:Boolean):void {
+				this.enabled = amIModerator;
+			}
 		]]>
 	</mx:Script>
 </views:LayoutButton>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/BroadcastButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/BroadcastButton.mxml
index ad1a62f977fcb649a96a605f7510a357484c4f62..2441c25e026951dcb30baee37d269d0153cbbdd2 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/BroadcastButton.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/BroadcastButton.mxml
@@ -23,34 +23,30 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		   xmlns:mate="http://mate.asfusion.com/"
 		   xmlns:views="org.bigbluebutton.modules.layout.views.*"
 		   toolTip="{ResourceUtil.getInstance().getString('bbb.layout.broadcastButton.toolTip')}"
-		   icon="{_icon}"
-		   click="onClick(event)"
-		   enabled="{UserManager.getInstance().getConference().amIModerator()}">
+		   styleName="broadcastLayoutButtonStyle"
+		   click="onClick(event)">
 
 	<mx:Script>
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
-			
-			import flash.events.Event;
-			
-			import org.bigbluebutton.common.Images;
+
 			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.modules.layout.events.LayoutEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
 
 			private var _dispatcher:Dispatcher = new Dispatcher();
-			private var _images:Images = new Images();
-			[Bindable] private var _icon:Class = _images.page_link;
 			
 			private function init():void {
-				if (!UserManager.getInstance().getConference().amIModerator()) {
-					this.visible = false;
-				}
+				refreshRole(UserManager.getInstance().getConference().amIModerator());
 			}
 			
 			private function onClick(e:Event):void {
 				_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.BROADCAST_LAYOUT_EVENT));
 			}
+
+			public function refreshRole(amIModerator:Boolean):void {
+				this.visible = this.includeInLayout = this.enabled = amIModerator;
+			}
 		]]>
 	</mx:Script>
 </views:LayoutButton>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/CustomLayoutNameWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/CustomLayoutNameWindow.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..aac1111e6b78193bb368c0068f521192ff24759b
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/CustomLayoutNameWindow.mxml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+-->
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
+          xmlns:mate="http://mate.asfusion.com/"
+          verticalScrollPolicy="off"
+          horizontalScrollPolicy="off"
+          horizontalAlign="center"
+          showCloseButton="true"
+          close="onCancelClicked()"
+          creationComplete="onCreationComplete()"
+          width="250"
+          title="{ResourceUtil.getInstance().getString('bbb.layout.window.name')}">
+
+  <mate:Listener type="{LayoutNameInUseEvent.LAYOUT_NAME_IN_USE_EVENT}" method="handleLayoutNameInUse"/>
+
+  <mx:Script>
+    <![CDATA[
+      import com.asfusion.mate.events.Dispatcher;
+
+      import mx.managers.PopUpManager;
+      import org.bigbluebutton.util.i18n.ResourceUtil;
+      import org.bigbluebutton.modules.layout.events.LayoutEvent;
+      import org.bigbluebutton.modules.layout.events.LayoutNameInUseEvent;
+
+      public var savingForFileDownload:Boolean = false;
+
+      private function addButton_clickHandler():void {
+        var e:LayoutEvent = new LayoutEvent(LayoutEvent.ADD_CURRENT_LAYOUT_EVENT);
+        if (textInput.text != ResourceUtil.getInstance().getString('bbb.layout.combo.customName')) {
+          e.layoutName = textInput.text;
+        }
+        var dispatcher:Dispatcher = new Dispatcher();
+        dispatcher.dispatchEvent(e);
+      }
+
+      private function handleLayoutNameInUse(event:LayoutNameInUseEvent):void {
+        if (!event.inUse) {
+          PopUpManager.removePopUp(this);
+          if (savingForFileDownload) {
+            var dispatcher:Dispatcher = new Dispatcher();
+            dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.SAVE_LAYOUTS_WINDOW_EVENT));
+            savingForFileDownload = false;
+          }
+        } else {
+          trace("The name is already in use, waiting for overwrite command or rename");
+        }
+      }
+
+      private function onCreationComplete():void {
+        textInput.setFocus();
+      }
+
+      private function onCancelClicked():void {
+        PopUpManager.removePopUp(this);
+      }
+    ]]>
+  </mx:Script>
+
+  <mx:HBox width="100%" height="100%" horizontalAlign="center" verticalAlign="middle">
+      <mx:TextInput id="textInput" maxChars="140" width="100%" text="{ResourceUtil.getInstance().getString('bbb.layout.combo.customName')}" enter="addButton_clickHandler()"/>
+      <mx:Button id="addButton" click="addButton_clickHandler()" enabled="{textInput.text.length > 0}" styleName="addLayoutButtonStyle" toolTip="{ResourceUtil.getInstance().getString('bbb.layout.addButton.toolTip')}"/>
+  </mx:HBox>
+</mx:TitleWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml
index b775cee7d301a711a64f8197142d00f6e9b05c6b..205ea0db3b9620ed2ea83e1bd447a27e12c360bb 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LayoutsCombo.mxml
@@ -23,31 +23,33 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			toolTip="{ResourceUtil.getInstance().getString('bbb.layout.combo.toolTip')}"
 			prompt="{ResourceUtil.getInstance().getString('bbb.layout.combo.prompt')}"
 			height="{LayoutButton.BUTTON_SIZE}" creationComplete="init()"
-			disabledColor="{getStyle('color')}" rowCount="10"
+			change="onSelectedItemChanged(event)"
+			disabledColor="{getStyle('color')}" rowCount="10" width="240"
 			styleName="languageSelectorStyle" >
 	
 	<mate:Listener type="{SwitchedLayoutEvent.SWITCHED_LAYOUT_EVENT}" method="onLayoutChanged" />
 	<mate:Listener type="{LayoutsReadyEvent.LAYOUTS_READY}" method="populateLayoutsList"/>
   <mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
 	<mate:Listener type="{LocaleChangeEvent.LOCALE_CHANGED}" method="localeChanged" />
+	<mate:Listener type="{LayoutEvent.INVALIDATE_LAYOUT_EVENT}" method="invalidateLayout" />
   
 	<mx:Script>
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
 			
 			import mx.collections.ArrayCollection;
-			import mx.events.DropdownEvent;
-			import mx.events.ListEvent;
 			
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
 			import org.bigbluebutton.common.events.LocaleChangeEvent;
+			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.core.events.LockControlEvent;
 			import org.bigbluebutton.core.events.SwitchedLayoutEvent;
 			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.main.model.users.BBBUser;
 			import org.bigbluebutton.main.model.users.Conference;
 			import org.bigbluebutton.modules.layout.events.ChangeLayoutEvent;
+			import org.bigbluebutton.modules.layout.events.LayoutEvent;
 			import org.bigbluebutton.modules.layout.events.LayoutsReadyEvent;
 			import org.bigbluebutton.modules.layout.model.LayoutModel;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
@@ -61,7 +63,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         //trace(LOG + "initing");
         dataProvider = layoutNames;
         populateComboBox();
-        this.addEventListener(DropdownEvent.OPEN, openDropdownHandler);
+        refreshRole(UsersUtil.amIModerator());
       }
       
       private function lockSettingsChanged(e:LockControlEvent):void {
@@ -111,7 +113,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				if (idx == -1) {
 					prompt = e.layoutID;
 				} else {
-					prompt = ResourceUtil.getInstance().getString('bbb.layout.combo.prompt');
+					prompt = dataProvider[idx].label;
 				}
 				invalidateDisplayList();
 				
@@ -123,15 +125,19 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				populateComboBox();
 			}
 			
-			private function openDropdownHandler(e:DropdownEvent):void {
-				// a new dropdown object is created everytime the menu is opened
-				this.dropdown.addEventListener(ListEvent.ITEM_CLICK, itemClickHandler);
-			}
-			
-			private function itemClickHandler(e:ListEvent):void {
+			private function onSelectedItemChanged(e:Event):void {
 				_dispatcher.dispatchEvent(new ChangeLayoutEvent(e.currentTarget.selectedItem.localeKey));
 			}
 					
+			private function invalidateLayout(e:Event):void {
+				selectedIndex = -1;
+				prompt = ResourceUtil.getInstance().getString('bbb.layout.combo.custom');
+			}
+
+			public function refreshRole(amIModerator:Boolean):void {
+				var layoutLocked:Boolean = UserManager.getInstance().getConference().getLockSettings().getLockedLayout();
+				this.enabled = amIModerator || !layoutLocked;
+			}
 		]]>
 	</mx:Script>
 </mx:ComboBox>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LoadButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LoadButton.mxml
index c65a83312504988ef472f2eceafe157004269589..3fdcf612c26e426e1c1299715169c43b60b988a7 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LoadButton.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LoadButton.mxml
@@ -23,24 +23,19 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		   xmlns:mate="http://mate.asfusion.com/"
 		   xmlns:views="org.bigbluebutton.modules.layout.views.*"
 		   toolTip="{ResourceUtil.getInstance().getString('bbb.layout.loadButton.toolTip')}"
-		   icon="{icon_load}"
+		   styleName="loadLayoutButtonStyle"
 		   click="onClick(event)"
 		   enabled="{UserManager.getInstance().getConference().amIModerator()}">
 	
 	<mx:Script>
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
-			
-			import flash.events.Event;
-			
-			import org.bigbluebutton.common.Images;
+
 			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.modules.layout.events.LayoutEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
 
 			private var _dispatcher:Dispatcher = new Dispatcher();
-			private var _images:Images = new Images();
-			[Bindable] private var icon_load:Class = _images.folder;
 			
 			private function init():void {
 			}
@@ -49,6 +44,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.LOAD_LAYOUTS_EVENT));
 			}
 			
+			public function refreshRole(amIModerator:Boolean):void {
+				this.enabled = amIModerator;
+			}
 		]]>
 	</mx:Script>
 </views:LayoutButton>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LockButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LockButton.mxml
deleted file mode 100755
index 2baf393b7ceaa1ace6ad55461f9d3ecc5b675804..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/LockButton.mxml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-
-BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-
-Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
-
-This program is free software; you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free Software
-Foundation; either version 3.0 of the License, or (at your option) any later
-version.
-
-BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-
--->
-<views:LayoutButton xmlns:mx="http://www.adobe.com/2006/mxml" 
-		   creationComplete="init()" 
-		   xmlns:mate="http://mate.asfusion.com/"
-		   xmlns:views="org.bigbluebutton.modules.layout.views.*"
-		   toolTip="{ResourceUtil.getInstance().getString('bbb.layout.lockButton.toolTip')}"
-		   icon="{icon_unlocked}"
-		   click="onClick(event)"
-		   enabled="{UserManager.getInstance().getConference().amIModerator()}">
-	
-	<mx:Script>
-		<![CDATA[
-			import com.asfusion.mate.events.Dispatcher;
-			
-			import flash.events.Event;
-			
-			import org.bigbluebutton.common.Images;
-			import org.bigbluebutton.core.managers.UserManager;
-			import org.bigbluebutton.util.i18n.ResourceUtil;
-
-			private var _dispatcher:Dispatcher = new Dispatcher();
-			private var _images:Images = new Images();
-			[Bindable] private var icon_locked:Class = _images.locked;
-			[Bindable] private var icon_unlocked:Class = _images.unlocked;
-			
-			private function init():void {
-				if (!UserManager.getInstance().getConference().amIModerator()) {
-					this.visible = false;
-				}
-			}
-			
-			private function onClick(e:Event):void {
-				//_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.SYNC_LAYOUT_EVENT));
-			}
-			
-			private function onLockLayoutEvent(e:Event):void {
-				if (!UserManager.getInstance().getConference().amIModerator()) {
-					this.visible = true;
-				}
-				this.selected = true;
-				this.setStyle("icon", icon_locked);
-			}
-			
-			private function onUnlockLayoutEvent(e:Event):void {
-				if (!UserManager.getInstance().getConference().amIModerator()) {
-					this.visible = false;
-				}
-				this.selected = false;
-				this.setStyle("icon", icon_unlocked);
-			}
-		]]>
-	</mx:Script>
-</views:LayoutButton>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/SaveButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/SaveButton.mxml
index 6cccdc410be90bbfe041762f9c92718442eec2d3..6627aa7b29ff1c5c89c3fb0bacddd9c1145e23bf 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/SaveButton.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/SaveButton.mxml
@@ -23,24 +23,19 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		   xmlns:mate="http://mate.asfusion.com/"
 		   xmlns:views="org.bigbluebutton.modules.layout.views.*"
 		   toolTip="{ResourceUtil.getInstance().getString('bbb.layout.saveButton.toolTip')}"
-		   icon="{icon_save}"
+		   styleName="saveLayoutButtonStyle"
 		   click="onClick(event)"
 		   enabled="{UserManager.getInstance().getConference().amIModerator()}">
 	
 	<mx:Script>
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
-			
-			import flash.events.Event;
-			
-			import org.bigbluebutton.common.Images;
+
 			import org.bigbluebutton.core.managers.UserManager;
 			import org.bigbluebutton.modules.layout.events.LayoutEvent;
 			import org.bigbluebutton.util.i18n.ResourceUtil;
 
 			private var _dispatcher:Dispatcher = new Dispatcher();
-			private var _images:Images = new Images();
-			[Bindable] private var icon_save:Class = _images.disk;
 			
 			private function init():void {
 			}
@@ -49,6 +44,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				_dispatcher.dispatchEvent(new LayoutEvent(LayoutEvent.SAVE_LAYOUTS_EVENT));
 			}
 			
+			public function refreshRole(amIModerator:Boolean):void {
+				this.enabled = amIModerator;
+			}
 		]]>
 	</mx:Script>
 </views:LayoutButton>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/ToolbarComponent.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/ToolbarComponent.mxml
index 59dde95e8e26605af509589c52a3cb28ceae1648..bb7cdcd0830612d1dc759af60708623e696779fc 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/ToolbarComponent.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/layout/views/ToolbarComponent.mxml
@@ -47,6 +47,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			public function set enableEdit(arg:Boolean):void {
 				_enableEdit = arg && UserManager.getInstance().getConference().amIModerator();
 			}
+
+			public function refreshRole(amIModerator:Boolean):void {
+				comboBox.refreshRole(amIModerator);
+				addButton.refreshRole(amIModerator);
+				saveButton.refreshRole(amIModerator);
+				loadButton.refreshRole(amIModerator);
+				broadcastButton.refreshRole(amIModerator);
+			}
+
 			
 			public function set visibleTools(arg:Boolean):void {
 				_visibleTools = arg;
@@ -75,7 +84,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		]]>
 	</mx:Script>
 
-	<common:TabIndexer startIndex="110000" tabIndices="{[comboBox, addButton, saveButton, loadButton, broadcastButton, lockButton]}"/>
+	<common:TabIndexer startIndex="110000" tabIndices="{[comboBox, addButton, saveButton, loadButton, broadcastButton]}"/>
 	
 	<views:LayoutsCombo id="comboBox"/>
 	<views:AddButton id="addButton" 
@@ -87,9 +96,5 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<views:LoadButton id="loadButton" 
 					  includeInLayout="{_enableEdit}" 
 					  visible="{_enableEdit}"/>
-	<views:BroadcastButton id="broadcastButton"
-					  enabled="{!lockButton.selected}"/>
-	<views:LockButton id="lockButton"
-					  visible="false"
-					  includeInLayout="false"/>
+	<views:BroadcastButton id="broadcastButton"/>
 </mx:HBox>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/PhoneOptions.as b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/PhoneOptions.as
index 6cc32b3ec809ab74d9b05594eca684fa3cb4cd71..faaec427662287742245d31b7f09ff6537644b74 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/PhoneOptions.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/PhoneOptions.as
@@ -21,6 +21,8 @@ package org.bigbluebutton.modules.phone
 	import org.bigbluebutton.core.BBB;
 	
 	public class PhoneOptions {
+		static public var firstAudioJoin:Boolean = true;
+
     public var uri:String = "unknown";
     
 		[Bindable]
@@ -49,6 +51,12 @@ package org.bigbluebutton.modules.phone
 		
 		[Bindable]
 		public var showPhoneOption:Boolean = false;
+
+		[Bindable]
+		public var showMicrophoneHint:Boolean = true;
+
+		[Bindable]
+		public var forceListenOnly:Boolean = false;
 		
 		public function PhoneOptions() {
 			parseOptions();
@@ -81,12 +89,18 @@ package org.bigbluebutton.modules.phone
 				if (vxml.@listenOnlyMode != undefined) {
 					listenOnlyMode = (vxml.@listenOnlyMode.toString().toUpperCase() == "TRUE");
 				}
+				if (vxml.@forceListenOnly != undefined) {
+					forceListenOnly = (vxml.@forceListenOnly.toString().toUpperCase() == "TRUE");
+				}
 				if (vxml.@presenterShareOnly != undefined) {
 					presenterShareOnly = (vxml.@presenterShareOnly.toString().toUpperCase() == "TRUE");
 				}
 				if (vxml.@showPhoneOption != undefined) {
 					showPhoneOption = (vxml.@showPhoneOption.toString().toUpperCase() == "TRUE");
 				}
+				if (vxml.@showMicrophoneHint != undefined) {
+					showMicrophoneHint = (vxml.@showMicrophoneHint.toString().toUpperCase() == "TRUE");
+				}
 			}
 		}		
 	}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/managers/FlashCallManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/managers/FlashCallManager.as
index bab48ef7345453058369ad83338c26fe72c2a40c..e268c7c3b21546019049feaeef056e7336ea8814 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/managers/FlashCallManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/managers/FlashCallManager.as
@@ -116,7 +116,7 @@
       * after. (richard mar 28, 2014)
       */
       if (mic) {
-        if (options.skipCheck) {
+        if (options.skipCheck && PhoneOptions.firstAudioJoin) {
           LOGGER.debug("Calling into voice conference. skipCheck=[{0}] echoTestDone=[{1}]", [options.skipCheck, echoTestDone]);
 
           streamManager.useDefaultMic();
@@ -216,6 +216,16 @@
     }
     
     public function initialize():void {      
+      switch (state) {
+        case STOP_ECHO_THEN_JOIN_CONF:
+          // if we initialize usingFlash here, we won't be able to hang up from
+          // the flash connection
+          LOGGER.debug("Invalid state for initialize, aborting...");
+          return;
+        default:
+          break;
+      }
+
       printMics();
       if (options.useWebRTCIfAvailable && isWebRTCSupported()) {
         usingFlash = false;
@@ -362,7 +372,9 @@
             LOGGER.debug("ignoring join voice conf as usingFlash=[{0}] or eventMic=[{1}]", [usingFlash, !event.mic]);
           }
           break;
-		
+        case ON_LISTEN_ONLY_STREAM:
+          hangup();
+          break;
         default:
           LOGGER.debug("Ignoring join voice as state=[{0}]", [state]);
       }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/managers/WebRTCCallManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/managers/WebRTCCallManager.as
index 2f2fb63d0048c9c234838cbfdd3f7bd628f1c2a2..c0c485a1bb8a8d5c3fe71e59d1065cd8de8ace69 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/managers/WebRTCCallManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/managers/WebRTCCallManager.as
@@ -62,8 +62,6 @@ package org.bigbluebutton.modules.phone.managers
           ResourceUtil.getInstance().getString("bbb.clientstatus.webrtc.message"),
           'bbb.clientstatus.webrtc.title'));
       }
-      
-      usingWebRTC = checkIfToUseWebRTC();
     }
     
     private function isWebRTCSupported():Boolean {
@@ -157,9 +155,11 @@ package org.bigbluebutton.modules.phone.managers
       logData.message = "handleJoinVoiceConferenceCommand - usingWebRTC:";
       LOGGER.info(JSON.stringify(logData));
 
+      usingWebRTC = checkIfToUseWebRTC();
+
       if (!usingWebRTC || !event.mic) return;
       
-      if (options.skipCheck || echoTestDone) {
+      if ((options.skipCheck && PhoneOptions.firstAudioJoin) || echoTestDone) {
         joinVoiceConference();
       } else {
         startWebRTCEchoTest();
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/maps/FlashCallEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/maps/FlashCallEventMap.mxml
index 2aadf3376bb915fe986233b4f5946370b053ed17..9f2d3ab56d20732f1710aad7ca8afc6893f7ee23 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/maps/FlashCallEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/maps/FlashCallEventMap.mxml
@@ -102,6 +102,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   </EventHandlers>
   
   <EventHandlers type="{JoinVoiceConferenceCommand.JOIN_VOICE_CONF}">        
+    <MethodInvoker generator="{FlashCallManager}" method="initialize"/>
     <MethodInvoker generator="{FlashCallManager}" method="handleJoinVoiceConferenceCommand" arguments="{event}"/>
   </EventHandlers> 
   
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/views/assets/images/phone_sound.png b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/views/assets/images/phone_sound.png
deleted file mode 100644
index 7fdf1c58c0a0498c7a0d35a42c6fb08c9e053b88..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/views/assets/images/phone_sound.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/views/components/ToolbarButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/views/components/ToolbarButton.mxml
index d38292d647f774daef1df6701dcd62bb9660a6f7..d67e1f36bdc46ee71d876d9de3e40c229862f7c9 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/phone/views/components/ToolbarButton.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/phone/views/components/ToolbarButton.mxml
@@ -32,6 +32,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   <mate:Listener type="{FlashLeftVoiceConferenceEvent.LEFT_VOICE_CONFERENCE}" method="handleFlashLeftVoiceConferenceEvent" />
   <mate:Listener type="{FlashJoinedVoiceConferenceEvent.JOINED_VOICE_CONFERENCE}" method="handleFlashJoinedVoiceConferenceEvent" />
   <mate:Listener type="{FlashJoinedListenOnlyVoiceConferenceEvent.JOINED_LISTEN_ONLY_VOICE_CONFERENCE}" method="handleFlashJoinedListenOnlyConferenceEvent" />
+  <mate:Listener type="{FlashEchoTestStoppedEvent.ECHO_TEST_STOPPED}" method="handleStopEchoTestEvent" />
   <mate:Listener type="{WebRTCCallEvent.WEBRTC_CALL_STARTED}" method="handleWebRTCCallStartedEvent" />
   <mate:Listener type="{WebRTCCallEvent.WEBRTC_CALL_ENDED}" method="handleWebRTCCallEndedEvent" />
   <mate:Listener type="{AudioSelectionWindowEvent.CLOSED_AUDIO_SELECTION}" method="handleClosedAudioSelectionWindowEvent" />
@@ -51,6 +52,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.main.views.MainToolbar;
 			import org.bigbluebutton.modules.phone.PhoneOptions;
 			import org.bigbluebutton.modules.phone.events.AudioSelectionWindowEvent;
+			import org.bigbluebutton.modules.phone.events.FlashEchoTestStoppedEvent;
 			import org.bigbluebutton.modules.phone.events.FlashJoinedListenOnlyVoiceConferenceEvent;
 			import org.bigbluebutton.modules.phone.events.FlashJoinedVoiceConferenceEvent;
 			import org.bigbluebutton.modules.phone.events.FlashLeftVoiceConferenceEvent;
@@ -71,30 +73,29 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			[Bindable] public var phoneOptions:PhoneOptions = new PhoneOptions();
 			
 			private function startPhone():void {
-				var conference:Conference = UserManager.getInstance().getConference();
-				var thisUser:BBBUser = conference.getMyUser();
-				
 				LOGGER.debug("startPhone 1 enabled=[{0}] selected=[{1}]", [enabled, selected]);
 				// Disable the button right away to prevent the user from clicking
 				// multiple times.
 				this.enabled = false;
 				LOGGER.debug("startPhone 2 enabled=[{0}] selected=[{1}]", [enabled, selected]);
 				if (this.selected) {
-					if(thisUser.disableMyMic){
-						var command:JoinVoiceConferenceCommand = new JoinVoiceConferenceCommand();
-						command.mic = false;
-						dispatcher.dispatchEvent(command);
-					} else {
-						//trace(LOG + "Sending Join Conference command");
-						//dispatcher.dispatchEvent(new JoinVoiceConferenceCommand());
-						LOGGER.debug("Sending Show Audio Selection command");
-						dispatcher.dispatchEvent(new AudioSelectionWindowEvent(AudioSelectionWindowEvent.SHOW_AUDIO_SELECTION));
-					}
+					joinAudio();
 				} else {
-					LOGGER.debug("Sending Leave Conference command");
-					dispatcher.dispatchEvent(new LeaveVoiceConferenceCommand());
+					leaveAudio();
 				}				
 			}
+
+			private function get disableMyMic():Boolean {
+				var conference:Conference = UserManager.getInstance().getConference();
+				var thisUser:BBBUser = conference.getMyUser();
+
+				return ((phoneOptions.presenterShareOnly && !UsersUtil.amIPresenter() && !UsersUtil.amIModerator())
+						|| thisUser.disableMyMic);
+			}
+
+			private function get defaultListenOnlyMode():Boolean {
+				return (phoneOptions.listenOnlyMode && phoneOptions.forceListenOnly);
+			}
 			
 			public function remoteClick(event:ShortcutEvent):void{
 				this.selected = true;
@@ -115,33 +116,38 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				else
           this.styleName = "voiceConfDefaultButtonStyle";			
 			}
-			
-			private function onCreationComplete():void {
+
+			private function joinAudio():void {
 				var conference:Conference = UserManager.getInstance().getConference();
 				var thisUser:BBBUser = conference.getMyUser();
-				
+
+				if (phoneOptions.skipCheck || disableMyMic || defaultListenOnlyMode) {
+					var command:JoinVoiceConferenceCommand = new JoinVoiceConferenceCommand();
+					command.mic = !disableMyMic;
+					dispatcher.dispatchEvent(command);
+				} else {
+					LOGGER.debug("Sending Show Audio Selection command");
+					dispatcher.dispatchEvent(new AudioSelectionWindowEvent(AudioSelectionWindowEvent.SHOW_AUDIO_SELECTION));
+				}
+			}
+
+			private function leaveAudio():void {
+				LOGGER.debug("Sending Leave Conference command");
+				dispatcher.dispatchEvent(new LeaveVoiceConferenceCommand());
+			}
+			
+			private function onCreationComplete():void {
 				// when the button is added to the stage display the audio selection window if auto join is true
 				if (phoneOptions.autoJoin) {
-					if (phoneOptions.skipCheck || thisUser.disableMyMic) {
-						var command:JoinVoiceConferenceCommand = new JoinVoiceConferenceCommand();
-						if (
-							(phoneOptions.presenterShareOnly && !UsersUtil.amIPresenter() && !UsersUtil.amIModerator())
-							|| thisUser.disableMyMic
-						) {
-							command.mic = false;
-						} else {
-							command.mic = true;
-						}
-						
-						dispatcher.dispatchEvent(command);
-					} else {
-						LOGGER.debug("Sending Show Audio Selection command");
-						dispatcher.dispatchEvent(new AudioSelectionWindowEvent(AudioSelectionWindowEvent.SHOW_AUDIO_SELECTION));
-					}
+					joinAudio();
+				} else {
+					joinDefaultListenOnlyMode();
 				}
 			}
 
       private function onUserJoinedConference():void {
+        PhoneOptions.firstAudioJoin = false;
+
         this.selected = true;
         this.enabled = true;
 
@@ -151,6 +157,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         this.toolTip = ResourceUtil.getInstance().getString('bbb.toolbar.phone.toolTip.stop');	        
       }
       
+      private function onUserJoinedListenOnlyConference():void {
+        LOGGER.debug("onUserJoinedListenOnlyConference enabled=[" + enabled + "] selected=[" + selected + "]");
+
+        resetButtonState();
+      }
+
       private function onUserLeftConference():void {
         this.selected = false;
         this.enabled = true;
@@ -161,6 +173,14 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		UserManager.getInstance().getConference().resetBreakoutRooms();
       }
       
+      private function joinDefaultListenOnlyMode(micLeft:Boolean = true):void {
+        if (defaultListenOnlyMode && micLeft) {
+          var command:JoinVoiceConferenceCommand = new JoinVoiceConferenceCommand();
+          command.mic = false;
+          dispatcher.dispatchEvent(command);
+        }
+      }
+
       private function handleFlashJoinedVoiceConferenceEvent(event:FlashJoinedVoiceConferenceEvent):void {
         LOGGER.debug("User has joined the conference using flash");
         onUserJoinedConference();
@@ -168,12 +188,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       	
       private function handleFlashJoinedListenOnlyConferenceEvent(event:FlashJoinedListenOnlyVoiceConferenceEvent):void {
 		LOGGER.debug("User has joined the listen only conference using flash");
-        onUserJoinedConference();
+        if (defaultListenOnlyMode) {
+          onUserJoinedListenOnlyConference();
+        } else {
+          onUserJoinedConference();
+        }
       }
       
       private function handleFlashLeftVoiceConferenceEvent(event:FlashLeftVoiceConferenceEvent):void {
 		LOGGER.debug("User has left the conference using flash");
+        var micLeft:Boolean = (_currentState == ACTIVE_STATE);
         onUserLeftConference();
+        joinDefaultListenOnlyMode(micLeft);
       }
       
       private function handleWebRTCCallStartedEvent(event: WebRTCCallEvent):void {
@@ -184,8 +210,22 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	  private function handleWebRTCCallEndedEvent(event:WebRTCCallEvent):void {
 		LOGGER.debug("User has left the conference using webrtc");
         onUserLeftConference();
+        joinDefaultListenOnlyMode();
 	  }
 			
+			private function handleStopEchoTestEvent(event:Event):void {
+				resetButtonState();
+				joinDefaultListenOnlyMode();
+			}
+
+			private function resetButtonState():void {
+				this.selected = false;
+				this.enabled = true;
+				_currentState = DEFAULT_STATE;
+				this.styleName = "voiceConfDefaultButtonStyle";
+				this.toolTip = ResourceUtil.getInstance().getString('bbb.toolbar.phone.toolTip.start');
+			}
+
 			private function handleClosedAudioSelectionWindowEvent(event:AudioSelectionWindowEvent):void {
 				this.selected = false;
 				this.enabled = true;
@@ -193,6 +233,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				_currentState = DEFAULT_STATE;
         this.styleName = "voiceConfDefaultButtonStyle";
 				this.toolTip = ResourceUtil.getInstance().getString('bbb.toolbar.phone.toolTip.start');
+				joinDefaultListenOnlyMode();
 			}
 				
 			//For whatever reason the tooltip does not update when localization is changed dynamically. Overrideing it here
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/polling/assets/resizeCursorVH.gif b/bigbluebutton-client/src/org/bigbluebutton/modules/polling/assets/resizeCursorVH.gif
deleted file mode 100755
index 7da81d6f379062077edbb7a1b241bd479363a312..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/modules/polling/assets/resizeCursorVH.gif and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/QuickPollButton.as b/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/QuickPollButton.as
index 4a1af077b65a894af213951d7129e265af193cb4..8c3515408d9746a3d2d1d00312ce1776c64c410c 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/QuickPollButton.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/polling/views/QuickPollButton.as
@@ -5,6 +5,7 @@ package org.bigbluebutton.modules.polling.views {
 	
 	import org.as3commons.logging.api.ILogger;
 	import org.as3commons.logging.api.getClassLogger;
+	import org.bigbluebutton.core.UsersUtil;
 	import org.bigbluebutton.modules.present.events.PageLoadedEvent;
 	import org.bigbluebutton.modules.present.model.Page;
 	import org.bigbluebutton.modules.present.model.PresentationModel;
@@ -13,6 +14,16 @@ package org.bigbluebutton.modules.polling.views {
 	public class QuickPollButton extends Button {
 		private static const LOGGER:ILogger = getClassLogger(QuickPollButton);      
 
+		override public function set visible(vsb:Boolean):void {
+			if (vsb) {
+				// This button should only be visible when there is a polling at the current slide's text
+				var page:Page = PresentationModel.getInstance().getCurrentPage();
+				super.visible = page != null ? parseSlideText(page.txtData) : false;
+			} else {
+				super.visible = false;
+			}
+		}
+
 		public function QuickPollButton() {
 			super();
 			visible = false;
@@ -23,13 +34,10 @@ package org.bigbluebutton.modules.polling.views {
 		}
 		
 		private function handlePageLoadedEvent(e:PageLoadedEvent):void {
-			var page:Page = PresentationModel.getInstance().getPage(e.pageId);
-			if (page != null) {
-				parseSlideText(page.txtData);
-			}
+			visible = UsersUtil.amIPresenter();
 		}
 		
-		private function parseSlideText(text:String):void {
+		private function parseSlideText(text:String):Boolean {
 			var numRegex:RegExp = new RegExp("\n[^\s][\.\)]", "g");
 			var ynRegex:RegExp = new RegExp((ResourceUtil.getInstance().getString("bbb.polling.answer.Yes")+
 				"\s*/\s*"+
@@ -56,21 +64,21 @@ package org.bigbluebutton.modules.polling.views {
 				}
 				label = constructedLabel;
 				name = "A-"+len;
-				visible = true;
+				return true;
 			} else if (text.search(ynRegex) > -1 || text.search(nyRegex) > -1) {
 				label = ResourceUtil.getInstance().getString("bbb.polling.answer.Yes")+
 						"/"+
 						ResourceUtil.getInstance().getString("bbb.polling.answer.No");
 				name = "YN";
-				visible = true;
+				return true;
 			} else if (text.search(tfRegex) > -1 || text.search(ftRegex) > -1) {
 				label = ResourceUtil.getInstance().getString("bbb.polling.answer.True")+
 					"/"+
 					ResourceUtil.getInstance().getString("bbb.polling.answer.False");
 				name = "TF";
-				visible = true;
+				return true;
 			} else {
-				visible = false;
+				return false;
 			}
 		}
 	}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/business/FileUploadService.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/business/FileUploadService.as
index 11839bce8688bb8c5e0d6691436def93d205cfb1..c3f7e51e84a8ba51b74fc138a471d41d99e18611 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/business/FileUploadService.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/business/FileUploadService.as
@@ -70,8 +70,9 @@ package org.bigbluebutton.modules.present.business
 		 * @param file - The FileReference class of the file we wish to send
 		 * 
 		 */		
-		public function upload(presentationName:String, file:FileReference):void {
+		public function upload(presentationName:String, file:FileReference, downloadable:Boolean):void {
 			sendVars.presentation_name = presentationName;
+			sendVars.is_downloadable = downloadable;
 			var fileToUpload : FileReference = new FileReference();
 			fileToUpload = file;
 			
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/business/PresentProxy.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/business/PresentProxy.as
index 9356b9c0076074c03ffa58f4378445d6ee9a1c2e..5b040abab2b3a117859dfee3b2548a57694e8aa5 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/business/PresentProxy.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/business/PresentProxy.as
@@ -21,6 +21,8 @@ package org.bigbluebutton.modules.present.business
 	import com.asfusion.mate.events.Dispatcher;
 	
 	import flash.events.TimerEvent;
+	import flash.net.navigateToURL;
+	import flash.net.URLRequest;
 	import flash.utils.Timer;
 	
 	import mx.collections.ArrayCollection;
@@ -32,6 +34,7 @@ package org.bigbluebutton.modules.present.business
 	import org.bigbluebutton.modules.present.commands.GoToPageCommand;
 	import org.bigbluebutton.modules.present.commands.GoToPrevPageCommand;
 	import org.bigbluebutton.modules.present.commands.UploadFileCommand;
+	import org.bigbluebutton.modules.present.events.DownloadEvent;
 	import org.bigbluebutton.modules.present.events.GetListOfPresentationsReply;
 	import org.bigbluebutton.modules.present.events.PresentModuleEvent;
 	import org.bigbluebutton.modules.present.events.PresenterCommands;
@@ -144,9 +147,22 @@ package org.bigbluebutton.modules.present.business
 			if (uploadService == null) {
         uploadService = new FileUploadService(host + "/bigbluebutton/presentation/upload", conference, room);
       }
-			uploadService.upload(e.filename, e.file);
+			uploadService.upload(e.filename, e.file, e.isDownloadable);
 		}
 		
+		/**
+		 * Start downloading the selected file
+		 * @param e
+		 *
+		 */
+		public function startDownload(e:DownloadEvent):void {
+			var presentationName:String = e.fileNameToDownload;
+			var downloadUri:String = host + "/bigbluebutton/presentation/" + conference + "/" + room + "/" + presentationName + "/download";
+			LOGGER.debug("PresentationApplication::downloadPresentation()... " + downloadUri);
+			var req:URLRequest = new URLRequest(downloadUri);
+			navigateToURL(req,"_blank");
+		}
+
 		/**
 		 * To to the specified slide 
 		 * @param e - The event which holds the slide number
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/commands/UploadFileCommand.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/commands/UploadFileCommand.as
index 2d2c05c960ef18b64b77258b930d654e569ad399..55b3771f71216faacfd77e5f32b384a0dc5319f8 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/commands/UploadFileCommand.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/commands/UploadFileCommand.as
@@ -9,6 +9,7 @@ package org.bigbluebutton.modules.present.commands
     
     public var filename:String;
     public var file:FileReference;
+    public var isDownloadable:Boolean;
     
     public function UploadFileCommand()
     {
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/DownloadEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/DownloadEvent.as
new file mode 100755
index 0000000000000000000000000000000000000000..5f6a45e81ed0b2f285b457cb104e80d979452640
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/DownloadEvent.as
@@ -0,0 +1,34 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+package org.bigbluebutton.modules.present.events
+{
+	import flash.events.Event;
+
+	public class DownloadEvent extends Event {
+		public static const OPEN_DOWNLOAD_WINDOW:String = "OPEN_DOWNLOAD_WINDOW";
+		public static const CLOSE_DOWNLOAD_WINDOW:String = "CLOSE_DOWNLOAD_WINDOW";
+		public static const DOWNLOAD_PRESENTATION:String = "DOWNLOAD_PRESENTATION";
+
+		public var fileNameToDownload:String;
+
+		public function DownloadEvent(type:String) {
+			super(type, true, false);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/RemovePresentationEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/RemovePresentationEvent.as
index 34f3c4382901ec3732318c3518801e95b49b81d4..c685ca4ff61a7d548951ccc286480a4e3900103c 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/RemovePresentationEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/events/RemovePresentationEvent.as
@@ -27,6 +27,9 @@ package org.bigbluebutton.modules.present.events
 		
 		// Presentation has been removed from server.
 		public static const PRESENTATION_REMOVED_EVENT:String = "Presentation Removed Event";
+
+		// Presentation removed from the list of downloadable events.
+		public static const UPDATE_DOWNLOADABLE_FILES_EVENT:String = "Update Downloadable Files Event";
 		
 		public var presentationName:String;
 		
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as
index 31d1645957e3941dace2629ba09d1eb80741d26c..ba3c60c3b89a6c974e36e1ddd062dd55df1e609f 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/managers/PresentManager.as
@@ -30,6 +30,7 @@ package org.bigbluebutton.modules.present.managers
 	import org.bigbluebutton.common.events.OpenWindowEvent;
 	import org.bigbluebutton.modules.present.events.PresentModuleEvent;
 	import org.bigbluebutton.modules.present.events.UploadEvent;
+	import org.bigbluebutton.modules.present.ui.views.FileDownloadWindow;
 	import org.bigbluebutton.modules.present.ui.views.FileUploadWindow;
 	import org.bigbluebutton.modules.present.ui.views.PresentationWindow;
 	
@@ -37,6 +38,7 @@ package org.bigbluebutton.modules.present.managers
 	{
 		private var globalDispatcher:Dispatcher;
 		private var uploadWindow:FileUploadWindow;
+		private var downloadWindow:FileDownloadWindow;
 		private var presentWindow:PresentationWindow;
 		
 		public function PresentManager() {
@@ -81,5 +83,23 @@ package org.bigbluebutton.modules.present.managers
 			PopUpManager.removePopUp(uploadWindow);
 			uploadWindow = null;
 		}
+
+		public function handleOpenDownloadWindow():void {
+			if (downloadWindow != null) return;
+
+			downloadWindow = FileDownloadWindow(PopUpManager.createPopUp(FlexGlobals.topLevelApplication as DisplayObject, FileDownloadWindow, true));
+
+			var point1:Point = new Point();
+			point1.x = FlexGlobals.topLevelApplication.width / 2;
+			point1.y = FlexGlobals.topLevelApplication.height / 2;
+
+			downloadWindow.x = point1.x - (downloadWindow.width/2);
+			downloadWindow.y = point1.y - (downloadWindow.height/2);
+		}
+
+		public function handleCloseDownloadWindow():void {
+			PopUpManager.removePopUp(downloadWindow);
+			downloadWindow = null;
+		}
 	}
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/maps/PresentEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/present/maps/PresentEventMap.mxml
index 2f4df3d694358937b2e4733f753fb8c5c20a824c..39e7e39bee7e169c1e1062c6bb76adca8672f53a 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/maps/PresentEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/maps/PresentEventMap.mxml
@@ -41,6 +41,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       import org.bigbluebutton.modules.present.events.PresentationEvent;
       import org.bigbluebutton.modules.present.events.PresenterCommands;
       import org.bigbluebutton.modules.present.events.RemovePresentationEvent;
+      import org.bigbluebutton.modules.present.events.DownloadEvent;
       import org.bigbluebutton.modules.present.events.UploadEvent;
       import org.bigbluebutton.modules.present.managers.PresentManager;
       import org.bigbluebutton.modules.present.services.PageLoaderService;
@@ -71,6 +72,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<EventHandlers type="{PresentModuleEvent.STOP_MODULE}" >
 		<MethodInvoker generator="{PresentManager}" method="handleStopModuleEvent" />
 	</EventHandlers>
+
+	<EventHandlers type="{DownloadEvent.OPEN_DOWNLOAD_WINDOW}" >
+		<MethodInvoker generator="{PresentManager}" method="handleOpenDownloadWindow" />
+	</EventHandlers>
+
+	<EventHandlers type="{DownloadEvent.CLOSE_DOWNLOAD_WINDOW}" >
+		<MethodInvoker generator="{PresentManager}" method="handleCloseDownloadWindow" />
+	</EventHandlers>
+
+	<EventHandlers type="{DownloadEvent.DOWNLOAD_PRESENTATION}" >
+		<MethodInvoker generator="{PresentProxy}"  method="startDownload" arguments="{event}" />
+	</EventHandlers>
 	
 	<EventHandlers type="{BBBEvent.RECONNECT_BIGBLUEBUTTON_SUCCEEDED_EVENT}" >
 		<MethodInvoker generator="{PresentProxy}" method="getCurrentPresentationInfo" />
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/model/Presentation.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/model/Presentation.as
index f760b17c91067e685f987af67185e4d609dbedfc..eff8160d192956cf31b959a116cd1f9cf460ebc9 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/model/Presentation.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/model/Presentation.as
@@ -13,12 +13,14 @@ package org.bigbluebutton.modules.present.model
     private var _pages:ArrayCollection;
     
     private var _current:Boolean = false;
+    private var _downloadable:Boolean = false;
     
-    public function Presentation(id: String, name: String, current: Boolean, pages: ArrayCollection) {
+    public function Presentation(id: String, name: String, current: Boolean, pages: ArrayCollection, downloadable: Boolean) {
       _id = id;
       _name = name;
       _current = current;
       _pages = pages
+      _downloadable = downloadable;
     }
     
     public function get id():String {
@@ -69,5 +71,9 @@ package org.bigbluebutton.modules.present.model
       
       return pages;
     }
+
+    public function get downloadable():Boolean {
+      return _downloadable;
+    }
   }
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/model/PresentationModel.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/model/PresentationModel.as
index 8637d7218ea14679cc47880ddab63fbee2ac54f4..5a138d44b49326e15df41d890b1d4bc94faf1c60 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/model/PresentationModel.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/model/PresentationModel.as
@@ -182,6 +182,19 @@ package org.bigbluebutton.modules.present.model
       LOGGER.debug("Could not find presentation [{0}].", [presId]);
       return null;      
     }
+
+    public function getDownloadablePresentations():ArrayCollection {
+      var presos:ArrayCollection = new ArrayCollection();
+
+      for (var i:int = 0; i < _presentations.length; i++) {
+        var pres: Presentation = _presentations.getItemAt(i) as Presentation;
+        if (pres.downloadable) {
+          presos.addItem(pres);
+        }
+      }
+
+      return presos;
+    }
   }
 }
 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/PresentationService.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/PresentationService.as
index bf3dc9719f5d469bea031c325a621c15fbe9e883..0fad260c6f79819644ad10b43816a9478241d4f7 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/PresentationService.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/PresentationService.as
@@ -119,7 +119,7 @@ package org.bigbluebutton.modules.present.services
         presoPages.addItem(pg);
       }          
       
-      var presentation: Presentation = new Presentation(presVO.id, presVO.name, presVO.isCurrent(), presoPages);
+      var presentation: Presentation = new Presentation(presVO.id, presVO.name, presVO.isCurrent(), presoPages, presVO.downloadable);
       return presentation;
     }
     
@@ -168,6 +168,8 @@ package org.bigbluebutton.modules.present.services
 		}
 		
 		model.removePresentation(presentationID);
+		var updateEvent:RemovePresentationEvent = new RemovePresentationEvent(RemovePresentationEvent.UPDATE_DOWNLOADABLE_FILES_EVENT);
+		dispatcher.dispatchEvent(updateEvent); // this event will trigger the disabling of the download button.
 	}
   }
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/messages/PresentationVO.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/messages/PresentationVO.as
index 26eb7f54a0df917e6769d3c102dd92bdaf613958..d1dfd866659bf7640a8ecd36d1b19ab56a987537 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/messages/PresentationVO.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/messages/PresentationVO.as
@@ -7,12 +7,14 @@ package org.bigbluebutton.modules.present.services.messages
     private var _name:String;
     private var _current:Boolean = false;
     private var _pages:ArrayCollection;
+    private var _downloadable:Boolean = false;
     
-    public function PresentationVO(id: String, name: String, current: Boolean, pages: ArrayCollection) {
+    public function PresentationVO(id: String, name: String, current: Boolean, pages: ArrayCollection, downloadable: Boolean) {
       _id = id;
       _name = name;
       _current = current;
       _pages = pages
+      _downloadable = downloadable;
     }
     
     public function get id():String {
@@ -36,5 +38,9 @@ package org.bigbluebutton.modules.present.services.messages
       
       return pages;
     }
+
+    public function get downloadable():Boolean {
+      return _downloadable;
+    }
   }
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/messaging/MessageReceiver.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/messaging/MessageReceiver.as
index c7a89d1b3970bb8b3e48712ead9deb24e27d8c1e..3d4d9fdc4a0c93c70e2c472d4111d593ab6ca411 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/messaging/MessageReceiver.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/services/messaging/MessageReceiver.as
@@ -213,7 +213,7 @@ package org.bigbluebutton.modules.present.services.messaging
       }
       
       var preso:PresentationVO = new PresentationVO(presentation.id, presentation.name, 
-                                   presentation.current, presoPages);
+                                   presentation.current, presoPages, presentation.downloadable);
       return preso;
     }
     
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/DownloadPresentationRenderer.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/DownloadPresentationRenderer.mxml
new file mode 100755
index 0000000000000000000000000000000000000000..eb1970c3668b3e46f360cb6582559708633ff50e
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/DownloadPresentationRenderer.mxml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="90%" verticalAlign="middle">
+  <mx:Script>
+    <![CDATA[
+      import com.asfusion.mate.events.Dispatcher;
+      import org.bigbluebutton.util.i18n.ResourceUtil;
+      import org.bigbluebutton.modules.present.events.DownloadEvent;
+
+      private var globalDispatch:Dispatcher = new Dispatcher();
+
+      private function downloadPresentation():void {
+        var downloadEvent:DownloadEvent = new DownloadEvent(DownloadEvent.DOWNLOAD_PRESENTATION);
+        downloadEvent.fileNameToDownload = data.id as String;
+        globalDispatch.dispatchEvent(downloadEvent);
+      }
+    ]]>
+  </mx:Script>
+  <mx:Label id="presentationNameLabel"
+      width="{this.width-downloadBtn.width-30}"
+      text="{data.name as String}"
+      toolTip="{data.name as String}"
+      styleName="presentationNameLabelStyle"
+      truncateToFit="true"/>
+  <mx:Button id="downloadBtn"
+      label="{ResourceUtil.getInstance().getString('bbb.filedownload.downloadBtn')}"
+      toolTip="{ResourceUtil.getInstance().getString('bbb.filedownload.downloadBtn')}"
+      styleName="presentationUploadShowButtonStyle"
+      click="downloadPresentation()"
+      enabled="{data.downloadable as Boolean}"/>
+</mx:HBox>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileDownloadWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileDownloadWindow.mxml
new file mode 100755
index 0000000000000000000000000000000000000000..4e52eeaac2da81026cfb41322e47b1ceb1ae4665
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileDownloadWindow.mxml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+-->
+
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
+    xmlns:mate="http://mate.asfusion.com/"
+    layout="absolute"
+    width="580"
+    styleName="presentationFileUploadWindowStyle"
+    initialize="initData();">
+
+  <mate:Dispatcher id="globalDispatch"/>
+
+  <mx:Script>
+    <![CDATA[
+      import com.asfusion.mate.events.Dispatcher;
+      import mx.collections.ArrayCollection;
+      import org.bigbluebutton.modules.present.events.DownloadEvent;
+      import org.bigbluebutton.modules.present.model.PresentationModel;
+      import org.bigbluebutton.util.i18n.ResourceUtil;
+
+      [Bindable] private var downloadablePresentations:ArrayCollection;
+
+      override public function move(x:Number, y:Number):void
+      {
+        return;
+      }
+
+      private function initData():void {
+        downloadablePresentations = PresentationModel.getInstance().getDownloadablePresentations();
+      }
+    ]]>
+
+  </mx:Script>
+
+  <mx:VBox width="100%" height="100%">
+    <mx:Label text="{ResourceUtil.getInstance().getString('bbb.filedownload.title')}" styleName="presentationUploadTitleStyle" paddingBottom="0"/>
+    <mx:Canvas width="100%" height="205" verticalScrollPolicy="off">
+      <mx:List id="presentationNamesList"
+          alternatingItemColors="[#EFEFEF, #FEFEFE]"
+          allowMultipleSelection="false"
+          width="100%"
+          height="202"
+          left="5"
+          top="5"
+          right="5"
+          bottom="5"
+          itemRenderer="org.bigbluebutton.modules.present.ui.views.DownloadPresentationRenderer"
+          dragEnabled="false"
+          dataProvider="{downloadablePresentations}">
+      </mx:List>
+    </mx:Canvas>
+    <mx:Canvas width="100%" height="48">
+      <mx:Button id="okCancelBtn"
+          label="{ResourceUtil.getInstance().getString('bbb.fileupload.okCancelBtn')}"
+          styleName="presentationUploadCancelButtonStyle"
+          right="5"
+          bottom="15"
+          click="globalDispatch.dispatchEvent(new DownloadEvent(DownloadEvent.CLOSE_DOWNLOAD_WINDOW))"
+          toolTip="{ResourceUtil.getInstance().getString('bbb.fileupload.okCancelBtn.toolTip')}"/>
+    </mx:Canvas>
+  </mx:VBox>
+</mx:TitleWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileUploadWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileUploadWindow.mxml
index 410e40c51e043ae9827744d4fdb5644b72204f91..25e53bad62f574b268a71001a8eaaf0cf400c87a 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileUploadWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/FileUploadWindow.mxml
@@ -22,7 +22,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 <mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" 
 	xmlns:mate="http://mate.asfusion.com/"
-	 layout="absolute" width="580" height="410" styleName="presentationFileUploadWindowStyle"
+	 layout="absolute" width="580" height="426" styleName="presentationFileUploadWindowStyle"
       initialize="initData();">
 
     <mate:Dispatcher id="globalDispatch" />
@@ -82,6 +82,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       private var genThumbDots:String = ".";
 
       private var fileToUpload:FileReference = new FileReference();
+      [Bindable] private var presentOptions:PresentOptions = new PresentOptions();
 		
       override public function move(x:Number, y:Number):void{
         return;
@@ -172,12 +173,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
           progBarLbl.visible = true;          
           lblFileName.enabled = false;
+
+          var isDownloadable:Boolean = new Boolean(letUserDownload.selected);
           
           var uploadCmd:UploadFileCommand = new UploadFileCommand();
           uploadCmd.filename = presentationName;
           uploadCmd.file = fileToUpload;
+          uploadCmd.isDownloadable = isDownloadable;
           globalDispatch.dispatchEvent(uploadCmd);
-
+          letUserDownload.visible = false;
         }       		
       }
 
@@ -258,6 +262,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         selectBtn.enabled = true;
         uploadBtn.enabled = true;
         lblFileName.enabled = true;			
+        letUserDownload.visible = true;
       }
 
       private function handleConvertUpdate(e:ConversionUpdateEvent):void{
@@ -306,6 +311,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                  toolTip="{ResourceUtil.getInstance().getString('bbb.fileupload.uploadBtn.toolTip')}"  click="startUpload()"
                  enabled="false" icon="{bulletGoIcon}"/>
     </mx:HBox>
+    <mx:Box paddingLeft="5" paddingTop="5" visible="{presentOptions.enableDownload}" includeInLayout="{presentOptions.enableDownload}" >
+      <mx:CheckBox id="letUserDownload" label="{ResourceUtil.getInstance().getString('bbb.fileupload.letUserDownload')}" selected="{presentOptions.enableDownload}" toolTip="{ResourceUtil.getInstance().getString('bbb.fileupload.letUserDownload.tooltip')}"/>
+    </mx:Box>
     <mx:HBox id="progressReportBox" width="100%" paddingLeft="10" paddingTop="5" paddingBottom="10" includeInLayout="true" visible="false">
       <mx:Label id="progBarLbl" text="{ResourceUtil.getInstance().getString('bbb.fileupload.progBarLbl')}" 
                 styleName="presentationUploadProgressBarLabelStyle" visible="false"/>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentOptions.as b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentOptions.as
index 1f382403b69833b54ea70c2dd322b0091e2284c9..c4feeb8ebf219b5f70ea31cd559a49ab389a17fb 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentOptions.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentOptions.as
@@ -25,6 +25,7 @@ package org.bigbluebutton.modules.present.ui.views
 		[Bindable] public var baseTabIndex:int;
 		[Bindable] public var maxFileSize:Number;
     [Bindable] public var openExternalFileUploadDialog:Boolean = false;
+		[Bindable] public var enableDownload:Boolean = true;
 		
 		public function PresentOptions()
 		{
@@ -48,6 +49,9 @@ package org.bigbluebutton.modules.present.ui.views
 				else{
 					maxFileSize = 30;
 				}
+				if (vxml.@enableDownload != undefined) {
+					enableDownload = (vxml.@enableDownload.toString().toUpperCase() == "TRUE") ? true : false;
+				}
 			}
 		}
 	}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentationWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentationWindow.mxml
index 6f81352bbab3bf0714930b7258a125ad5f43d5d6..25294a913f9bc8f000001f4767f9c2d1938cde97 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentationWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/PresentationWindow.mxml
@@ -38,7 +38,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	creationComplete="onCreationComplete()" 
 	width="{DEFAULT_WINDOW_WIDTH}" height="{DEFAULT_WINDOW_HEIGHT}" 
 	x="{DEFAULT_X_POSITION}" y="{DEFAULT_Y_POSITION}"
-	title="{ResourceUtil.getInstance().getString('bbb.presentation.titleWithPres',[currentPresentation])}"
+	title="{ResourceUtil.getInstance().getString('bbb.presentation.title')}"
 	xmlns:views="org.bigbluebutton.modules.present.ui.views.*" 
 	xmlns:poll="org.bigbluebutton.modules.polling.views.*"
 	>
@@ -61,14 +61,20 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	<mate:Listener type="{ShortcutEvent.FIT_TO_PAGE}" method="remotePage" />	
 	<mate:Listener type="{ShortcutEvent.MINIMIZE_PRES}" method="remoteMinimize" />
 	<mate:Listener type="{ShortcutEvent.MAXIMIZE_PRES}" method="remoteMaximize" />
+	<mate:Listener type="{RemovePresentationEvent.UPDATE_DOWNLOADABLE_FILES_EVENT}" method="handleUpdateDownloadableFilesEvent" />
 	<mate:Listener type="{PollStartedEvent.POLL_STARTED}" method="pollStartedHandler" />
 	<mate:Listener type="{PollStoppedEvent.POLL_STOPPED}" method="pollStoppedHandler" />
 	<mate:Listener type="{PollShowResultEvent.SHOW_RESULT}" method="pollShowResultHandler" />
-	
+	<mate:Listener type="{ShareEvent.CREATE_SCREENSHARE_PUBLISH_TAB}" method="createScreensharePublishTab" />
+	<mate:Listener type="{ShareEvent.CLEAN_SCREENSHARE_PUBLISH_TAB}" method="cleanScreensharePublishTab" />
+	<mate:Listener type="{ShareEvent.OPEN_SCREENSHARE_VIEW_TAB}" method="openScreenshareViewTab" />
+	<mate:Listener type="{ShareEvent.CLOSE_SCREENSHARE_VIEW_TAB}" method="closeScreenshareViewTab" />
+
 	<mx:Script>
 		<![CDATA[
 			import flash.geom.Point;
 			
+			import mx.collections.ArrayCollection;
 			import mx.controls.Menu;
 			import mx.events.MenuEvent;
 			import mx.events.ResizeEvent;
@@ -78,13 +84,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			import org.as3commons.logging.api.ILogger;
 			import org.as3commons.logging.api.getClassLogger;
+			import org.bigbluebutton.common.IBbbCanvas;
 			import org.bigbluebutton.common.IBbbModuleWindow;
 			import org.bigbluebutton.common.events.LocaleChangeEvent;
 			import org.bigbluebutton.core.BBB;
 			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.main.events.MadePresenterEvent;
 			import org.bigbluebutton.main.events.ShortcutEvent;
+			import org.bigbluebutton.main.events.PresenterStatusEvent;
 			import org.bigbluebutton.main.views.MainCanvas;
+			import org.bigbluebutton.modules.screenshare.events.ShareEvent;
+			import org.bigbluebutton.modules.screenshare.events.RequestToStartSharing;
+			import org.bigbluebutton.modules.screenshare.view.components.ScreenshareViewWindow;
 			import org.bigbluebutton.modules.polling.events.PollShowResultEvent;
 			import org.bigbluebutton.modules.polling.events.PollStartedEvent;
 			import org.bigbluebutton.modules.polling.events.PollStoppedEvent;
@@ -96,9 +107,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.modules.present.commands.GoToPrevPageCommand;
 			import org.bigbluebutton.modules.present.events.AddOverlayCanvasEvent;
 			import org.bigbluebutton.modules.present.events.DisplaySlideEvent;
+			import org.bigbluebutton.modules.present.events.DownloadEvent;
 			import org.bigbluebutton.modules.present.events.NavigationEvent;
 			import org.bigbluebutton.modules.present.events.PresentationChangedEvent;
 			import org.bigbluebutton.modules.present.events.PresenterCommands;
+			import org.bigbluebutton.modules.present.events.RemovePresentationEvent;
 			import org.bigbluebutton.modules.present.events.UploadEvent;
 			import org.bigbluebutton.modules.present.model.Page;
 			import org.bigbluebutton.modules.present.model.PresentationModel;
@@ -109,6 +122,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       
       public static const TITLE:String = "Presentation";
 			private static const GOTO_PAGE_BUTTON:String = "Go to Page...";
+
+			private static const TAB_MAX_WIDTH:Number = 200;
+			private static const NO_TAB_INDEX:Number = -1;
+			private static const PRESENTATION_TAB_INDEX:Number = 0;
+			private static const SCREENSHARE_PUBLISH_TAB_INDEX:Number = 1;
+			private static const SCREENSHARE_VIEW_TAB_INDEX:Number = 2;
+			private var currentTabIndex:Number = PRESENTATION_TAB_INDEX;
+
+			private var sharing:Boolean = false;
 			
 			[Bindable] 
       private var thumbY:Number;
@@ -118,8 +140,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			[Bindable] private var DEFAULT_X_POSITION:Number = 237;
 			[Bindable] private var DEFAULT_Y_POSITION:Number = 0;
 			
-			private static const TOP_WINDOW_BORDER:Number = 30;
-			private static const WIDTH_PADDING:Number = 6;
+			private static const TOP_WINDOW_BORDER:Number = 54;
+			private static const WIDTH_PADDING:Number = 8;
 
 			[Bindable] private var DEFAULT_WINDOW_WIDTH:Number = 510;
 			[Bindable] private var DEFAULT_WINDOW_HEIGHT:Number = 451;
@@ -132,6 +154,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 									
 			private var mouseDown:Boolean = false;
 
+			private static const PRESENTATION_NAME_MAX_LENGTH:Number = 20;
 			[Bindable] private var currentPresentation:String = "";
 			
 			[Bindable] private var presentOptions:PresentOptions;
@@ -148,6 +171,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			[Embed(source="../../../polling/sounds/Poll.mp3")] 
 			private var noticeSoundClass:Class;
 			private var noticeSound:Sound = new noticeSoundClass() as Sound;
+
+			private var whiteboardOverlay:IBbbCanvas = null;
+			private var screenshareView:ScreenshareViewWindow = null;
 			
 			private function init():void{
 				presentOptions = new PresentOptions();
@@ -175,6 +201,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         t.addEventListener(TimerEvent.TIMER, addWhiteboardToolbar);
         t.start();
         
+        presenterTabs.addEventListener(MouseEvent.CLICK, onSelectTabEvent, true);
+
         if (UsersUtil.amIPresenter()) {
           becomePresenter();
         } else {
@@ -186,6 +214,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
       private function addWhiteboardToolbar(event:TimerEvent):void {
         LOGGER.debug("Sending event to add whiteboard canvas.");
+         callLater(fitSlideToWindowMaintainingAspectRatio);
          // Tell the WhiteboardManager to add the toolbar
          var e:WhiteboardButtonEvent = new WhiteboardButtonEvent(WhiteboardButtonEvent.WHITEBOARD_ADDED_TO_PRESENTATION);
          e.window = this;
@@ -266,15 +295,21 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private function fitSlideToWindowMaintainingAspectRatio():void {
 				if (this.minimized) return;
 				
-				// Send the available space to display the slide.				
-				sendWindowResizedEvent((this.width - WIDTH_PADDING), (this.height - controlBar.height - TOP_WINDOW_BORDER));
+				// Send the available space to display the slide.
+				if (controlBar != null) {
+					sendWindowResizedEvent((this.width - WIDTH_PADDING), (this.height - controlBar.height - TOP_WINDOW_BORDER));
+				}
 			}
 			
 			/*
 			 * Notify the slide container telling it the available dimensions to display the slide.
 			 */
-			private function sendWindowResizedEvent(parentWidth:Number, parentHeight:Number):void {				
-				slideView.onParentResized(parentWidth, parentHeight);
+			private function sendWindowResizedEvent(parentWidth:Number, parentHeight:Number):void {
+				if (currentTabIndex == PRESENTATION_TAB_INDEX && slideView != null) {
+					slideView.onParentResized(parentWidth, parentHeight);
+				} else if (currentTabIndex == SCREENSHARE_VIEW_TAB_INDEX && screenshareView != null) {
+					screenshareView.onParentResized(parentWidth, parentHeight);
+				}
 			}
 			
 			private function handleDisplaySlideEvent(event:DisplaySlideEvent):void {		
@@ -348,6 +383,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       }
       
 			private function becomePresenter():void{
+				startDeskshareTabCreation();
 				setupPresenter(true);
 				addContextMenuItems();
 			}
@@ -373,10 +409,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				displaySlideNavigationControls(isPresenter, !!page);
 				
 				setControlBarState("presenter");
+				currentTabIndex = NO_TAB_INDEX;
+				selectPresentationTab();
 			}
             private function handlePresentationChangedEvent(e:PresentationChangedEvent) : void {
 				currentPresentation = PresentationModel.getInstance().getCurrentPresentationName();
 
+				if (currentPresentation.length > PRESENTATION_NAME_MAX_LENGTH) {
+					presenterTabs.getTabAt(PRESENTATION_TAB_INDEX).width = TAB_MAX_WIDTH;
+				}
+
                 slideView.setSlides();
                 slideView.visible = true;
                 var page : Page = PresentationModel.getInstance().getCurrentPage();
@@ -391,6 +433,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                     displaySlideNavigationControls(false, !!page)
                 }
                 onResetZoom();
+                updateDownloadBtn();
             }
 
 			
@@ -398,6 +441,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				var showButtons:Boolean = isPresenter && activePresentation;
 				
 				pollStartBtn.visible = showButtons;
+				quickPollBtn.visible = showButtons;
 				backButton.visible = showButtons;
 				forwardButton.visible = showButtons;
 				zoomSlider.visible = showButtons;
@@ -408,6 +452,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				fitSlideToWindowMaintainingAspectRatio();
 			}
 			
+			private function startDeskshareTabCreation():void {
+				if(screenshareTab.numElements == 0) {
+					LOGGER.debug("DISPATCHING startDeskshareTabCreation");
+					dispatchEvent(new ShareEvent(ShareEvent.START_SHARING));
+				}
+			}
+
 			private function addContextMenuItems():void{
 				var contextMenuItems:Array = new Array();
 				
@@ -450,6 +501,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				slideView.setSelectedSlide(0);
 				btnSlideNum.label = "";
 				
+				pollStartBtn.visible = false;
+				quickPollBtn.visible = false;
+
 				backButton.visible = false;
 				forwardButton.visible = false;
 				zoomSlider.visible = false;
@@ -491,13 +545,27 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       
       private function addOverlayCanvas(e:AddOverlayCanvasEvent):void{
         LOGGER.debug("OVERLAYING WHITEBOARD CANVAS");
+        whiteboardOverlay = e.canvas;
+
+        LOGGER.debug("addOverlayCanvas: Adding whiteboard canvas to SlideView");
         e.canvas.acceptOverlayCanvas(slideView);
         slideView.acceptOverlayCanvas(e.canvas);
+
+        if (currentTabIndex == SCREENSHARE_VIEW_TAB_INDEX && screenshareView != null) {
+           LOGGER.debug("addOverlayCanvas: Adding whiteboard canvas to ScreenshareViewWindow");
+           screenshareView.acceptOverlayCanvas(whiteboardOverlay);
+           whiteboardOverlay.acceptOverlayCanvas(screenshareView);
+        }
       }
 					
 			override protected function resourcesChanged():void{
 				super.resourcesChanged();
-				if ((slideView != null) && (!slideView.visible)) this.title = ResourceUtil.getInstance().getString('bbb.presentation.title');
+				if (slideView != null && !slideView.visible) {
+					presentationTab.label = currentPresentation;
+					if (currentPresentation.length > PRESENTATION_NAME_MAX_LENGTH) {
+						presenterTabs.getTabAt(PRESENTATION_TAB_INDEX).width = TAB_MAX_WIDTH;
+					}
+				}
 				
 				if (titleBarOverlay != null) {
 					titleBarOverlay.accessibilityName = ResourceUtil.getInstance().getString('bbb.presentation.titleBar');
@@ -519,6 +587,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 				addContextMenuItems();
 				
+				updateDownloadBtnTooltip();
 				setPollMenuData();
 			}
 			
@@ -533,11 +602,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
 			
 			override protected function hideAllChildren():void {
-				slideView.includeInLayout=false;
+				presentationTab.includeInLayout = false;
 			}
 			
 			override protected function showAllChildren():void {
-				slideView.includeInLayout=true;
+				presentationTab.includeInLayout = true;
 			}
 			
 			private function remoteUpload(e:ShortcutEvent):void{
@@ -581,6 +650,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					onFitToPage(true);
 				}
 			}
+
+			private function onDownloadButtonClicked():void {
+				openDownloadWindow();
+			}
+
+			private function openDownloadWindow():void {
+				var event:DownloadEvent = new DownloadEvent(DownloadEvent.OPEN_DOWNLOAD_WINDOW);
+				dispatchEvent(event);
+			}
 			
 			private function onUploadButtonClicked():void {
 				openUploadWindow();	
@@ -747,20 +825,39 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			
 			private function setControlBarState(state:String):void {
 				if (state == "vote") {
+					btnActualSize.visible = false;
 					presenterControls.visible = false;
 					presenterControls.includeInLayout = false;
 					pollVoteBox.visible = true;
 					pollVoteBox.includeInLayout = true;
-				} else if (state == "presenter" && UsersUtil.amIPresenter()) {
+					downloadPres.visible = false;
+				} else if (state == "presenter" && UsersUtil.amIPresenter() && currentTabIndex == PRESENTATION_TAB_INDEX) {
+					downloadPres.visible = true;
+					pollStartBtn.visible = true;
 					presenterControls.visible = true;
 					presenterControls.includeInLayout = true;
 					pollVoteBox.visible = false;
 					pollVoteBox.includeInLayout = false;
+					btnClosePublish.visible = false;
+					btnActualSize.visible = false;
+					presenterTabs.getTabAt(SCREENSHARE_PUBLISH_TAB_INDEX).visible = true;
+					presenterTabs.getTabAt(SCREENSHARE_PUBLISH_TAB_INDEX).includeInLayout = true;
 				} else {
-					presenterControls.visible = false;
-					presenterControls.includeInLayout = false;
 					pollVoteBox.visible = false;
 					pollVoteBox.includeInLayout = false;
+					if (currentTabIndex == PRESENTATION_TAB_INDEX) {
+						pollStartBtn.visible = false;
+						downloadPres.visible = true;
+						presenterControls.visible = false;
+						presenterControls.includeInLayout = false;
+						btnActualSize.visible = false;
+						btnClosePublish.visible = false;
+						presenterTabs.getTabAt(SCREENSHARE_PUBLISH_TAB_INDEX).visible = false;
+						presenterTabs.getTabAt(SCREENSHARE_PUBLISH_TAB_INDEX).includeInLayout = false;
+					} else if (currentTabIndex == SCREENSHARE_VIEW_TAB_INDEX) {
+						btnActualSize.visible = true;
+						downloadPres.visible = true;
+					}
 				}
 				
 				// Need to call the function later because the heights haven't been validated yet
@@ -776,28 +873,258 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				setControlBarState("presenter");
 			}
 
+			private function handleUpdateDownloadableFilesEvent(e:RemovePresentationEvent):void {
+				updateDownloadBtn();
+			}
+
+			private function updateDownloadBtn():void {
+				if (downloadPres == null) {
+					return;
+				}
+
+				if (currentTabIndex == SCREENSHARE_PUBLISH_TAB_INDEX || pollVoteBox.visible) {
+					downloadPres.visible = false;
+					return;
+				}
+
+				downloadPres.visible = presentOptions.enableDownload;
+				var downloadablePresentations:ArrayCollection = PresentationModel.getInstance().getDownloadablePresentations();
+				if (downloadablePresentations.length > 0) {
+					LOGGER.debug("Enabling download presentation button. There are {0} presentations available for downloading.", [downloadablePresentations.length]);
+					downloadPres.enabled = true;
+					downloadPres.styleName = "presentationDownloadButtonStyle";
+				} else {
+					LOGGER.debug("Disabling download presentation button. There are {0} presentations available for downloading.", [downloadablePresentations.length]);
+					downloadPres.enabled = false;
+					downloadPres.styleName = "presentationDownloadButtonDisabledStyle";
+				}
+				updateDownloadBtnTooltip();
+			}
+
+			private function updateDownloadBtnTooltip():void {
+				if (downloadPres == null) {
+					return;
+				}
+
+				const res:String = downloadPres.enabled? "bbb.presentation.downloadPresBtn.toolTip": "bbb.presentation.downloadPresBtn.disabledToolTip";
+				downloadPres.toolTip = ResourceUtil.getInstance().getString(res);
+			}
+
+			private function selectPresentationTab():void {
+				presenterTabs.selectedIndex = PRESENTATION_TAB_INDEX;
+				onSelectTab();
+			}
+
+			private function selectDesksharePublishTab():void {
+				presenterTabs.selectedIndex = SCREENSHARE_PUBLISH_TAB_INDEX;
+				onSelectTab();
+			}
+
+			private function selectDeskshareViewTab():void {
+				presenterTabs.selectedIndex = SCREENSHARE_VIEW_TAB_INDEX;
+				onSelectTab();
+			}
+
+			private function onSelectTabEvent(event:MouseEvent):void {
+				onSelectTab();
+			}
+
+			private function onSelectTab():void {
+				if (presenterTabs.selectedIndex != currentTabIndex) {
+					if(presenterTabs.selectedIndex == PRESENTATION_TAB_INDEX) {
+						handlePresentationTabSelected();
+					} else if (presenterTabs.selectedIndex == SCREENSHARE_PUBLISH_TAB_INDEX) {
+						handleDesktopPublishTabSelected();
+					} else {
+						handleDesktopViewTabSelected();
+					}
+					updateDownloadBtn();
+				}
+				callLater(fitSlideToWindowMaintainingAspectRatio);
+			}
+
+			private function handlePresentationTabSelected():void {
+				LOGGER.debug("Handling Presentation Tab selected");
+				currentTabIndex = PRESENTATION_TAB_INDEX;
+
+				if (sharing) {
+					stopSharing();
+				}
+
+				if (whiteboardOverlay != null) {
+					slideView.acceptOverlayCanvas(whiteboardOverlay);
+					whiteboardOverlay.acceptOverlayCanvas(slideView);
+				}
+
+				btnActualSize.visible = false;
+				btnClosePublish.visible = false;
+				if (UsersUtil.amIPresenter()) {
+					setControlBarState("presenter");
+					annotationsPermissionChanged(true);
+				} else if(presenterTabs.getTabAt(SCREENSHARE_PUBLISH_TAB_INDEX).visible) {
+					presenterTabs.getTabAt(SCREENSHARE_PUBLISH_TAB_INDEX).visible = false;
+					presenterTabs.getTabAt(SCREENSHARE_PUBLISH_TAB_INDEX).includeInLayout = false;
+				}
+			}
+
+			private function handleDesktopPublishTabSelected():void {
+				LOGGER.debug("Handling Desktop Publish Tab selected");
+				currentTabIndex = SCREENSHARE_PUBLISH_TAB_INDEX;
+				startDeskshareTabCreation();
+
+				if (UsersUtil.amIPresenter()) {
+					dispatchEvent(new RequestToStartSharing());
+					presenterControls.visible = false;
+					presenterControls.includeInLayout = false;
+					pollStartBtn.visible = false;
+					annotationsPermissionChanged(false);
+				}
+			}
+
+			private function handleDesktopViewTabSelected():void {
+				LOGGER.debug("Handling Desktop View Tab selected");
+				currentTabIndex = SCREENSHARE_VIEW_TAB_INDEX;
+
+				if (whiteboardOverlay != null && screenshareView != null) {
+					LOGGER.debug("Adding whiteboard layer to Deskshare View Canvas");
+					screenshareView.acceptOverlayCanvas(whiteboardOverlay);
+					whiteboardOverlay.acceptOverlayCanvas(screenshareView);
+					if(UsersUtil.amIPresenter()) {
+						annotationsPermissionChanged(true);
+					}
+				} else {
+					LOGGER.debug("openScreenshareViewTab: whiteboard overlay or desktop view canvas is null!");
+				}
+
+				if (!pollVoteBox.visible) {
+					btnActualSize.visible = true;
+				}
+				if (UsersUtil.amIPresenter()) {
+					pollStartBtn.visible = true;
+					btnClosePublish.visible = true;
+				}
+			}
+
+			private function stopSharing():void {
+				LOGGER.debug("Stopping desktop publish");
+				presenterTabs.getTabAt(SCREENSHARE_VIEW_TAB_INDEX).visible = false;
+				presenterTabs.getTabAt(SCREENSHARE_VIEW_TAB_INDEX).includeInLayout = false;
+				dispatchEvent(new ShareEvent(ShareEvent.STOP_SHARING));
+				sharing = false;
+			}
+
+			private function createScreensharePublishTab(e:ShareEvent):void {
+				if (e.publishTabContent != null && screenshareTab.numElements == 0) {
+
+					LOGGER.debug("Setting the content of dekstop share PUBLISHING tab");
+					e.publishTabContent.percentHeight = 100;
+					e.publishTabContent.percentWidth = 100;
+					screenshareTab.addChild(e.publishTabContent);
+				} else {
+					LOGGER.debug("publishTabContent is NULL.");
+				}
+			}
+
+			private function cleanScreensharePublishTab(e:ShareEvent):void {
+				if (screenshareTab.numElements != 0) {
+					LOGGER.debug("Removing content of dekstop share PUBLISHING tab");
+					screenshareTab.removeAllElements();
+				}
+			}
+
+			private function openScreenshareViewTab(e:ShareEvent):void {
+				if (e.viewTabContent != null && presenterTabs.numElements == 2) {
+					screenshareView = e.viewTabContent;
+
+					LOGGER.debug("Opening a new tab for dekstop share VIEWING");
+					e.viewTabContent.percentHeight = 100;
+					e.viewTabContent.percentWidth = 100;
+					e.viewTabContent.setStyle("horizontalAlign","center");
+					e.viewTabContent.label = ResourceUtil.getInstance().getString('bbb.screenshareView.title');
+
+					presenterTabs.addChild(e.viewTabContent);
+					selectDeskshareViewTab();
+
+					if (UsersUtil.amIPresenter()) {
+						sharing = true;
+						presenterTabs.getTabAt(SCREENSHARE_PUBLISH_TAB_INDEX).visible = false;
+						presenterTabs.getTabAt(SCREENSHARE_PUBLISH_TAB_INDEX).includeInLayout = false;
+					}
+				} else {
+					LOGGER.debug("viewTabContent is NULL.");
+				}
+			}
+
+			private function closeScreenshareViewTab(e:ShareEvent):void {
+				LOGGER.debug("Closing the dekstop share VIEWING tab");
+				selectPresentationTab();
+				if (screenshareViewTabExists()) {
+					btnActualSize.selected = false;
+					presenterTabs.removeChildAt(SCREENSHARE_VIEW_TAB_INDEX);
+					screenshareView = null;
+				}
+			}
+
+			private function screenshareViewTabExists():Boolean {
+				return presenterTabs.numElements == 3;
+			}
+
+			private function annotationsPermissionChanged(enableAnnotations:Boolean):void {
+				var event:PresenterStatusEvent = new PresenterStatusEvent(PresenterStatusEvent.ANNOTATIONS_PERMISSION_CHANGE);
+				event.enableAnnotations = enableAnnotations;
+				dispatchEvent(event);
+			}
+
+			private function changeVideoDisplayMode():void {
+				var e:ShareEvent = new ShareEvent(ShareEvent.CHANGE_VIDEO_DISPLAY_MODE);
+				e.fullScreen = btnActualSize.selected;
+				LOGGER.debug("Dispatching event for change desktop video display mode. Full screen = " + e.fullScreen);
+				dispatchEvent(e);
+			}
+
+			private function startDeskshare(event:TimerEvent):void {
+				if (UsersUtil.amIPresenter()) {
+					LOGGER.debug("Handling deskshare auto start");
+					selectDesksharePublishTab();
+					sendShareScreenEvent(true);
+				}
+			}
+
+			private function sendShareScreenEvent(fullScreen:Boolean):void {
+				var e:ShareEvent = new ShareEvent(ShareEvent.SHARE_SCREEN);
+				e.fullScreen = fullScreen;
+				dispatchEvent(e);
+			}
 		]]>
 	</mx:Script>
 	
 	<pres:TabIndexer startIndex="{presentOptions.baseTabIndex + 1}"
-					 tabIndices="{[minimizeBtn, maximizeRestoreBtn, closeBtn, slideView.slideLoader, uploadPres, pollStartBtn, quickPollBtn, backButton, btnSlideNum, forwardButton, zoomSlider, btnFitToWidth, btnFitToPage]}"/>
+			tabIndices="{[minimizeBtn, maximizeRestoreBtn, closeBtn, slideView.slideLoader, pollStartBtn, quickPollBtn, uploadPres, backButton, btnSlideNum, forwardButton, zoomSlider, btnFitToWidth, btnFitToPage, btnClosePublish, btnActualSize]}"/>
   	 
 	<mx:Fade id="thumbFadeIn" alphaFrom="1" alphaTo="0" duration="100" />
 	<mx:Fade id="thumbFadeOut" alphaFrom="0" alphaTo="1" duration="100" />
 
-	<views:SlideView id="slideView" width="100%" height="100%" visible="false" mouseDown="mouseDown = true"
-		mouseUp="mouseDown = false" verticalScrollPolicy="off" horizontalScrollPolicy="off"/>			    
-	<mx:ControlBar id="presCtrlBar" name="presCtrlBar" width="100%" verticalAlign="middle" styleName="presentationWindowControlsStyle" 
-				   paddingTop="2" paddingBottom="2">
-		<mx:HBox id="presenterControls" width="100%" height="100%" visible="false" includeInLayout="false" horizontalAlign="center">
-			<mx:Button id="uploadPres" visible="false" height="30" styleName="presentationUploadButtonStyle"
+	<mx:TabNavigator id="presenterTabs" borderStyle="none" width="100%" height="100%" creationPolicy="all" paddingTop="0" paddingBottom="0" paddingLeft="0" paddingRight="0" backgroundAlpha="0.0">
+		<mx:VBox id="presentationTab" label="{currentPresentation}" width="100%" height="100%" paddingTop="0" paddingBottom="0" paddingLeft="0" paddingRight="0" verticalAlign="middle" horizontalAlign="center" backgroundAlpha="0.0" verticalScrollPolicy="off" horizontalScrollPolicy="off">
+			<views:SlideView id="slideView" width="100%" height="100%" visible="false" mouseDown="mouseDown = true" mouseUp="mouseDown = false" verticalScrollPolicy="off" horizontalScrollPolicy="off"/>
+		</mx:VBox>
+		<mx:VBox id="screenshareTab" label="{ResourceUtil.getInstance().getString('bbb.screensharePublish.title')}" width="100%" height="100%" paddingTop="7" paddingBottom="0" paddingLeft="0" paddingRight="0" verticalAlign="middle" horizontalAlign="center" backgroundAlpha="0.0"/>
+	</mx:TabNavigator>
+
+	<mx:ControlBar id="presCtrlBar" name="presCtrlBar" width="100%" verticalAlign="middle" styleName="presentationWindowControlsStyle" paddingTop="2" paddingBottom="2">
+		<mx:Button id="pollStartBtn" visible="false" height="30" styleName="pollStartButtonStyle"
+				toolTip="{ResourceUtil.getInstance().getString('bbb.polling.startButton.tooltip')}"
+				click="onPollStartButtonClicked()" includeInLayout="{pollStartBtn.visible}"/>
+		<poll:QuickPollButton id="quickPollBtn" height="30"
+				click="quickPollClicked(event)"
+				includeInLayout="{quickPollBtn.visible}" />
+		<mx:Button id="downloadPres" visible="{presentOptions.enableDownload}"
+				includeInLayout="{downloadPres.visible}" height="30" width="30"
+				click="onDownloadButtonClicked()" creationComplete="updateDownloadBtn()"/>
+		<mx:HBox id="presenterControls" width="100%" height="100%" visible="false" includeInLayout="false" horizontalAlign="left">
+			<mx:Button id="uploadPres" visible="false" height="30" width="30" styleName="presentationUploadButtonStyle"
 					   toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.uploadPresBtn.toolTip')}" 
 					   click="onUploadButtonClicked()"/>
-			<mx:Button id="pollStartBtn" visible="false" height="30" styleName="pollStartButtonStyle"
-					   toolTip="{ResourceUtil.getInstance().getString('bbb.polling.startButton.tooltip')}" 
-					   click="onPollStartButtonClicked()"/>
-			<poll:QuickPollButton id="quickPollBtn" height="30"
-								  click="quickPollClicked(event)" />
 			<mx:Spacer width="100%" id="spacer1"/>
 			<mx:Button id="backButton" visible="false" width="45" height="30" styleName="presentationBackButtonStyle"
 					   toolTip="{ResourceUtil.getInstance().getString('bbb.presentation.backBtn.toolTip')}" click="gotoPreviousSlide()"/>
@@ -820,6 +1147,21 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			<!-- This spacer is to prevent the whiteboard toolbar from overlapping the fit-ot-page button -->
 			<mx:Spacer width="30" height="30" id="spacer4"/>
 		</mx:HBox>
+
+		<mx:Button id="btnClosePublish"
+				label="{ResourceUtil.getInstance().getString('bbb.screensharePublish.stopButton.label')}"
+				visible="false"
+				includeInLayout="{btnClosePublish.visible}"
+				click="selectPresentationTab()"/>
+
+		<mx:Button id="btnActualSize"
+				visible="false"
+				includeInLayout="{btnActualSize.visible}"
+				toggle="true"
+				click="changeVideoDisplayMode()"
+				selected="false"
+				label="{btnActualSize.selected ? ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow') : ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize')}"/>
+
 		<mx:HBox id="pollVoteBox" width="100%" height="100%" visible="false" includeInLayout="false" horizontalAlign="center" />
     </mx:ControlBar>
 </pres:CustomMdiWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/SlideView.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/SlideView.mxml
index d6c612abef275bafff48e29f5a7b382f91a6d76a..398114c5b0feb3b5e243645748ae834b02148ee2 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/SlideView.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/SlideView.mxml
@@ -473,6 +473,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
 			
 			public function acceptOverlayCanvas(overlay:IBbbCanvas):void{
+				cleanCanvasHolder();
 				whiteboardCanvas = overlay;
 				var c:Canvas = overlay as Canvas;
                 // add the canvas below the thumbnails
@@ -517,6 +518,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				focusManager.setFocus(slideLoader);
 				slideLoader.drawFocus(true);
 			}
+
+			private function cleanCanvasHolder():void{
+				while (this.whiteboardCanvasHolder.rawChildren.numChildren > 0) {
+					this.whiteboardCanvasHolder.rawChildren.removeChildAt(0);
+				}
+			}
 			
 		]]>
 	</mx:Script>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/UploadedPresentationRenderer.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/UploadedPresentationRenderer.mxml
index 48732ac416e388f67d9b5f69ff95a233a24d2dce..1981450bf06774a4f1c0d42b5762aee9fcc49e41 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/UploadedPresentationRenderer.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/present/ui/views/UploadedPresentationRenderer.mxml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" 
 		 width="90%" 
+		 creationComplete="onCreationComplete()"
 		 verticalScrollPolicy="off" 
 		 horizontalScrollPolicy="off" 
 		 toolTip="{data as String}" 
@@ -11,6 +12,7 @@
 		
 		import org.as3commons.logging.api.ILogger;
 		import org.as3commons.logging.api.getClassLogger;
+		import org.bigbluebutton.common.Images;
 		import org.bigbluebutton.modules.present.commands.ChangePresentationCommand;
 		import org.bigbluebutton.modules.present.events.RemovePresentationEvent;
 		import org.bigbluebutton.modules.present.events.UploadEvent;
@@ -20,6 +22,11 @@
 
 		private var globalDispatch:Dispatcher = new Dispatcher();
       
+      private function onCreationComplete():void {
+          var images:Images = new Images();
+          isDownloadable.source = images.disk_grayscale;
+      }
+
       private function showPresentation():void {
         LOGGER.debug("FileUploadWindow::showPresentation() {0}", [data.id]);   
         var changePresCommand:ChangePresentationCommand = new ChangePresentationCommand(data.id);
@@ -37,7 +44,10 @@
       }
     ]]>
   </mx:Script>
-  <mx:Label id="presentationNameLabel" width="{this.width-showBtn.width-deleteBtn.width-30}" text="{data.name as String}" styleName="presentationNameLabelStyle"/>
+  <mx:Label id="presentationNameLabel" width="{this.width-isDownloadable.width-showBtn.width-deleteBtn.width-30}" text="{data.name as String}" styleName="presentationNameLabelStyle"/>
+  <mx:Image id="isDownloadable" visible="{data.downloadable as Boolean}"
+             toolTip="{ResourceUtil.getInstance().getString('bbb.filedownload.thisFileIsDownloadable')}"
+             verticalAlign="middle" />
   <mx:Button id="showBtn" label="{ResourceUtil.getInstance().getString('bbb.fileupload.showBtn')}" 
              toolTip="{ResourceUtil.getInstance().getString('bbb.fileupload.showBtn.toolTip')}" 
              styleName="presentationUploadShowButtonStyle" height="26"
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/events/ShareEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/events/ShareEvent.as
index 4f07471be3060460ce18f1cb4394d10f0aee384b..a9e773e6ae1331786ca5f812a254b4e5b9e62211 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/events/ShareEvent.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/events/ShareEvent.as
@@ -19,12 +19,27 @@
 package org.bigbluebutton.modules.screenshare.events
 {
 	import flash.events.Event;
+	import org.bigbluebutton.modules.screenshare.view.components.ScreensharePublishWindow;
+	import org.bigbluebutton.modules.screenshare.view.components.ScreenshareViewWindow;
 
 	public class ShareEvent extends Event
 	{
 		public static const START_SHARING:String = "SCREENSHARE START SHARING";
 		public static const STOP_SHARING:String = "SCREENSHARE STOP SHARING";
+
+		public static const CREATE_SCREENSHARE_PUBLISH_TAB:String = "CREATE SCREENSHARE PUBLISH TAB";
+		public static const CLEAN_SCREENSHARE_PUBLISH_TAB:String = "CLEAN SCREENSHARE PUBLISH TAB";
+
+		public static const OPEN_SCREENSHARE_VIEW_TAB:String = "OPEN SCREENSHARE VIEW TAB";
+		public static const CLOSE_SCREENSHARE_VIEW_TAB:String = "CLOSE SCREENSHARE VIEW TAB";
+
+		public static const SHARE_SCREEN:String = "SHARE SCREEN";
+		public static const CHANGE_VIDEO_DISPLAY_MODE:String = "CHANGE VIDEO DISPLAY MODE";
 		
+		public var publishTabContent:ScreensharePublishWindow;
+		public var viewTabContent:ScreenshareViewWindow;
+		public var fullScreen:Boolean;
+
 		public function ShareEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
 		{
 			super(type, bubbles, cancelable);
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/PublishWindowManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/PublishWindowManager.as
index af93712d3a4a445da1002feffd9bcb7a2e953f28..441345e6079aa62c81ca2e5ddd6c559aca2ef4c9 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/PublishWindowManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/PublishWindowManager.as
@@ -31,6 +31,7 @@ package org.bigbluebutton.modules.screenshare.managers {
     import org.bigbluebutton.common.events.OpenWindowEvent;
     import org.bigbluebutton.modules.screenshare.services.ScreenshareService;
     import org.bigbluebutton.modules.screenshare.view.components.ScreensharePublishWindow;
+    import org.bigbluebutton.modules.screenshare.events.ShareEvent;
     
     public class PublishWindowManager {
         private static const LOGGER:ILogger = getClassLogger(PublishWindowManager);
@@ -47,7 +48,10 @@ package org.bigbluebutton.modules.screenshare.managers {
         }
         
         public function stopSharing():void {
-            if (shareWindow != null) shareWindow.stopSharing();
+            if (shareWindow != null) {
+                shareWindow.stopSharing();
+                shareWindow = null;
+            }
         }
         
         public function startSharing(uri:String, room:String):void {
@@ -59,23 +63,27 @@ package org.bigbluebutton.modules.screenshare.managers {
               openWindow(shareWindow);
             }
         }
+
+        public function handleShareScreenEvent(fullScreen:Boolean):void {
+            if (shareWindow != null) {
+                LOGGER.debug("Starting deskshare publishing. fullScreen = " + fullScreen);
+                shareWindow.shareScreen(fullScreen);
+            }
+        }
         
         public function handleShareWindowCloseEvent():void {
-            closeWindow(shareWindow);
+            closeWindow();
         }
         
-        private function openWindow(window:IBbbModuleWindow):void {
-            var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
-            event.window = window;
-            globalDispatcher.dispatchEvent(event);
+        private function openWindow(window:ScreensharePublishWindow):void {
+            var e:ShareEvent = new ShareEvent(ShareEvent.CREATE_SCREENSHARE_PUBLISH_TAB);
+            e.publishTabContent = window;
+            globalDispatcher.dispatchEvent(e);
         }
         
-        private function closeWindow(window:IBbbModuleWindow):void {
-            var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
-            event.window = window;
-            globalDispatcher.dispatchEvent(event);
-            
-            shareWindow = null;
+        private function closeWindow():void {
+            var e:ShareEvent = new ShareEvent(ShareEvent.CLEAN_SCREENSHARE_PUBLISH_TAB);
+            globalDispatcher.dispatchEvent(e);
         }
     }
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ScreenshareManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ScreenshareManager.as
index de6bd81eb4342a99b3877c44be5c08c24debe850..144d620fb7236b56521dd43cb683e028629fca4a 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ScreenshareManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ScreenshareManager.as
@@ -85,12 +85,7 @@ package org.bigbluebutton.modules.screenshare.managers {
             ScreenshareModel.getInstance().height = event.height;
             ScreenshareModel.getInstance().url = event.url;
             
-            if (UsersUtil.amIPresenter()) {
-                //        var dispatcher:Dispatcher = new Dispatcher();
-                //        dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));        
-            } else {
-                handleStreamStartEvent(ScreenshareModel.getInstance().streamId, event.width, event.height);
-            }
+            handleStreamStartEvent(ScreenshareModel.getInstance().streamId, event.width, event.height);
             
             var dispatcher:Dispatcher = new Dispatcher();
             dispatcher.dispatchEvent(new ViewStreamEvent(ViewStreamEvent.START));
@@ -208,6 +203,15 @@ package org.bigbluebutton.modules.screenshare.managers {
             sharing = true;
         }
         
+        public function handleShareScreenEvent(fullScreen:Boolean):void {
+            publishWindowManager.handleShareScreenEvent(fullScreen);
+        }
+
+        public function handleStopSharingEvent():void {
+            sharing = false;
+            publishWindowManager.stopSharing();
+        }
+
         public function handleShareWindowCloseEvent():void {
             //toolbarButtonManager.enableToolbarButton();
             publishWindowManager.handleShareWindowCloseEvent();
@@ -231,5 +235,16 @@ package org.bigbluebutton.modules.screenshare.managers {
           JSLog.warn("ScreenshareManager::handleDeskshareToolbarStopEvent", {});
           toolbarButtonManager.stoppedSharing();
         }
+
+        public function handleStopViewStreamEvent():void {
+            viewWindowManager.stopViewing();
+            if (UsersUtil.amIPresenter()) {
+                publishWindowManager.stopSharing();
+            }
+        }
+
+        public function handleVideoDisplayModeEvent(actualSize:Boolean):void {
+            viewWindowManager.handleVideoDisplayModeEvent(actualSize);
+        }
     }
 }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/SmartWindowResizer.as b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/SmartWindowResizer.as
new file mode 100644
index 0000000000000000000000000000000000000000..f57a6acb9e22a37e262e4ad7dce5addcfd4f52b6
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/SmartWindowResizer.as
@@ -0,0 +1,76 @@
+package org.bigbluebutton.modules.screenshare.managers {
+    public class SmartWindowResizer {
+
+        static private var RESIZING_DIRECTION_UNKNOWN:int = 0;
+        static private var RESIZING_DIRECTION_VERTICAL:int = 1;
+        static private var RESIZING_DIRECTION_HORIZONTAL:int = 2;
+        static private var RESIZING_DIRECTION_BOTH:int = 3;
+        private var _resizeDirection:int;
+
+        public function SmartWindowResizer() {}
+
+        public function onResizeStart():void {
+            /**
+             * when the window is resized by the user, the application doesn't know
+             * about the resize direction
+             */
+            _resizeDirection = RESIZING_DIRECTION_UNKNOWN;
+        }
+
+        public function onResizeEnd():void {
+            /**
+             * after the resize ends, the direction is set to BOTH because of the
+             * non-user resize actions - like when the window is docked, and so on
+             */
+            _resizeDirection = RESIZING_DIRECTION_BOTH;
+        }
+
+        public function onResize(externalWidth:int, externalHeight:int, maximized:Boolean, internalWidth:int, internalHeight:int, internalAspectRatio:Number, keepInternalAspectRatio:Boolean, callback:Function):void {
+            var internalWidthCandidate:int = externalWidth;
+            var internalHeightCandidate:int = externalHeight;
+
+            // try to discover in which direction the user is resizing the window
+            if (_resizeDirection != RESIZING_DIRECTION_BOTH) {
+                if (internalWidthCandidate == internalWidth && internalHeightCandidate != internalHeight) {
+                    _resizeDirection = (_resizeDirection == RESIZING_DIRECTION_VERTICAL || _resizeDirection == RESIZING_DIRECTION_UNKNOWN? RESIZING_DIRECTION_VERTICAL: RESIZING_DIRECTION_BOTH);
+                } else if (internalWidthCandidate != internalWidth && internalHeightCandidate == internalHeight) {
+                    _resizeDirection = (_resizeDirection == RESIZING_DIRECTION_HORIZONTAL || _resizeDirection == RESIZING_DIRECTION_UNKNOWN? RESIZING_DIRECTION_HORIZONTAL: RESIZING_DIRECTION_BOTH);
+                } else {
+                    _resizeDirection = RESIZING_DIRECTION_BOTH;
+                }
+            }
+
+            // depending on the direction, the tmp size is different
+            switch (_resizeDirection) {
+                case RESIZING_DIRECTION_VERTICAL:
+                    internalWidthCandidate = Math.floor(internalHeightCandidate * internalAspectRatio);
+                    break;
+                case RESIZING_DIRECTION_HORIZONTAL:
+                    internalHeightCandidate = Math.floor(internalWidthCandidate / internalAspectRatio);
+                    break;
+                case RESIZING_DIRECTION_BOTH:
+                    // this direction is used also for non-user window resize actions
+                    internalWidthCandidate = Math.min (internalWidthCandidate, Math.floor(internalHeightCandidate * internalAspectRatio));
+                    internalHeightCandidate = Math.min (internalHeightCandidate, Math.floor(internalWidthCandidate / internalAspectRatio));
+                    break;
+            }
+
+            var internalOffsetX:int;
+            var internalOffsetY:int;
+
+            if (!keepInternalAspectRatio || maximized) {
+                // center the video in the window
+                internalOffsetX = Math.floor ((externalWidth - internalWidthCandidate) / 2);
+                internalOffsetY = Math.floor ((externalHeight - internalHeightCandidate) / 2);
+            } else {
+                // fit window dimensions on video
+                internalOffsetX = 0;
+                internalOffsetY = 0;
+                externalWidth = internalWidthCandidate;
+                externalHeight = internalHeightCandidate;
+            }
+
+            callback(externalWidth, externalHeight, internalWidthCandidate, internalHeightCandidate, internalOffsetX, internalOffsetY);
+        }
+    }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ViewerWindowManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ViewerWindowManager.as
index 09e9d40c9d71b5d14d98ea180898dbff1c13f312..6ee704fcd8ba29a00732846367529eced52ee7a4 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ViewerWindowManager.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/managers/ViewerWindowManager.as
@@ -28,6 +28,7 @@ package org.bigbluebutton.modules.screenshare.managers {
     import org.bigbluebutton.common.events.OpenWindowEvent;
     import org.bigbluebutton.modules.screenshare.services.ScreenshareService;
     import org.bigbluebutton.modules.screenshare.view.components.ScreenshareViewWindow;
+    import org.bigbluebutton.modules.screenshare.events.ShareEvent;
     
     public class ViewerWindowManager {
         private static const LOGGER:ILogger = getClassLogger(ViewerWindowManager);
@@ -46,23 +47,21 @@ package org.bigbluebutton.modules.screenshare.managers {
             if (isViewing) viewWindow.stopViewing();
         }
         
-        
-        private function openWindow(window:IBbbModuleWindow):void {
-            var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
-            event.window = window;
-            globalDispatcher.dispatchEvent(event);
+        private function openWindow(window:ScreenshareViewWindow):void {
+            var e:ShareEvent = new ShareEvent(ShareEvent.OPEN_SCREENSHARE_VIEW_TAB);
+            e.viewTabContent = window;
+            globalDispatcher.dispatchEvent(e);
         }
         
         public function handleViewWindowCloseEvent():void {
             LOGGER.debug("ViewerWindowManager Received stop viewing command");
-            closeWindow(viewWindow);
+            closeWindow();
             isViewing = false;
         }
         
-        private function closeWindow(window:IBbbModuleWindow):void {
-            var event:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
-            event.window = window;
-            globalDispatcher.dispatchEvent(event);
+        private function closeWindow():void {
+            var e:ShareEvent = new ShareEvent(ShareEvent.CLOSE_SCREENSHARE_VIEW_TAB);
+            globalDispatcher.dispatchEvent(e);
         }
         
         public function startViewing(streamId:String, videoWidth:Number, videoHeight:Number):void {
@@ -73,5 +72,11 @@ package org.bigbluebutton.modules.screenshare.managers {
             
             isViewing = true;
         }
+
+        public function handleVideoDisplayModeEvent(actualSize:Boolean):void{
+            if (isViewing) {
+                viewWindow.actualSize = actualSize;
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/maps/ScreenshareEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/maps/ScreenshareEventMap.mxml
index d38492fd05be8abac19799d9a92e0d4d2ad614bc..2839ebb9a4446598a9abfc452ddf289fe3dda211 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/maps/ScreenshareEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/maps/ScreenshareEventMap.mxml
@@ -58,6 +58,22 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		<ObjectBuilder generator="{ScreenshareManager}"/>
 	</EventHandlers>
 		
+	<EventHandlers type="{ShareEvent.SHARE_SCREEN}">
+		<MethodInvoker generator="{ScreenshareManager}" method="handleShareScreenEvent" arguments="{event.fullScreen}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{ShareEvent.STOP_SHARING}">
+		<MethodInvoker generator="{ScreenshareManager}" method="handleStopSharingEvent"/>
+	</EventHandlers>
+
+	<EventHandlers type="{ShareEvent.CHANGE_VIDEO_DISPLAY_MODE}">
+		<MethodInvoker generator="{ScreenshareManager}" method="handleVideoDisplayModeEvent" arguments="{event.fullScreen}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{BBBEvent.START_DESKSHARE}">
+		<MethodInvoker generator="{ScreenshareManager}" method="handleStartSharingEvent"/>
+	</EventHandlers>
+
 	<EventHandlers type="{ShareEvent.START_SHARING}">
 		<MethodInvoker generator="{ScreenshareManager}" method="handleStartSharingEvent"/>
 	</EventHandlers>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreensharePublishWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreensharePublishWindow.mxml
index 240c0e7f2ee98fc4c2b278122a5ee370d0a18f6d..0b6e61a53fe868b6bbf78ce7057171630297d1cf 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreensharePublishWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreensharePublishWindow.mxml
@@ -20,21 +20,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 
 -->
 
-<dspub:MDIWindow 
+<mx:Canvas
   xmlns:mx="http://www.adobe.com/2006/mxml" 
-  implements="org.bigbluebutton.common.IBbbModuleWindow"
   xmlns:mate="http://mate.asfusion.com/"
-  xmlns:dspub="flexlib.mdi.containers.*"
-  backgroundColor="#C0C0C0"
-  initialize="init()"
   creationComplete="onCreationComplete()"	
+  xmlns:dspub="org.bigbluebutton.common.*"
   verticalScrollPolicy="off" horizontalScrollPolicy="off"
-  width="700" height="350"
-  title="{ResourceUtil.getInstance().getString('bbb.screensharePublish.title')}"
-  resizable="false">
+  width="700" height="350">
   
   <mate:Listener type="{StartShareRequestSuccessEvent.START_SHARE_REQUEST_SUCCESS}" method="handleStartShareRequestSuccessEvent" />
-  <mate:Listener type="{ScreenSharePausedEvent.SCREENSHARE_PAUSED}" method="handleScreenSharePausedEvent" />
+  <!--mate:Listener type="{ScreenSharePausedEvent.SCREENSHARE_PAUSED}" method="handleScreenSharePausedEvent" /-->
   <mate:Listener type="{ShareStoppedEvent.SHARE_STOPPED}" method="handleScreenShareShareStoppedEvent" />
   <mate:Listener type="{ViewStreamEvent.START}" method="handleStartViewStreamEvent" />
   <mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="onChangedPresenter" />
@@ -132,20 +127,20 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         
         browser = ExternalInterface.call("determineBrowser")[0];
         
-        windowControls.maximizeRestoreBtn.enabled = false;
+        //windowControls.maximizeRestoreBtn.enabled = false;
         
-        titleBarOverlay.tabIndex = baseIndex;
-        titleBarOverlay.focusEnabled = true;
+        //titleBarOverlay.tabIndex = baseIndex;
+        //titleBarOverlay.focusEnabled = true;
         
-        minimizeBtn.tabIndex = baseIndex+1;
-        maximizeRestoreBtn.tabIndex = baseIndex+2;
-        closeBtn.tabIndex = baseIndex+3;
+        //minimizeBtn.tabIndex = baseIndex+1;
+        //maximizeRestoreBtn.tabIndex = baseIndex+2;
+        //closeBtn.tabIndex = baseIndex+3;
         
         resourcesChanged();
       }
       
       private function remoteFocus(e:ShortcutEvent):void{
-        focusManager.setFocus(minimizeBtn);
+        //focusManager.setFocus(minimizeBtn);
       }
       
       public function get defaultWidth():int{
@@ -208,18 +203,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         
         if (showReason) {
           helpInfoBox.visible = helpInfoBox.includeInLayout = false;
-          previewBox.visible = previewBox.includeInLayout = false;
+          //previewBox.visible = previewBox.includeInLayout = false;
           errorBox.visible = errorBox.includeInLayout = true;
           
           shareTypeBox.visible = false;
-          cancelBtn.visible = cancelBtn.includeInLayout = true;
+          //cancelBtn.visible = cancelBtn.includeInLayout = true;
           startBtn.visible = startBtn.includeInLayout = false;
-          stopBtn.visible = stopBtn.includeInLayout = false;
+          //stopBtn.visible = stopBtn.includeInLayout = false;
         } else {
           closeWindow();
         }
       }
-      
+/*
       private function handleScreenSharePausedEvent(event:ScreenSharePausedEvent):void {
         if (videoWrapper != null && video != null && video.parent == videoWrapper) {
             videoWrapper.removeChild(video);
@@ -236,7 +231,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			}
         }
       }
-      
+*/
       public function shareScreen(fullScreen:Boolean):void {
         LOGGER.debug("Calling shareScreen");
         startBtn.enabled = false;
@@ -269,7 +264,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         
         //closeWindow();
       }
-      
+/*
       public function pauseSharing():void {
         LOGGER.debug("Calling pauseSharing");
         if (!paused) {
@@ -292,7 +287,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
           dispatchEvent(restartSharingEvent);
         }
       }
-      
+*/
       public function stopSharingEvent(evt:StopSharingButtonEvent):void{
         if (streaming) {
           stopStream();
@@ -308,9 +303,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         var width: int = ScreenshareModel.getInstance().width;
         var height: int = ScreenshareModel.getInstance().height;
         var streamId: String = ScreenshareModel.getInstance().streamId;
-        startPreviewStream(connection.getConnection(), streamId, width, height);
+        //startPreviewStream(connection.getConnection(), streamId, width, height);
       }
-      
+/*
       private function startPreviewStream(nc:NetConnection, streamId:String, capWidth:Number, capHeight:Number):void{
         
         switchView(false);
@@ -363,7 +358,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         pauseBox.width = vidW;
         pauseBox.height = vidH;
       }
-      
+*/
       public function onMetaData(info:Object):void{
         LOGGER.debug("metadata: width=" + info.width + " height=" + info.height);
       }
@@ -412,13 +407,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       * Override the close handler. We want the Event Map to send a message to
       * the MDIManager to close this window;
       */
+/*
       override public function close(event:MouseEvent = null):void {
         stopSharing();
         closeWindow();
       }
-      
+*/
       override protected function resourcesChanged():void{
         super.resourcesChanged();
+/*
         this.title = ResourceUtil.getInstance().getString('bbb.screensharePublish.title');
         
         if (titleBarOverlay != null) {
@@ -435,7 +432,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
           closeBtn.toolTip = ResourceUtil.getInstance().getString('bbb.screensharePublish.closeBtn.toolTip');
           closeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.screensharePublish.closeBtn.accessibilityName");
         }
-        
+*/
         shareTypeProvider = [ResourceUtil.getInstance().getString('bbb.screensharePublish.shareType.fullScreen'),
                              ResourceUtil.getInstance().getString('bbb.screensharePublish.shareType.region')];
         
@@ -520,12 +517,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       
       private function switchView(showHelp:Boolean):void {
         helpInfoBox.visible = helpInfoBox.includeInLayout = showHelp;
-        previewBox.visible = !showHelp;
+        //previewBox.visible = !showHelp;
         
         shareTypeBox.visible = showHelp;
-        cancelBtn.visible = cancelBtn.includeInLayout = showHelp;
+        //cancelBtn.visible = cancelBtn.includeInLayout = showHelp;
         startBtn.visible = startBtn.includeInLayout = showHelp;
-        stopBtn.visible = stopBtn.includeInLayout = !showHelp;
+        //stopBtn.visible = stopBtn.includeInLayout = !showHelp;
       }
     ]]>
   </mx:Script>
@@ -545,7 +542,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                        toolTip="{ResourceUtil.getInstance().getString('bbb.screensharePublish.helpbutton.toolTip')}"
                        accessibilityName="{ResourceUtil.getInstance().getString('bbb.screensharePublish.helpbutton.accessibilityName')}"/>
       </mx:HBox>
-      <mx:HBox id="helpBox" width="100%" horizontalAlign="center">
+      <mx:VBox id="helpBox" width="100%" verticalAlign="middle">
         <mx:VBox width="30%" horizontalAlign="center">
           <mx:Image id="helpImg1" source="{helpImg1.getStyle('imageSource')}" />
           <mx:Label id="helpLbl1" styleName="desktopShareTextStyle" />
@@ -562,9 +559,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
           <mx:Image id="helpImg4" source="{helpImg4.getStyle('imageSource')}" />
           <mx:Label id="helpLbl4" styleName="desktopShareTextStyle" />
         </mx:VBox>
-      </mx:HBox>
+      </mx:VBox>
     </mx:VBox>
-    <mx:VBox id="previewBox" width="100%" height="100%" visible="false" horizontalAlign="center" >
+    <!--mx:VBox id="previewBox" width="100%" height="100%" visible="false" horizontalAlign="center" >
       <mx:Box id="videoHolder" width="100%" height="90%" horizontalAlign="center">
         <mx:UIComponent id="videoWrapper" width="100%" height="100%" />
         <mx:VBox id="pauseBox" visible="false" includeInLayout="false" styleName="desksharePublishPauseBox" >
@@ -580,7 +577,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                  click="pauseSharing()"
                  toolTip="{ResourceUtil.getInstance().getString('bbb.screensharePublish.restart.tooltip')}" 
                  label="{ResourceUtil.getInstance().getString('bbb.screensharePublish.restart.label')}" />
-    </mx:VBox>
+    </mx:VBox-->
     <mx:VBox id="errorBox" width="100%" height="100%" visible="false" includeInLayout="false" horizontalAlign="center" verticalAlign="middle">
       <mx:Label id="startFailedLbl" width="70%" visible="false" includeInLayout="false" textAlign="center" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.startFailed.label')}"/>
       <mx:Label id="restartFailedLbl" width="70%" textAlign="center" visible="false" includeInLayout="false" styleName="desktopShareTextStyle" text="{ResourceUtil.getInstance().getString('bbb.screensharePublish.restartFailed.label')}"/>
@@ -596,7 +593,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       </mx:HBox>
     <mx:Spacer width="80%" />
     <mx:Button id="startBtn" click="onStartButtonClick()" label="{ResourceUtil.getInstance().getString('bbb.screensharePublish.startButton.label')}" />
-    <mx:Button id="cancelBtn" click="closeWindow()" label="{ResourceUtil.getInstance().getString('bbb.screensharePublish.cancelButton.label')}" />
-    <mx:Button id="stopBtn" visible="false" includeInLayout="false" click="close()" label="{ResourceUtil.getInstance().getString('bbb.screensharePublish.stopButton.label')}" />
+    <!--mx:Button id="cancelBtn" click="closeWindow()" label="{ResourceUtil.getInstance().getString('bbb.screensharePublish.cancelButton.label')}" />
+    <mx:Button id="stopBtn" visible="false" includeInLayout="false" click="close()" label="{ResourceUtil.getInstance().getString('bbb.screensharePublish.stopButton.label')}" /-->
   </mx:ControlBar>
-</dspub:MDIWindow>
+</mx:Canvas>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreenshareViewWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreenshareViewWindow.mxml
index fbf95f7a868d9ef21f09eae4d2e28d68efc026c3..b8c3b4a52dfecec3e688b81a21d710a00df95f30 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreenshareViewWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/ScreenshareViewWindow.mxml
@@ -20,17 +20,14 @@
 
 -->
 
-<MDIWindow xmlns="flexlib.mdi.containers.*"
-           xmlns:mx="http://www.adobe.com/2006/mxml"
-           width="600"
-           height="400"
-           initialize="init()"
-           creationComplete="onCreationComplete()"
-           implements="org.bigbluebutton.common.IBbbModuleWindow"
-           xmlns:mate="http://mate.asfusion.com/"
-           title="{    ResourceUtil.getInstance().getString('bbb.screenshareView.title')    }"
-           showCloseButton="false"
-           resize="fitToWindow()">
+<mx:Canvas xmlns="org.bigbluebutton.common.*"
+        xmlns:mx="http://www.adobe.com/2006/mxml"
+        width="100%"
+        height="100%"
+        creationComplete="onCreationComplete()"
+        implements="org.bigbluebutton.common.IBbbCanvas"
+        xmlns:mate="http://mate.asfusion.com/"
+        backgroundColor="#C0C0C0">
 
     <mate:Listener type="{    ViewStreamEvent.STOP    }" method="onStopViewStreamEvent" />
     <mate:Listener type="{    LocaleChangeEvent.LOCALE_CHANGED    }" method="localeChanged" />
@@ -40,6 +37,7 @@
         <![CDATA[
       import com.asfusion.mate.events.Dispatcher;     
       import flexlib.mdi.events.MDIWindowEvent;      
+      import mx.events.ResizeEvent;
       import mx.core.UIComponent;      
       import org.bigbluebutton.common.Images;
       import org.bigbluebutton.common.events.LocaleChangeEvent;
@@ -50,6 +48,7 @@
       import org.bigbluebutton.modules.screenshare.events.StartedViewingEvent;
       import org.bigbluebutton.modules.screenshare.events.ViewStreamEvent;
       import org.bigbluebutton.modules.screenshare.events.ViewWindowEvent;
+      import org.bigbluebutton.modules.screenshare.managers.SmartWindowResizer;
       import org.bigbluebutton.modules.screenshare.model.ScreenshareModel;
       import org.bigbluebutton.modules.screenshare.model.ScreenshareOptions;
       import org.bigbluebutton.util.i18n.ResourceUtil;
@@ -67,20 +66,28 @@
 			private var screenWidth:Number = Capabilities.screenResolutionX;
 						
 			private var images:Images = new Images();
-			[Bindable] public var fitToWidthIcon:Class = images.magnifier;
-			[Bindable] public var fitToActualSizeIcon:Class = images.mag_reset;
+			//[Bindable] public var fitToWidthIcon:Class = images.magnifier;
+			//[Bindable] public var fitToActualSizeIcon:Class = images.mag_reset;
 					
       private var streamAvailable:Boolean = false;
       
 			private var video:Video;
 			private var ns:NetStream;
-			private var videoHolder:UIComponent = new UIComponent();
+			private var videoWithWarnings:VideoWithWarnings = new VideoWithWarnings();
+			private var videoHolder:UIComponent;
 			private var streamId:String;
 			private var videoHeight:Number = 1;
 			private var videoWidth:Number = 1;
+			private var loaded:Boolean = false;
 			
 			private static const VIDEO_WIDTH_PADDING:int = 7;
 			private static const VIDEO_HEIGHT_PADDING:int = 65;
+			[Bindable] private var _actualSize:Boolean = false;
+
+			private var resizer:SmartWindowResizer = new SmartWindowResizer();
+
+			private var whiteboardCanvas:IBbbCanvas = null;
+			private var whiteboardCanvasHolder:Canvas = new Canvas();
 
 			// The following code block is to deal with a bug in FLexLib 
 			// with MDI windows not responding well to being maximized
@@ -102,20 +109,15 @@
 			private function onCreationComplete():void{
         viewScreenshareStream();
         
-				videoHolder.addChild(video);				
-				this.addChild(videoHolder);
+				addEventListener(ResizeEvent.RESIZE, onResizeEvent);
+				this.addChildAt(videoWithWarnings,0);
+				videoHolder = videoWithWarnings.videoHolder;
 				videoHolder.percentWidth = 100;
 				videoHolder.percentHeight = 100;
-				addEventListener(MDIWindowEvent.RESIZE_END, onResizeEndEvent);				
-				fitToActualSize();				
-				maximize();
 				
 				resourcesChanged();
-				
-				titleBarOverlay.tabIndex = baseIndex;
-				minimizeBtn.tabIndex = baseIndex+1;
-				maximizeRestoreBtn.tabIndex = baseIndex+2;
-				closeBtn.tabIndex = baseIndex+3;
+				onResizeEvent();
+				loaded = true;
                
         var logData:Object = UsersUtil.initLogData();
         logData.tags = ["screenshare"];
@@ -126,9 +128,13 @@
         LOGGER.info(JSON.stringify(logData));
 			}
 			
-			private function onResizeEndEvent(event:MDIWindowEvent):void {
-				if (event.window == this && streamAvailable) {
-					fitToWindow();
+			private function onResizeEvent(e:ResizeEvent = null):void {
+				if (!loaded) return;
+				LOGGER.debug("ScreenshareViewWindow::onResizeEvent");
+				if (actualSize) {
+					onResizeCallback(this.width, this.height, videoWidth, videoHeight, Math.max((this.width - videoWidth) / 2, 0), Math.max((this.height - videoHeight) / 2, 0));
+				} else {
+					resizer.onResize(this.width, this.height, false, video.width, video.height, videoWidth / videoHeight, false, onResizeCallback);
 				}
 			}
 					
@@ -170,10 +176,9 @@
         video.smoothing = true;
         video.attachNetStream(ns);
         ns.play(streamId);	
-        this.title = "Viewing Remote Desktop";
         streamAvailable = true;
-        
-        fitToWindow();
+
+        videoWithWarnings.setCallback(setVideo);
       }
       
       public function onMetaData(info:Object):void{
@@ -187,6 +192,80 @@
         LOGGER.info(JSON.stringify(logData));
       }
       
+
+			public function onParentResized(width:Number, height:Number):void {
+				onResizeEvent();
+			}
+
+			private function onResizeCallback(externalWidth:int, externalHeight:int, internalWidth:int, internalHeight:int, internalOffsetX:int, internalOffsetY:int):void {
+				if(videoHolder != null) {
+					/* Reposition video within window */
+					videoWithWarnings.x = internalOffsetX;
+					videoWithWarnings.y = internalOffsetY;
+
+					videoWithWarnings.width = video.width = internalWidth;
+					videoWithWarnings.height = video.height = internalHeight;
+
+					// update the whiteboard canvas holder and overlay with new video dimensions
+					updateWhiteboardCanvasHolder();
+					updateWhiteboardCanvasOverlay();
+				}
+			}
+
+			private function setVideo():void {
+				LOGGER.debug("Callback called. Adding video, its whiteboard canvas and resizing components...");
+				videoHolder.addChild(video);
+				addWhiteboardCanvasHolder();
+				addWhiteboardCanvasOverlay();
+				onResizeEvent();
+			}
+
+			private function addWhiteboardCanvasHolder():void{
+				if(video != null) {
+					this.addChildAt(whiteboardCanvasHolder, 1);
+					LOGGER.debug("Whiteboard canvas holder added");
+				}
+			}
+
+			private function cleanCanvasHolder():void{
+				while (this.whiteboardCanvasHolder.rawChildren.numChildren > 0) {
+					this.whiteboardCanvasHolder.rawChildren.removeChildAt(0);
+				}
+			}
+
+			private function updateWhiteboardCanvasHolder():void{
+				if (video != null && videoHolder != null) {
+					whiteboardCanvasHolder.x = videoWithWarnings.x;
+					whiteboardCanvasHolder.y = videoWithWarnings.y;
+					whiteboardCanvasHolder.width = videoWithWarnings.width;
+					whiteboardCanvasHolder.height = videoWithWarnings.height;
+					LOGGER.debug("Whiteboard canvas holder dimensions updated");
+				}
+			}
+
+			public function addWhiteboardCanvasOverlay():void {
+				updateWhiteboardCanvasOverlay();
+				if (video != null && whiteboardCanvas != null && videoHolder != null) {
+					this.addChild(whiteboardCanvas as Canvas);
+					LOGGER.debug("Whiteboard Canvas OVERLAY added.");
+				}
+				else {
+					LOGGER.error("COULD NOT add whiteboard overlay");
+				}
+			}
+
+			private function updateWhiteboardCanvasOverlay():void{
+				if (video != null && whiteboardCanvas != null && videoHolder != null) {
+					whiteboardCanvas.moveCanvas(videoWithWarnings.x, videoWithWarnings.y);
+
+					var zoomPercentage:Number = (videoWithWarnings.width / videoWidth)*100;
+					if(zoomPercentage > 0)
+						whiteboardCanvas.zoomCanvas(videoWithWarnings.width, videoWithWarnings.height, zoomPercentage);
+
+					LOGGER.debug("Whiteboard canvas overlay dimensions updated");
+				}
+			}
+/*
       protected function updateButtonsPosition():void {
         if (this.width < bottomBar.width) {
           bottomBar.visible = false;
@@ -199,7 +278,7 @@
           bottomBar.x = (this.width - bottomBar.width) / 2;
         }
       }
-      
+*/
 			public function stopViewing():void {
 				ns.close();
 				closeWindow();				
@@ -235,90 +314,17 @@
 				}
 			}
 			
-			public function getPrefferedPosition():String{
-				return MainCanvas.DESKTOP_SHARING_VIEW;
-			}
-												
-			/**
-			 * resizes the desktop sharing video to fit to this window
-			 */
-			private function fitToWindow():void{
-        if (!streamAvailable) return;
-        
-				if (videoIsSmallerThanWindow()) {
-					fitWindowToVideo();
-				}
-				
-				// Ignore if we are displaying the actual size of the video
-				if (! btnActualSize.selected) {
-					fitVideoToWindow();
-				}
-			}
-			
-			private function fitVideoToWindow():void {
-				if (this.width < this.height) {
-					fitToWidthAndAdjustHeightToMaintainAspectRatio();				
-				} else {
-					fitToHeightAndAdjustWidthToMaintainAspectRatio();
-				}				
-			}
-						
-			private function fitWindowToVideo():void {	
-				video.width = videoWidth;
-				videoHolder.width = videoWidth;
-				video.height = videoHeight;
-				videoHolder.height = videoHeight;			
-				this.height = videoHeight + VIDEO_HEIGHT_PADDING;
-				this.width = videoWidth + VIDEO_WIDTH_PADDING;
-			}
-			
-			private function videoIsSmallerThanWindow():Boolean {
-				return (videoHeight < this.height) && (videoWidth < this.width);
+			private function toggleActualSize():void {
+				actualSize = !actualSize;
 			}
 			
-		
-			private function fitToWidthAndAdjustHeightToMaintainAspectRatio():void {
-					video.width = this.width - VIDEO_WIDTH_PADDING;
-					videoHolder.width = video.width;
-					// Maintain aspect-ratio
-					video.height = (videoHeight * video.width) / videoWidth;
-					videoHolder.height = video.height;
-					this.height = video.height + VIDEO_HEIGHT_PADDING;					
-			}
-				
-			private function fitToHeightAndAdjustWidthToMaintainAspectRatio():void {
-					video.height = this.height - VIDEO_HEIGHT_PADDING;
-					videoHolder.height = video.height;
-					// Maintain aspect-ratio
-					video.width = (videoWidth * video.height) / videoHeight;
-					videoHolder.width = video.width;
-					this.width = video.width + VIDEO_WIDTH_PADDING;					
-			}
-								
-			/**
-			 * resizes the desktop sharing video to actual video resolution
-			 */
-			private function fitToActualSize():void{
-				if (videoIsSmallerThanWindow()) {
-					fitWindowToVideo();
-				} else {
-					video.width = videoWidth;
-					videoHolder.width = videoWidth;
-					video.height = videoHeight;
-					videoHolder.height = videoHeight;
-				}
+			public function set actualSize(value:Boolean):void {
+				_actualSize = value;
+				onResizeEvent();
 			}
 			
-			private function determineHowToDisplayVideo():void {
-				if (btnActualSize.selected) {
-					fitToActualSize();			
-					btnActualSize.toolTip = ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow');	
-					btnActualSize.label = ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow');
-				} else {
-					fitToWindow();
-					btnActualSize.toolTip = ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize');
-					btnActualSize.label = ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize');
-				}
+			public function get actualSize():Boolean {
+				return _actualSize;
 			}
 			
 			private function closeWindow():void {
@@ -327,23 +333,46 @@
 			
 			override protected function resourcesChanged():void{
 				super.resourcesChanged();
-				this.title = ResourceUtil.getInstance().getString('bbb.screenshareView.title');
-				
-				if (windowControls != null) {
-					minimizeBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.minimizeBtn.toolTip");
-					minimizeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.screenshareView.minimizeBtn.accessibilityName");
-
-					maximizeRestoreBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.maximizeRestoreBtn.toolTip");
-					maximizeRestoreBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.screenshareView.maximizeRestoreBtn.accessibilityName");
-
-					closeBtn.toolTip = ResourceUtil.getInstance().getString("bbb.window.closeBtn.toolTip");
-					closeBtn.accessibilityName = ResourceUtil.getInstance().getString("bbb.screenshareView.closeBtn.accessibilityName");
-				}
 			}
 			
 			private function localeChanged(e:Event):void{
 				resourcesChanged();
 			}
+
+			/** Inherited from IBbbCanvas*/
+			public function addRawChild(child:DisplayObject):void {
+				whiteboardCanvasHolder.rawChildren.addChild(child);
+			}
+
+			public function removeRawChild(child:DisplayObject):void {
+				this.whiteboardCanvasHolder.rawChildren.removeChild(child);
+			}
+
+			public function doesContain(child:DisplayObject):Boolean {
+				return this.whiteboardCanvasHolder.rawChildren.contains(child);
+			}
+
+			public function acceptOverlayCanvas(overlay:IBbbCanvas):void {
+				LOGGER.debug("ScreenshareViewWindow: acceptOverlayCanvas");
+				cleanCanvasHolder();
+				whiteboardCanvas = overlay;
+			}
+
+			private function handleWhiteboardCanvasClick(e:MouseEvent):void {
+				LOGGER.debug("ScreenshareViewWindow: handleWhiteboardCanvasClick");
+			}
+
+			public function moveCanvas(x:Number, y:Number):void {
+				LOGGER.debug("ScreenshareViewWindow: moveCanvas");
+			}
+
+			public function zoomCanvas(width:Number, height:Number, zoom:Number):void {
+				LOGGER.debug("ScreenshareViewWindow: zoomCanvas");
+			}
+
+			public function showCanvas(show:Boolean):void {
+				LOGGER.debug("ScreenshareViewWindow: showCanvas");
+			}
             
        public function handleDisconnectedEvent(event:BBBEvent):void {
           if (event.payload.type == ReconnectionManager.DESKSHARE_CONNECTION) {
@@ -354,17 +383,4 @@
 		]]>
     </mx:Script>
 
-    <mx:HBox id="bottomBar" visible="true" height="30" horizontalAlign="center" paddingTop="0" paddingBottom="0" width="100%">
-        <mx:Button id="btnActualSize"
-                   paddingTop="0"
-                   paddingBottom="0"
-                   styleName="deskshareControlButtonStyle"
-                   toggle="true"
-                   click="determineHowToDisplayVideo()"
-                   selected="false"
-                   height="90%"
-                   label="{    btnActualSize.selected ? ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow') : ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize')    }"
-                   toolTip="{    btnActualSize.selected ? ResourceUtil.getInstance().getString('bbb.screenshareView.fitToWindow') : ResourceUtil.getInstance().getString('bbb.screenshareView.actualSize')    }"
-                   tabIndex="{    baseIndex + 4    }" />
-    </mx:HBox>
-</MDIWindow>
+</mx:Canvas>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/VideoWithWarnings.as b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/VideoWithWarnings.as
new file mode 100755
index 0000000000000000000000000000000000000000..b94aed426241ff183d008acd27c7333ee71d0255
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/screenshare/view/components/VideoWithWarnings.as
@@ -0,0 +1,46 @@
+package org.bigbluebutton.modules.screenshare.view.components
+{
+    import mx.events.FlexEvent;
+    import mx.core.UIComponent;
+
+    import org.as3commons.logging.api.ILogger;
+    import org.as3commons.logging.api.getClassLogger;
+    import org.bigbluebutton.util.i18n.ResourceUtil;
+    import org.bigbluebutton.main.views.VideoWithWarningsBase;
+    import org.bigbluebutton.core.UsersUtil;
+
+    public class VideoWithWarnings extends VideoWithWarningsBase {
+
+        private static const LOGGER:ILogger = getClassLogger(VideoWithWarnings);
+
+        private var callback:Function = null;
+
+        public function VideoWithWarnings() {
+            super();
+            this.addEventListener(FlexEvent.CREATION_COMPLETE , creationCompleteHandler);
+        }
+
+        private function creationCompleteHandler(e:FlexEvent):void {
+            if(callback != null) {
+               callback();
+               if(UsersUtil.amIPresenter())
+                  setWarning();
+            }
+        }
+
+        private function setWarning():void {
+            _text.setStyle("styleName", "deskshareWarningLabelStyle");
+            _text.text = ResourceUtil.getInstance().getString('bbb.screensharePublish.sharingMessage');
+            _text.visible = true;
+            _textBackground.setStyle("styleName", "deskshareWarningBackgroundStyle");
+        }
+
+        public function setCallback(callback:Function):void {
+            this.callback = callback;
+        }
+
+        public function get videoHolder():UIComponent {
+            return _videoHolder;
+        }
+    }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/SharedNotesOptions.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/SharedNotesOptions.as
new file mode 100755
index 0000000000000000000000000000000000000000..c8ba9d3694df87e66df3814dae6e2c7f81e5fdb0
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/SharedNotesOptions.as
@@ -0,0 +1,62 @@
+package org.bigbluebutton.modules.sharednotes
+{
+	import org.bigbluebutton.core.BBB;
+
+	public class SharedNotesOptions
+	{
+		[Bindable]
+		public var refreshDelay:int = 500;
+
+		[Bindable]
+		public var position:String = "bottom-left";
+
+		[Bindable]
+		public var autoStart:Boolean = false;
+
+		[Bindable]
+		public var showButton:Boolean = false;
+
+		[Bindable]
+		public var enableMultipleNotes:Boolean = false;
+
+		[Bindable]
+		public var toolbarVisibleByDefault:Boolean = false;
+
+		[Bindable]
+		public var showToolbarButton:Boolean = false;
+
+		[Bindable]
+		public var fontSize:int = 10;
+
+		public function SharedNotesOptions()
+		{
+			var vxml:XML = BBB.getConfigForModule("SharedNotesModule");
+			if (vxml != null) {
+				if (vxml.@refreshDelay != undefined) {
+					refreshDelay = Number(vxml.@refreshDelay);
+				}
+				if (vxml.@position != undefined) {
+					position = vxml.@position.toString();
+				}
+				if (vxml.@autoStart != undefined) {
+					autoStart = (vxml.@autoStart.toString().toUpperCase() == "TRUE") ? true : false;
+				}
+				if (vxml.@showButton != undefined) {
+					showButton = (vxml.@showButton.toString().toUpperCase() == "TRUE") ? true : false;
+				}
+				if (vxml.@enableMultipleNotes != undefined) {
+					enableMultipleNotes = (vxml.@enableMultipleNotes.toString().toUpperCase() == "TRUE") ? true : false;
+				}
+				if (vxml.@toolbarVisibleByDefault != undefined) {
+					toolbarVisibleByDefault = (vxml.@toolbarVisibleByDefault.toString().toUpperCase() == "TRUE") ? true : false;
+				}
+				if (vxml.@showToolbarButton != undefined) {
+					showToolbarButton = (vxml.@showToolbarButton.toString().toUpperCase() == "TRUE") ? true : false;
+				}
+				if (vxml.@fontSize != undefined) {
+					fontSize = Number(vxml.@fontSize);
+				}
+			}
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/SharedNotesWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/SharedNotesWindow.mxml
deleted file mode 100755
index 81499a413fb0bf884c18d180e185a6397cf68c7b..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/SharedNotesWindow.mxml
+++ /dev/null
@@ -1,219 +0,0 @@
-<!--
-
-BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-
-Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
-
-This program is free software; you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free Software
-Foundation; either version 3.0 of the License, or (at your option) any later
-version.
-
-BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-
--->
-<containers:CustomMdiWindow xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:containers="org.bigbluebutton.common.*" 
-					 layout="absolute" width="508" height="494" implements="org.bigbluebutton.common.IBbbModuleWindow" 
-					 title="Notes" creationComplete="init()" xmlns:components="org.bigbluebutton.modules.sharednotes.components.*">
-	<mx:Script>
-		<![CDATA[
-			import com.asfusion.mate.events.Dispatcher;
-			
-			import flash.utils.getTimer;
-			
-			import flexlib.mdi.events.MDIWindowEvent;
-			
-			import mx.events.ResizeEvent;
-			import mx.events.SliderEvent;
-			
-			import org.bigbluebutton.common.IBbbModuleWindow;
-			import org.bigbluebutton.main.views.MainCanvas;
-			import org.bigbluebutton.modules.sharednotes.infrastructure.Client;
-			import org.bigbluebutton.modules.sharednotes.infrastructure.ServerConnection;
-			
-			private var _xPosition:int, _yPosition:int;
-			private var _defaultWidth:int = 400;
-			private var _defaultHeight:int = 300;
-			private var client:org.bigbluebutton.modules.sharednotes.infrastructure.Client;
-			
-			private static var _room:String;
-			
-			public static const SHARED_NOTES_CLOSED:String = "SHARED_NOTES_CLOSED";
-			
-			private var resizeTimer:Timer = new Timer(500);
-			
-			public function init():void {
-				textArea.addEventListener(Event.CHANGE, onTextChange);
-				addEventListener(ServerConnection.SYNCED_EVENT, onSynced);
-				addEventListener(ServerConnection.SYNCING_EVENT, onSyncing);
-				addEventListener(MDIWindowEvent.RESIZE, onResize);
-				addEventListener(MDIWindowEvent.MAXIMIZE, function(e:Event):void { resizeTimer.start(); });
-				addEventListener(MDIWindowEvent.RESTORE, function(e:Event):void { resizeTimer.start(); });
-				addEventListener(MDIWindowEvent.CLOSE, function(e:Event):void { if (client) client.shutdown(); });
-				resizeTimer.addEventListener(TimerEvent.TIMER, onResizeTimer);
-
-				client = new Client(textArea, this);
-			}
-			
-			private function onResizeTimer(e:Event):void {
-				onResize();
-				resizeTimer.stop();
-			}
-			
-			private function addBlur():void {
-				var bf:BlurFilter = new BlurFilter(0,0,0);
-				
-				var myFilters:Array = new Array();
-				
-				myFilters.push(bf);
-				
-				textArea.filters = myFilters;
-			}
-			
-			private function onResize(e:Event = null):void {
-				const RIGHT_PADDING:int = textArea.x * 2, TOP_PADDING:int = 35, BOTTOM_PADDING:int = 60;
-				
-				textArea.width = canvas.width - RIGHT_PADDING;
-				textArea.height = canvas.height - BOTTOM_PADDING;
-				txtPlayback.width = canvas.width - RIGHT_PADDING;
-				txtPlayback.height = canvas.height - BOTTOM_PADDING - 20;
-				btnPlayback.y = canvas.height - TOP_PADDING;
-				btnBackPlayback.y = canvas.height - TOP_PADDING;
-				icoSynced.y = canvas.height - TOP_PADDING;
-				icoSyncing.y = canvas.height - TOP_PADDING;
-				icoSynced.x = canvas.width - RIGHT_PADDING - 10;
-				icoSyncing.x = canvas.width - RIGHT_PADDING - 10;
-				playbackSlider.width = canvas.width - playbackSlider.x - RIGHT_PADDING;
-				playbackSlider.y = canvas.height - BOTTOM_PADDING - 10;
-				lblPlaybackVersion.y = playbackSlider.y + 3;
-			}
-			
-			private function onSynced(e:Event):void {
-				if (client.version > 0 && !btnBackPlayback.visible) { btnPlayback.visible = true; }
-				icoSynced.visible = true;
-				icoSyncing.visible = false;
-				lblConnecting.visible = false;
-			}
-			
-			private function onSyncing(e:Event):void {
-				icoSyncing.visible = true;
-				icoSynced.visible = false;
-			}
-			
-			private function onTextChange(e:Event):void {
-				onSyncing(e);
-			}
-			
-			protected function btnPlay_clickHandler(event:MouseEvent):void
-			{
-				if (client.isTypingTestRunning())
-				{
-					client.stopTyping();
-					btnPlay.label = "Start";
-				}
-				else
-				{
-					client.startTyping();
-					btnPlay.label = "Stop";
-				}
-			}
-			
-			private var previousSliderValue:int = 0;
-			protected function playbackSlider_changeHandler(event:SliderEvent):void
-			{
-				txtPlayback.text = client.getSnapshotAtVersion(previousSliderValue, event.value, txtPlayback.text);
-				lblPlaybackVersion.text = "Version " + event.value + ":";
-			}
-			
-			protected function btnPlayback_clickHandler(event:MouseEvent):void
-			{
-				playbackSlider.maximum = client.version;
-				playbackSlider.value = 0;
-				textArea.visible = false;
-				btnBackPlayback.visible = true;
-				btnPlayback.visible = false;
-				previousSliderValue = 0;
-				txtPlayback.text = client.getSnapshotAtVersion(0, 0, "");
-			}
-			
-			protected function btnBackPlayback_clickHandler(event:MouseEvent):void
-			{
-				textArea.visible = true;
-				btnBackPlayback.visible = false;
-				btnPlayback.visible = true;
-			}
-			
-			public function get xPosition():int {
-				return _xPosition;
-			} 
-			
-			public function get yPosition():int {
-				return _yPosition;
-			}
-			
-			public function set xPosition(x:int):void {
-				_xPosition = x;
-			}
-			
-			public function set yPosition(y:int):void {
-				_yPosition = y;
-			}
-			
-			public function get defaultWidth():int{
-				return _defaultWidth;
-			}
-			
-			public function get defaultHeight():int{
-				return _defaultHeight;
-			}
-			
-			public function set defaultHeight(height:int):void{
-				this._defaultHeight = height;
-			}
-			
-			public function set defaultWidth(width:int):void{
-				this._defaultWidth = width;
-			}
-			
-			public function resetWidthAndHeight():void{
-				this.width = _defaultWidth;
-				this.height = _defaultHeight;
-			}
-			
-			public function getPrefferedPosition():String{
-				return MainCanvas.MIDDLE;
-			}
-			
-			public static function set document(document:String):void {
-				Client.documentName = document;
-			}
-			
-			override public function close(event:MouseEvent=null):void {
-				new Dispatcher().dispatchEvent(new Event(SHARED_NOTES_CLOSED, true));
-				super.close(event);
-			}
-		]]>
-	</mx:Script>
-	<mx:Fade id="dissolveOut" duration="1000" alphaFrom="1.0" alphaTo="0.0"/>
-	<mx:Fade id="dissolveIn" duration="1000" alphaFrom="0.0" alphaTo="1.0"/>
-	
-	<mx:Canvas id="canvas" x="0" y="0" width="100%" height="100%">
-
-	<mx:Button x="10" y="425" label="Playback" id="btnPlayback" click="btnPlayback_clickHandler(event)" icon="@Embed(source='images/play-icon.png')" visible="false"/>
-	<mx:HSlider x="79" y="395" width="413" id="playbackSlider" liveDragging="true" snapInterval="1" change="playbackSlider_changeHandler(event)" maximum="0"/>
-	<mx:TextArea x="10" y="10" width="482" height="387" id="txtPlayback"/>
-	<mx:Image x="476" y="431" source="@Embed(source='images/tick.png')" id="icoSynced" visible="false" toolTip="Document up to date."/>	
-	<mx:Image x="476" y="431" source="@Embed(source='images/action_refresh.gif')" id="icoSyncing" visible="false" toolTip="Updating document..."/>
-	<mx:Button x="10" y="425" icon="@Embed(source='images/arrow_left.png')" id="btnBackPlayback" click="btnBackPlayback_clickHandler(event)" visible="false"/>
-	<mx:Label id="lblPlaybackVersion" x="10" y="399" text="Version 0:"/>
-	<components:PatchableTextArea x="10" y="10" id="textArea" hideEffect="{dissolveOut}" showEffect="{dissolveIn}" creationComplete="addBlur()" width="482" height="407"/>
-	<mx:Button x="114" y="425" label="Start" id="btnPlay" click="btnPlay_clickHandler(event)" visible="false"/>
-	<mx:Label x="211.5" y="186" text="Connecting..." id="lblConnecting"/>
-		
-	</mx:Canvas>
-</containers:CustomMdiWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/ToolbarButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/ToolbarButton.mxml
deleted file mode 100755
index 4c29691f6c1cbc4cd8fb3cb43a4eea68ca563818..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/ToolbarButton.mxml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-
-BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
-
-Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
-
-This program is free software; you can redistribute it and/or modify it under the
-terms of the GNU Lesser General Public License as published by the Free Software
-Foundation; either version 3.0 of the License, or (at your option) any later
-version.
-
-BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License along
-with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
-
--->
-
-<mx:Button xmlns:mx="http://www.adobe.com/2006/mxml" icon="{notesIcon}" 
-		   click="openPublishWindow()" creationComplete="init()" 
-		   toolTip="{ResourceUtil.getInstance().getString('bbb.toolbar.video.toolTip')}" xmlns:mate="http://mate.asfusion.com/"
-		   implements="org.bigbluebutton.common.IBbbToolbarComponent">
-	
-	<mate:Listener type="{SharedNotesWindow.SHARED_NOTES_CLOSED}" method="closeEventHandler" />
-	<mx:Script>
-		<![CDATA[
-			import com.asfusion.mate.events.Dispatcher;
-			
-			import org.bigbluebutton.common.IBbbModuleWindow;
-			import org.bigbluebutton.common.Images;
-			import org.bigbluebutton.common.events.OpenWindowEvent;
-			import org.bigbluebutton.main.views.MainToolbar;
-			import org.bigbluebutton.util.i18n.ResourceUtil;
-			
-			[Embed(source="images/note_edit.png")]
-			public var notes:Class;
-			
-			
-			[Bindable] public var notesIcon:Class = notes;
-			
-			private var dispatcher:Dispatcher;
-			
-			private function init():void{
-				dispatcher = new Dispatcher();
-				this.addEventListener(SharedNotesWindow.SHARED_NOTES_CLOSED, closeEventHandler);
-			}
-			
-			private function openPublishWindow():void{
-				var window:IBbbModuleWindow = new SharedNotesWindow();
-				
-				var event:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
-				event.window = window;
-				dispatcher.dispatchEvent(event);
-				this.enabled = false;
-			}
-			
-			public function show():void{
-				this.enabled = true;
-			}
-			
-			private function closeEventHandler(e:Event):void {
-				show();
-			}
-			
-			public function getAlignment():String{
-				return MainToolbar.ALIGN_LEFT;
-			}
-		]]>
-	</mx:Script>
-</mx:Button>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/components/PatchableTextArea.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/components/PatchableTextArea.as
deleted file mode 100755
index 566209502274cd3d435b668594d330cc844495bc..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/components/PatchableTextArea.as
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
- * 
- * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
- *
- * This program is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation; either version 3.0 of the License, or (at your option) any later
- * version.
- * 
- * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along
- * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-package org.bigbluebutton.modules.sharednotes.components
-{
-	import mx.controls.TextArea;
-	
-	import org.bigbluebutton.modules.sharednotes.util.DiffPatch;
-	
-	public class PatchableTextArea extends TextArea
-	{
-		private var _tackOnText : String = "";
-		private var _tackOnTextChanged : Boolean = false;
-		
-		private var _patch : String = "";
-		private var _patchChanged : Boolean = false;
-		
-		public function set tackOnText(value:String):void
-		{
-			_tackOnText = value;
-			_tackOnTextChanged = true;
-			invalidateProperties();
-		}
-		
-		public function get tackOnText():String
-		{
-			return _tackOnText;
-		}
-		
-		public function set patch(value:String):void
-		{
-			_patch = value;
-			_patchChanged = true;
-			invalidateProperties();
-		}
-		
-		public function get patch():String
-		{
-			return _patch;
-		} 
-		
-		override protected function commitProperties():void
-		{
-			super.commitProperties();
-			
-			if (_patchChanged) {
-					patchClientText();
-					patch = "";
-					_patchChanged = false;
-			}
-			
-			if(_tackOnTextChanged) {
-				this.textField.text += tackOnText;
-				tackOnText = "";
-				_tackOnTextChanged = false;
-			}
-		}
-		
-		public function get textFieldText():String {
-			return this.textField.text;
-		}
-		
-		private function patchClientText():void {
-			var results:Array = DiffPatch.patchClientText(patch, textField.text, selectionBeginIndex, selectionEndIndex);
-			
-			textField.text = results[1];
-
-			var cursorSelection:Array = results[0];
-			textField.setSelection(cursorSelection[0], cursorSelection[1]);
-		}
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/AddNoteEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/AddNoteEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..883470324bc62a3b6d68c11df0bb9ff858785e8d
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/AddNoteEvent.as
@@ -0,0 +1,34 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package org.bigbluebutton.modules.sharednotes.events
+{
+    import flash.events.Event;
+
+    public class AddNoteEvent extends Event
+    {
+        public static const ADD_NOTE:String = 'ADD_NOTE';
+        public var document:String;
+        public var userid:String;
+
+        public function AddNoteEvent(type:String = CURRENT_DOCUMENT, bubbles:Boolean=true, cancelable:Boolean=false)
+        {
+            super(type, bubbles, cancelable);
+        }
+    }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/CurrentDocumentEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/CurrentDocumentEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..952cdd0ce60aa496b97e13dd9ae9cfb7ff40d3ca
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/CurrentDocumentEvent.as
@@ -0,0 +1,34 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Hugo Lazzari <hslazzari@gmail.com>
+ */
+package org.bigbluebutton.modules.sharednotes.events
+{
+	import flash.events.Event;
+
+	public class CurrentDocumentEvent extends Event
+	{
+		public static const CURRENT_DOCUMENT:String = 'CURRENT_DOCUMENT';
+		public var document:Object;
+
+		public function CurrentDocumentEvent(type:String = CURRENT_DOCUMENT, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/Patch.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/GetCurrentDocumentEvent.as
old mode 100755
new mode 100644
similarity index 61%
rename from bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/Patch.as
rename to bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/GetCurrentDocumentEvent.as
index 6b69894cf15c0843b230716558e03585325d250f..46334581799223bc9b7c24981da4fb34319937b0
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/Patch.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/GetCurrentDocumentEvent.as
@@ -1,31 +1,33 @@
-/**
- * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
- * 
- * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
- *
- * This program is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation; either version 3.0 of the License, or (at your option) any later
- * version.
- * 
- * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along
- * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-package org.bigbluebutton.modules.sharednotes.infrastructure
-{
-	public class Patch
-	{
-		public var version:int, data:String;
-		
-		public function Patch(version:int, data:String)
-		{
-			this.version = version;
-			this.data = data;
-		}
-	}
-}
\ No newline at end of file
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Hugo Lazzari <hslazzari@gmail.com>
+ */
+package org.bigbluebutton.modules.sharednotes.events
+{
+	import flash.events.Event;
+
+	public class GetCurrentDocumentEvent extends Event
+	{
+		public static const GET_CURRENT_DOCUMENT:String = 'GET_CURRENT_DOCUMENT';
+
+		public function GetCurrentDocumentEvent(type:String = GET_CURRENT_DOCUMENT, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/ReceivePatchEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/ReceivePatchEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..a70b042cdda5f4539b76360f4546ebfc4755cd18
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/ReceivePatchEvent.as
@@ -0,0 +1,38 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Hugo Lazzari <hslazzari@gmail.com>
+ */
+package org.bigbluebutton.modules.sharednotes.events
+{
+	import flash.events.Event;
+
+	public class ReceivePatchEvent extends Event
+	{
+		public static const RECEIVE_PATCH_EVENT:String = 'RECEIVE_PATCH_EVENT';
+		public var patch:String;
+		public var noteId:String;
+		public var patchId:Number;
+		public var undo:Boolean;
+		public var redo:Boolean;
+
+		public function ReceivePatchEvent(type:String = RECEIVE_PATCH_EVENT, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/SendPatchEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/SendPatchEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..eadd69a510dd266e9914f6821c1f8abc79530d23
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/SendPatchEvent.as
@@ -0,0 +1,36 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Hugo Lazzari <hslazzari@gmail.com>
+ */
+package org.bigbluebutton.modules.sharednotes.events
+{
+	import flash.events.Event;
+
+	public class SendPatchEvent extends Event
+	{
+		public static const SEND_PATCH_EVENT:String = 'SEND_PATCH_EVENT';
+		public var patch:String = "";
+		public var noteId:String;
+		public var operation:String;
+
+		public function SendPatchEvent(type:String = SEND_PATCH_EVENT, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/SharedNotesEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/SharedNotesEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..4b30270b5883528f2c8992e55e6d1e51923c4411
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/SharedNotesEvent.as
@@ -0,0 +1,48 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Hugo Lazzari <hslazzari@gmail.com>
+ */
+package org.bigbluebutton.modules.sharednotes.events
+{
+	import org.bigbluebutton.main.events.BBBEvent;
+
+	public class SharedNotesEvent extends BBBEvent
+	{
+		public static const CREATE_ADDITIONAL_NOTES_REQUEST_EVENT:String = 'SHARED_NOTES_CREATE_ADDITIONAL_NOTES_REQUEST';
+		public static const CREATE_ADDITIONAL_NOTES_REPLY_EVENT:String = 'SHARED_NOTES_CREATE_ADDITIONAL_NOTES_REPLY';
+		public static const DESTROY_ADDITIONAL_NOTES_REQUEST_EVENT:String = 'SHARED_NOTES_DESTROY_ADDITIONAL_NOTES_REQUEST';
+		public static const DESTROY_ADDITIONAL_NOTES_REPLY_EVENT:String = 'SHARED_NOTES_DESTROY_ADDITIONAL_NOTES_REPLY';
+
+		public static const REQUEST_ADDITIONAL_NOTES_SET_EVENT:String = 'SHARED_NOTES_ADDITIONAL_NOTES_SET_REQUEST';
+
+		public static const CURRENT_DOCUMENT_REQUEST_EVENT:String = 'SHARED_NOTES_CURRENT_DOCUMENT_REQUEST';
+		public static const CURRENT_DOCUMENT_REPLY_EVENT:String = 'SHARED_NOTES_CURRENT_DOCUMENT_REPLY';
+		public static const CONNECT_EVENT:String = 'SHARED_NOTES_CONNECT';
+		public static const SEND_PATCH_EVENT:String = 'SHARED_NOTES_SEND_PATCH';
+		public static const RECEIVE_PATCH_EVENT:String = 'SHARED_NOTES_RECEIVE_PATCH';
+		public static const SYNC_NOTE_REQUEST_EVENT:String = 'SYNC_NOTE_REQUEST_EVENT';
+		public static const SYNC_NOTE_REPLY_EVENT:String = 'SYNC_NOTE_REPLY_EVENT';
+
+		public var noteName:String = "";
+
+		public function SharedNotesEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, null, bubbles, cancelable);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/StartSharedNotesModuleEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/StartSharedNotesModuleEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..d9dab8a031a8804db5b45fd068342df77d74dd59
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/StartSharedNotesModuleEvent.as
@@ -0,0 +1,34 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Hugo Lazzari <hslazzari@gmail.com>
+ */
+package org.bigbluebutton.modules.sharednotes.events
+{
+	import flash.events.Event;
+
+	public class StartSharedNotesModuleEvent extends Event
+	{
+		public static const START_SHAREDNOTES_MODULE_EVENT:String = 'START_SHAREDNOTES_MODULE_EVENT';
+		public var attributes:Object;
+
+		public function StartSharedNotesModuleEvent(type:String=START_SHAREDNOTES_MODULE_EVENT, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/StopSharedNotesModuleEvent.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/StopSharedNotesModuleEvent.as
new file mode 100644
index 0000000000000000000000000000000000000000..1c79cbe0145c1497438c30bedc3d255e80aa882d
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/events/StopSharedNotesModuleEvent.as
@@ -0,0 +1,33 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 2.1 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Hugo Lazzari <hslazzari@gmail.com>
+ */
+package org.bigbluebutton.modules.sharednotes.events
+{
+	import flash.events.Event;
+
+	public class StopSharedNotesModuleEvent extends Event
+	{
+		public static const STOP_SHAREDNOTES_MODULE_EVENT:String = 'STOP_SHAREDNOTES_MODULE_EVENT';
+
+		public function StopSharedNotesModuleEvent(type:String=STOP_SHAREDNOTES_MODULE_EVENT, bubbles:Boolean=true, cancelable:Boolean=false)
+		{
+			super(type, bubbles, cancelable);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/action_refresh.gif b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/action_refresh.gif
deleted file mode 100644
index 8268958a19e016741fffb8309b1174e548f5ce19..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/action_refresh.gif and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/arrow_left.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/arrow_left.png
deleted file mode 100644
index 5dc696781e6135d37b5bf2e98e46fd94f020c48d..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/arrow_left.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/note_edit.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/note_edit.png
deleted file mode 100644
index 291bfc764709a7e595050c1ed43b675f7af29c56..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/note_edit.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/play-icon.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/play-icon.png
deleted file mode 100644
index 3e4705db020c64cc3c46b877a86992bc2f22c06e..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/play-icon.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/tick.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/tick.png
deleted file mode 100644
index a9925a06ab02db30c1e7ead9c701c15bc63145cb..0000000000000000000000000000000000000000
Binary files a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/images/tick.png and /dev/null differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/Client.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/Client.as
deleted file mode 100644
index 90f386be97bea2187c66f2814639428f30bc614b..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/Client.as
+++ /dev/null
@@ -1,208 +0,0 @@
-/**
- * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
- * 
- * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
- *
- * This program is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation; either version 3.0 of the License, or (at your option) any later
- * version.
- * 
- * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along
- * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-package org.bigbluebutton.modules.sharednotes.infrastructure
-{
-	import com.adobe.crypto.SHA1;
-	
-	import flash.events.Event;
-	import flash.events.IEventDispatcher;
-	import flash.events.TimerEvent;
-	import flash.utils.Timer;
-	
-	import org.as3commons.logging.api.ILogger;
-	import org.as3commons.logging.api.getClassLogger;
-	import org.bigbluebutton.modules.sharednotes.components.PatchableTextArea;
-	import org.bigbluebutton.modules.sharednotes.util.DiffPatch;
-
-
-	public class Client
-	{
-		private static const LOGGER:ILogger = getClassLogger(Client);      
-
-		private var _id:int;
-		
-		private var textArea:PatchableTextArea;	// the text component to display the document
-		private var documentShadow:String = ""; // the shadow of the current document
-		private var initialDocument:String;	// for storing the initial document
-		
-		private var logPrefix:String;		// used for logging
-		
-		private var patchHistory:Array = new Array();		// a history of the patches
-		
-		private var server:ServerConnection;
-		
-		private var testCharacterTimer:Timer;
-		private var documentCheckTimer:Timer;	// timer to check for changes in the document
-		private var timeoutTimer:Timer = new Timer(5000); // setting the timeout for server requests to 5 seconds
-		
-		public static var documentName:String = "";
-		
-	
-		public function Client(textComponent:PatchableTextArea, dispatcher:IEventDispatcher) {
-			textArea = textComponent;
-			server = new HTTPServerConnection(this, dispatcher);
-		}
-		
-		public function initClient(id:int, serverConnection:ServerConnection, document:String = ""):void {
-			_id = id;
-			documentShadow = new String(document);
-			textArea.text = new String(document);
-			initialDocument = new String(document);
-			server = serverConnection;
-			
-			logPrefix = "[Client " + id + "] ";
-			initDocumentCheckTimer();
-			
-			timeoutTimer.addEventListener(TimerEvent.TIMER, function(e:Event):void {
-				timeoutTimer.stop();
-				sendMessage();
-			});
-			
-			// used for testing
-			testCharacterTimer = new Timer(10);
-			testCharacterTimer.addEventListener(TimerEvent.TIMER, playSentence);
-		}
-		
-		private function initDocumentCheckTimer():void {
-			documentCheckTimer = new Timer(500);
-			documentCheckTimer.addEventListener(TimerEvent.TIMER, documentCheckEventHandler);
-			documentCheckTimer.start();
-		}
-		
-		private function documentCheckEventHandler(e:TimerEvent):void {
-			if (!server.pendingResponse) {
-				sendMessage();
-			}
-		}
-
-		public function sendMessage():void {
-			var messageToSend:Message = new Message(id, documentName, ServerConnection.connectionType);
-			
-			if (documentShadow != textArea.textFieldText) {
-				LOGGER.debug("****** SENDING MESSAGE *******");
-				
-				textArea.editable = false;
-				var clientText:String = new String(textArea.textFieldText); // a snapshot of the client text
-				
-				messageToSend.patchData = DiffPatch.diff(documentShadow, clientText);
-				
-				patchHistory.push(messageToSend.patchData);
-				
-				documentShadow = clientText;
-
-				messageToSend.checksum = SHA1.hash(documentShadow);
-				
-				textArea.editable = true;
-				
-				LOGGER.debug("{0} sending {1}", [logPrefix, messageToSend]);
-			}
-			
-			//server.send("m, " + JSON.encode(messageToSend));
-
-			timeoutTimer.start();
-		}
-		
-		public function receiveMessage(serverMessage:Message): void {
-			timeoutTimer.stop();	// we received a response - cancel the time out
-			
-			LOGGER.debug("{0} received message.\nMessage: {1}", [logPrefix, serverMessage]);
-			
-			if (serverMessage.patchData != "") {
-				var result:String = DiffPatch.patch(serverMessage.patchData, documentShadow);
-				
-				if (SHA1.hash(result) == serverMessage.checksum) {
-					documentShadow = result;
-					textArea.patch = serverMessage.patchData;
-					patchHistory.push(serverMessage.patchData);
-				}
-				else {
-					throw new Error("Checksum mismatch");
-				}
-			}
-			
-			server.pendingResponse = false;
-		}
-		
-		public function getSnapshotAtVersion(initialVersion:int, finalVersion:int, documentSnapshot:String = ""):String {
-			if (initialVersion == 0) documentSnapshot = initialDocument;
-			
-			if (initialVersion < finalVersion) {
-				for (var i:int = initialVersion; i < finalVersion; i++) {
-					documentSnapshot = DiffPatch.patch(patchHistory[i], documentSnapshot);
-				}
-			}
-			else {
-				for (i = finalVersion; i < initialVersion;i++) {
-					documentSnapshot = DiffPatch.unpatch(patchHistory[i], documentSnapshot);
-				}
-			}
-			
-			return documentSnapshot;
-		}
-		
-		public function startTyping():void {
-			testCharacterTimer.start();
-		}
-		
-		public function stopTyping():void {
-			testCharacterTimer.stop();
-		}
-		
-		private var testSentence:String = "The quick brown fox jumps over the lazy dog.";
-		
-		private var testCounter:int = 0;
-		
-		private function playSentence(event:TimerEvent):void {
-			if (textArea.editable) {
-				if (testCounter == testSentence.length)  {
-					testCounter = 0;
-					textArea.tackOnText += "\n";
-				}
-				else {
-					textArea.tackOnText += testSentence.charAt(testCounter++);
-				}
-				textArea.editable = true;
-			}
-		}
-		
-		public function isTypingTestRunning():Boolean {
-			return testCharacterTimer.running;
-		}
-		
-		private var pendingServerMessage:Message;
-		private function startReceive(e:TimerEvent):void {
-			receiveMessage(pendingServerMessage);
-		}
-		
-		private function timeoutHandler(event:TimerEvent):void {
-			sendMessage();
-		}
-		
-		public function get version():int { return patchHistory.length; }
-		
-		public function get id():int { return _id; }
-		
-		public function shutdown():void {
-			server.shutdown();
-			if (testCharacterTimer) testCharacterTimer.stop();
-			if (documentCheckTimer) documentCheckTimer.stop();
-			if (timeoutTimer) timeoutTimer.stop();
-		}
-	}
-}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/HTTPServerConnection.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/HTTPServerConnection.as
deleted file mode 100644
index d94d59fd47d0679243e696a3c5daa885cbbd89ea..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/HTTPServerConnection.as
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
- * 
- * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
- *
- * This program is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation; either version 3.0 of the License, or (at your option) any later
- * version.
- * 
- * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along
- * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-package org.bigbluebutton.modules.sharednotes.infrastructure
-{
-	import flash.events.Event;
-	import flash.events.IEventDispatcher;
-	import flash.net.URLLoader;
-	import flash.net.URLRequest;
-	import flash.net.URLRequestMethod;
-	import flash.net.URLVariables;
-	
-	import org.as3commons.logging.api.ILogger;
-	import org.as3commons.logging.api.getClassLogger;
-	
-	public class HTTPServerConnection extends ServerConnection
-	{
-		private static const LOGGER:ILogger = getClassLogger(HTTPServerConnection);      
-
-		public static var syncURL:String = "";
-		private var loader:URLLoader = new URLLoader();		// used for connecting to the server
-		
-		public function HTTPServerConnection(client:Client, dispatcher:IEventDispatcher)
-		{
-			super(client, dispatcher);
-			ServerConnection.connectionType = "http";
-			loader.addEventListener(Event.COMPLETE, completeHandler);
-			sendConnectRequest();
-		}
-		
-		private function completeHandler(event:Event):void {
-			var loader:URLLoader = URLLoader(event.target);
-			loader.close();
-			
-			receive(loader.data);
-		}
-		
-		public override function send(message:String):void {
-			var params : URLVariables = new URLVariables();
-			params.message = message;
-			var request:URLRequest = new URLRequest(syncURL);
-			request.data = params;
-			request.method = URLRequestMethod.POST;
-			try {
-				loader.load(request);
-				pendingResponse = true;
-			} catch (error:Error) {
-				LOGGER.debug("Unable to load requested document.");
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/Message.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/Message.as
deleted file mode 100755
index ef6b54f259e107f08c661cbec0b43b06665350d6..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/Message.as
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
- * 
- * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
- *
- * This program is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation; either version 3.0 of the License, or (at your option) any later
- * version.
- * 
- * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along
- * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-package org.bigbluebutton.modules.sharednotes.infrastructure
-{
-	public class Message
-	{
-		public var senderId:int;
-		public var patchData:String;
-		public var checksum:String;
-		public var documentName:String;
-		public var conType:String;
-		
-		public function Message(senderId:int, documentName:String, conType:String, patchData:String = "" , checksum:String = ""){
-			this.senderId = senderId;
-			this.documentName = documentName;
-			this.patchData = patchData;
-			this.checksum = checksum;
-			this.conType = conType;
-		}
-		
-		public static function deserialize(o:Object):Message {
-			var patchData:String = "", checksum:String = "";
-			
-			if (o.checksum) checksum = o.checksum;
-			if (o.patchData) patchData = o.patchData;
-			
-			return new Message(o.senderId, o.documentName, o.conType, patchData, checksum);
-		}
-		
-		public function toString():String {
-			return "Message: " + ", senderId " + senderId + ", patchData: " + patchData + ", checksum " + checksum
-		}
-
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/ServerConnection.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/ServerConnection.as
deleted file mode 100644
index ad49433f019a594fd1110378ea8b550cfe3f9ab1..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/ServerConnection.as
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
- * 
- * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
- *
- * This program is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation; either version 3.0 of the License, or (at your option) any later
- * version.
- * 
- * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along
- * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-package org.bigbluebutton.modules.sharednotes.infrastructure
-{
-	import flash.events.Event;
-	import flash.events.IEventDispatcher;
-	import flash.events.TimerEvent;
-	import flash.utils.Timer;
-	
-	import org.as3commons.logging.api.ILogger;
-	import org.as3commons.logging.api.getClassLogger;
-
-	public class ServerConnection
-	{
-		private static const LOGGER:ILogger = getClassLogger(ServerConnection);      
-
-		public static const SYNCING_EVENT : String = "SN_SYNCING_EVENT";
-		public static const SYNCED_EVENT : String = "SN_SYNCED_EVENT";
-		
-		private var client:Client;
-		protected var dispatcher:IEventDispatcher;
-		
-		private var _pendingResponse:Boolean = false;		// flag indicating if a response has been received from the server
-		private var connectionTimeout:Timer = new Timer(5000); //TODO: change the timeout
-		
-		public static var connectionType:String = ""; // determines the type of server connection (whether socket or http)
-		
-		public function ServerConnection(client:Client, dispatcher:IEventDispatcher) {
-			this.client = client;
-			this.dispatcher = dispatcher;
-			connectionTimeout.addEventListener(TimerEvent.TIMER, function(e:Event):void { 
-				connectionTimeout.stop(); 
-				sendConnectRequest();
-			});
-		}
-		
-		protected function sendConnectRequest():void {
-			var request:Object = new Object();
-			request.documentName = Client.documentName;
-			request.connectionType = ServerConnection.connectionType;
-			//send("c, " + JSON.encode(request));
-			connectionTimeout.start();
-		}
-		
-		public function send(message:String):void { } // to be overridden
-		
-		protected function receive(data:String):void { 
-			if (data.indexOf("c,") == 0) {
-				LOGGER.debug("Received connection data: {0}", [data]);
-				//var clientData:Object = JSON.decode(data.substring(2));
-				//client.initClient(clientData.id, this, clientData.initialDocument);
-				connectionTimeout.stop();
-				pendingResponse = false;
-			}
-			else if (data.indexOf("m,") == 0) {
-				//var message:Message = Message.deserialize(JSON.decode(data.substring(2)));
-				//client.receiveMessage(message);
-			}
-			else {
-				LOGGER.debug("unrecognized data: {0}", [data]);
-			}
-		}
-		
-		public function get pendingResponse():Boolean { 
-			return _pendingResponse; 
-		}
-		
-		public function set pendingResponse(value : Boolean):void {
-			_pendingResponse = value;
-			
-			if (_pendingResponse) {
-				dispatcher.dispatchEvent(new Event(SYNCING_EVENT));
-			} else {
-				dispatcher.dispatchEvent(new Event(SYNCED_EVENT));
-			}
-		}
-		
-		public function shutdown():void {
-			connectionTimeout.stop();
-		}
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/XMLServerConnection.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/XMLServerConnection.as
deleted file mode 100644
index 096a3c4a3c1cc3d7e961b9d92924f905b83b9d30..0000000000000000000000000000000000000000
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/infrastructure/XMLServerConnection.as
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
- * 
- * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
- *
- * This program is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation; either version 3.0 of the License, or (at your option) any later
- * version.
- * 
- * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along
- * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-package org.bigbluebutton.modules.sharednotes.infrastructure
-{
-	import flash.events.DataEvent;
-	import flash.events.Event;
-	import flash.events.IEventDispatcher;
-	import flash.events.TimerEvent;
-	import flash.net.XMLSocket;
-	import flash.utils.Timer;
-	
-	import org.as3commons.logging.api.ILogger;
-	import org.as3commons.logging.api.getClassLogger;
-	
-	public class XMLServerConnection extends ServerConnection
-	{
-		public static var serverURL:String = "192.168.0.104";
-		private static const LOGGER:ILogger = getClassLogger(XMLServerConnection);      
-
-		public static const XML_CONNECTION_FAILED:String = "XML_CONNECTION_FAILED";
-		private static const MAXIMUM_CONNECTION_ATTEMPTS:int = 5;
-		
-		private var _socket: XMLSocket;
-		private var timeoutTimer: Timer = new Timer(5000);
-		private var connectionAttempts:int = MAXIMUM_CONNECTION_ATTEMPTS;	// attempt to connect five times before dispatching a failure
-		
-		private function get socket():XMLSocket {
-			return _socket;
-		}
-		
-		public function XMLServerConnection(client:Client, dispatcher:IEventDispatcher)
-		{
-			super(client, dispatcher);
-			ServerConnection.connectionType = "xmlsocket";
-			
-			timeoutTimer.addEventListener(TimerEvent.TIMER, function(e:Event):void { timeoutTimer.stop(); connect(); });
-			connect();
-		}
-				
-		public function connect():void {
-			_socket = new XMLSocket();
-			_socket.addEventListener(Event.CONNECT, function(e:Event):void { 
-				connectionAttempts = MAXIMUM_CONNECTION_ATTEMPTS; 
-				
-				sendConnectRequest(); 
-			});
-			_socket.addEventListener(DataEvent.DATA, function(e:DataEvent):void { receive(e.data); });
-			socket.connect(serverURL, 8095);
-		}
-		
-		public override function send(message:String):void {
-			try {
-				pendingResponse = true;
-				socket.send(message);
-			} catch(e:Error) {
-				//socket.close();
-				if (connectionAttempts > 0) {
-					LOGGER.debug(e.message);
-					connectionAttempts--;
-					timeoutTimer.start();
-				} else {
-					dispatcher.dispatchEvent(new Event(XML_CONNECTION_FAILED));
-				}
-			}
-		}
-	}
-}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/managers/SharedNotesManager.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/managers/SharedNotesManager.as
new file mode 100755
index 0000000000000000000000000000000000000000..8d8e6d01da111bc48f502b94cd677890fcc5fc53
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/managers/SharedNotesManager.as
@@ -0,0 +1,73 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+package org.bigbluebutton.modules.sharednotes.managers {
+	import com.asfusion.mate.events.Dispatcher;
+
+	import org.as3commons.logging.api.ILogger;
+	import org.as3commons.logging.api.getClassLogger;
+	import org.bigbluebutton.modules.sharednotes.events.SendPatchEvent;
+	import org.bigbluebutton.modules.sharednotes.events.SharedNotesEvent;
+	import org.bigbluebutton.modules.sharednotes.services.MessageReceiver;
+	import org.bigbluebutton.modules.sharednotes.services.MessageSender;
+	import org.bigbluebutton.core.managers.UserManager;
+
+	public class SharedNotesManager {
+		private static const LOGGER:ILogger = getClassLogger(SharedNotesManager);
+
+		public var sender:MessageSender;
+		public var receiver:MessageReceiver;
+		private var attributes:Object;
+
+		public function SharedNotesManager() {}
+
+		public function setModuleAttributes(attributes:Object):void {
+			this.attributes = attributes;
+		}
+
+		public function patchDocument(e:SendPatchEvent):void {
+			sender.patchDocument(e.noteId, UserManager.getInstance().getConference().getMyUserId(), e.patch, e.operation);
+		}
+
+		public function getCurrentDocument():void {
+			sender.currentDocument();
+		}
+
+		public function createAdditionalNotes(e:SharedNotesEvent):void {
+			sender.createAdditionalNotes(e.noteName);
+		}
+
+		public function destroyAdditionalNotes(notesId:String):void {
+			LOGGER.debug("SharedNotesManager: destroying notes " + notesId);
+			sender.destroyAdditionalNotes(notesId);
+		}
+
+		public function requestAdditionalNotesSet(e:SharedNotesEvent):void {
+			var notesSet:Number = e.payload.numAdditionalSharedNotes;
+			LOGGER.debug("SharedNotesManager: requested to open a new notes set");
+			LOGGER.debug("SharedNotesManager: set size: " + notesSet);
+			sender.requestAdditionalNotesSet(notesSet);
+		}
+
+		public function sharedNotesSyncNoteRequest(e:SharedNotesEvent):void {
+			var noteId:String = e.payload.noteId;
+			sender.sharedNotesSyncNoteRequest(noteId);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/maps/SharedNotesEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/maps/SharedNotesEventMap.mxml
new file mode 100755
index 0000000000000000000000000000000000000000..bf45a51f39d85537d37cc3630de7a46318be2440
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/maps/SharedNotesEventMap.mxml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  BigBlueButton open source conferencing system - http://www.bigbluebutton.org
+
+  Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+
+  BigBlueButton is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Lesser General Public License as published by the Free Software
+  Foundation; either version 2.1 of the License, or (at your option) any later
+  version.
+
+  BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+  PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License along
+  with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+-->
+
+<EventMap xmlns="http://mate.asfusion.com/"
+	xmlns:mx="http://www.adobe.com/2006/mxml">
+	<mx:Script>
+		<![CDATA[
+			import org.bigbluebutton.main.events.BBBEvent;
+			import org.bigbluebutton.modules.sharednotes.events.StartSharedNotesModuleEvent;
+			import org.bigbluebutton.modules.sharednotes.events.StopSharedNotesModuleEvent;
+			import org.bigbluebutton.modules.sharednotes.managers.SharedNotesManager;
+			import org.bigbluebutton.modules.sharednotes.services.MessageReceiver;
+			import org.bigbluebutton.modules.sharednotes.services.MessageSender;
+			import org.bigbluebutton.modules.sharednotes.events.GetCurrentDocumentEvent;
+			import org.bigbluebutton.modules.sharednotes.events.CurrentDocumentEvent;
+			import org.bigbluebutton.modules.sharednotes.events.SendPatchEvent;
+			import org.bigbluebutton.modules.sharednotes.events.SharedNotesEvent;
+			import mx.events.FlexEvent;
+		]]>
+	</mx:Script>
+
+	<!--
+	This is the main event map for the chat module, think of it as the application controller.
+	-->
+	<EventHandlers type="{FlexEvent.PREINITIALIZE}">
+		<!--
+		The FlexEvent.PREINITIALIZE event is a good place for creating and initializing managers.
+		-->
+		<ObjectBuilder generator="{SharedNotesEventMapDelegate}"/>
+		<ObjectBuilder generator="{SharedNotesManager}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{StartSharedNotesModuleEvent.START_SHAREDNOTES_MODULE_EVENT}">
+		<MethodInvoker generator="{SharedNotesManager}" method="setModuleAttributes" arguments="{event.attributes}"/>
+		<MethodInvoker generator="{SharedNotesEventMapDelegate}" method="addMainWindow"/>
+		<MethodInvoker generator="{SharedNotesManager}" method="getCurrentDocument"/>
+	</EventHandlers>
+
+	<EventHandlers type="{StopSharedNotesModuleEvent.STOP_SHAREDNOTES_MODULE_EVENT}">
+		<MethodInvoker generator="{SharedNotesEventMapDelegate}" method="stopSharedNotesRemoveAll"/>
+		<!-- <MethodInvoker generator="{SharedNotesManager}" method="disconnectFromSharedNotes"/> -->
+	</EventHandlers>
+
+	<EventHandlers type="{GetCurrentDocumentEvent.GET_CURRENT_DOCUMENT}">
+		<MethodInvoker generator="{SharedNotesManager}" method="getCurrentDocument"/>
+	</EventHandlers>
+
+	<EventHandlers type="{CurrentDocumentEvent.CURRENT_DOCUMENT}">
+		<MethodInvoker generator="{SharedNotesEventMapDelegate}" method="addRemoteDocuments" arguments="{event}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{SendPatchEvent.SEND_PATCH_EVENT}">
+		<MethodInvoker generator="{SharedNotesManager}" method="patchDocument" arguments="{event}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{SharedNotesEvent.CREATE_ADDITIONAL_NOTES_REQUEST_EVENT}">
+		<MethodInvoker generator="{SharedNotesManager}" method="createAdditionalNotes" arguments="{event}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{SharedNotesEvent.CREATE_ADDITIONAL_NOTES_REPLY_EVENT}">
+		<MethodInvoker generator="{SharedNotesEventMapDelegate}" method="createAdditionalNotes" arguments="{[event.payload.notesId, event.payload.noteName]}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{SharedNotesEvent.	DESTROY_ADDITIONAL_NOTES_REQUEST_EVENT}">
+		<MethodInvoker generator="{SharedNotesManager}" method="destroyAdditionalNotes" arguments="{event.payload.notesId}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{SharedNotesEvent.DESTROY_ADDITIONAL_NOTES_REPLY_EVENT}">
+		<MethodInvoker generator="{SharedNotesEventMapDelegate}" method="destroyAdditionalNotes" arguments="{event.payload.notesId}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{SharedNotesEvent.REQUEST_ADDITIONAL_NOTES_SET_EVENT}">
+		<MethodInvoker generator="{SharedNotesManager}" method="requestAdditionalNotesSet" arguments="{event}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{SharedNotesEvent.SYNC_NOTE_REQUEST_EVENT}">
+		<MethodInvoker generator="{SharedNotesManager}" method="sharedNotesSyncNoteRequest" arguments="{event}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{BBBEvent.RECONNECT_DISCONNECTED_EVENT}">
+		<MethodInvoker generator="{SharedNotesEventMapDelegate}" method="destroyAllAdditionalNotes" arguments="{event}"/>
+	</EventHandlers>
+
+	<EventHandlers type="{BBBEvent.RECONNECT_BIGBLUEBUTTON_SUCCEEDED_EVENT}">
+		<EventAnnouncer generator="{GetCurrentDocumentEvent}" type="{GetCurrentDocumentEvent.GET_CURRENT_DOCUMENT}"/>
+	</EventHandlers>
+
+	<Injectors target="{SharedNotesManager}">
+		<PropertyInjector targetKey="receiver" source="{MessageReceiver}"/>
+		<PropertyInjector targetKey="sender" source="{MessageSender}"/>
+	</Injectors>
+
+	<Injectors target="{MessageReceiver}">
+		<PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/>
+	</Injectors>
+
+	<Injectors target="{MessageSender}">
+		<PropertyInjector targetKey="dispatcher" source="{scope.dispatcher}"/>
+	</Injectors>
+</EventMap>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/maps/SharedNotesEventMapDelegate.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/maps/SharedNotesEventMapDelegate.as
new file mode 100755
index 0000000000000000000000000000000000000000..2d657218167fbdd2d78f641e9f73b95da35158db
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/maps/SharedNotesEventMapDelegate.as
@@ -0,0 +1,130 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 2.1 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+package org.bigbluebutton.modules.sharednotes.maps
+{
+	import com.asfusion.mate.events.Dispatcher;
+
+	import mx.binding.utils.BindingUtils;
+	import mx.utils.ObjectUtil;
+
+	import org.as3commons.logging.api.ILogger;
+	import org.as3commons.logging.api.getClassLogger;
+	import org.bigbluebutton.core.managers.UserManager;
+	import org.bigbluebutton.main.events.BBBEvent;
+	import org.bigbluebutton.modules.sharednotes.views.SharedNotesWindow;
+	import org.bigbluebutton.modules.sharednotes.views.AdditionalSharedNotesWindow;
+	import org.bigbluebutton.common.events.CloseWindowEvent;
+	import org.bigbluebutton.common.events.OpenWindowEvent;
+	import org.bigbluebutton.modules.sharednotes.SharedNotesOptions;
+	import org.bigbluebutton.modules.sharednotes.events.CurrentDocumentEvent;
+	import org.bigbluebutton.modules.sharednotes.events.SharedNotesEvent;
+
+	public class SharedNotesEventMapDelegate {
+		private static const LOGGER:ILogger = getClassLogger(SharedNotesEventMapDelegate);
+
+		private var globalDispatcher:Dispatcher;
+
+		private var windows:Array = [];
+		private var window:SharedNotesWindow;
+
+		private var options:SharedNotesOptions = new SharedNotesOptions();
+
+		public function SharedNotesEventMapDelegate() {
+			globalDispatcher = new Dispatcher();
+			window = new SharedNotesWindow();
+		}
+
+		public function addRemoteDocuments(e:CurrentDocumentEvent):void {
+			window.addRemoteDocument(e.document);
+			for(var id:String in e.document){
+				LOGGER.debug("NoteId:" + id +":"+e.document[id] + ":" + e.type);
+				if (id != window.noteId && !windows.hasOwnProperty(id)) {
+					createAdditionalNotes(id, "");
+					windows[id].addRemoteDocument(e.document);
+				}
+			}
+
+			BindingUtils.bindSetter(openAdditionalNotesSet, UserManager.getInstance().getConference(), "numAdditionalSharedNotes");
+		}
+
+		private function openAdditionalNotesSet(numAdditionalSharedNotes:Number):void {
+			var e:SharedNotesEvent = new SharedNotesEvent(SharedNotesEvent.REQUEST_ADDITIONAL_NOTES_SET_EVENT);
+			e.payload.numAdditionalSharedNotes = numAdditionalSharedNotes;
+			globalDispatcher.dispatchEvent(e);
+		}
+
+		public function addMainWindow():void {
+			var openEvent:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
+			openEvent.window = window;
+			globalDispatcher.dispatchEvent(openEvent);
+		}
+
+		private function get windowsAsString():String {
+			return ObjectUtil.toString(windows).split("\n").filter(function(element:*, index:int, arr:Array):Boolean {
+				return element.substring(0, 4) != "    ";
+			}).join("\n");
+		}
+
+		public function createAdditionalNotes(notesId:String, noteName:String):void {
+			LOGGER.debug(": creating additional notes " + notesId);
+
+			if(!windows.hasOwnProperty(notesId)) {
+				var newWindow:AdditionalSharedNotesWindow = new AdditionalSharedNotesWindow(notesId);
+				newWindow.noteName = noteName;
+				windows[notesId] = newWindow;
+
+				var openEvent:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
+				openEvent.window = newWindow;
+				globalDispatcher.dispatchEvent(openEvent);
+			}
+		}
+
+		public function destroyAdditionalNotes(notesId:String):void {
+			LOGGER.debug(": destroying additional notes, notesId: " + notesId);
+
+			var destroyWindow:AdditionalSharedNotesWindow = windows[notesId];
+			if (destroyWindow != null) {
+				LOGGER.debug(": notes found, removing window");
+
+				var closeEvent:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
+				closeEvent.window = destroyWindow;
+				globalDispatcher.dispatchEvent(closeEvent);
+
+				LOGGER.debug(": removing from windows list");
+				delete windows[notesId];
+			}
+		}
+
+		public function destroyAllAdditionalNotes(e:BBBEvent):void {
+			if (e.payload.type == "BIGBLUEBUTTON_CONNECTION") {
+				for (var noteId:String in windows) destroyAdditionalNotes(noteId);
+			}
+		}
+
+		public function stopSharedNotesRemoveAll():void {
+			//remove the additional
+			for (var noteId:String in windows) destroyAdditionalNotes(noteId);
+			//remove the main window
+			var closeEvent:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
+			closeEvent.window = window;
+			globalDispatcher.dispatchEvent(closeEvent);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/services/MessageReceiver.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/services/MessageReceiver.as
new file mode 100644
index 0000000000000000000000000000000000000000..12ec518201ea294a7b01ca2e36684815ba8ebca9
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/services/MessageReceiver.as
@@ -0,0 +1,149 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ * 
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 3.0 of the License, or (at your option) any later
+ * version.
+ * 
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package org.bigbluebutton.modules.sharednotes.services
+{
+  import flash.events.IEventDispatcher;
+  import flash.events.TimerEvent;
+  import flash.utils.Timer;
+
+  import mx.collections.ArrayCollection;
+
+  import org.as3commons.logging.api.ILogger;
+  import org.as3commons.logging.api.getClassLogger;
+  import org.bigbluebutton.core.BBB;
+  import org.bigbluebutton.core.UsersUtil;
+  import org.bigbluebutton.main.model.users.IMessageListener;
+  import org.bigbluebutton.modules.sharednotes.events.CurrentDocumentEvent;
+  import org.bigbluebutton.modules.sharednotes.events.SharedNotesEvent;
+  import org.bigbluebutton.modules.sharednotes.events.ReceivePatchEvent;
+
+  public class MessageReceiver implements IMessageListener {
+    private static const LOGGER:ILogger = getClassLogger(MessageReceiver);
+
+    private var buffering:Boolean = true;
+    private var patchDocumentBuffer:ArrayCollection = new ArrayCollection();
+    private var bufferingTimeout:Timer = new Timer(5000, 1);
+    private var bufferReader:Timer = new Timer(1000, 1);
+    public var dispatcher:IEventDispatcher;
+
+    public function MessageReceiver()
+    {
+      BBB.initConnectionManager().addMessageListener(this);
+      bufferingTimeout.addEventListener(TimerEvent.TIMER, endBuffering);
+      bufferReader.addEventListener(TimerEvent.TIMER, consumeBuffer);
+    }
+
+    public function onMessage(messageName:String, message:Object):void
+    {
+      switch (messageName) {
+        case "PatchDocumentCommand":
+          if (buffering || patchDocumentBuffer.length != 0) {
+            patchDocumentBuffer.addItem(message);
+            if (!bufferReader.running) {
+              bufferReader.start();
+            }
+          } else {
+            handlePatchDocumentCommand(message);
+          }
+          break;
+        case "GetCurrentDocumentCommand":
+          handleGetCurrentDocumentCommand(message);
+          bufferingTimeout.start();
+          break;
+        case "CreateAdditionalNotesCommand":
+          handleCreateAdditionalNotesCommand(message);
+          break;
+        case "DestroyAdditionalNotesCommand":
+          handleDestroyAdditionalNotesCommand(message);
+          break;
+        case "SharedNotesSyncNoteCommand":
+          handleSharedNotesSyncNoteCommand(message);
+          break;
+        default:
+           break;
+      }
+    }
+
+    private function endBuffering(e:TimerEvent):void {
+      buffering = false;
+    }
+
+    private function consumeBuffer(e:TimerEvent):void {
+      while (patchDocumentBuffer.length > 0) {
+        handlePatchDocumentCommand(patchDocumentBuffer.removeItemAt(0));
+      }
+    }
+
+    private function handlePatchDocumentCommand(msg: Object):void {
+      LOGGER.debug("Handling patch document message [" + msg.msg + "]");
+      var map:Object = JSON.parse(msg.msg);
+
+      var receivePatchEvent:ReceivePatchEvent = new ReceivePatchEvent();
+      if (map.userID != UsersUtil.getMyUserID()) {
+        receivePatchEvent.patch = map.patch;
+      } else {
+        receivePatchEvent.patch = "";
+      }
+      receivePatchEvent.noteId = map.noteID;
+      receivePatchEvent.patchId = map.patchID;
+      receivePatchEvent.undo = map.undo;
+      receivePatchEvent.redo = map.redo;
+
+      dispatcher.dispatchEvent(receivePatchEvent);
+    }
+
+    private function handleGetCurrentDocumentCommand(msg: Object):void {
+      LOGGER.debug("Handling get current document message [" + msg.msg + "]");
+      var map:Object = JSON.parse(msg.msg);
+
+      var currentDocumentEvent:CurrentDocumentEvent = new CurrentDocumentEvent();
+      currentDocumentEvent.document = map.notes;
+      dispatcher.dispatchEvent(currentDocumentEvent);
+    }
+
+    private function handleCreateAdditionalNotesCommand(msg: Object):void {
+      LOGGER.debug("Handling create additional notes message [" + msg.msg + "]");
+      var map:Object = JSON.parse(msg.msg);
+
+      var e:SharedNotesEvent = new SharedNotesEvent(SharedNotesEvent.CREATE_ADDITIONAL_NOTES_REPLY_EVENT);
+      e.payload.notesId = map.noteID;
+      e.payload.noteName = map.noteName;
+      dispatcher.dispatchEvent(e);
+    }
+
+    private function handleDestroyAdditionalNotesCommand(msg: Object):void {
+      LOGGER.debug("Handling destroy additional notes message [" + msg.msg + "]");
+      var map:Object = JSON.parse(msg.msg);
+
+      var e:SharedNotesEvent = new SharedNotesEvent(SharedNotesEvent.DESTROY_ADDITIONAL_NOTES_REPLY_EVENT);
+      e.payload.notesId = map.noteID;
+      dispatcher.dispatchEvent(e);
+    }
+
+    private function handleSharedNotesSyncNoteCommand(msg: Object):void {
+      LOGGER.debug("Handling sharednotes sync note message [" + msg.msg + "]");
+      var map:Object = JSON.parse(msg.msg);
+
+      var e:SharedNotesEvent = new SharedNotesEvent(SharedNotesEvent.SYNC_NOTE_REPLY_EVENT);
+      e.payload.noteId = map.noteID;
+      e.payload.note = map.note;
+      dispatcher.dispatchEvent(e);
+    }
+  }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/services/MessageSender.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/services/MessageSender.as
new file mode 100644
index 0000000000000000000000000000000000000000..a41ca5a03b6c6642eeb182788741ef0d28e8f431
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/services/MessageSender.as
@@ -0,0 +1,123 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 3.0 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package org.bigbluebutton.modules.sharednotes.services
+{
+  import flash.events.IEventDispatcher;
+
+  import org.as3commons.logging.api.ILogger;
+  import org.as3commons.logging.api.getClassLogger;
+  import org.bigbluebutton.core.BBB;
+  import org.bigbluebutton.core.managers.ConnectionManager;
+
+  public class MessageSender
+  {
+    private static const LOGGER:ILogger = getClassLogger(MessageSender);
+
+    public var dispatcher:IEventDispatcher;
+    
+    private var onSuccessDebugger:Function = function(result:String):void {
+      LOGGER.debug(result);
+    };
+    private var onErrorDebugger:Function = function(result:String):void {
+      LOGGER.debug(result);
+    };
+
+    public function currentDocument():void {
+      LOGGER.debug("Sending [sharednotes.currentDocument] to server.");
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "sharednotes.currentDocument",
+        onSuccessDebugger,
+        onErrorDebugger
+      );
+    }
+
+    public function createAdditionalNotes(noteName:String):void {
+      LOGGER.debug("Sending [sharednotes.createAdditionalNotes] to server.");
+      var message:Object = new Object();
+      message["noteName"] = noteName;
+
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "sharednotes.createAdditionalNotes",
+        onSuccessDebugger,
+        onErrorDebugger,
+        message
+      );
+    }
+
+    public function destroyAdditionalNotes(notesId:String):void {
+      LOGGER.debug("Sending [sharednotes.destroyAdditionalNotes] to server.");
+      var message:Object = new Object();
+      message["noteID"] = notesId;
+
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "sharednotes.destroyAdditionalNotes",
+        onSuccessDebugger,
+        onErrorDebugger,
+        message
+      );
+    }
+
+    public function patchDocument(noteId:String, userid:String, patch:String, operation:String):void {
+      LOGGER.debug("Sending [sharednotes.patchDocument] to server.");
+      var message:Object = new Object();
+      message["noteID"] = noteId;
+      message["patch"] = patch;
+      message["operation"] = operation;
+
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "sharednotes.patchDocument",
+        onSuccessDebugger,
+        onErrorDebugger,
+        message
+      );
+    }
+
+    public function requestAdditionalNotesSet(additionalNotesSetSize:Number):void {
+      LOGGER.debug("Sending [sharednotes.requestAdditionalNotesSet] to server.");
+      var message:Object = new Object();
+      message["additionalNotesSetSize"] = additionalNotesSetSize;
+
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "sharednotes.requestAdditionalNotesSet",
+        onSuccessDebugger,
+        onErrorDebugger,
+        message
+      );
+    }
+
+    public function sharedNotesSyncNoteRequest(noteId:String):void {
+      LOGGER.debug("Sending [sharednotes.sharedNotesSyncNoteRequest] to server.");
+      var message:Object = new Object();
+      message["noteID"] = noteId;
+
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "sharednotes.sharedNotesSyncNoteRequest",
+        onSuccessDebugger,
+        onErrorDebugger,
+        message
+      );
+    }
+  }
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/util/shared_notes.js b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/util/shared_notes.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ba4bcfa1503b1a3f414950a0de8a59897fa55a7
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/util/shared_notes.js
@@ -0,0 +1,295 @@
+/*
+    This file is part of BBB-Notes.
+
+    Copyright (c) Islam El-Ashi. All rights reserved.
+
+    BBB-Notes is free software: you can redistribute it and/or modify
+    it under the terms of the Lesser GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    any later version.
+
+    BBB-Notes is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    Lesser GNU General Public License for more details.
+
+    You should have received a copy of the Lesser GNU General Public License
+    along with BBB-Notes.  If not, see <http://www.gnu.org/licenses/>.
+
+    Author: Islam El-Ashi <ielashi@gmail.com>, <http://www.ielashi.com>
+*/
+var dmp = new diff_match_patch();
+var debug = false;
+
+function diff(text1, text2) {
+  return dmp.patch_toText(dmp.patch_make(dmp.diff_main(unescape(text1),unescape(text2))));
+}
+
+function patch(patch, text) {
+  return dmp.patch_apply(dmp.patch_fromText(patch), unescape(text))[0];
+}
+
+function unpatch(patch, text) {
+  return dmp.patch_apply_reverse(dmp.patch_fromText(patch), unescape(text))[0];
+}
+
+
+/**
+ * Helper Methods
+ */
+
+/**
+ * MobWrite - Real-time Synchronization and Collaboration Service
+ *
+ * Copyright 2006 Google Inc.
+ * http://code.google.com/p/google-mobwrite/
+ *
+ * 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.
+ */
+
+/**
+ * Modify the user's plaintext by applying a series of patches against it.
+ * @param {Array.<patch_obj>} patches Array of Patch objects.
+ * @param {String} client text
+ */
+function patchClientText(patches, text, selectionStart, selectionEnd) {
+  text = unescape(text)
+  // Set some constants which tweak the matching behaviour.
+  // Maximum distance to search from expected location.
+  dmp.Match_Distance = 1000;
+  // At what point is no match declared (0.0 = perfection, 1.0 = very loose)
+  dmp.Match_Threshold = 0.6;
+
+  var oldClientText = text
+  oldClientText = oldClientText + "``````````````````````";
+  var cursor = captureCursor_(oldClientText, selectionStart, selectionEnd);
+  // Pack the cursor offsets into an array to be adjusted.
+  // See http://neil.fraser.name/writing/cursor/
+  var offsets = [];
+  if (cursor) {
+    offsets[0] = cursor.startOffset;
+    if ('endOffset' in cursor) {
+      offsets[1] = cursor.endOffset;
+    }
+  }
+  var newClientText = patch_apply_(patches, oldClientText, offsets);
+  // Set the new text only if there is a change to be made.
+  if (oldClientText != newClientText) {
+    //this.setClientText(newClientText);
+    if (cursor) {
+      // Unpack the offset array.
+      cursor.startOffset = offsets[0];
+      if (offsets.length > 1) {
+        cursor.endOffset = offsets[1];
+        if (cursor.startOffset >= cursor.endOffset) {
+          cursor.collapsed = true;
+        }
+      }
+      return [restoreCursor_(cursor, newClientText), newClientText.substring(0,newClientText.length-22)];
+    }
+  }
+  // no change in client text
+
+  return [[selectionStart, selectionEnd], newClientText.substring(0,newClientText.length-22)];
+}
+
+/**
+ * Merge a set of patches onto the text.  Return a patched text.
+ * @param {Array.<patch_obj>} patches Array of patch objects.
+ * @param {string} text Old text.
+ * @param {Array.<number>} offsets Offset indices to adjust.
+ * @return {string} New text.
+ */
+function patch_apply_(patchText, text, offsets) {
+  var patches = dmp.patch_fromText(patchText);
+  if (patches.length == 0) {
+    return text;
+  }
+
+  // Deep copy the patches so that no changes are made to originals.
+  patches = dmp.patch_deepCopy(patches);
+  var nullPadding = dmp.patch_addPadding(patches);
+  text = nullPadding + text + nullPadding;
+
+  dmp.patch_splitMax(patches);
+  // delta keeps track of the offset between the expected and actual location
+  // of the previous patch.  If there are patches expected at positions 10 and
+  // 20, but the first patch was found at 12, delta is 2 and the second patch
+  // has an effective expected position of 22.
+  var delta = 0;
+  for (var x = 0; x < patches.length; x++) {
+    var expected_loc = patches[x].start2 + delta;
+    var text1 = dmp.diff_text1(patches[x].diffs);
+    var start_loc;
+    var end_loc = -1;
+    if (text1.length > dmp.Match_MaxBits) {
+      // patch_splitMax will only provide an oversized pattern in the case of
+      // a monster delete.
+      start_loc = dmp.match_main(text, text1.substring(0, dmp.Match_MaxBits), expected_loc);
+      if (start_loc != -1) {
+        end_loc = dmp.match_main(text, text1.substring(text1.length - dmp.Match_MaxBits),
+          expected_loc + text1.length - dmp.Match_MaxBits);
+        if (end_loc == -1 || start_loc >= end_loc) {
+          // Can't find valid trailing context.  Drop this patch.
+          start_loc = -1;
+        }
+      }
+    } else {
+      start_loc = dmp.match_main(text, text1, expected_loc);
+    }
+    if (start_loc == -1) {
+      // No match found.  :(
+      if (debug) {
+        window.console.warn('Patch failed: ' + patches[x]);
+      }
+      // Subtract the delta for this failed patch from subsequent patches.
+      delta -= patches[x].length2 - patches[x].length1;
+    } else {
+      // Found a match.  :)
+      if (debug) {
+        window.console.info('Patch OK.');
+      }
+      delta = start_loc - expected_loc;
+      var text2;
+      if (end_loc == -1) {
+        text2 = text.substring(start_loc, start_loc + text1.length);
+      } else {
+        text2 = text.substring(start_loc, end_loc + dmp.Match_MaxBits);
+      }
+      // Run a diff to get a framework of equivalent indices.
+      var diffs = dmp.diff_main(text1, text2, false);
+      if (text1.length > dmp.Match_MaxBits && dmp.diff_levenshtein(diffs) / text1.length > dmp.Patch_DeleteThreshold) {
+        // The end points match, but the content is unacceptably bad.
+        if (debug) {
+          window.console.warn('Patch contents mismatch: ' + patches[x]);
+        }
+      } else {
+        var index1 = 0;
+        var index2;
+        for (var y = 0; y < patches[x].diffs.length; y++) {
+          var mod = patches[x].diffs[y];
+          if (mod[0] !== DIFF_EQUAL) {
+            index2 = dmp.diff_xIndex(diffs, index1);
+          }
+          if (mod[0] === DIFF_INSERT) {  // Insertion
+            text = text.substring(0, start_loc + index2) + mod[1] + text.substring(start_loc + index2);
+            for (var i = 0; i < offsets.length; i++) {
+              if (offsets[i] + nullPadding.length > start_loc + index2) {
+                offsets[i] += mod[1].length;
+              }
+            }
+          } else if (mod[0] === DIFF_DELETE) {  // Deletion
+            var del_start = start_loc + index2;
+            var del_end = start_loc + dmp.diff_xIndex(diffs, index1 + mod[1].length);
+            text = text.substring(0, del_start) + text.substring(del_end);
+            for (var i = 0; i < offsets.length; i++) {
+              if (offsets[i] + nullPadding.length > del_start) {
+                if (offsets[i] + nullPadding.length < del_end) {
+                  offsets[i] = del_start - nullPadding.length;
+                } else {
+                  offsets[i] -= del_end - del_start;
+                }
+              }
+            }
+          }
+          if (mod[0] !== DIFF_DELETE) {
+            index1 += mod[1].length;
+          }
+        }
+      }
+    }
+  }
+  // Strip the padding off.
+  text = text.substring(nullPadding.length, text.length - nullPadding.length);
+  return text;
+}
+
+/**
+ * Record information regarding the current cursor.
+ * @return {Object?} Context information of the cursor.
+ * @private
+ */
+function captureCursor_(text, selectionStart, selectionEnd) {
+  var padLength = dmp.Match_MaxBits / 2;  // Normally 16.
+  var cursor = {};
+
+  cursor.startPrefix = text.substring(selectionStart - padLength, selectionStart);
+  cursor.startSuffix = text.substring(selectionStart, selectionStart + padLength);
+  cursor.startOffset = selectionStart;
+  cursor.collapsed = (selectionStart == selectionEnd);
+  if (!cursor.collapsed) {
+    cursor.endPrefix = text.substring(selectionEnd - padLength, selectionEnd);
+    cursor.endSuffix = text.substring(selectionEnd, selectionEnd + padLength);
+    cursor.endOffset = selectionEnd;
+  }
+
+  return cursor;
+}
+
+/**
+ * Attempt to restore the cursor's location.
+ * @param {Object} cursor Context information of the cursor.
+ * @private
+ */
+function restoreCursor_(cursor, text) {
+  // Set some constants which tweak the matching behaviour.
+  // Maximum distance to search from expected location.
+  dmp.Match_Distance = 1000;
+  // At what point is no match declared (0.0 = perfection, 1.0 = very loose)
+  dmp.Match_Threshold = 0.9;
+
+  var padLength = dmp.Match_MaxBits / 2;  // Normally 16.
+  var newText = text;
+  // Find the start of the selection in the new text.
+  var pattern1 = cursor.startPrefix + cursor.startSuffix;
+  var pattern2, diff;
+  var cursorStartPoint = dmp.match_main(newText, pattern1, cursor.startOffset - padLength);
+
+  if (cursorStartPoint !== null) {
+    pattern2 = newText.substring(cursorStartPoint, cursorStartPoint + pattern1.length);
+    // Run a diff to get a framework of equivalent indicies.
+    diff = dmp.diff_main(pattern1, pattern2, false);
+    cursorStartPoint += dmp.diff_xIndex(diff, cursor.startPrefix.length);
+  }
+
+  var cursorEndPoint = null;
+  if (!cursor.collapsed) {
+    // Find the end of the selection in the new text.
+    pattern1 = cursor.endPrefix + cursor.endSuffix;
+    cursorEndPoint = dmp.match_main(newText, pattern1, cursor.endOffset - padLength);
+    if (cursorEndPoint !== null) {
+      pattern2 = newText.substring(cursorEndPoint, cursorEndPoint + pattern1.length);
+      // Run a diff to get a framework of equivalent indicies.
+      diff = dmp.diff_main(pattern1, pattern2, false);
+      cursorEndPoint += dmp.diff_xIndex(diff, cursor.endPrefix.length);
+    }
+  }
+
+  // Deal with loose ends
+  if (cursorStartPoint === null && cursorEndPoint !== null) {
+    // Lost the start point of the selection, but we have the end point.
+    // Collapse to end point.
+    cursorStartPoint = cursorEndPoint;
+  } else if (cursorStartPoint === null && cursorEndPoint === null) {
+    // Lost both start and end points.
+    // Jump to the offset of start.
+    cursorStartPoint = cursor.startOffset;
+  }
+  if (cursorEndPoint === null) {
+    // End not known, collapse to start.
+    cursorEndPoint = cursorStartPoint;
+  }
+
+  return [cursorStartPoint, cursorEndPoint];
+}
+
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/AdditionalSharedNotesWindow.as b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/AdditionalSharedNotesWindow.as
new file mode 100644
index 0000000000000000000000000000000000000000..8e7d78744ff9531389899ce8f2cdd567c9acf3f6
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/AdditionalSharedNotesWindow.as
@@ -0,0 +1,83 @@
+package org.bigbluebutton.modules.sharednotes.views
+{
+	import flash.display.Sprite;
+	import flash.events.MouseEvent;
+
+	import mx.controls.Alert;
+	import mx.events.CloseEvent;
+
+	import org.as3commons.logging.api.ILogger;
+	import org.as3commons.logging.api.getClassLogger;
+	import org.bigbluebutton.core.UsersUtil;
+	import org.bigbluebutton.main.views.MainCanvas;
+	import org.bigbluebutton.modules.sharednotes.events.SharedNotesEvent;
+	import org.bigbluebutton.util.i18n.ResourceUtil;
+
+	public class AdditionalSharedNotesWindow extends SharedNotesWindow
+	{
+		private static const LOGGER:ILogger = getClassLogger(AdditionalSharedNotesWindow);
+
+		private var _windowName:String;
+
+		public function AdditionalSharedNotesWindow(n:String) {
+			super();
+
+			LOGGER.debug("AdditionalSharedNotesWindow: in-constructor additional notes " + n);
+			_noteId = n;
+			_windowName = "AdditionalSharedNotesWindow_" + noteId;
+
+			showCloseButton = UsersUtil.amIModerator();
+			width = 240;
+			height = 240;
+
+			closeBtn.addEventListener(MouseEvent.CLICK, onCloseBtnClick);
+		}
+
+		public function get windowName():String {
+			return this._windowName;
+		}
+
+		public function set noteName(name:String):void {
+			this._noteName = name;
+		}
+
+		override public function onCreationComplete():void {
+			super.onCreationComplete();
+
+			LOGGER.debug("AdditionalSharedNotesWindow: [2] in-constructor additional notes " + noteId);
+
+			btnNew.visible = btnNew.includeInLayout = false;
+		}
+
+		private function onCloseBtnClick(e:MouseEvent):void {
+			var alert:Alert = Alert.show(
+					ResourceUtil.getInstance().getString('bbb.sharedNotes.additionalNotes.closeWarning.message'),
+					ResourceUtil.getInstance().getString('bbb.sharedNotes.additionalNotes.closeWarning.title'),
+					Alert.YES | Alert.NO, parent as Sprite, alertClose, null, Alert.YES);
+			e.stopPropagation();
+		}
+
+		private function alertClose(e:CloseEvent):void {
+			if (e.detail == Alert.YES) {
+				showCloseButton = false;
+
+				LOGGER.debug("AdditionalSharedNotesWindow: requesting to destroy notes " + noteId);
+				var destroyNotesEvent:SharedNotesEvent = new SharedNotesEvent(SharedNotesEvent.DESTROY_ADDITIONAL_NOTES_REQUEST_EVENT);
+				destroyNotesEvent.payload.notesId = noteId;
+				_dispatcher.dispatchEvent(destroyNotesEvent);
+			}
+		}
+
+		override public function getPrefferedPosition():String {
+			return MainCanvas.POPUP;
+		}
+
+		override protected function updateTitle():void {
+			if (_noteName.length > 0) {
+				title = _noteName;
+			} else {
+				title = ResourceUtil.getInstance().getString('bbb.sharedNotes.title') + " " + noteId;
+			}
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/SharedNotesNameWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/SharedNotesNameWindow.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..06baeb243488817463bd21bfb3a4d779e1a8b5d5
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/SharedNotesNameWindow.mxml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+-->
+
+<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
+    xmlns:mate="http://mate.asfusion.com/"
+    verticalScrollPolicy="off"
+    horizontalScrollPolicy="off"
+    horizontalAlign="center"
+    showCloseButton="true"
+    close="onCancelClicked()"
+    creationComplete="onCreationComplete()"
+    width="250"
+    title="{ResourceUtil.getInstance().getString('bbb.sharedNotes.name')}">
+
+  <mx:Script>
+    <![CDATA[
+      import com.asfusion.mate.events.Dispatcher;
+
+      import mx.managers.PopUpManager;
+
+      import org.bigbluebutton.util.i18n.ResourceUtil;
+      import org.bigbluebutton.modules.sharednotes.events.SharedNotesEvent;
+
+      private function btnNew_clickHandler(event:MouseEvent):void {
+        var e:SharedNotesEvent = new SharedNotesEvent(SharedNotesEvent.CREATE_ADDITIONAL_NOTES_REQUEST_EVENT);
+        if (textInput.text != ResourceUtil.getInstance().getString('bbb.sharedNotes.title')) {
+          e.noteName = textInput.text;
+        }
+
+        var dispatcher:Dispatcher = new Dispatcher();
+        dispatcher.dispatchEvent(e);
+
+        PopUpManager.removePopUp(this);
+      }
+
+      private function onCreationComplete():void {
+        textInput.setFocus();
+      }
+
+      private function onCancelClicked():void {
+        PopUpManager.removePopUp(this);
+      }
+    ]]>
+  </mx:Script>
+
+  <mx:HBox width="100%" height="100%">
+      <mx:TextInput id="textInput"
+          restrict="a-zA-Z0-9 "
+          maxChars="20"
+          width="100%"
+          text="{ResourceUtil.getInstance().getString('bbb.sharedNotes.title')}"/>
+      <mx:Button id="btnNew"
+          click="btnNew_clickHandler(event)"
+          styleName="sharedNotesNewButtonStyle"
+          toolTip="{ResourceUtil.getInstance().getString('bbb.sharedNotes.new.toolTip')}"/>
+  </mx:HBox>
+</mx:TitleWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/SharedNotesWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/SharedNotesWindow.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..727abc4d7aad0e89ae9e87be19377d72b062e0bd
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/SharedNotesWindow.mxml
@@ -0,0 +1,492 @@
+<!--
+	This file is part of BBB-Notes.
+
+	Copyright (c) Islam El-Ashi. All rights reserved.
+
+	BBB-Notes is free software: you can redistribute it and/or modify
+	it under the terms of the Lesser GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	any later version.
+
+	BBB-Notes is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	Lesser GNU General Public License for more details.
+
+	You should have received a copy of the Lesser GNU General Public License
+	along with BBB-Notes.  If not, see <http://www.gnu.org/licenses/>.
+
+	Author: Islam El-Ashi <ielashi@gmail.com>, <http://www.ielashi.com>
+-->
+<CustomMdiWindow xmlns="org.bigbluebutton.common.*"
+		xmlns:mx="http://www.adobe.com/2006/mxml"
+		xmlns:mate="http://mate.asfusion.com/"
+		implements="org.bigbluebutton.common.IBbbModuleWindow"
+		creationComplete="onCreationComplete()"
+		xmlns:components="org.bigbluebutton.modules.sharednotes.views.components.*"
+		showCloseButton="false">
+
+	<mate:Listener type="{ReceivePatchEvent.RECEIVE_PATCH_EVENT}" method="receivePatch"/>
+	<mate:Listener type="{CurrentDocumentEvent}" method="gotCurrentDocument"/>
+	<mate:Listener type="{SharedNotesEvent.SYNC_NOTE_REPLY_EVENT}" method="handleSyncNote"/>
+
+	<mx:Script>
+		<![CDATA[
+			import org.as3commons.logging.api.ILogger;
+			import org.as3commons.logging.api.getClassLogger;
+			import com.asfusion.mate.events.Dispatcher;
+
+			import flash.events.KeyboardEvent;
+			import flash.ui.Keyboard;
+
+			import flexlib.mdi.events.MDIWindowEvent;
+
+			import mx.binding.utils.BindingUtils;
+			import mx.controls.Alert;
+			import mx.controls.Menu;
+			import mx.core.FlexGlobals;
+			import mx.core.IFlexDisplayObject;
+			import mx.events.MenuEvent;
+			import mx.managers.PopUpManager;
+
+			import org.bigbluebutton.core.UsersUtil;
+			import org.bigbluebutton.common.IBbbModuleWindow;
+			import org.bigbluebutton.common.Role;
+			import org.bigbluebutton.main.views.WellPositionedMenu;
+			import org.bigbluebutton.modules.sharednotes.views.components.SharedNotesRichTextEditor;
+			import org.bigbluebutton.modules.sharednotes.views.SharedNotesNameWindow;
+			import org.bigbluebutton.modules.sharednotes.SharedNotesOptions;
+			import org.bigbluebutton.modules.sharednotes.events.GetCurrentDocumentEvent;
+			import org.bigbluebutton.modules.sharednotes.events.CurrentDocumentEvent;
+			import org.bigbluebutton.modules.sharednotes.events.SendPatchEvent;
+			import org.bigbluebutton.modules.sharednotes.events.ReceivePatchEvent;
+			import org.bigbluebutton.modules.sharednotes.events.SharedNotesEvent;
+			import org.bigbluebutton.modules.sharednotes.util.DiffPatch;
+			import org.bigbluebutton.util.i18n.ResourceUtil;
+
+			private static const LOGGER:ILogger = getClassLogger(SharedNotesWindow);
+
+			protected var _dispatcher:Dispatcher = new Dispatcher();
+			private var _document:String = "";
+			private var _lastPatch:Number = 0;
+			protected var _noteId:String="MAIN_WINDOW";
+			protected var _noteName:String = "";
+
+			[Bindable] private var options:SharedNotesOptions = new SharedNotesOptions();
+
+			private var sendUpdateTimer:Timer;
+			private var getDocumentTimer:Timer = new Timer(5000);
+
+			public function onCreationComplete():void {
+				sendUpdateTimer = new Timer(options.refreshDelay, 1);
+
+				/*
+				 * This is a workaround on a Flex issue,
+				 * for more details see http://dev.mconf.org/redmine/issues/1712
+				 */
+				this.addEventListener(flexlib.mdi.events.MDIWindowEvent.FOCUS_END, function(e:MDIWindowEvent):void {
+					richTextEditor.refresh();
+				});
+
+				richTextEditor.addEventListener(Event.CHANGE, function(e:Event):void {
+					if (!sendUpdateTimer.running) {
+						sendUpdateTimer.reset();
+						sendUpdateTimer.start();
+					}
+				});
+
+				sendUpdateTimer.addEventListener(TimerEvent.TIMER, function(e:Event):void {
+					sendPatch();
+				});
+
+				BindingUtils.bindSetter(updateRoleDependentProperties, UsersUtil.getMyself(), "role");
+
+				updateTitle();
+
+				if (noteId == "MAIN_WINDOW") {
+					this.enabled = false;
+					getDocumentTimer.addEventListener(TimerEvent.TIMER, checkCurrentDocument);
+					getDocumentTimer.start();
+				}
+			}
+
+			private function gotCurrentDocument():void {
+				if(noteId == "MAIN_WINDOW"){
+					getDocumentTimer.stop();
+				}
+			}
+
+			private function checkCurrentDocument(e:Event):void {
+				if (!this.enabled) {
+					_dispatcher.dispatchEvent(new GetCurrentDocumentEvent());
+				} else {
+					getDocumentTimer.stop();
+				}
+			}
+
+			private function initSharedNotesRichTextEditor():void {
+				richTextEditor.textArea.setStyle("fontSize", options.fontSize);
+
+				richTextEditor.linkTextInput.visible = false;
+				richTextEditor.linkTextInput.height = 0;
+				richTextEditor.linkTextInput.width = 0;
+
+				// Bullets are messy: http://dev.mconf.org/redmine/issues/1715
+				richTextEditor.bulletButton.visible = false;
+				richTextEditor.bulletButton.height = 0;
+				richTextEditor.bulletButton.width = 0;
+			}
+
+			private function updateRoleDependentProperties(role:String):void {
+				if(noteId == "MAIN_WINDOW"){
+					btnNew.visible = btnNew.includeInLayout = options.enableMultipleNotes && role == Role.MODERATOR;
+				} else {
+					showCloseButton = role == Role.MODERATOR;
+				}
+			}
+
+			public function get noteId():String{
+				return _noteId;
+			}
+
+			public function addRemoteDocument(notes:Object):void{
+				var note:Object = notes[noteId];
+				_document = note["document"];
+				_noteName = note["name"];
+				_lastPatch = note["patchCounter"];
+				richTextEditor.htmlText = _document;
+				if (!this.enabled) this.enabled = true;
+				updateTitle();
+				updateUndoRedoButtons(note["undo"], note["redo"]);
+			}
+
+			private function sendPatch():void {
+				var clientText:String = new String(richTextEditor.htmlText); // a snapshot of the client text
+//				LOGGER.debug("SEND PATCH" + clientText + "::" + _document);
+				if (_document != clientText) {
+					richTextEditor.textArea.editable = false;
+					var sendPatchEvent:SendPatchEvent = new SendPatchEvent();
+					sendPatchEvent.noteId = noteId;
+					sendPatchEvent.patch = DiffPatch.diff(_document, clientText);
+					sendPatchEvent.operation = "PATCH";
+					_dispatcher.dispatchEvent(sendPatchEvent);
+					_document = clientText;
+					richTextEditor.textArea.editable = true;
+				}
+			}
+
+			private function possiblePatchError():Boolean {
+				if (richTextEditor.htmlText != _document) {
+					// When losing sync between UI and server
+					return true;
+				}
+
+				return false;
+			}
+
+			private function receivePatch(e:ReceivePatchEvent):void {
+//				LOGGER.debug("SharedNotesWindow: patch received");
+//				LOGGER.debug("=====\n" + e.patch + "\n=====");
+				if (e.noteId == noteId) {
+					if (_lastPatch == (e.patchId - 1)) {
+						if (e.patch != "") {
+							var result:String = DiffPatch.patch(e.patch, _document);
+//							LOGGER.debug("SharedNotesWindow: before the patch\n" + _document);
+//							LOGGER.debug("SharedNotesWindow: after the patch\n" + result);
+							_document = result;
+//							LOGGER.debug("SharedNotes: patching local with server modifications");
+							richTextEditor.patch(e.patch);
+							if (possiblePatchError()) {
+								syncNote();
+								return;
+							}
+						}
+						_lastPatch = e.patchId;
+						updateUndoRedoButtons(e.undo, e.redo);
+					} else {
+						LOGGER.error("Patch missmatch");
+						// Resync if we missed a patch
+						if (e.patchId > (_lastPatch + 1)) {
+							syncNote();
+							return;
+						}
+					}
+				}
+			}
+
+			private function syncNote():void {
+				richTextEditor.textArea.editable = false;
+				var sharedNotesSyncNoteRequestEvent:SharedNotesEvent = new SharedNotesEvent(SharedNotesEvent.SYNC_NOTE_REQUEST_EVENT);
+				sharedNotesSyncNoteRequestEvent.payload["noteId"] = noteId;
+				_dispatcher.dispatchEvent(sharedNotesSyncNoteRequestEvent);
+			}
+
+			private function handleSyncNote(e:SharedNotesEvent):void {
+				if (e.payload.noteId == noteId) {
+					LOGGER.debug("Syncing note: {0}", [noteId]);
+					_document = e.payload.note["document"];
+					_lastPatch = e.payload.note["patchCounter"];
+					richTextEditor.htmlText = _document;
+					if (!richTextEditor.textArea.editable) richTextEditor.textArea.editable = true;
+					updateUndoRedoButtons(e.payload.note["undo"], e.payload.note["redo"]);
+				}
+			}
+
+			private function updateUndoRedoButtons(undo:Boolean, redo:Boolean):void {
+				btnUndo.styleName = undo ? "sharedNotesEnabledUndoButtonStyle" : "sharedNotesDisabledUndoButtonStyle";
+				btnRedo.styleName = redo ? "sharedNotesEnabledRedoButtonStyle" : "sharedNotesDisabledRedoButtonStyle";
+				btnUndo.enabled = undo;
+				btnRedo.enabled = redo;
+			}
+
+			protected function saveNotes(title:String, text:String, extension:String):void {
+				var filename:String = title.replace(/\s+/g, '-').toLowerCase() + "." + extension;
+				var fileRef:FileReference = new FileReference();
+				fileRef.addEventListener(Event.COMPLETE, function(e:Event):void {
+					Alert.show(ResourceUtil.getInstance().getString('bbb.sharedNotes.save.complete'), "", Alert.OK);
+				});
+
+				var cr:String = String.fromCharCode(13);
+				var lf:String = String.fromCharCode(10);
+				var crlf:String = String.fromCharCode(13, 10);
+
+				text = text.replace(new RegExp(crlf, "g"), '\n');
+				text = text.replace(new RegExp(cr, "g"), '\n');
+				text = text.replace(new RegExp(lf, "g"), '\n');
+				text = text.replace(new RegExp('\n', "g"), crlf);
+
+				var b:ByteArray = new ByteArray();
+				// Include the byte order mark for UTF-8 (http://stackoverflow.com/a/16201680)
+				b.writeByte(0xEF);
+				b.writeByte(0xBB);
+				b.writeByte(0xBF);
+				b.writeUTFBytes(text);
+
+				fileRef.save(b, filename);
+			}
+
+			private function fixFormatTags(text:String):String {
+				const fontRegex:RegExp = /<font ([^>]*)>(.*?)<\/font>/gi;
+				const textFormatRegex:RegExp = /<textformat [^>]*>|<\/textformat>/gi;
+				const emptyParagraphRegex:RegExp = /<p [^>]*><\/p>/gi;
+				// transform font tags in span tags
+				text = text.replace(fontRegex, replaceFontTag);
+				// remove textformat tags
+				text = text.replace(textFormatRegex, "");
+				// transform empty paragraph tags in breakline tags
+				text = text.replace(emptyParagraphRegex, "<br/>");
+				text = "<HEAD><style>p { margin: 0px; }</style></HEAD>" + text;
+				return text;
+			}
+
+			private function translateFontFamily(font:String):String {
+				switch (font) {
+					case "_sans": return "sans-serif";
+					case "_serif": return "serif";
+					case "_typewriter": return "monospace";
+					default: return font;
+				}
+			}
+
+			private function removeHtmlTags(text:String):String {
+				const tagRegex:RegExp = /<[^>]*>/gi;
+				return text.replace(tagRegex, "");
+			}
+
+			private function replaceFontTag(matchedSubstring:String, fontAttributes:String, text:String, index:int, str:String):String {
+				// remove html tags and all white spaces to see if there's any visible character
+				if (removeHtmlTags(text).replace(/\s/g, "").length == 0) {
+					return "";
+				}
+
+				var regex:Object = {
+					"font-size": /SIZE="(\d+)"/gi,
+					"color": /COLOR="(\#\S{6})"/gi,
+					"font-family": /FACE="([^\"]*)"/gi,
+					"letter-spacing": /LETTERSPACING="(\d+)"/gi
+				}
+				var style:Object = {};
+				var i:String;
+				for (i in regex) {
+					var result:Array = regex[i].exec(fontAttributes);
+					if (result != null) {
+						switch (i) {
+							case "font-size":
+							case "letter-spacing":
+								style[i] = result[1] + "px";
+								break;
+							case "font-family":
+								style[i] = translateFontFamily(result[1]);
+								break;
+							default:
+								style[i] = result[1];
+								break;
+						}
+					}
+				}
+
+				var styleStr:String = "";
+				for (i in style) {
+					styleStr += i + ": " + style[i] + "; ";
+				}
+				return "<span style=\"" + styleStr + "\">" + text + "</span>";
+			}
+
+			protected function saveNotesWithFormat(title:String):void {
+				saveNotes(title, fixFormatTags(richTextEditor.htmlText), "html");
+			}
+
+			protected function saveNotesWithoutFormat(title:String):void {
+				saveNotes(title, richTextEditor.text, "txt");
+			}
+
+			protected function btnSave_clickHandler(event:MouseEvent):void {
+				var menuData:Array = [];
+				menuData.push( {label: ResourceUtil.getInstance().getString('bbb.sharedNotes.save.htmlLabel'), handler: function():void { saveNotesWithFormat(title); }} );
+				menuData.push( {label: ResourceUtil.getInstance().getString('bbb.sharedNotes.save.txtLabel'), handler: function():void { saveNotesWithoutFormat(title); }} );
+
+				var menu:Menu = WellPositionedMenu.createMenu(null, menuData, btnSave, true);
+
+				registerListenersOnSaveMenu(menu);
+				menu.show();
+			}
+
+			private function registerListenersOnSaveMenu(menu:Menu):void {
+				menu.addEventListener(MenuEvent.ITEM_CLICK, saveMenuClickHandler);
+				menu.addEventListener(MenuEvent.MENU_HIDE, saveMenuHideHandler);
+			}
+
+			private function unregisterListenersOnSaveMenu(menu:Menu):void {
+				menu.removeEventListener(MenuEvent.ITEM_CLICK, saveMenuClickHandler);
+				menu.removeEventListener(MenuEvent.MENU_HIDE, saveMenuHideHandler);
+			}
+
+			private function saveMenuClickHandler(e:MenuEvent):void {
+				e.item.handler();
+			}
+
+			private function saveMenuHideHandler(e:MenuEvent):void {
+				var menu:Menu = e.currentTarget as Menu;
+				unregisterListenersOnSaveMenu(menu);
+
+				btnSave.emphasized = false;
+			}
+
+			protected function btnNew_clickHandler(event:MouseEvent):void {
+				var noteNameWindow:IFlexDisplayObject = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as DisplayObject, SharedNotesNameWindow, true);
+				PopUpManager.centerPopUp(noteNameWindow);
+			}
+
+			protected function btnUndo_clickHandler(event:MouseEvent = null):void {
+				var sendPatchEvent:SendPatchEvent = new SendPatchEvent();
+				sendPatchEvent.noteId = noteId;
+				sendPatchEvent.operation = "UNDO";
+				_dispatcher.dispatchEvent(sendPatchEvent);
+			}
+
+			protected function btnRedo_clickHandler(event:MouseEvent = null):void {
+				var sendPatchEvent:SendPatchEvent = new SendPatchEvent();
+				sendPatchEvent.noteId = noteId;
+				sendPatchEvent.operation = "REDO";
+				_dispatcher.dispatchEvent(sendPatchEvent);
+			}
+
+			public function handleCtrlCmd(event:KeyboardEvent):void {
+				switch (event.keyCode) {
+					case Keyboard.Z:
+						if (btnUndo.enabled) btnUndo_clickHandler();
+						break;
+					case Keyboard.Y:
+						if (btnRedo.enabled) btnRedo_clickHandler();
+						break;
+					default:
+						break;
+				}
+			}
+
+			protected function btnToolbar_clickHandler(event:MouseEvent):void {
+				richTextEditor.showControlBar = !richTextEditor.showControlBar;
+			}
+
+			public function getPrefferedPosition():String {
+				return options.position;
+			}
+
+			override protected function resourcesChanged():void {
+				super.resourcesChanged();
+
+				updateTitle();
+			}
+
+			protected function updateTitle():void {
+				title = ResourceUtil.getInstance().getString('bbb.sharedNotes.title');
+			}
+
+			public function handleDraggableStatus(value:Boolean):void {
+				this.draggable = value;
+			}
+
+			public function handleResizableStatus(value:Boolean):void {
+				this.resizable = value;
+			}
+
+		]]>
+	</mx:Script>
+
+	<mx:VBox width="100%" height="100%">
+		<components:SharedNotesRichTextEditor id="richTextEditor"
+				width="100%"
+				height="100%"
+				showControlBar="{options.toolbarVisibleByDefault}"
+				dropShadowEnabled="false"
+				headerHeight="0"
+				borderThicknessLeft="0"
+				borderThicknessRight="0"
+				borderThicknessTop="0"
+				borderThicknessBottom="0"
+				minWidth="120"
+				minHeight="100"
+				initialize="initSharedNotesRichTextEditor()"/>
+
+		<mx:HBox width="100%" paddingTop="0">
+			<mx:HBox width="100%" horizontalAlign="left" paddingTop="0">
+				<mx:Button id="btnUndo"
+						styleName="sharedNotesDisabledUndoButtonStyle"
+						width="26"
+						height="26"
+						click="btnUndo_clickHandler(event)"
+						toolTip="{ResourceUtil.getInstance().getString('bbb.sharedNotes.undo.toolTip')}"
+						enabled="false"
+						visible="true"/>
+				<mx:Button id="btnRedo"
+						styleName="sharedNotesDisabledRedoButtonStyle"
+						width="26"
+						height="26"
+						click="btnRedo_clickHandler(event)"
+						toolTip="{ResourceUtil.getInstance().getString('bbb.sharedNotes.redo.toolTip')}"
+						enabled="false" visible="true"/>
+			</mx:HBox>
+			<mx:HBox width="100%" horizontalAlign="right" paddingTop="0">
+				<mx:Button id="btnNew"
+						styleName="sharedNotesNewButtonStyle"
+						width="26"
+						height="26"
+						click="btnNew_clickHandler(event)"
+						toolTip="{ResourceUtil.getInstance().getString('bbb.sharedNotes.new.toolTip')}"/>
+				<mx:Button id="btnFormat"
+						styleName="sharedNotesFormatButtonStyle"
+						width="26" height="26"
+						click="btnToolbar_clickHandler(event)"
+						toolTip="{ResourceUtil.getInstance().getString('bbb.sharedNotes.toolbar.toolTip')}"
+						visible="{options.showToolbarButton}"
+						includeInLayout="{options.showToolbarButton}"/>
+				<mx:Button id="btnSave"
+						styleName="sharedNotesSaveButtonStyle"
+						width="26"
+						height="26"
+						click="btnSave_clickHandler(event)"
+						toolTip="{ResourceUtil.getInstance().getString('bbb.sharedNotes.save.toolTip')}"/>
+			</mx:HBox>
+		</mx:HBox>
+	</mx:VBox>
+</CustomMdiWindow>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/SharedNotesRichTextEditor.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/SharedNotesRichTextEditor.mxml
new file mode 100644
index 0000000000000000000000000000000000000000..5c2190777bd19e279404730def86986815c1ae90
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/SharedNotesRichTextEditor.mxml
@@ -0,0 +1,1343 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<!---
+ The RichTextEditor control lets users enter and format text. The text characteristics that users can vary
+ include the font family, color, size, and style, and other properties such as  text alignment, bullets and
+ URL links. The control consists of a Panel control with two direct children:
+ <ul>
+  <li>A Text Area control where users can enter text.</li>
+  <li>A Container with format controls that let a
+ user specify the text characteristics. The format controls affect text being typed or selected text.</li>
+ </ul>
+ <p>The RichTextEditor has a default height and width of 300 by 325 pixels
+ and a default minimum height and width of 200 by 220 pixels.
+ If you put a RichTextEditor control in a DividedBox control, make sure that
+ the DividedBox control is large enough to contain the RichTextEditor control
+ at its minimum dimensions.
+ Also, you can explicitly set the RichTextEditor control's minHeight or
+ minWidth property to <code>NaN</code> to let the DividedBox container
+ reduce the control's dimensions to 0.</p>
+ <p>The following table describes the  subcontrols that you can access and modify:</p>
+ <table class="innertable" >
+  <tr>
+    <th>Control Type </th>
+    <th>ID</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><a href="../controls/TextArea.html">TextArea</a></td>
+    <td>textArea</td>
+    <td>Area where the user can enter text.</td>
+  </tr>
+  <tr>
+    <td><a href="../core/Container.html">Container</a></td>
+    <td>toolbar</td>
+    <td>The container for the formatting controls; puts the controls in a single
+        horizontal row, if they fit, or multiple rows, otherwise.</td>
+  </tr>
+  <tr>
+    <td><a href="../controls/ComboBox.html">ComboBox</a></td>
+    <td>fontFamilyCombo</td>
+    <td>Specifies the text font family. The ComboBox dataProvider is an Array of Strings with the following values:
+     <ul>
+         <li>_sans</li>
+         <li>_serif</li>
+         <li>_typewriter</li>
+         <li>Arial</li>
+         <li>Courier</li>
+         <li>Courier New</li>
+         <li>Geneva</li>
+         <li>Georgia</li>
+         <li>Helvetica</li>
+         <li>Times New Roman</li>
+         <li>Times</li>
+         <li>Verdana (default)</li>
+    </ul></td>
+  </tr>
+  <tr>
+    <td><a href="../controls/ComboBox.html">ComboBox</a></td>
+    <td>fontSizeCombo</td>
+    <td>Specifies the font size. The ComboBox dataProvider is an Array of Strings with the following values:
+        8, 9, 10 (default), 11, 12, 14, 16, 18, 20, 24, 26, 28, 36, 48, 72.
+    <p><strong>Note:</strong>This specification is the actual pixel value for the font size. These sizes are not equivalent to the
+        relative font sizes specified in HTML using the <code>size</code> attribute of the &lt;font&gt; tag.</p></td>
+  </tr>
+  <tr>
+    <td><a href="../containers/HBox.html">HBox</a></td>
+    <td>toolBar2</td>
+    <td>Contains the font characteristic buttons.</td>
+  </tr>
+  <tr>
+    <td><a href="../controls/Button.html">Button</a></td>
+    <td>boldButton</td>
+    <td>When toggled to selected=&quot;true&quot;, sets the font to bold. </td>
+  </tr>
+  <tr>
+    <td><a href="../controls/Button.html">Button</a></td>
+    <td>italicButton</td>
+    <td>When toggled to selected=&quot;true&quot;, sets the font to italic. </td>
+  </tr>
+  <tr>
+    <td><a href="../controls/Button.html">Button</a></td>
+    <td>underlineButton</td>
+    <td>When toggled to selected=&quot;true&quot;, sets the font to underlined.</td>
+  </tr>
+  <tr>
+    <td><a href="../controls/ColorPicker.html">ColorPicker</a></td>
+    <td>colorPicker</td>
+    <td>Specifies the color of the text. </td>
+  </tr>
+  <tr>
+    <td><a href="../controls/ToggleButtonBar.html">ToggleButtonBar</a></td>
+    <td>alignButtons</td>
+    <td>Specifies the text alignment. The control's data provider consists of an Array Of objects, with the object <code>action</code> field specifying the justification type. The available actions are as follows:
+      <ul>
+        <li>left (default) </li>
+    <li>center</li>
+    <li>right</li>
+    <li>justify</li>
+    </ul></td>
+  </tr>
+  <tr>
+    <td><a href="../controls/Button.html">Button</a></td>
+    <td>bulletButton</td>
+    <td>When toggled to selected=&quot;true&quot;, sets the current line, or the selected line, to a list item, preceded by a bullet.</td>
+  </tr>
+  <tr>
+    <td><a href="../controls/TextInput.html">TextInput</a></td>
+    <td>linkTextInput</td>
+    <td>This field is enabled only when text is selected.
+        When the user enters a URL in this field and presses the Enter key, Flex inserts
+        the equivalent of an HTML <code>&lt;a href=&quot;<em>user_text</em>&quot;
+        target=&quot;blank&quot;&gt;&lt;/a&gt;</code> tag in the TextArea subcontrol
+        at around the currently selected text.
+
+        <p>Flex initially fills this control with the text specified by the
+        <code>defaultLinkProtocol</code> property; users can append the rest of the link
+        to this text, or replace it.</p>
+ </td>
+  </tr>
+ </table>
+
+ <p>To access one of the subcontrols, you can use syntax similar to the following:
+ <pre>
+ myRTE.toolBar2.setStyle("backgroundColor", 0xCC6633);
+ </pre>
+ </p>
+
+ <p>The RichTextEditor control has the following default sizing
+    characteristics:</p>
+    <table class="innertable">
+       <tr>
+          <th>Characteristic</th>
+          <th>Description</th>
+       </tr>
+       <tr>
+          <td>Default size</td>
+          <td>325 pixels wide by 300 pixels high</td>
+       </tr>
+       <tr>
+          <td>Minimum size</td>
+          <td>220 pixels wide by 200 pixels high</td>
+       </tr>
+       <tr>
+          <td>Maximum size</td>
+          <td>10000 by 10000 pixels</td>
+       </tr>
+    </table>
+
+  @mxml
+
+  <p>The &lt;mx:RichTextEditor&gt; tag inherits all the members
+  of its parent and adds the following members:</p>
+ <pre>
+  &lt;RichTextEditor
+    <strong>Properties</strong>
+    defaultLinkProtocol="http://"
+    htmlText=""
+    showControlBar="true | false"
+    showToolTips="false | true"
+    text=""
+
+    <strong>Events</strong>
+    change
+  /&gt;
+
+ </pre>
+
+ @see mx.containers.ControlBar
+ @see mx.containers.Panel
+ @see mx.controls.ToggleButtonBar
+ @see mx.controls.Button
+ @see mx.controls.ColorPicker
+ @see mx.controls.ComboBox
+ @see mx.controls.TextArea
+ @see mx.controls.TextInput
+
+ @includeExample examples/RichTextEditorExample.mxml
+
+ @langversion 3.0
+ @playerversion Flash 9
+ @playerversion AIR 1.1
+ @productversion Flex 3
+ -->
+ <mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" minWidth="220" minHeight="200" width="325" height="300">
+    <mx:Metadata>
+        <![CDATA[
+        /**
+        * Dispatched when the user changes the contents or format of the text in the
+        * TextArea control.
+        * This event is not dispatched if you change the TextArea contents by
+        * resetting the <code>text</code> or <code>htmlText</code> property.
+        *
+        * @eventType flash.events.Event.CHANGE
+        *
+        *  @langversion 3.0
+        *  @playerversion Flash 9
+        *  @playerversion AIR 1.1
+        *  @productversion Flex 3
+        */
+        [Event(name="change", type="flash.events.Event")]
+
+        [DefaultTriggerEvent("change")]
+
+        /**
+         *  Name of the CSS Style declaration to use for the styles for the TextArea.
+         *  By default, the TextArea uses the the RichTextEditor's inheritable styles.
+         *
+         *  @langversion 3.0
+         *  @playerversion Flash 9
+         *  @playerversion AIR 1.1
+         *  @productversion Flex 3
+         */
+        [Style(name="textAreaStyleName", type="String", inherit="no")]
+
+        [IconFile("RichTextEditor.png")]
+
+        [Exclude(name="alignButtons", kind="property")]
+        [Exclude(name="boldButton", kind="property")]
+        [Exclude(name="bulletButton", kind="property")]
+        [Exclude(name="colorPicker", kind="property")]
+        [Exclude(name="defaultButton", kind="property")]
+        [Exclude(name="fontFamilyArray", kind="property")]
+        [Exclude(name="fontFamilyCombo", kind="property")]
+        [Exclude(name="fontSizeArray", kind="property")]
+        [Exclude(name="fontSizeCombo", kind="property")]
+        [Exclude(name="icon", kind="property")]
+        [Exclude(name="italicButton", kind="property")]
+        [Exclude(name="label", kind="property")]
+        [Exclude(name="layout", kind="property")]
+        [Exclude(name="linkTextInput", kind="property")]
+        [Exclude(name="toolBar", kind="property")]
+        [Exclude(name="toolBar2", kind="property")]
+        [Exclude(name="underlineButton", kind="property")]
+        ]]>
+    </mx:Metadata>
+    <mx:Array id="fontFamilyArray">
+        <mx:String>_sans</mx:String>
+        <mx:String>_serif</mx:String>
+        <mx:String>_typewriter</mx:String>
+        <mx:String>Arial</mx:String>
+        <mx:String>Courier</mx:String>
+        <mx:String>Courier New</mx:String>
+        <mx:String>Geneva</mx:String>
+        <mx:String>Georgia</mx:String>
+        <mx:String>Helvetica</mx:String>
+        <mx:String>Times New Roman</mx:String>
+        <mx:String>Times</mx:String>
+        <mx:String>Verdana</mx:String>
+    </mx:Array>
+    <mx:Array id="fontSizeArray">
+        <mx:String>8</mx:String>
+        <mx:String>9</mx:String>
+        <mx:String>10</mx:String>
+        <mx:String>11</mx:String>
+        <mx:String>12</mx:String>
+        <mx:String>14</mx:String>
+        <mx:String>16</mx:String>
+        <mx:String>18</mx:String>
+        <mx:String>20</mx:String>
+        <mx:String>22</mx:String>
+        <mx:String>24</mx:String>
+        <mx:String>26</mx:String>
+        <mx:String>28</mx:String>
+        <mx:String>36</mx:String>
+        <mx:String>48</mx:String>
+        <mx:String>72</mx:String>
+    </mx:Array>
+    <mx:Script>
+    <![CDATA[
+
+    import org.as3commons.logging.api.ILogger;
+    import org.as3commons.logging.api.getClassLogger;
+
+    import flash.events.Event;
+    import flash.events.TextEvent;
+    import flash.events.ContextMenuEvent;
+    import flash.ui.ContextMenuItem;
+    import flash.net.FileReference;
+    import flash.text.*;
+
+    import org.bigbluebutton.modules.sharednotes.util.DiffPatch;
+
+    import mx.collections.ArrayCollection;
+    import mx.controls.textClasses.TextRange;
+    import mx.core.mx_internal;
+    import mx.core.IUITextField;
+    import mx.core.UITextFormat;
+    use namespace mx_internal;
+
+    private static const LOGGER:ILogger = getClassLogger(SharedNotesRichTextEditor);
+
+    /**
+    * A carret position control to handle the Paste action from mouse ContextMenu to comply with the
+    * text formatting rules of the Shared Notes Rich Text Editor.
+    */
+    public var pasteCarIndex:int = -1;
+    public var retPasteCarIndex:int = -1;
+
+    /**
+     * The ToolTip that appears when the user hovers over the font drop-down list. To view ToolTips,
+     * you must also set the <code>showToolTips</code> property of the RichTextEditor control to <code>true</code>.
+     *
+     * @default "Font Family"
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var fontFamilyToolTip:String = "Font Family";
+    /**
+     * The ToolTip that appears when the user hovers over the font size drop-down list. To view ToolTips,
+     * you must also set the <code>showToolTips</code> property of the RichTextEditor control to <code>true</code>.
+     *
+     * @default "Font Size"
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var fontSizeToolTip:String = "Font Size";
+    /**
+     * The ToolTip that appears when the user hovers over the text bold button. To view ToolTips,
+     * you must also set the <code>showToolTips</code> property of the RichTextEditor control to <code>true</code>.
+     *
+     * @default "Bold"
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var boldToolTip:String = "Bold";
+    /**
+     * The ToolTip that appears when the user hovers over the text italic button. To view ToolTips,
+     * you must also set the <code>showToolTips</code> property of the RichTextEditor control to <code>true</code>.
+     *
+     * @default "Italic"
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var italicToolTip:String = "Italic";
+    /**
+     * The ToolTip that appears when the user hovers over the text underline button. To view ToolTips,
+     * you must also set the <code>showToolTips</code> property of the RichTextEditor control to <code>true</code>.
+     *
+     * @default "Underline"
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var underlineToolTip:String = "Underline";
+    /**
+     * The ToolTip that appears when the user hovers over the ColorPicker control. To view ToolTips,
+     * you must also set the <code>showToolTips</code> property of the RichTextEditor control to <code>true</code>.
+     *
+     * @default "Color"
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var colorPickerToolTip:String = "Color";
+    /**
+     * The ToolTip that appears when the user hovers over the text alignment buttons. All the buttons
+     * share the same ToolTip. To view ToolTips, you must also set the <code>showToolTips</code>
+     * property of the RichTextEditor control to <code>true</code>.
+     *
+     * @default "Align"
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var alignToolTip:String = "Align";
+    /**
+     * The ToolTip that appears when the user hovers over the bulleted list button. To view ToolTips,
+     * you must also set the <code>showToolTips</code> property of the RichTextEditor control to <code>true</code>.
+     *
+     * @default "Bullet"
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var bulletToolTip:String = "Bullet";
+    /**
+     * The ToolTip that appears when the user hovers over the link text input field. To view ToolTips,
+     * you must also set the <code>showToolTips</code> property of the RichTextEditor control to <code>true</code>.
+     * @default "Link"
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     *
+     */
+    public var linkToolTip:String = "Link";
+    private var linkTextCommitted:Boolean = false;
+    private var showControlBarChanged:Boolean = false;
+    private var showToolTipsChanged:Boolean = false;
+    private var textChanged:Boolean = false;
+    private var htmlTextChanged:Boolean = false;
+    private var previousTextFormat:TextFormat = null;
+    private var textFormatChanged:Boolean = false;
+    // -1 is used to force updation of the ToolBar styles
+    private var lastCaretIndex:int = -1;
+    private var invalidateToolBarFlag:Boolean = false;
+    private var firstTime:Boolean = true;
+
+    /*
+    public function RichTextEditor()
+    {
+        super();
+    }
+    */
+
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------
+    //----------------------------------
+    //  defaultLinkProtocol
+    //----------------------------------
+    private var _defaultLinkProtocol:String = "http://";
+    [Inspectable(defaultValue="http://")]
+
+    /**
+     * The default protocol string to use at the start of link text.
+     * This string appears in the LinkTextInput subcontrol, so users do
+     * not have to type the protocol identifier when entering link text.
+     *
+     * @default "http://"
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get defaultLinkProtocol():String
+    {
+        return _defaultLinkProtocol;
+    }
+    /**
+     * @private
+     */
+    public function set defaultLinkProtocol(value:String):void
+    {
+        _defaultLinkProtocol = value;
+
+        if (linkTextInput)
+            linkTextInput.text = _defaultLinkProtocol;
+    }
+    //----------------------------------
+    //  showControlBar
+    //----------------------------------
+    private var _showControlBar:Boolean = true;
+    [Inspectable(category="General", defaultValue="true")]
+
+    /**
+     * Specifies whether to display the control bar that contains the text
+     * formatting controls.
+     *
+     * @default true
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get showControlBar():Boolean
+    {
+        return _showControlBar;
+    }
+    /**
+     * @private
+     */
+    public function set showControlBar(value:Boolean):void
+    {
+        _showControlBar = value;
+        showControlBarChanged = true;
+        invalidateProperties();
+    }
+    //----------------------------------
+    //  showToolTips
+    //----------------------------------
+    private var _showToolTips:Boolean = false;
+    [Inspectable(defaultValue="false")]
+
+    /**
+     * Specifies whether to display tooltips for the text formatting controls.
+     *
+     * @default false
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get showToolTips():Boolean
+    {
+        return _showToolTips;
+    }
+    /**
+     * @private
+     */
+    public function set showToolTips(value:Boolean):void
+    {
+        _showToolTips = value;
+        showToolTipsChanged = true;
+        invalidateProperties();
+    }
+    //----------------------------------
+    //  selection
+    //----------------------------------
+    /**
+     *  A TextRange object containing the selected text in the TextArea subcontrol.
+     *
+     *  @see mx.controls.textClasses.TextRange
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get selection():TextRange
+    {
+        return new TextRange(this, true);
+    }
+    //----------------------------------
+    //  text
+    //----------------------------------
+    private var _text:String = "";
+    [Bindable("valueCommit")]
+    [CollapseWhiteSpace]
+    [NonCommittingChangeEvent("change")]
+    [Inspectable(category="General")]
+    /**
+     * Plain text without markup that displays in the RichTextEditor control's TextArea subcontrol.
+     * You cannot set this property and the <code>htmlText</code> property simultaneously.
+     * If you set one property, it replaces any value set using the other property.
+     * You can get both properties; the <code>text</code> property always returns a plain
+     * text String with no formatting information.
+     * For more information on using this property, see the TextArea documentation.
+     *
+     * @default ""
+     *
+     * @see mx.controls.TextArea
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get text():String
+    {
+        return textArea ? textArea.text : _text;
+    }
+    /**
+     * @private
+     */
+    public function set text(value:String):void
+    {
+        _text = value;
+        textChanged = true;
+        invalidateProperties();
+    }
+    //----------------------------------
+    //  htmlText
+    //----------------------------------
+    private var _htmlText:String = "";
+    [Bindable("valueCommit")]
+    [CollapseWhiteSpace]
+    [NonCommittingChangeEvent("change")]
+    [Inspectable(category="General")]
+    /**
+     * Text containing HTML markup that displays in the RichTextEditor
+     * control's TextArea subcontrol.
+     * You cannot set this property and the <code>text</code> property simultaneously.
+     * If you set one property, it replaces any value set using  the other property.
+     * You can get both properties; the <code>htmlText</code> property always returns
+     * a String containing HTML markup that represents the current text formatting.
+     * For more information on using this property, see the TextArea documentation.
+     *
+     * @default ""
+     *
+     * @see mx.controls.TextArea
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get htmlText():String
+    {
+        return textArea ? textArea.htmlText : _htmlText;
+    }
+    /**
+     * @private
+     */
+    public function set htmlText(value:String):void
+    {
+        _htmlText = value;
+        htmlTextChanged = true;
+        invalidateProperties();
+    }
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden methods
+    //
+    //--------------------------------------------------------------------------
+    /**
+     * @private
+     */
+    override protected function commitProperties():void
+    {
+        super.commitProperties();
+        if (firstTime)
+        {
+            firstTime = false;
+            var textAreaStyleName:String = getStyle(
+                                "textAreaStyleName");
+            if (textAreaStyleName)
+                textArea.styleName = textAreaStyleName;
+            textArea.getTextField().alwaysShowSelection = true;
+        }
+
+        if (showControlBarChanged)
+        {
+            if (_showControlBar)
+            {
+                controlBar.height = NaN;
+                controlBar.visible = true;
+            }
+            else
+            {
+                controlBar.height = 0;
+                controlBar.visible = false;
+            }
+            showControlBarChanged = false;
+        }
+
+        if (showToolTipsChanged)
+        {
+            if (_showToolTips)
+            {
+                fontFamilyCombo.toolTip = fontFamilyToolTip;
+                fontSizeCombo.toolTip = fontSizeToolTip;
+                boldButton.toolTip = boldToolTip;
+                italicButton.toolTip = italicToolTip;
+                underlineButton.toolTip = underlineToolTip;
+                colorPicker.toolTip = colorPickerToolTip;
+                alignButtons.toolTip = alignToolTip;
+                bulletButton.toolTip = bulletToolTip;
+                linkTextInput.toolTip = linkToolTip;
+            }
+            else
+            {
+                fontFamilyCombo.toolTip = "";
+                fontSizeCombo.toolTip = "";
+                boldButton.toolTip = "";
+                italicButton.toolTip = "";
+                underlineButton.toolTip = "";
+                colorPicker.toolTip = "";
+                alignButtons.toolTip = "";
+                bulletButton.toolTip = "";
+                linkTextInput.toolTip = "";
+            }
+            showToolTipsChanged = false;
+        }
+
+        if (textChanged || htmlTextChanged)
+        {
+            // Revert previously set TextFormat.
+            var tf:UITextFormat = IUITextField(textArea.getTextField()).getUITextFormat();
+            // bullet style is not exposed in flex
+            // hence has to be explicitly defaulted.
+            tf.bullet = false;
+            textArea.getTextField().defaultTextFormat = tf;
+            if (textChanged)
+            {
+                    textArea.text = _text;
+                textChanged = false;
+            }
+            else
+            {
+                    textArea.htmlText = _htmlText;
+                htmlTextChanged = false;
+            }
+        }
+    }
+
+    /**
+     * @private
+     */
+    override protected function measure():void
+    {
+        // Called only when explicitWidth and
+        // explicitHeight are set to NaN, since
+        // we have set width and height explicitly
+        // for RTE's panel.
+        super.measure();
+        measuredMinWidth = 220;
+        measuredWidth = 320;
+        measuredMinHeight = 200;
+        measuredHeight = 300;
+    }
+    /**
+     *  @private
+     */
+    override public function styleChanged(styleProp:String):void
+    {
+        super.styleChanged(styleProp);
+        if (styleProp == null || styleProp == "textAreaStyleName")
+        {
+            if (textArea)
+            {
+                var textAreaStyleName:String = getStyle("textAreaStyleName");
+                textArea.styleName = textAreaStyleName;
+            }
+        }
+
+        if (!invalidateToolBarFlag)
+        {
+            invalidateToolBarFlag = true;
+            callLater(getTextStyles);
+        }
+    }
+    //--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    //--------------------------------------------------------------------------
+    private function setTextStyles(type:String, value:Object = null):void
+    {
+        var tf:TextFormat;
+        var wholeParagraph:Boolean = false;
+        var beginIndex:int = textArea.getTextField().selectionBeginIndex;
+        var endIndex:int = textArea.getTextField().selectionEndIndex;
+        if (beginIndex == endIndex)
+        {
+            tf = previousTextFormat;
+        }
+        else {
+            tf = new TextFormat();
+            var lines:ArrayCollection = getLinesList(beginIndex, endIndex);
+        }
+
+        if (type == "bold" || type == "italic" || type == "underline")
+        {
+            tf[type] = value;
+        }
+        else if (type == "align" || type == "bullet" || type == "font" || type == "size" || type == "color" || type == 'kerning')
+        {
+            wholeParagraph = true;
+            // Apply the paragraph styles to the whole paragraph instead of just
+            // the selected text
+            if (beginIndex == endIndex)
+            {
+                tf = new TextFormat();
+                beginIndex = textArea.getTextField().getFirstCharInParagraph(beginIndex);
+                beginIndex = Math.max(0, beginIndex);
+                endIndex = textArea.getTextField().getFirstCharInParagraph(beginIndex) +
+                        textArea.getTextField().getParagraphLength(beginIndex);
+            }
+            else
+            {
+                beginIndex = textArea.getTextField().getFirstCharInParagraph(beginIndex);
+                beginIndex = Math.max(0, beginIndex);
+                endIndex = textArea.getTextField().getFirstCharInParagraph(endIndex);
+                endIndex = textArea.getTextField().getFirstCharInParagraph(endIndex) +
+                        textArea.getTextField().getParagraphLength(endIndex);
+            }
+            if (endIndex > textArea.text.length)
+            {
+                endIndex--;
+            }
+            if (type == "font")
+            {
+                tf[type] = fontFamilyCombo.text;
+                previousTextFormat[type] = fontFamilyCombo.text;
+            }
+            else if (type == "size")
+            {
+                var fontSize:uint = uint(fontSizeCombo.text);
+                if (fontSize > 0)
+                {
+                    tf[type] = fontSize;
+                    previousTextFormat[type] = fontSize;
+                }
+            }
+            else if (type == "color")
+            {
+                tf[type] = uint(colorPicker.selectedColor);
+                previousTextFormat[type] = uint(colorPicker.selectedColor);
+            }
+            else if(type == "kerning")
+            {
+                tf[type] = value;
+                previousTextFormat[type] = value;
+            }
+            else
+            {
+                tf[type] = value;
+                previousTextFormat[type] = value;
+            }
+            if (!endIndex)
+                textArea.getTextField().defaultTextFormat = tf;
+        }
+        else if (type == "url")
+        {
+            if (value != defaultLinkProtocol && value != "")
+            {
+                tf[type] = value;
+                tf["target"] = "_blank";
+            }
+            else if (tf[type] != "")
+            {
+                tf[type] = "";
+                tf["target"] = "";
+            }
+        }
+        textFormatChanged = true;
+
+        if (beginIndex == endIndex)
+        {
+            previousTextFormat = tf;
+        }
+        else
+        {
+            if (wholeParagraph)
+            {
+                textArea.getTextField().setTextFormat(tf,beginIndex,endIndex);
+            }
+            else
+            {
+                for each (var line:Array in lines)
+                {
+                    textArea.getTextField().setTextFormat(tf,line[0],line[1]);
+                }
+            }
+        }
+        dispatchEvent(new Event("change"));
+
+        var caretIndex:int = textArea.getTextField().caretIndex;
+        var lineIndex:int = textArea.getTextField().getLineIndexOfChar(caretIndex);
+        textArea.invalidateDisplayList();
+        textArea.validateDisplayList();
+        // Scroll to make the line containing the caret under viewable area
+        while (lineIndex >= textArea.getTextField().bottomScrollV)
+        {
+            textArea.verticalScrollPosition++;
+        }
+        callLater(textArea.setFocus);
+    }
+    private function getTextStyles():void
+    {
+        if (!textArea)
+            return;
+
+        var tf:TextFormat;
+        var beginIndex:int = textArea.getTextField().selectionBeginIndex;
+        var endIndex:int = textArea.getTextField().selectionEndIndex;
+        if (beginIndex == endIndex)
+            linkTextInput.enabled = false;
+        else
+            linkTextInput.enabled = true;
+
+        if (textFormatChanged)
+            previousTextFormat = null;
+        if (beginIndex == endIndex)
+        {
+            tf = textArea.getTextField().defaultTextFormat;
+            if (tf.url != "")
+            {
+                var carIndex:int = textArea.getTextField().caretIndex;
+                if (carIndex < textArea.getTextField().length)
+                {
+                    var tfNext:TextFormat=textArea.getTextField().getTextFormat(carIndex, carIndex + 1);
+                    if (!tfNext.url || tfNext.url == "")
+                        tf.url = tf.target = "";
+                }
+                else
+                    tf.url = tf.target = "";
+            }
+        }
+        else
+            tf = textArea.getTextField().getTextFormat(beginIndex,endIndex);
+        if (!previousTextFormat || previousTextFormat.font != tf.font)
+            setComboSelection(fontFamilyCombo, tf.font ? tf.font : "");
+        if (!previousTextFormat || previousTextFormat.size != tf.size)
+            setComboSelection(fontSizeCombo, tf.size ? String(tf.size) : "");
+        if (!previousTextFormat || previousTextFormat.color != tf.color)
+            colorPicker.selectedColor = Number(tf.color);
+
+        if (!previousTextFormat || previousTextFormat.bold != tf.bold)
+            boldButton.selected = tf.bold;
+        if (!previousTextFormat || previousTextFormat.italic != tf.italic)
+            italicButton.selected = tf.italic;
+        if (!previousTextFormat || previousTextFormat.underline != tf.underline)
+            underlineButton.selected = tf.underline;
+        if (!previousTextFormat || previousTextFormat.align != tf.align)
+        {
+            if (tf.align == "left")
+                alignButtons.selectedIndex = 0;
+            else if (tf.align == "center")
+                alignButtons.selectedIndex = 1;
+            else if (tf.align == "right")
+                alignButtons.selectedIndex = 2;
+            else if (tf.align == "justify")
+                alignButtons.selectedIndex = 3;
+        }
+        if (!previousTextFormat || previousTextFormat.bullet != tf.bullet)
+            bulletButton.selected = tf.bullet;
+        if (!previousTextFormat || previousTextFormat.url != tf.url)
+            linkTextInput.text = (tf.url == "" || tf.url == null) ? defaultLinkProtocol : tf.url;
+
+        if (textArea.getTextField().defaultTextFormat != tf)
+            textArea.getTextField().defaultTextFormat = tf;
+        previousTextFormat = tf;
+        textFormatChanged = false;
+
+        lastCaretIndex = textArea.getTextField().caretIndex;
+        invalidateToolBarFlag = false;
+    }
+    private function setComboSelection(combo:ComboBox,val:String):void
+    {
+        var length:uint = combo.dataProvider.length;
+
+        for (var i:uint = 0; i < length; i++)
+        {
+            if (combo.dataProvider.getItemAt(i).toLowerCase() == val.toLowerCase())
+            {
+                combo.selectedIndex = i;
+                return;
+            }
+        }
+        combo.selectedIndex = -1;
+        combo.validateNow();
+        combo.text = val;
+    }
+    /**
+     *  @private
+     *  This method is called when the user clicks on the textArea, drags
+     *  out of it and releases the mouse button outside the TextArea.
+     */
+    private function systemManager_mouseUpHandler(event:MouseEvent):void
+    {
+        if (lastCaretIndex != textArea.getTextField().caretIndex)
+            getTextStyles();
+        else
+        {
+            if (textArea.getTextField().selectionBeginIndex == textArea.getTextField().selectionEndIndex)
+                linkTextInput.enabled = false;
+            else
+                linkTextInput.enabled = true;
+        }
+        systemManager.removeEventListener(
+            MouseEvent.MOUSE_UP, systemManager_mouseUpHandler, true);
+    }
+
+    //----------------------------------
+    //  Shared Notes
+    //----------------------------------
+    private var refreshSelection:Boolean = false;
+    private var shiftPressed:Boolean = false;
+    private var ctrlPressed:Boolean = false;
+
+    public function restoreVerticalScroll(oldVerticalScroll:Number):void
+    {
+        textArea.getTextField().scrollV = oldVerticalScroll;
+    }
+
+    public function restoreCursor(endIndex:Number, oldPosition:Number):void
+    {
+        var cursorLine:Number = 0;
+
+        if (endIndex == 0 && text.length == 0)
+        {
+            cursorLine = 0;
+        }
+        else if (endIndex == text.length)
+        {
+            cursorLine = textArea.getTextField().getLineIndexOfChar(endIndex - 1);
+        }
+        else
+        {
+            cursorLine = textArea.getTextField().getLineIndexOfChar(endIndex);
+        }
+
+        var relativePositon:Number = cursorLine - textArea.verticalScrollPosition;
+
+        var desloc:Number = relativePositon - oldPosition;
+        textArea.verticalScrollPosition += desloc;
+    }
+
+    public function getOldVerticalScroll():Number
+    {
+
+        var oldVerticalScroll:Number = 0;
+
+        oldVerticalScroll = textArea.getTextField().scrollV;
+
+        return oldVerticalScroll;
+    }
+
+    public function getOldPosition():Number
+    {
+        var oldPosition:Number = 0;
+
+        if (textArea.selectionEndIndex == 0 && text.length == 0)
+        {
+            oldPosition = 0;
+        }
+        else if (textArea.selectionEndIndex == text.length)
+        {
+            oldPosition = textArea.getTextField().getLineIndexOfChar(textArea.selectionEndIndex - 1);
+        }
+        else
+        {
+            oldPosition = textArea.getTextField().getLineIndexOfChar(textArea.selectionEndIndex);
+        }
+
+        oldPosition -= textArea.verticalScrollPosition;
+        return oldPosition;
+    }
+
+    public function patch(patch:String):void
+    {
+        var results:Array;
+
+        var _lastBegin:int = textArea.selectionBeginIndex;
+        var _lastEnd:int = textArea.selectionEndIndex;
+        var oldPosition:Number = getOldPosition();
+        var oldVerticalScroll:Number = getOldVerticalScroll();
+
+        var oldText:String = text;
+        htmlText = DiffPatch.patch(patch, htmlText);
+        validateNow();
+
+        var plainPatch:String = DiffPatch.diff(oldText, text);
+        results = DiffPatch.patchClientText(plainPatch, oldText, _lastBegin, _lastEnd);
+
+        if (results[0][0] == _lastBegin && results[0][1] > _lastEnd)
+        {
+            var str1:String = oldText.substring(_lastBegin, _lastEnd);
+            var str2:String = results[1].substring(_lastBegin, _lastEnd);
+
+            if (str1 != str2)
+            {
+                _lastEnd = results[0][1];
+            }
+
+        }
+        else
+        {
+            _lastBegin = results[0][0];
+            _lastEnd = results[0][1];
+        }
+
+        restoreCursor(_lastEnd, oldPosition);
+        validateNow();
+
+        textArea.selectable = true;
+        textArea.setSelection(_lastBegin, _lastEnd);
+        validateNow();
+
+        //Will update the position of the window next time there is a validate, just before updating the client's view.
+        callLater(restoreVerticalScroll, [oldVerticalScroll]);
+    }
+
+    public function refresh():void
+    {
+//        LOGGER.debug("TextArea refresh")
+        textArea.htmlText = htmlText;
+    }
+
+    private function getLinesList(beginIndex:int, endIndex:int):ArrayCollection
+    {
+        var lines:ArrayCollection = new ArrayCollection();
+        var index:int = beginIndex;
+
+        while (index < endIndex)
+        {
+            var paragraphLength:int = textArea.getTextField().getParagraphLength(index) - 1;
+            var paragraphEndIndex:int = textArea.getTextField().getFirstCharInParagraph(index) +
+                    textArea.getTextField().getParagraphLength(index) - 1;
+            if (endIndex >= paragraphEndIndex + 1 && paragraphLength > 0 && textArea.text.charCodeAt(paragraphEndIndex) != 13)
+            {
+                paragraphEndIndex++;
+            }
+            if (paragraphLength > 0)
+            {
+                if (paragraphEndIndex < endIndex)
+                {
+                    lines.addItem([index, paragraphEndIndex]);
+                    index = paragraphEndIndex;
+                }
+                else
+                {
+                    lines.addItem([index, endIndex]);
+                    break;
+                }
+            }
+            else if (textArea.text.charCodeAt(paragraphEndIndex) != 13)
+            {
+                lines.addItem([index, endIndex]);
+                break;
+            }
+            index++;
+        }
+        return lines;
+    }
+
+    private function clearTextStyle():void
+    {
+        setTextStyles('bold', false);
+        boldButton.selected = false;
+        setTextStyles('italic', false);
+        italicButton.selected = false;
+        setTextStyles('underline', false);
+        underlineButton.selected = false;
+    }
+
+    private function refreshTextStyle():void
+    {
+        setTextStyles('font', previousTextFormat.font);
+        setTextStyles('size', previousTextFormat.size);
+        setTextStyles('color', previousTextFormat.color);
+        setTextStyles('kerning', true);
+    }
+
+    private function checkNavigableButtonDown(e:KeyboardEvent):void
+    {
+        if (e.shiftKey && !shiftPressed)
+        {
+            shiftPressed = true;
+            parentDocument.handleDraggableStatus(false);
+        }
+        if (e.ctrlKey)
+        {
+            parentDocument.handleCtrlCmd(e);
+            if (!ctrlPressed)
+            {
+                ctrlPressed = true;
+                parentDocument.handleResizableStatus(false);
+            }
+        }
+    }
+
+    private function checkNavigableButtonUp(e:KeyboardEvent):void
+    {
+        if (!e.shiftKey && shiftPressed)
+        {
+            shiftPressed = false;
+            parentDocument.handleDraggableStatus(true);
+        }
+        if (!e.ctrlKey && ctrlPressed)
+        {
+            ctrlPressed = false;
+            parentDocument.handleResizableStatus(true);
+        }
+    }
+
+    private function onKeyDown(event:KeyboardEvent):void
+    {
+        checkNavigableButtonDown(event);
+        if (textArea.selectionBeginIndex != textArea.selectionEndIndex)
+        {
+            var beginIndex:int = textArea.getTextField().getLineIndexOfChar(textArea.selectionBeginIndex);
+            var endIndex:int = textArea.getTextField().getLineIndexOfChar(textArea.selectionEndIndex);
+            if (beginIndex != endIndex && ((event.keyCode >= 65 && event.keyCode <= 111) || event.keyCode == 32))
+            {
+                refreshSelection = true;
+            }
+        }
+        if (event.keyCode == 13)
+        {
+            clearTextStyle();
+        }
+        if (textFormatChanged)
+        {
+            textArea.getTextField().defaultTextFormat=previousTextFormat;
+            textFormatChanged = false;
+        }
+    }
+
+    private function onTextInput(e:TextEvent):void
+    {
+        if (e.text.length > 0) refreshSelection = true;
+
+        if (ctrlPressed) e.preventDefault();
+    }
+
+    private function onKeyUp(event:KeyboardEvent):void
+    {
+        checkNavigableButtonUp(event);
+        getTextStyles();
+        if (event.keyCode == 8 || event.keyCode == 46 || refreshSelection) {
+            refreshTextStyle();
+            refreshSelection = false;
+        }
+    }
+
+    private function onChange ( e:Event ):void
+    {
+        if (pasteCarIndex != -1){
+          getTextStyles();
+          refreshTextStyle();
+          retPasteCarIndex = textArea.getTextField().caretIndex;
+          textArea.setSelection(pasteCarIndex,pasteCarIndex);
+          getTextStyles();
+          refreshTextStyle();
+          pasteCarIndex = -1;
+          textArea.setSelection(retPasteCarIndex,retPasteCarIndex);
+        }
+    }
+
+    //This will happen every time the user activate the ContextMenu and can be used to ensure that mouse Paste will comply to the text formatting rules.
+    private function onRightClick ( e:MouseEvent ):void
+    {
+        pasteCarIndex = textArea.getTextField().caretIndex;
+    }
+
+    private function releaseNavigableButton(focus:FocusEvent):void
+    {
+        if (shiftPressed)
+        {
+            shiftPressed = false;
+            parentDocument.handleDraggableStatus(true);
+        }
+        if (ctrlPressed)
+        {
+            ctrlPressed = false;
+            parentDocument.handleResizableStatus(true);
+        }
+    }
+    ]]>
+    </mx:Script>
+    <!--- @private -->
+    <!-- There is a restrict in this textArea to avoid a known issue where a \u007F, which is the delete character, would be seen written in some browsers as an invalid character -->
+    <mx:TextArea id="textArea"
+            restrict="^\u007F"
+            height="100%"
+            width="100%"
+            minHeight="0"
+            minWidth="0"
+            change="onChange(event); dispatchEvent(event);"
+            valueCommit="dispatchEvent(event);"
+            keyUp="onKeyUp(event);"
+            keyDown="onKeyDown(event);"
+            mouseDown="systemManager.addEventListener(MouseEvent.MOUSE_UP, systemManager_mouseUpHandler, true);"
+            textInput= "onTextInput(event);"
+            rollOut= "onRightClick(event);"
+            focusOut="releaseNavigableButton(event)"/>
+    <mx:ControlBar>
+        <!--- @private -->
+        <mx:ToolBar id="toolbar"
+                width="100%"
+                horizontalGap="7">
+            <mx:ComboBox id="fontFamilyCombo"
+                editable="true"
+                creationComplete="getTextStyles();lastCaretIndex = -1;"
+                dataProvider = "{fontFamilyArray}"
+                close="setTextStyles('font');"
+                enter="setTextStyles('font');"/>
+            <mx:ComboBox id="fontSizeCombo"
+                editable="true"
+                paddingLeft="2" paddingRight="2"
+                dataProvider = "{fontSizeArray}"
+                close="setTextStyles('size');"
+                enter="setTextStyles('size');"/>
+            <mx:HBox id="toolBar2"
+                    horizontalGap="0">
+                <mx:Button id="boldButton"
+                        width="20"
+                        toggle="true"
+                        icon="@Embed('assets/icon_style_bold.png')"
+                        click="setTextStyles('bold', event.currentTarget.selected);"/>
+                <mx:Button id="italicButton"
+                        width="20"
+                        toggle="true"
+                        icon="@Embed('assets/icon_style_italic.png')"
+                        click="setTextStyles('italic', event.currentTarget.selected);"/>
+                <mx:Button id="underlineButton"
+                        width="20"
+                        toggle="true"
+                        icon="@Embed('assets/icon_style_underline.png')"
+                        click="setTextStyles('underline', event.currentTarget.selected);"/>
+            </mx:HBox>
+            <mx:ColorPicker id="colorPicker"
+                    width="22"
+                    height="22"
+                    close="setTextStyles('color');"/>
+            <mx:VRule height="{alignButtons.height}"/>
+            <mx:ToggleButtonBar id="alignButtons"
+                    buttonWidth="20"
+                    itemClick="setTextStyles('align', ToggleButtonBar(event.currentTarget).dataProvider.getItemAt(ToggleButtonBar(event.currentTarget).selectedIndex).action);">
+                <mx:dataProvider>
+                    <mx:Array>
+                        <mx:Object icon="@Embed('assets/icon_align_left.png')" action="left"/>
+                        <mx:Object icon="@Embed('assets/icon_align_center.png')" action="center"/>
+                        <mx:Object icon="@Embed('assets/icon_align_right.png')" action="right"/>
+                        <mx:Object icon="@Embed('assets/icon_align_justify.png')" action="justify"/>
+                    </mx:Array>
+                </mx:dataProvider>
+            </mx:ToggleButtonBar>
+            <mx:Button id="bulletButton"
+                    width="20"
+                    toggle="true"
+                    icon="@Embed('assets/icon_bullet.png')"
+                    click="setTextStyles('bullet', event.currentTarget.selected);" />
+            <mx:VRule height="{linkTextInput.height}"/>
+            <mx:TextInput id="linkTextInput"
+                    width="140"
+                    focusOut="if (linkTextCommitted) { trace('already committed'); linkTextCommitted = false; } else { trace('not committed'); setTextStyles('url', linkTextInput.text); linkTextInput.text=defaultLinkProtocol;}"
+                    enter="setTextStyles('url', linkTextInput.text); linkTextInput.text = defaultLinkProtocol; linkTextCommitted = true;"/>
+        </mx:ToolBar>
+    </mx:ControlBar>
+</mx:Panel>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_center.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_center.png
new file mode 100644
index 0000000000000000000000000000000000000000..3fac48d0e751a944a2398b73e018e161bbb89e67
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_center.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_justify.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_justify.png
new file mode 100644
index 0000000000000000000000000000000000000000..bf4a6d6afa65c1effefe6270264c4189d40a806e
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_justify.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_left.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_left.png
new file mode 100644
index 0000000000000000000000000000000000000000..c9f45f6107b1b9b57e8b7ff88d6b0c1901b14bb6
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_left.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_right.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_right.png
new file mode 100644
index 0000000000000000000000000000000000000000..1bdcda3dce26b6ee9d144fc43e4327277d4f7062
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_align_right.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_bullet.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_bullet.png
new file mode 100644
index 0000000000000000000000000000000000000000..a99e9a2b2cd051632df9a2706d3d7dd72497d095
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_bullet.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_style_bold.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_style_bold.png
new file mode 100644
index 0000000000000000000000000000000000000000..a0a71d1dabb40ee47d394c3f3b8b322e14c637f2
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_style_bold.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_style_italic.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_style_italic.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d0221df7b26caeeca91234617c4f77bf8614df1
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_style_italic.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_style_underline.png b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_style_underline.png
new file mode 100644
index 0000000000000000000000000000000000000000..316b2f1d183be9093a49ab6410e7d5f5f9841af4
Binary files /dev/null and b/bigbluebutton-client/src/org/bigbluebutton/modules/sharednotes/views/components/assets/icon_style_underline.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml
index 9647fef19918c54f5acdc2f0504ccb1263bf09d8..9a864e3c9351ca5063737ef5fd8dd878e7fed426 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/maps/UsersMainEventMap.mxml
@@ -30,10 +30,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.main.events.BBBEvent;
 			import org.bigbluebutton.main.events.BreakoutRoomEvent;
 			import org.bigbluebutton.main.events.LogoutEvent;
+			<!--TODO: Move guest events to user events? -->
+			import org.bigbluebutton.main.events.ResponseModeratorEvent;
+			import org.bigbluebutton.main.events.SuccessfulLoginEvent;
 			import org.bigbluebutton.main.events.UserServicesEvent;
+			import org.bigbluebutton.main.model.GuestManager;
 			import org.bigbluebutton.main.model.users.UserService;
 			import org.bigbluebutton.main.model.users.events.BroadcastStartedEvent;
 			import org.bigbluebutton.main.model.users.events.BroadcastStoppedEvent;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
+			import org.bigbluebutton.main.model.users.events.ChangeRoleEvent;
 			import org.bigbluebutton.main.model.users.events.EmojiStatusEvent;
 			import org.bigbluebutton.main.model.users.events.KickUserEvent;
 			import org.bigbluebutton.main.model.users.events.RoleChangeEvent;
@@ -44,6 +50,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	
 	<EventHandlers type="{FlexEvent.APPLICATION_COMPLETE}" >
     <ObjectBuilder generator="{UserService}" cache="global" />
+    <ObjectBuilder generator="{GuestManager}" cache="global" />
 	</EventHandlers>
 	
   <EventHandlers type="{LogoutEvent.USER_LOGGED_OUT}" >
@@ -102,10 +109,17 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     <MethodInvoker generator="{UserService}" method="changeRecordingStatus" arguments="{event}" />
   </EventHandlers>
   
+  <EventHandlers type="{BBBEvent.ACTIVITY_RESPONSE_EVENT}">
+    <MethodInvoker generator="{UserService}" method="activityResponse" />
+  </EventHandlers>
+
   <EventHandlers type="{KickUserEvent.KICK_USER}" >
     <MethodInvoker generator="{UserService}" method="kickUser" arguments="{event}" />
   </EventHandlers>
   
+  <EventHandlers type="{ChangeRoleEvent.CHANGE_ROLE_EVENT}" >
+    <MethodInvoker generator="{UserService}" method="changeRole" arguments="{event}" />
+  </EventHandlers>
   
   <EventHandlers type="{VoiceConfEvent.EJECT_USER}" >
     <MethodInvoker generator="{UserService}" method="ejectUser" arguments="{event}" />
@@ -155,4 +169,45 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   <EventHandlers type="{RoleChangeEvent.ASSIGN_PRESENTER}">
     <MethodInvoker generator="{UserService}" method="assignPresenter" arguments="{event}" />
   </EventHandlers>
+
+  <EventHandlers type="{BBBEvent.RECONNECT_DISCONNECTED_EVENT}">
+    <MethodInvoker generator="{UserService}" method="onReconnecting"  arguments="{event}" />
+  </EventHandlers>
+  <!-- End Lock Events -->
+
+  <!-- Guest Events -->
+  <EventHandlers type="{BBBEvent.ADD_GUEST_TO_LIST}" >
+    <MethodInvoker generator="{GuestManager}" method="addGuest" arguments="{event}" />
+  </EventHandlers>
+
+  <EventHandlers type="{BBBEvent.REMOVE_GUEST_FROM_LIST}" >
+    <MethodInvoker generator="{GuestManager}" method="removeGuest" arguments="{event.payload.userId}" />
+  </EventHandlers>
+
+  <EventHandlers type="{LogoutEvent.MODERATOR_DENIED_ME}" >
+    <MethodInvoker generator="{UserService}" method="guestDisconnect" />
+    <MethodInvoker generator="{UserService}" method="logoutUser" />
+  </EventHandlers>
+
+  <EventHandlers type="{ResponseModeratorEvent.RESPONSE}" >
+    <MethodInvoker generator="{UserService}" method="responseToGuest" arguments="{event}" />
+    <!-- MethodInvoker generator="{GuestManager}" method="removeGuest" arguments="{event.userid}" /-->
+  </EventHandlers>
+
+  <EventHandlers type="{ResponseModeratorEvent.RESPONSE_ALL}" >
+    <MethodInvoker generator="{UserService}" method="responseToGuest" arguments="{event}" />
+  </EventHandlers>
+
+  <EventHandlers type="{BBBEvent.BROADCAST_GUEST_POLICY}" >
+    <MethodInvoker generator="{UserService}" method="setGuestPolicy" arguments="{event}" />
+  </EventHandlers>
+
+  <EventHandlers type="{BBBEvent.LOGOUT_END_MEETING_EVENT}" >
+    <MethodInvoker generator="{UserService}" method="logoutEndMeeting" />
+  </EventHandlers>
+
+  <EventHandlers type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" >
+    <MethodInvoker generator="{GuestManager}" method="refreshGuestView" />
+  </EventHandlers>
+  <!-- End Guest Events -->
 </EventMap>
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as
index cc55686dc9fec847d40e12b183b2be979ef1ad3a..e98037e04e127893000e30cda5810f35bbde87d3 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageReceiver.as
@@ -35,6 +35,7 @@ package org.bigbluebutton.modules.users.services
   import org.bigbluebutton.main.api.JSLog;
   import org.bigbluebutton.main.events.BBBEvent;
   import org.bigbluebutton.main.events.BreakoutRoomEvent;
+  import org.bigbluebutton.main.events.LogoutEvent;
   import org.bigbluebutton.main.events.MadePresenterEvent;
   import org.bigbluebutton.main.events.PresenterStatusEvent;
   import org.bigbluebutton.main.events.SwitchedPresenterEvent;
@@ -44,6 +45,7 @@ package org.bigbluebutton.modules.users.services
   import org.bigbluebutton.main.model.users.BreakoutRoom;
   import org.bigbluebutton.main.model.users.Conference;
   import org.bigbluebutton.main.model.users.IMessageListener;
+  import org.bigbluebutton.main.model.users.events.ChangeMyRole;
   import org.bigbluebutton.main.model.users.events.StreamStoppedEvent;
   import org.bigbluebutton.main.model.users.events.UsersConnectionEvent;
   import org.bigbluebutton.modules.screenshare.events.WebRTCViewStreamEvent;
@@ -55,6 +57,7 @@ package org.bigbluebutton.modules.users.services
 
     private var dispatcher:Dispatcher;
     private var _conference:Conference;
+    public var onAllowedToJoin:Function = null;
     private static var globalDispatcher:Dispatcher = new Dispatcher();
 
     public function MessageReceiver() {
@@ -88,6 +91,12 @@ package org.bigbluebutton.modules.users.services
         case "meetingState":
           handleMeetingState(message);
           break;  
+        case "inactivityWarning":
+          handleInactivityWarning(message);
+          break;
+        case "meetingIsActive":
+          handleMeetingIsActive(message);
+          break;
         case "participantJoined":
           handleParticipantJoined(message);
           break;
@@ -97,6 +106,9 @@ package org.bigbluebutton.modules.users.services
         case "participantStatusChange":
           handleParticipantStatusChange(message);
           break;
+        case "participantRoleChange":
+          handleParticipantRoleChange(message);
+          break;
         case "userJoinedVoice":
           handleUserJoinedVoice(message);
           break;
@@ -164,6 +176,15 @@ package org.bigbluebutton.modules.users.services
         case "DeskShareRTMPBroadcastNotification":
           handleDeskShareRTMPBroadcastNotification(message);
           break;
+        case "get_guest_policy_reply":
+          handleGetGuestPolicyReply(message);
+          break;
+        case "guest_policy_changed":
+          handleGuestPolicyChanged(message);
+          break;
+        case "guest_access_denied":
+          handleGuestAccessDenied(message);
+          break;
       }
     }
 
@@ -244,6 +265,16 @@ package org.bigbluebutton.modules.users.services
         var viewerEvent:MadePresenterEvent = new MadePresenterEvent(MadePresenterEvent.SWITCH_TO_VIEWER_MODE);
         dispatcher.dispatchEvent(viewerEvent);
       }
+
+      var myRole:String = UserManager.getInstance().getConference().whatsMyRole();
+      var role:String = map.user.role;
+      // If a (pro/de)moted user refresh his browser he must reassing his role for permissions
+      if (role != myRole) {
+        UserManager.getInstance().getConference().newUserRole(userid, role);
+        UserManager.getInstance().getConference().setMyRole(role);
+        var changeMyRole:ChangeMyRole = new ChangeMyRole(role);
+        dispatcher.dispatchEvent(changeMyRole);
+      }
     }
     
     private function handleMeetingMuted(msg:Object):void {
@@ -266,6 +297,19 @@ package org.bigbluebutton.modules.users.services
       UserManager.getInstance().getConference().applyLockSettings();
     }
     
+    private function handleInactivityWarning(msg:Object):void {
+      var map:Object = JSON.parse(msg.msg);
+
+      var bbbEvent:BBBEvent = new BBBEvent(BBBEvent.INACTIVITY_WARNING_EVENT);
+      bbbEvent.payload.duration = map.duration;
+      globalDispatcher.dispatchEvent(bbbEvent);
+    }
+
+    private function handleMeetingIsActive(msg:Object):void {
+      var bbbEvent:BBBEvent = new BBBEvent(BBBEvent.MEETING_IS_ACTIVE_EVENT);
+      globalDispatcher.dispatchEvent(bbbEvent);
+    }
+
     private function handleGetRecordingStatusReply(msg: Object):void {     
       var map:Object = JSON.parse(msg.msg);
       sendRecordingStatusUpdate(map.recording);      
@@ -423,6 +467,12 @@ package org.bigbluebutton.modules.users.services
       
       UsersService.getInstance().userLeft(webUser);
       
+      if(webUser.waitingForAcceptance) {
+        var removeGuest:BBBEvent = new BBBEvent(BBBEvent.REMOVE_GUEST_FROM_LIST);
+        removeGuest.payload.userId = webUser.userId;
+        dispatcher.dispatchEvent(removeGuest);
+      }
+
       var user:BBBUser = UserManager.getInstance().getConference().getUser(webUserId);
       
 	  if (user != null) {
@@ -491,7 +541,7 @@ package org.bigbluebutton.modules.users.services
       var externUserID:String = webUser.externUserID;
       var internUserID:String = webUser.userId;
       
-      if (UsersUtil.getMyExternalUserID() == externUserID) {
+      if (UsersUtil.getMyUserID() == internUserID) {
         _conference.muteMyVoice(voiceUser.muted);
         _conference.setMyVoiceJoined(voiceUser.joined);
       }
@@ -592,12 +642,15 @@ package org.bigbluebutton.modules.users.services
       user.userID = joinedUser.userId;
       user.name = joinedUser.name;
       user.role = joinedUser.role;
+      user.guest = joinedUser.guest;
+      user.waitingForAcceptance = joinedUser.waitingForAcceptance;
       user.externUserID = joinedUser.externUserID;
       user.isLeavingFlag = false;
       user.listenOnly = joinedUser.listenOnly;
       user.userLocked = joinedUser.locked;
       user.avatarURL = joinedUser.avatarURL;
-	   
+      user.me = (user.userID == UserManager.getInstance().getConference().getMyUserId());
+
       UserManager.getInstance().getConference().addUser(user);
       
       if (joinedUser.hasStream) {
@@ -617,6 +670,36 @@ package org.bigbluebutton.modules.users.services
       var joinEvent:UserJoinedEvent = new UserJoinedEvent(UserJoinedEvent.JOINED);
       joinEvent.userID = user.userID;
       dispatcher.dispatchEvent(joinEvent);	
+
+      if (user.guest) {
+        if (user.waitingForAcceptance) {
+          if (user.me) {
+            var waitCommand:BBBEvent = new BBBEvent(BBBEvent.WAITING_FOR_MODERATOR_ACCEPTANCE);
+            dispatcher.dispatchEvent(waitCommand);
+          } else {
+            var e:BBBEvent = new BBBEvent(BBBEvent.ADD_GUEST_TO_LIST);
+            e.payload.userId = user.userID;
+            e.payload.name = user.name;
+            dispatcher.dispatchEvent(e);
+          }
+        } else {
+          if (user.me) {
+            var allowedCommand:BBBEvent = new BBBEvent(BBBEvent.MODERATOR_ALLOWED_ME_TO_JOIN);
+            dispatcher.dispatchEvent(allowedCommand);
+          } else {
+            var removeGuest:BBBEvent = new BBBEvent(BBBEvent.REMOVE_GUEST_FROM_LIST);
+            removeGuest.payload.userId = user.userID;
+            dispatcher.dispatchEvent(removeGuest);
+          }
+        }
+      }
+
+      if (user.me && (!user.guest || !user.waitingForAcceptance)) {
+        if (onAllowedToJoin != null) {
+          onAllowedToJoin();
+          onAllowedToJoin = null;
+        }
+      }
     }
     
     /**
@@ -691,5 +774,42 @@ package org.bigbluebutton.modules.users.services
 		UserManager.getInstance().getConference().removeBreakoutRoom(map.breakoutMeetingId);
 	}
 
+    public function handleParticipantRoleChange(msg:Object):void {
+      var map:Object = JSON.parse(msg.msg);
+      LOGGER.debug("*** received participant role change [" + map.userID + "," + map.role + "]");
+      UserManager.getInstance().getConference().newUserRole(map.userID, map.role);
+      if(UserManager.getInstance().getConference().amIThisUser(map.userID)) {
+        UserManager.getInstance().getConference().setMyRole(map.role);
+        var e:ChangeMyRole = new ChangeMyRole(map.role);
+        dispatcher.dispatchEvent(e);
+      }
+    }
+
+    public function handleGuestPolicyChanged(msg:Object):void {
+      LOGGER.debug("*** handleGuestPolicyChanged " + msg.msg + " **** \n");
+      var map:Object = JSON.parse(msg.msg);
+
+      var policy:BBBEvent = new BBBEvent(BBBEvent.RETRIEVE_GUEST_POLICY);
+      policy.payload['guestPolicy'] = map.guestPolicy;
+      dispatcher.dispatchEvent(policy);
+    }
+
+    public function handleGetGuestPolicyReply(msg:Object):void {
+      LOGGER.debug("*** handleGetGuestPolicyReply " + msg.msg + " **** \n");
+      var map:Object = JSON.parse(msg.msg);
+
+      var policy:BBBEvent = new BBBEvent(BBBEvent.RETRIEVE_GUEST_POLICY);
+      policy.payload['guestPolicy'] = map.guestPolicy;
+      dispatcher.dispatchEvent(policy);
+    }
+
+    public function handleGuestAccessDenied(msg:Object):void {
+      LOGGER.debug("*** handleGuestAccessDenied " + msg.msg + " ****");
+      var map:Object = JSON.parse(msg.msg);
+
+      if (UsersUtil.getMyUserID() == map.userId) {
+        dispatcher.dispatchEvent(new LogoutEvent(LogoutEvent.MODERATOR_DENIED_ME));
+      }
+    }
   }
 }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as
index 2f38c5f280e3730f3dc75532524b456f521a786c..0fbcc5c7d2dfbb8ed6bbcf9a44aeb2942e5413b5 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/services/MessageSender.as
@@ -213,6 +213,25 @@ package org.bigbluebutton.modules.users.services
       );
     }
     
+    public function logoutEndMeeting(userID:String):void {
+      var message:Object = new Object();
+      message["userId"] = userID;
+
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "participants.logoutEndMeeting",
+        function(result:String):void { // On successful result
+        },
+        function(status:String):void { // status - On error occurred
+                var logData:Object = UsersUtil.initLogData();
+                logData.tags = ["apps"];
+                logData.message = "Error occured logout and end meeting.";
+                LOGGER.info(JSON.stringify(logData));
+        },
+        message
+      );
+    }
+
     public function queryForRecordingStatus():void {
       var _nc:ConnectionManager = BBB.initConnectionManager();
       _nc.sendMessage(
@@ -248,6 +267,22 @@ package org.bigbluebutton.modules.users.services
 		);
 	}
     
+
+    public function activityResponse():void {
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "participants.activityResponse", // Remote function name
+        function(result:String):void { // On successful result
+        },
+        function(status:String):void { // status - On error occurred
+                var logData:Object = UsersUtil.initLogData();
+                logData.tags = ["apps"];
+                logData.message = "Error occured activity response.";
+                LOGGER.info(JSON.stringify(logData));
+        }
+      ); //_netConnection.call
+    }
+
     public function changeRecordingStatus(userID:String, recording:Boolean):void {
       var message:Object = new Object();
       message["userId"] = userID;
@@ -487,5 +522,88 @@ package org.bigbluebutton.modules.users.services
         newLockSettings
       );      
     }
+
+    public function changeRole(userID:String, role:String):void {
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      var message:Object = new Object();
+      message["userId"] = userID;
+      message["role"] = role;
+
+      _nc.sendMessage(
+        "participants.setParticipantRole",// Remote function name
+        function(result:String):void { // On successful result
+          LOGGER.debug(result);
+        },
+        function(status:String):void { // status - On error occurred
+                var logData:Object = UsersUtil.initLogData();
+                logData.tags = ["apps"];
+                logData.message = "Error occured change role.";
+                LOGGER.info(JSON.stringify(logData));
+        },
+        message
+      );
+    }
+
+    public function queryForGuestPolicy():void {
+      LOGGER.debug("queryForGuestPolicy");
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "participants.getGuestPolicy",
+         function(result:String):void { // On successful result
+           LOGGER.debug(result);
+         },
+         function(status:String):void { // status - On error occurred
+                var logData:Object = UsersUtil.initLogData();
+                logData.tags = ["apps"];
+                logData.message = "Error occured query guest policy.";
+                LOGGER.info(JSON.stringify(logData));
+         }
+       );
+    }
+
+    public function setGuestPolicy(policy:String):void {
+      LOGGER.debug("setGuestPolicy - new policy:[" + policy + "]");
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "participants.setGuestPolicy",
+         function(result:String):void { // On successful result
+           LOGGER.debug(result);
+         },
+         function(status:String):void { // status - On error occurred
+                var logData:Object = UsersUtil.initLogData();
+                logData.tags = ["apps"];
+                logData.message = "Error occured set guest policy.";
+                LOGGER.info(JSON.stringify(logData));
+         },
+         policy
+       );
+    }
+
+    public function responseToGuest(userId:String, response:Boolean):void {
+      LOGGER.debug("responseToGuest - userId:[" + userId + "] response:[" + response + "]");
+
+      var message:Object = new Object();
+      message["userId"] = userId;
+      message["response"] = response;
+
+      var _nc:ConnectionManager = BBB.initConnectionManager();
+      _nc.sendMessage(
+        "participants.responseToGuest",
+         function(result:String):void { // On successful result
+           LOGGER.debug(result);
+         },
+         function(status:String):void { // status - On error occurred
+                var logData:Object = UsersUtil.initLogData();
+                logData.tags = ["apps"];
+                logData.message = "Error occured response guest.";
+                LOGGER.info(JSON.stringify(logData));
+         },
+         message
+       );
+    }
+
+    public function responseToAllGuests(response:Boolean):void {
+      responseToGuest(null, response);
+    }
   }
 }
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/MediaItemRenderer.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/MediaItemRenderer.mxml
index c76b914f42c0deb108683963059e335becc56da4..803d4895469b070c42ea329333161e998c6a8189 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/MediaItemRenderer.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/MediaItemRenderer.mxml
@@ -24,10 +24,13 @@
 	xmlns:mate="http://mate.asfusion.com/"
 	verticalScrollPolicy="off" horizontalScrollPolicy="off"
 	verticalAlign="middle"
+	horizontalGap="8"
+	horizontalAlign="center"
 	creationComplete="onCreationComplete()" > 
 	
 	<mate:Listener type="{UsersRollEvent.USER_ROLL_OVER}" method="onRollOver" />
 	<mate:Listener type="{UsersRollEvent.USER_ROLL_OUT}" method="onRollOut" />
+	<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="onChangeMyRole"/>
 	
 	<mx:Script>
 		<![CDATA[
@@ -35,14 +38,20 @@
 			import flash.filters.GlowFilter;
 			
 			import mx.binding.utils.BindingUtils;
+			import mx.controls.Menu;
 			import mx.events.FlexEvent;
+			import mx.events.MenuEvent;
 			
 			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.common.Role;
 			import org.bigbluebutton.core.events.LockControlEvent;
 			import org.bigbluebutton.core.events.VoiceConfEvent;
 			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.core.UsersUtil;
 			import org.bigbluebutton.core.vo.LockSettingsVO;
 			import org.bigbluebutton.main.model.users.BBBUser;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
+			import org.bigbluebutton.main.model.users.events.ChangeRoleEvent;
 			import org.bigbluebutton.main.model.users.events.KickUserEvent;
 			import org.bigbluebutton.modules.users.events.UsersRollEvent;
 			import org.bigbluebutton.modules.users.events.ViewCameraEvent;
@@ -63,9 +72,10 @@
 			private var lockRolled:Boolean = false;
 			
 			private var options:UsersOptions;
+			private var myMenu:Menu = null;
 			
 			private function onCreationComplete():void{
-				lockBtn.enabled = muteBtn.enabled = kickUserBtn.enabled = moderator = UserManager.getInstance().getConference().amIModerator();
+				refreshRole(UserManager.getInstance().getConference().amIModerator());
 				
 				this.addEventListener(FlexEvent.DATA_CHANGE, dataChangeHandler);
 				
@@ -87,18 +97,31 @@
 			}
 			
 			private function onRollOver(e:UsersRollEvent):void{
-				if (moderator && (e.userID == data.userID)) {
+				if ((moderator || UsersUtil.isMe(e.userID)) && (e.userID == data.userID)) {
 					rolledOver = true;
 					updateButtons();
 				}
 			}
 			
 			private function onRollOut(e:UsersRollEvent):void{
-				if (moderator && rolledOver) {
+				if ((moderator || UsersUtil.isMe(e.userID)) && rolledOver) {
 					rolledOver = false;
 					updateButtons();
 				}
 			}
+
+			private function onChangeMyRole(e:ChangeMyRole):void {
+				rolledOver = false;
+				updateButtons();
+				// close the menu if it was opened
+				if (myMenu) myMenu.hide();
+
+				refreshRole(e.role == Role.MODERATOR);
+			}
+
+			private function refreshRole(amIModerator:Boolean):void {
+				lockBtn.enabled = settingsBtn.enabled = moderator = amIModerator;
+			}
 			
 			private function muteMouseOverHandler():void {
 				rolledOverMute = true;
@@ -155,7 +178,7 @@
 				var ls:LockSettingsVO = UserManager.getInstance().getConference().getLockSettings();
 				
 				if (data != null) {
-					kickUserBtn.visible = !data.me && rolledOver && options.allowKickUser;
+					settingsBtn.visible = rolledOver && !data.me;
 					
 					if (!data.voiceJoined) {
 						if (data.listenOnly) {
@@ -181,7 +204,8 @@
 							muteImg.includeInLayout = !rolledOver;
 							muteBtn.visible = rolledOver;
 							muteBtn.includeInLayout = rolledOver;
-							
+							muteBtn.enabled = true;
+
 							if(data.talking && !rolledOver){
 								muteImg.filters = [new GlowFilter(0x000000, 1, 6, 6, 2, BitmapFilterQuality.HIGH, false, false)];
 							}else{
@@ -190,8 +214,12 @@
 						}
 					}
 					
-					//If it's not a moderator, it always can be locked.
-					if(	data.role != BBBUser.MODERATOR && ls.isAnythingLocked() ){
+					if (data.role == BBBUser.MODERATOR){
+						lockImg.visible = false;
+						lockImg.includeInLayout = true;
+						lockBtn.visible = false;
+						lockBtn.includeInLayout = false;
+					} else if(moderator && ls.isAnythingLocked()) {
 						lockImg.visible = !rolledOver;
 						lockImg.includeInLayout = !rolledOver;
 						lockBtn.visible = rolledOver;
@@ -248,13 +276,75 @@
 							muteBtn.setStyle("icon", images.audio_muted);
 						
 						if (data.userLocked == rolledOverLock)
-							lockBtn.setStyle("icon", images.unlocked);
+							lockBtn.setStyle("icon", images.unlocked_20);
 						else
-							lockBtn.setStyle("icon", images.locked);
+							lockBtn.setStyle("icon", images.locked_20);
 					}
 				}
 			}
-			
+
+			private function promoteUser():void {
+				changeUserRole(Role.MODERATOR);
+			}
+
+			private function demoteUser():void {
+				changeUserRole(Role.VIEWER);
+			}
+
+			private function changeUserRole(role:String):void {
+				var changeRoleEvent:ChangeRoleEvent = new ChangeRoleEvent(data.userID, role);
+				dispatchEvent(changeRoleEvent);
+			}
+
+			private function openSettings():void {
+				if (data != null) {
+					var myMenuData:Array = [];
+
+					if (data.role == Role.MODERATOR) {
+						myMenuData.push({
+							label: ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer.demoteUser',[data.name]),
+							icon: images.user_delete,
+							callback: demoteUser
+						});
+					} else {
+						myMenuData.push({
+							label: ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer.promoteUser',[data.name]),
+							icon: images.user_add,
+							callback: promoteUser
+						});
+					}
+
+					if (options.allowKickUser) {
+						myMenuData.push({
+							label: ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer.kickUser',[data.name]),
+							icon: images.eject_user_new,
+							callback: kickUser
+						});
+					}
+
+					// make sure the previous menu is closed before opening a new one
+					// This could be improved to include a flag that tells if the menu is open,
+					// but it would require an extra listener for the MenuCloseEvent.
+					if (myMenu) myMenu.hide();
+
+					myMenu = Menu.createMenu(null, myMenuData, true);
+					myMenu.variableRowHeight = true;
+
+					var settingsBtnPos:Point = settingsBtn.localToGlobal(new Point(0,0));
+
+					var myMenuPos:Point = new Point();
+					myMenuPos.x = settingsBtnPos.x + settingsBtn.width;
+					myMenuPos.y = settingsBtnPos.y;
+
+					myMenu.addEventListener(MenuEvent.ITEM_CLICK, menuClickHandler);
+					myMenu.show(myMenuPos.x, myMenuPos.y);
+					myMenu.setFocus();
+				}
+			}
+
+			private function menuClickHandler(e:MenuEvent):void {
+				e.item.callback();
+			}
 		]]>
 	</mx:Script>
 	
@@ -272,16 +362,19 @@
 				mouseOver="muteMouseOverHandler()"
 				mouseOut="muteMouseOutHandler()"
 				toolTip="{data.voiceMuted ? ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer.pushToTalk',[data.name]) : ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer.pushToMute',[data.name])}" />
-	<mx:Button id="kickUserBtn" icon="{images.eject_user_new}" 
-				width="20" height="20" visible="false"
-				toolTip="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer.kickUser',[data.name])}"
-				click="kickUser()"/>
 	<mx:Image id="lockImg" visible="false" includeInLayout="false" width="20" height="20" />
 	<mx:Button id="lockBtn" visible="false" includeInLayout="false" enabled="false"
 				width="20" height="20" click="toggleLockState()"
 				mouseOver="lockMouseOverHandler()"
 				mouseOut="lockMouseOutHandler()"
 				toolTip="{data.userLocked ? ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer.pushToUnlock',[data.name]) : ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer.pushToLock',[data.name])}" />		
+	<mx:Button id="settingsBtn"
+			visible="false"
+			width="20"
+			height="20"
+			click="openSettings()"
+			icon="{images.users_settings}"
+			toolTip="{ResourceUtil.getInstance().getString('bbb.users.settings.buttonTooltip')}"/>
 	<!-- Helper objects because using BindingUtil with data break when the itemRenderer is recycled -->
 	<mx:Image id="muteInd" includeInLayout="false" visible="{data.voiceMuted}" />
 	<mx:Image id="voiceJoinedInd" includeInLayout="false" visible="{data.voiceJoined}" />
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/MoodMenu.as b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/MoodMenu.as
new file mode 100644
index 0000000000000000000000000000000000000000..6306fa0b82445e80b6d274af9d0d7a36905c03e4
--- /dev/null
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/MoodMenu.as
@@ -0,0 +1,115 @@
+/**
+ * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+ *
+ * Copyright (c) 2015 BigBlueButton Inc. and by respective authors (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation; either version 3.0 of the License, or (at your option) any later
+ * version.
+ *
+ * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package org.bigbluebutton.modules.users.views {
+
+	import com.asfusion.mate.events.Dispatcher;
+	import mx.collections.ArrayCollection;
+	import mx.containers.VBox;
+	import mx.controls.Button;
+	import mx.controls.Menu;
+	import mx.core.ScrollPolicy;
+	import mx.events.FlexMouseEvent;
+	import mx.events.MenuEvent;
+	import mx.managers.PopUpManager;
+	import org.bigbluebutton.common.Images;
+	import org.bigbluebutton.core.managers.UserManager;
+	import org.bigbluebutton.main.model.users.events.EmojiStatusEvent;
+	import org.bigbluebutton.main.views.WellPositionedMenu;
+	import org.bigbluebutton.util.i18n.ResourceUtil;
+
+	public class MoodMenu extends VBox {
+		private const MOODS:Array = [
+				"raiseHand",
+				"applause",
+				"agree",
+				"disagree",
+				"speakFaster",
+				"speakSlower",
+				"speakLouder",
+				"speakSofter",
+				"beRightBack",
+				"happy",
+				"sad",
+				"clear"];
+
+		private var dispatcher:Dispatcher;
+
+		private var images:Images;
+
+		private var menu:Menu;
+
+		private var _btn:Button;
+
+		public function set btn(btn:Button):void {
+			_btn = btn;
+			drawMoodMenu();
+		}
+
+		public function MoodMenu() {
+			dispatcher = new Dispatcher();
+			images = new Images();
+			addEventListener(FlexMouseEvent.MOUSE_DOWN_OUTSIDE, mouseDownOutsideHandler, false, 0, true);
+			this.horizontalScrollPolicy = ScrollPolicy.OFF;
+			this.verticalScrollPolicy = ScrollPolicy.OFF;
+		}
+
+		public function show():void {
+			if (menu != null) {
+				menu.show();
+			}
+		}
+
+		private function drawMoodMenu():void {
+			var moods:ArrayCollection = new ArrayCollection();
+			for each (var mood:String in MOODS) {
+				if (mood == "clear" && UserManager.getInstance().getConference().myEmojiStatus == "none") {
+					continue;
+				}
+
+				var item:Object = {
+					label: ResourceUtil.getInstance().getString('bbb.users.emojiStatus.' + mood),
+					icon: images["mood_" + mood]
+				};
+
+				moods.addItem(item);
+			}
+			menu = WellPositionedMenu.createMenu(null, moods.toArray(), _btn, true);
+			menu.addEventListener(MenuEvent.ITEM_CLICK, buttonMouseEventHandler, false, 0, true);
+		}
+
+		protected function buttonMouseEventHandler(event:MenuEvent):void {
+			var mood:String = MOODS[event.index];
+			if (mood == "clear") {
+				dispatcher.dispatchEvent(new EmojiStatusEvent(EmojiStatusEvent.EMOJI_STATUS, "none"));
+			} else {
+				var e:EmojiStatusEvent = new EmojiStatusEvent(EmojiStatusEvent.EMOJI_STATUS, mood);
+				dispatcher.dispatchEvent(e);
+			}
+			hide();
+		}
+
+		protected function mouseDownOutsideHandler(event:FlexMouseEvent):void {
+			hide();
+		}
+
+		public function hide():void {
+			PopUpManager.removePopUp(this);
+		}
+	}
+}
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/StatusItemRenderer.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/StatusItemRenderer.mxml
index 1ecff5ba30de625a5499f67b99960d490915dc4c..98d33c7160301ff3e093534913354646b7668774 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/StatusItemRenderer.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/StatusItemRenderer.mxml
@@ -25,11 +25,13 @@
 	creationComplete="onCreationComplete()"
 	verticalScrollPolicy="off" horizontalScrollPolicy="off"
 	verticalAlign="middle"
+	horizontalGap="8"
 	horizontalAlign="center">
 	
 	<mate:Listener type="{UsersRollEvent.USER_ROLL_OVER}" method="onRollOver" />
 	<mate:Listener type="{UsersRollEvent.USER_ROLL_OUT}" method="onRollOut" />
 	<mate:Listener type="{LocaleChangeEvent.LOCALE_CHANGED}" method="localeChanged" />
+	<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="onChangeMyRole" />
 	
 	<mx:Script>
 		<![CDATA[
@@ -41,6 +43,7 @@
 			import org.bigbluebutton.common.Role;
 			import org.bigbluebutton.common.events.LocaleChangeEvent;
 			import org.bigbluebutton.core.managers.UserManager;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
 			import org.bigbluebutton.main.model.users.events.EmojiStatusEvent;
 			import org.bigbluebutton.main.model.users.events.RoleChangeEvent;
 			import org.bigbluebutton.modules.users.events.UsersRollEvent;
@@ -51,7 +54,7 @@
   			private var moderator:Boolean = false;
   			
   			private function onCreationComplete():void {
-  				moderator = UserManager.getInstance().getConference().amIModerator();
+  				refreshRole(UserManager.getInstance().getConference().amIModerator());
   				
   				/* I was trying to the binds through actionscript, but every time the itemrenderer was recycled 
   				 * the binds would stop functioning. I think it might have been because I was using strong 
@@ -125,14 +128,14 @@
 			
 			private function updateEmojiComponents() : void {
 				if (rolledOver && data.hasEmojiStatus) {
-					emojiBtn.setStyle("icon", images["emoji_" + data.emojiStatus]);
+					emojiBtn.setStyle("icon", images["mood_" + data.emojiStatus]);
 					emojiBtn.toolTip = ResourceUtil.getInstance().getString('bbb.users.usersGrid.statusItemRenderer.clearStatus') + " - " + data.emojiStatusTime.hours + ":" + data.emojiStatusTime.minutes + ":" + data.emojiStatusTime.seconds;
 					emojiImg.visible = false;
 					emojiBtn.visible = true;
 					emojiBtn.enabled = true;
 				} else if (data.hasEmojiStatus) {
-					emojiImg.source = images["emoji_" + data.emojiStatus];
-					emojiImg.toolTip = ResourceUtil.getInstance().getString('bbb.users.emojiStatus.' + data.emojiStatus) + " - " + data.emojiStatusTime.hours + ":" + data.emojiStatusTime.minutes + ":" + data.emojiStatusTime.seconds;
+					emojiImg.source = images["mood_" + data.emojiStatus];
+					emojiImg.toolTip = ResourceUtil.getInstance().getString('bbb.users.usersGrid.statusItemRenderer.' + data.emojiStatus) + " - " + data.emojiStatusTime.hours + ":" + data.emojiStatusTime.minutes + ":" + data.emojiStatusTime.seconds;
 					emojiImg.visible = true;
 					emojiBtn.visible = false;
 					emojiBtn.enabled = false;
@@ -160,6 +163,17 @@
 				}
 			}
   			
+			private function onChangeMyRole(e:ChangeMyRole):void {
+				rolledOver = false;
+				updateButtons();
+
+				refreshRole(e.role == Role.MODERATOR);
+			}
+
+			private function refreshRole(amIModerator:Boolean):void {
+				moderator = amIModerator;
+			}
+
   			private function roleBtnClicked():void {
                 if (!data.presenter) {
     				var e:RoleChangeEvent = new RoleChangeEvent(RoleChangeEvent.ASSIGN_PRESENTER);
@@ -181,10 +195,10 @@
 			}
 		]]>
 	</mx:Script>
-	<mx:Image id="emojiImg" visible="true" width="16" height="16" includeInLayout="{emojiImg.visible}" />
+	<mx:Image id="emojiImg" visible="true" width="20" height="20" includeInLayout="{emojiImg.visible}" />
 	<mx:Button id="emojiBtn" visible="false" enabled="false" width="20" height="20" click="emojiBtnClicked()" includeInLayout="{emojiBtn.visible}" />
 	
-	<mx:Image id="roleImg" visible="true" width="16" height="16" includeInLayout="{roleImg.visible}" />
+	<mx:Image id="roleImg" visible="true" width="20" height="20" includeInLayout="{roleImg.visible}" />
 	<mx:Button id="roleBtn" visible="false" enabled="false" width="20" height="20" click="roleBtnClicked()" includeInLayout="{roleBtn.visible}" />
 	
 	<!-- Helper objects because direct bindings to data break when the itemRenderer is recycled -->
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml
index ad652990da7f395add122120aba899e054af4f06..001cf36e3f6cc842e419cbb5ed8d1b4e4798bb88 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/users/views/UsersWindow.mxml
@@ -37,6 +37,7 @@
 	<mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="handleChangedLockSettingsEvent" />
 	<mate:Listener type="{BreakoutRoomEvent.UPDATE_REMAINING_TIME_PARENT}" method="handleRemainingTimeUpdate" />
 	<mate:Listener type="{BreakoutRoomEvent.BREAKOUT_JOIN_URL}" method="handleBreakoutJoinUrl" />
+	<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="onChangeMyRole" />
 	<mx:Script>
 		<![CDATA[
 			import com.asfusion.mate.events.Dispatcher;
@@ -59,6 +60,7 @@
 			import org.as3commons.logging.api.getClassLogger;
 			import org.bigbluebutton.common.IBbbModuleWindow;
 			import org.bigbluebutton.common.Images;
+			import org.bigbluebutton.common.Role;
 			import org.bigbluebutton.common.events.LocaleChangeEvent;
 			import org.bigbluebutton.core.TimerUtil;
 			import org.bigbluebutton.core.UsersUtil;
@@ -71,11 +73,14 @@
 			import org.bigbluebutton.main.events.ShortcutEvent;
 			import org.bigbluebutton.main.model.users.BBBUser;
 			import org.bigbluebutton.main.model.users.BreakoutRoom;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
+			import org.bigbluebutton.main.model.users.events.ChangeRoleEvent;
 			import org.bigbluebutton.main.model.users.events.EmojiStatusEvent;
 			import org.bigbluebutton.main.model.users.events.KickUserEvent;
 			import org.bigbluebutton.main.model.users.events.RoleChangeEvent;
 			import org.bigbluebutton.main.views.MainCanvas;
 			import org.bigbluebutton.modules.phone.events.LeaveVoiceConferenceCommand;
+			import org.bigbluebutton.main.views.WellPositionedMenu;
 			import org.bigbluebutton.modules.users.events.MeetingMutedEvent;
 			import org.bigbluebutton.modules.users.events.UsersRollEvent;
 			import org.bigbluebutton.modules.users.model.BreakoutRoomsOptions;
@@ -130,6 +135,10 @@
 			
 			private var muteMeRolled:Boolean = false;
 			
+			private function onChangeMyRole(e:ChangeMyRole):void {
+				refreshRole(e.role == Role.MODERATOR);
+			}
+
 			private function onCreationComplete():void {
 				dispatcher = new Dispatcher();
 			
@@ -143,6 +152,7 @@
 				
 				settingsBtn.visible = settingsBtn.includeInLayout = partOptions.enableSettingsButton && amIModerator;
 				closeRoomsBtn.visible = closeRoomsBtn.includeInLayout = amIModerator;
+				refreshRole(UserManager.getInstance().getConference().amIModerator());
 				
 				BindingUtils.bindSetter(updateNumberofUsers, users, "length");
 				
@@ -169,6 +179,16 @@
 				addContextMenuItems();
 			}
 			
+			private function refreshRole(moderator:Boolean = true):void {
+				amIModerator = moderator;
+
+				settingsBtn.visible = settingsBtn.includeInLayout = partOptions.enableSettingsButton && amIModerator;
+
+				changeButtons(UserManager.getInstance().getConference().amIPresenter);
+
+				if (paramsMenu) paramsMenu.hide();
+			}
+
 			public function getPrefferedPosition():String {
 				return MainCanvas.TOP_LEFT;
 			}
@@ -254,10 +274,9 @@
 			}
 
 			private function openEmojiStatusMenu():void {
-				var grid:EmojiGrid = PopUpManager.createPopUp(DisplayObject(FlexGlobals.topLevelApplication), EmojiGrid, false) as EmojiGrid;
-				var menuXY:Point = emojiStatusBtn.localToGlobal(new Point(emojiStatusBtn.width + 2, emojiStatusBtn.height - grid.height));
-				grid.x = menuXY.x;
-				grid.y = menuXY.y;
+				var moodMenu:MoodMenu = PopUpManager.createPopUp(DisplayObject(FlexGlobals.topLevelApplication), MoodMenu, false) as MoodMenu;
+				moodMenu.btn = emojiStatusBtn;
+				moodMenu.show();
 			}
 
 			private function openSettings():void {
@@ -285,13 +304,10 @@
 				// but it would require an extra listener for the MenuCloseEvent.
 				if (paramsMenu) {
 					paramsMenu.removeEventListener(MenuEvent.ITEM_CLICK, menuClickHandler);
-					paramsMenu.removeEventListener(MenuEvent.MENU_SHOW, menuShowHandler);
 					paramsMenu.hide();
 				}
-				paramsMenu = Menu.createMenu(null, paramsMenuData, true);
-				paramsMenu.variableRowHeight = false;
+				paramsMenu = WellPositionedMenu.createMenu(null, paramsMenuData, settingsBtn, true);
 				paramsMenu.addEventListener(MenuEvent.ITEM_CLICK, menuClickHandler);
-				paramsMenu.addEventListener(MenuEvent.MENU_SHOW, menuShowHandler);
 				paramsMenu.show();
 			}
 			
@@ -301,13 +317,6 @@
 				}
 			}
 			
-			private function menuShowHandler(e:MenuEvent):void {
-				paramsMenu.setFocus();
-				var menuXY:Point = settingsBtn.localToGlobal(new Point(settingsBtn.width + 2, settingsBtn.height - paramsMenu.height));
-				paramsMenu.x = menuXY.x;
-				paramsMenu.y = menuXY.y;
-			}
-			
 			private function handleChangedLockSettingsEvent(e:LockControlEvent):void {
 				var lockSettings:LockSettingsVO = UserManager.getInstance().getConference().getLockSettings();
 				roomLocked = lockSettings.isAnythingLocked() && (lockSettings.getLockOnJoin() || UsersUtil.isAnyoneLocked());
@@ -613,11 +622,11 @@
 		itemRollOut="onItemRollOut(event)" 
 		accessibilityName="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.accessibilityName')}" >
     	<mx:columns>
-    		<mx:DataGridColumn dataField="userStatus" headerText="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.statusItemRenderer')}" editable="false" width="45" minWidth="45"
+    		<mx:DataGridColumn dataField="userStatus" headerText="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.statusItemRenderer')}" editable="false" width="56" resizable="false"
     			itemRenderer="org.bigbluebutton.modules.users.views.StatusItemRenderer" sortable="false" />
-    		<mx:DataGridColumn dataField="displayName" headerText="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.nameItemRenderer')}" editable="false" sortable="false" minWidth="60"
+    		<mx:DataGridColumn dataField="name" headerText="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.nameItemRenderer')}" editable="false" sortable="false"
     			itemRenderer="org.bigbluebutton.modules.users.views.NameItemRenderer"/>
-    		<mx:DataGridColumn dataField="media" headerText="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer')}" sortable="false" width="110" minWidth="110"
+    		<mx:DataGridColumn dataField="media" headerText="{ResourceUtil.getInstance().getString('bbb.users.usersGrid.mediaItemRenderer')}" sortable="false" width="112" resizable="false"
     			itemRenderer="org.bigbluebutton.modules.users.views.MediaItemRenderer"/>
     	</mx:columns>
     </mx:DataGrid>
@@ -649,7 +658,7 @@
 	</mx:VBox>
 
 	<mx:ControlBar width="100%">
-		<mx:Button id="emojiStatusBtn" icon="{images.emoji_raiseHand}" width="30" height="30"
+		<mx:Button id="emojiStatusBtn" icon="{images.mood}" width="30" height="30"
 				   accessibilityName="{ResourceUtil.getInstance().getString('bbb.users.emojiStatusBtn.toolTip')}"
 				   toolTip="{ResourceUtil.getInstance().getString('bbb.users.emojiStatusBtn.toolTip')}" click="openEmojiStatusMenu()"
 				   visible="true" />
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/ToolbarPopupButton.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/ToolbarPopupButton.mxml
index 00fb0c3e2f3e9643da218c01bcb1d491d09ee20f..8368f3d4807bd218c3acc097a82f32f0a4583c4e 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/ToolbarPopupButton.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/ToolbarPopupButton.mxml
@@ -24,18 +24,18 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		   xmlns:mate="http://mate.asfusion.com/"
 		   click="openPublishWindow()"
 		   initialize="init()"
-		   mouseOver = "mouseOverHandler(event)"
-		   mouseOut = "mouseOutHandler(event)"
            height="24"
 		   toolTip="{_currentState == ON_STATE ? ResourceUtil.getInstance().getString('bbb.toolbar.video.toolTip.stop') : ResourceUtil.getInstance().getString('bbb.toolbar.video.toolTip.start')}"
 		   visible="false"
 		   enabled="true"
+		   selected="false"
 		   implements="org.bigbluebutton.common.IBbbToolbarComponent">
 
 	<mate:Listener type="{ShortcutEvent.SHARE_WEBCAM}" method="remoteClick" />
 	<mate:Listener type="{BBBEvent.CAM_SETTINGS_CLOSED}" method="handleCamSettingsClosedEvent"/>
 	<mate:Listener type="{ShareCameraRequestEvent.SHARE_CAMERA_REQUEST}" receive="enabled=false" />
 	<mate:Listener type="{LockControlEvent.CHANGED_LOCK_SETTINGS}" method="lockSettingsChanged" />
+	<mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
 	
 	<mx:Script>
 		<![CDATA[
@@ -55,6 +55,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			import org.bigbluebutton.main.events.ShortcutEvent;
 			import org.bigbluebutton.main.model.users.BBBUser;
 			import org.bigbluebutton.main.model.users.Conference;
+			import org.bigbluebutton.main.model.users.events.ChangeMyRole;
 			import org.bigbluebutton.main.views.MainToolbar;
 			import org.bigbluebutton.modules.videoconf.events.ShareCameraRequestEvent;
 			import org.bigbluebutton.modules.videoconf.events.StopShareCameraRequestEvent;
@@ -74,25 +75,33 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			private var dp:Object = [];
 			private var dataMenu:Menu;
 			public var numberOfCamerasOff:int = 0;
-
+
 			private var dispatcher:Dispatcher;
-
+
 			public function lockSettingsChanged(e:*):void{
+				updateButton();
+			}
+
+			private function refreshRole(e:ChangeMyRole):void {
+				updateButton();
+			}
+
+			private function updateButton():void {
 				var userManager:UserManager = UserManager.getInstance();
 				var conference:Conference = userManager.getConference();
 				var me:BBBUser = conference.getMyUser();
-
+
 				this.visible = !me.disableMyCam;
 				this.includeInLayout = !me.disableMyCam;
 			}
-
+
 			private function init():void{
 				dispatcher = new Dispatcher();
 				numberOfCamerasOff = Media.availableCameras;
 				for(var i:int = 0; i < Media.availableCameras; i++) {
 					dp.push({label: Media.getCameraName(i), status: OFF_STATE});
 				}
-
+
 				dataMenu = Menu.createMenu(this, dp, false);
 				dataMenu.addEventListener("itemClick", changeHandler);
 				dataMenu.addEventListener("mouseOver", mouseOverHandler);
@@ -100,7 +109,20 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				dataMenu.iconFunction = webcamMenuIcon;
 
 				this.popUp = dataMenu;
-				switchStateToNormal();
+
+				if (Media.availableCameras == 0) {
+					setAsNoMedia();
+				} else {
+					this.addEventListener("mouseOver", mouseOverHandler);
+					this.addEventListener("mouseOut", mouseOutHandler);
+					switchStateToNormal();
+				}
+			}
+
+			private function setAsNoMedia():void {
+				this.enabled = false;
+				this.styleName = "webcamOffButtonStyle";
+				this.toolTip = ResourceUtil.getInstance().getString('bbb.video.publish.hint.noCamera');
 			}
 
 			private function webcamMenuIcon(item:Object):Class {
@@ -117,6 +139,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 				this.toolTip = ResourceUtil.getInstance().getString('bbb.toolbar.video.toolTip.start');
 				this.styleName = "webcamDefaultButtonStyle";
 				this.enabled = true;
+				this.selected = false;
 				_currentState = OFF_STATE;
 				lockSettingsChanged(null);
 			}
@@ -136,6 +159,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					//this.toolTip = ResourceUtil.getInstance().getString('bbb.toolbar.video.toolTip.stop');
 					this.styleName = "webcamOnButtonStyle";
 					this.enabled = true;
+					this.selected = true;
 				}
 				else {
 					if(camID != -1) {
@@ -174,12 +198,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 						numberOfCamerasOff--;
 					_currentState = ON_STATE;
 					this.styleName = "webcamOnButtonStyle";
+					this.selected = true;
 					var shareCameraRequestEvent:ShareCameraRequestEvent = new ShareCameraRequestEvent();
 					shareCameraRequestEvent.camerasArray = dp;
 					dispatchEvent(shareCameraRequestEvent);
 				}
 			}
-
+
 			private function handleCamSettingsClosedEvent(e:BBBEvent):void {
 				this.setFocus();
 				this.enabled = true;
@@ -197,6 +222,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					this.styleName = "webcamOffButtonStyle";
 				else
 					this.styleName = "webcamOnButtonStyle";
+				this.selected = false;
 			}
 
 			private function mouseOutHandler(event:MouseEvent):void {
@@ -204,6 +230,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 					this.styleName = "webcamOnButtonStyle";
 				else
 					this.styleName = "webcamDefaultButtonStyle";
+				this.selected = false;
 			}
 
 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserGraphicHolder.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserGraphicHolder.mxml
index 7c89cf12c30471e3a698cc1f15bc16a2f2163391..919435729001eb20cc204f75edc4ef0e8c273d0b 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserGraphicHolder.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/videoconf/views/UserGraphicHolder.mxml
@@ -263,6 +263,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
             private function handleUserVoiceChangedEvent(event:BBBEvent):void {
                 if (user && event.payload.userID == user.userID) {
                     updateButtons();
+                    updateTalkingStatus();
                 }
             }
 
diff --git a/bigbluebutton-client/src/org/bigbluebutton/modules/whiteboard/views/WhiteboardToolbar.mxml b/bigbluebutton-client/src/org/bigbluebutton/modules/whiteboard/views/WhiteboardToolbar.mxml
index 4e4c75aed67d5952f1d289c9bb715fa3326b0110..117b029bf5d065adccc31758d3fda9c6a43e3e0c 100644
--- a/bigbluebutton-client/src/org/bigbluebutton/modules/whiteboard/views/WhiteboardToolbar.mxml
+++ b/bigbluebutton-client/src/org/bigbluebutton/modules/whiteboard/views/WhiteboardToolbar.mxml
@@ -29,7 +29,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     xmlns:mate="http://mate.asfusion.com/" 
     creationComplete="onCreationComplete()"
     visible="{showWhiteboardToolbar}" 
-    styleName="whiteboardToolbarStyle">
+    includeInLayout="{showWhiteboardToolbar}"
+    styleName="whiteboardToolbarStyle"
+    hideEffect="{fadeOut}" showEffect="{fadeIn}">
 
   <mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="presenterMode" />
   <mate:Listener type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}" method="viewerMode" />
@@ -38,9 +40,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   <mate:Listener type="{GraphicObjectFocusEvent.OBJECT_SELECTED}" method="graphicObjSelected" />
   <mate:Listener type="{GraphicObjectFocusEvent.OBJECT_DESELECTED}" method="graphicObjDeselected" />
   <mate:Listener type="{WhiteboardButtonEvent.WHITEBOARD_BUTTON_PRESSED}" method="handleWhiteboardButtonPressed"/>
+  <mate:Listener type="{ChangeMyRole.CHANGE_MY_ROLE_EVENT}" method="refreshRole" />
   <mate:Listener type="{NavigationEvent.GOTO_PAGE}" method="handleSlideChange" />
   <mate:Listener type="{DisplaySlideEvent.DISPLAY_SLIDE_EVENT}" method="handleSlideLoaded" />
   <mate:Listener type="{UploadEvent.PRESENTATION_READY}" method="handlePresentationSwitch" />
+  <mate:Listener type="{PresenterStatusEvent.ANNOTATIONS_PERMISSION_CHANGE}" method="handleEnableAnnotations" />
     
   <mx:Style>
     .colorPickerStyle {
@@ -73,7 +77,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 		import org.bigbluebutton.common.Images;
 		import org.bigbluebutton.core.UsersUtil;
 		import org.bigbluebutton.main.events.MadePresenterEvent;
+		import org.bigbluebutton.main.events.PresenterStatusEvent;
 		import org.bigbluebutton.main.events.ShortcutEvent;
+		import org.bigbluebutton.main.model.users.events.ChangeMyRole;
 		import org.bigbluebutton.modules.present.events.DisplaySlideEvent;
 		import org.bigbluebutton.modules.present.events.NavigationEvent;
 		import org.bigbluebutton.modules.present.events.UploadEvent;
@@ -115,6 +121,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
       
 			private var mousedOver:Boolean = false;
 			private var slideLoaded:Boolean = false;
+			private var enableAnnotations:Boolean = true;
 			
 			public var canvas:WhiteboardCanvas;
 			private var presentationWindow:PresentationWindow;
@@ -122,12 +129,15 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 			[Bindable] private var colorPickerColours:Array = ['0x000000', '0xFFFFFF' , '0xFF0000', '0xFF8800',
                 '0xCCFF00', '0x00FF00', '0x00FF88', '0x00FFFF', '0x0088FF', '0x0000FF', '0x8800FF', '0xFF00FF', '0xC0C0C0'];
 			
+			private var _hideToolbarTimer:Timer = new Timer(500, 1);
+
 			private function init():void{
 				wbOptions = new WhiteboardOptions();
 			}
 			
       private function onCreationComplete():void {
         setToolType(WhiteboardConstants.TYPE_ZOOM, null);
+        _hideToolbarTimer.addEventListener(TimerEvent.TIMER, onHideToolbarTimerComplete);
       }
 
       private function handleWhiteboardButtonPressed(e:WhiteboardButtonEvent):void {
@@ -249,15 +259,33 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
                 }
 			}
 			
+			private function refreshRole(e:ChangeMyRole):void {
+				checkVisibility();
+			}
+
             private function checkVisibility(e:MadePresenterEvent = null):void {
-                if (toolbarAllowed() && slideLoaded && (wbOptions.keepToolbarVisible || mousedOver)) {
+                if (toolbarAllowed() && slideLoaded && enableAnnotations && (wbOptions.keepToolbarVisible || mousedOver) && !presentationWindow.minimized) {
                     setPositionAndDepth();
-                    showWhiteboardToolbar = true;
+                    showToolbar();
                 } else {
-                    showWhiteboardToolbar = false;
+                    hideToolbar();
                 }
             }
             
+			private function showToolbar():void {
+				_hideToolbarTimer.reset();
+				showWhiteboardToolbar = true;
+			}
+
+			private function hideToolbar():void {
+				_hideToolbarTimer.reset();
+				_hideToolbarTimer.start();
+			}
+
+			private function onHideToolbarTimerComplete(event:TimerEvent):void {
+				showWhiteboardToolbar = false;
+			}
+
 			private function setPositionAndDepth(e:Event = null):void {
 				this.x = presentationWindow.x + presentationWindow.width - 43;
 				this.y = presentationWindow.y + 30;
@@ -328,9 +356,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         return UsersUtil.amIModerator();
       }
 		           
+      private function handleEnableAnnotations(e:PresenterStatusEvent):void {
+        enableAnnotations = e.enableAnnotations;
+        checkVisibility();
+      }
+
 		]]>
 	</mx:Script>
 	
+	<mx:Fade id="fadeOut" duration="200" alphaFrom="1.0" alphaTo="0.0" />
+	<mx:Fade id="fadeIn" duration="200" alphaFrom="0.0" alphaTo="1.0" />
 	<common:TabIndexer startIndex="{wbOptions.baseTabIndex}"
 					   tabIndices="{[panzoomBtn, scribbleBtn, rectangleBtn, circleBtn, triangleBtn, lineBtn, textBtn, clearBtn, undoBtn, cpik, sld]}"/>
 	
diff --git a/bigbluebutton-client/src/org/bigbluebutton/util/i18n/ResourceUtil.as b/bigbluebutton-client/src/org/bigbluebutton/util/i18n/ResourceUtil.as
index a29d34af03943a0de3fd11b46bf680c657b83892..ebd754710e89733b9a0facec51b6be4008a6f60d 100755
--- a/bigbluebutton-client/src/org/bigbluebutton/util/i18n/ResourceUtil.as
+++ b/bigbluebutton-client/src/org/bigbluebutton/util/i18n/ResourceUtil.as
@@ -24,6 +24,8 @@ package org.bigbluebutton.util.i18n
 	import flash.events.EventDispatcher;
 	import flash.events.IEventDispatcher;
 	import flash.external.ExternalInterface;
+	import flash.globalization.Collator;
+	import flash.globalization.CollatorMode;
 	import flash.net.URLLoader;
 	import flash.net.URLRequest;
 	
@@ -49,14 +51,15 @@ package org.bigbluebutton.util.i18n
 		
 		private static var BBB_RESOURCE_BUNDLE:String = 'bbbResources';
 		private static var MASTER_LOCALE:String = "en_US";
+		private static var DEFAULT_LOCALE_IDENTIFIER:String = "default";
 		
-		[Bindable] public var localeCodes:Array = new Array();
-		[Bindable] public var localeNames:Array = new Array();
-		[Bindable] public var localeIndex:Number;
+		[Bindable] public var locales:Array = new Array();
 		
 		private var eventDispatcher:IEventDispatcher;
 		private var resourceManager:IResourceManager;
 		private var preferredLocale:String
+		private var masterLocaleLoaded:Boolean = false;
+		private var masterLocaleLoadedCallback:Function = null;
 		
 		
 		public function ResourceUtil(enforcer:SingletonEnforcer) {
@@ -103,9 +106,16 @@ package org.bigbluebutton.util.i18n
 			var list:XMLList = xml.locale;
 			var locale:XML;
 						
+			locales.push({
+				code: DEFAULT_LOCALE_IDENTIFIER,
+				name: ""
+			});
+
 			for each(locale in list){
-				localeCodes.push(locale.@code);
-				localeNames.push(locale.@name);
+				locales.push({
+					code: locale.@code,
+					name: locale.@name
+				});
 			}							
 		}
 		
@@ -114,44 +124,77 @@ package org.bigbluebutton.util.i18n
 		}
 		
 		private function isPreferredLocaleAvailable(prefLocale:String):Boolean {
-			for (var i:Number = 0; i < localeCodes.length; i++){
-				if (prefLocale == localeCodes[i]) 
+			for each(var item:* in locales) {
+				if (prefLocale == item.code)
 					return true;
 			}
 			return false;
 		}
 		
 		private function getIndexForLocale(prefLocale:String):int {
-			for (var i:Number = 0; i < localeCodes.length; i++){
-				if (prefLocale == localeCodes[i]) 
+			for (var i:Number = 0; i < locales.length; i++) {
+				if (prefLocale == locales[i].code)
 					return i;
 			}
 			return -1;
 		}
 		
-		public function getPreferredLocaleName():String {
-			return localeNames[localeIndex];
-		}
-		
 		public function setPreferredLocale(locale:String):void {
+			if (locale == DEFAULT_LOCALE_IDENTIFIER) {
+				locale = getDefaultLocale();
+			}
+
 			if (isPreferredLocaleAvailable(locale)) {
 				preferredLocale = locale;
 			}else{
 				preferredLocale = MASTER_LOCALE;
 			}
-			localeIndex = getIndexForLocale(preferredLocale);
+
 			changeLocale(preferredLocale);
 		}
 		
+		private function localesCompareFunction(a:Object, b:Object):int {
+			var sorter:Collator = new Collator(preferredLocale, CollatorMode.SORTING);
+			// position the "Default language" option at the top of the list
+			if (a.code == DEFAULT_LOCALE_IDENTIFIER) {
+				return -1;
+			}
+			if (b.code == DEFAULT_LOCALE_IDENTIFIER) {
+				return 1;
+			}
+			return sorter.compare(a.name, b.name);
+		}
+
+		private function reloadLocaleNames():void {
+			for each (var item:* in locales) {
+				if (item.code == DEFAULT_LOCALE_IDENTIFIER) {
+					item.name = ResourceUtil.getInstance().getString("bbb.langSelector." + item.code, null, getDefaultLocale());
+				} else {
+					item.name = ResourceUtil.getInstance().getString("bbb.langSelector." + item.code, null, preferredLocale);
+				}
+			}
+			locales.sort(localesCompareFunction);
+		}
+
 		private function loadMasterLocale(locale:String):void {					
 			/**
 			 *  http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/resources/IResourceManager.html#localeChain
 			 *  Always load the default language, so if the chosen language 
 			 *  doesn't provide a resource, the default language resource is used
 			 */
-			loadResource(locale);					
+			var dispatcher:IEventDispatcher = loadResource(locale);
+			dispatcher.addEventListener(ResourceEvent.COMPLETE, onMasterLocaleLoaded);
 		}
 		
+		private function onMasterLocaleLoaded(event:ResourceEvent):void {
+			LOGGER.debug("Master locale is loaded");
+			masterLocaleLoaded = true;
+			if (masterLocaleLoadedCallback != null) {
+				LOGGER.debug("Calling callback to load a second language");
+				masterLocaleLoadedCallback();
+			}
+		}
+
 		private function loadResource(language:String):IEventDispatcher {
 			// Add a random string on the query so that we don't get a cached version.
 			
@@ -167,17 +210,28 @@ package org.bigbluebutton.util.i18n
 			return instance;
         }
         
-		public function changeLocale(locale:String):void{        	
+		private function changeLocaleHelper(locale:String):void {
 			eventDispatcher = loadResource(locale);
 			eventDispatcher.addEventListener(ResourceEvent.COMPLETE, localeChangeComplete);
 			eventDispatcher.addEventListener(ResourceEvent.ERROR, handleResourceNotLoaded);
 		}
+
+		public function changeLocale(locale:String):void {
+			if (masterLocaleLoaded || locale == MASTER_LOCALE) {
+				LOGGER.debug("Loading immediately " + locale);
+				changeLocaleHelper(locale);
+			} else {
+				LOGGER.debug("Registering callback to load " + locale + " later");
+				masterLocaleLoadedCallback = function():void {
+					changeLocaleHelper(locale);
+				}
+			}
+		}
 		
 		private function localeChangeComplete(event:ResourceEvent):void {
 			// Set the preferred locale and master as backup.
 			if (preferredLocale != MASTER_LOCALE) {
 				resourceManager.localeChain = [preferredLocale, MASTER_LOCALE];
-				localeIndex = getIndexForLocale(preferredLocale);
 			} else {
 				if (preferredLocale != MASTER_LOCALE) {
                     var logData:Object = UsersUtil.initLogData();
@@ -185,10 +239,9 @@ package org.bigbluebutton.util.i18n
                     logData.message = "Failed to load locale = " + preferredLocale;
                     LOGGER.info(JSON.stringify(logData));
 				}
-	
+				masterLocaleLoaded = true;
 				resourceManager.localeChain = [MASTER_LOCALE];
 				preferredLocale = MASTER_LOCALE;
-				localeIndex = getIndexForLocale(preferredLocale);
 			}
 			sendAppAndLocaleVersions();
 			update();
@@ -206,13 +259,15 @@ package org.bigbluebutton.util.i18n
 		 * @param event
 		 */        
 		private function handleResourceNotLoaded(event:ResourceEvent):void{
+			LOGGER.debug("Resource locale [" + preferredLocale + "] could not be loaded.");
 			resourceManager.localeChain = [MASTER_LOCALE];
 			preferredLocale = MASTER_LOCALE;
-			localeIndex = getIndexForLocale(preferredLocale);
 			update();
 		}
 		
 		public function update():void{
+			reloadLocaleNames();
+
 			var dispatcher:Dispatcher = new Dispatcher;
 			dispatcher.dispatchEvent(new LocaleChangeEvent(LocaleChangeEvent.LOCALE_CHANGED));
 			dispatchEvent(new Event(Event.CHANGE));
@@ -227,8 +282,12 @@ package org.bigbluebutton.util.i18n
 			 * the key is available in the locale and thus not bother falling back to the master locale.
 			 *    (ralam dec 15, 2011).
 			 */
-			var localeTxt:String = resourceManager.getString(BBB_RESOURCE_BUNDLE, resourceName, parameters, null);
-			if ((localeTxt == "") || (localeTxt == null)) {
+			if (resourceManager.getObject(BBB_RESOURCE_BUNDLE, resourceName, locale) == undefined) {
+				locale = MASTER_LOCALE;
+			}
+
+			var localeTxt:String = resourceManager.getString(BBB_RESOURCE_BUNDLE, resourceName, parameters, locale);
+			if (locale != MASTER_LOCALE && (localeTxt == "" || localeTxt == null)) {
 				localeTxt = resourceManager.getString(BBB_RESOURCE_BUNDLE, resourceName, parameters, MASTER_LOCALE);
 			}
 			return localeTxt;
@@ -238,8 +297,12 @@ package org.bigbluebutton.util.i18n
 			return preferredLocale;
 		}
 				
-		public function getLocaleCodeForIndex(index:int):String {
-			return localeCodes[index];
+		public function getCurrentLanguage():Object {
+			return locales[getCurrentLanguageIndex()];
+		}
+
+		public function getCurrentLanguageIndex():int {
+			return getIndexForLocale(preferredLocale);
 		}
 	}
 }
diff --git a/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as b/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as
index 22a97d38461ec4467f5740123b227bb07d59aad7..da5f038b89eb6ecfda0d11afebf85dadd66843ea 100644
--- a/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as
+++ b/bigbluebutton-client/src/org/red5/flash/bwcheck/ClientServerBandwidth.as
@@ -139,5 +139,15 @@ package org.red5.flash.bwcheck
 				break;
 			}
 		}
+
+		public function onBWCheck(obj:Object):void
+		{
+//			dispatchStatus(obj);
+		}
+
+		public function onBWDone(obj:Object):void
+		{
+//			dispatchComplete(obj);
+		}
 	}
 }
diff --git a/bigbluebutton-config/bin/bbb-conf b/bigbluebutton-config/bin/bbb-conf
index 948e21e3b0b78d41d230c9548c91c1d6a434a9a4..ff385c1a4f05611d861f84ad0b4eb4003220053a 100755
--- a/bigbluebutton-config/bin/bbb-conf
+++ b/bigbluebutton-config/bin/bbb-conf
@@ -630,6 +630,9 @@ while [ $# -gt 0 ]; do
 			echo "       URL: $BBB_WEB_URL/bigbluebutton/"
 			echo "    Secret: $SECRET"
 			echo
+			echo "      Link to the API-Mate:"
+			echo "      http://mconf.github.io/api-mate/#server=$BBB_WEB_URL/bigbluebutton/&sharedSecret=$SECRET"
+			echo
 			exit 0
 		fi
 		shift; shift
diff --git a/bigbluebutton-config/bin/bbb-record b/bigbluebutton-config/bin/bbb-record
index f108dd09d98c98e74e67d68321685f6e21eb0de4..b345c4905d69281a93588a273041d9a7927dce8a 100755
--- a/bigbluebutton-config/bin/bbb-record
+++ b/bigbluebutton-config/bin/bbb-record
@@ -337,12 +337,12 @@ if [ $REPUBLISH ]; then
 fi 
 
 if [ $CLEAN ]; then
-	sudo /etc/init.d/bbb-record stop
+	sudo /etc/init.d/bbb-record-core stop
 	for type in $TYPES; do
 		echo " clearning logs in /var/log/bigbluebutton/$type"
 		find /var/log/bigbluebutton/$type -name "*.log" -exec sudo rm '{}' \;
 	done
-	sudo /etc/init.d/bbb-record start
+	sudo /etc/init.d/bbb-record-core start
 fi
 
 if [ $DELETE ]; then
diff --git a/bigbluebutton-config/web/default.pdf b/bigbluebutton-config/web/default.pdf
old mode 100644
new mode 100755
index 8bd18ac603171b590e0280ec26bd4328c9225b42..88d153dd5861cd3a0f17401efcd6cd7991513931
Binary files a/bigbluebutton-config/web/default.pdf and b/bigbluebutton-config/web/default.pdf differ
diff --git a/bigbluebutton-config/web/favicon.ico b/bigbluebutton-config/web/favicon.ico
index 2a399b83be1833fa8a206a7f33d35f8bb745031e..41c8cb123a1ebe2b686b808fb4f75e752b3b6b42 100644
Binary files a/bigbluebutton-config/web/favicon.ico and b/bigbluebutton-config/web/favicon.ico differ
diff --git a/bigbluebutton-config/web/index.html b/bigbluebutton-config/web/index.html
index 0cb6b40f63d7f50cb3d554522205af4ea5db64b0..e90bf452ed14a18fafb59fca4f4d1651448d90eb 100644
--- a/bigbluebutton-config/web/index.html
+++ b/bigbluebutton-config/web/index.html
@@ -1,272 +1,12 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-
-    <title>BigBlueButton - Open Source Web Conferencing</title>
-    <meta name="description" content="BigBlueButton enables universities and colleges to deliver a high-quality learning experience to remote students.">
-    <meta name="keywords" content="BigBlueButton, Open Source Web Conferencing, Distance Education, Courses Online, Web Conferencing, Open Source, Desktop Sharing, Video Conferencing, Video Collaboration, Presentation Sharing, Audio Sharing, Voice Collaboration, Public Chat, Webcam Sharing, Annotation, Whiteboard, Integrated Voice Over IP, Collaboration Software, Online Collaboration, Collaborative Learning, Virtual Classroom">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-		<link rel="icon" href="images/favicon.png">
-
-    <link rel="stylesheet" href="css/bijou.min.css">
-    <link rel="stylesheet" href="css/style.css">
-    <link rel="stylesheet" href="css/font-awesome.min.css">
-    <link rel="stylesheet" href="css/bbb-bootstrap.css">
-
-    <script src="js/jquery.min.js"></script>
-    <script src="js/bootstrap.min.js"></script>
-    <script src="js/bigbluebutton.js"></script>
-	</head>
-  <body>
-    <div class='main'>
-
-    <!-- Github Fork Ribbon -->
-    <a href="https://github.com/bigbluebutton/bigbluebutton">
-        <img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub">
-    </a>
-
-    <!-- Messages -->
-    <div id='messages' class='hidden'>
-    </div>
-
-    <!-- Header -->
-    <div class='navbar'>
-      <div class='container'>
-        <div class="logo">
-          <img src="images/bbb-logo.png" alt="BigBlueButton Demo"/>
-        </div>
-      </div>
-    </div>
-
-    <!-- Body -->
-    <div class='container'>
-
-      <!-- Welcome Message & Login Into Demo -->
-      <div class='row'>
-        <div class='span five'>
-          <h2>Welcome</h2>
-          <p> <a href="http://bigbluebutton.org/" target="_blank">BigBlueButton</a> is an open source web conferencing system for on-line learning. </p>
-          <p> We believe that every student with a web browser should have access to a high-quality on-line learning experience </p>
-          <p> We intend to make that possible with BigBlueButton.</p>
-
-          <h4>For Developers</h4>
-          <p> The BigBlueButton project is <a href="http://bigbluebutton.org/support">supported</a> by a community of developers that care about good design and a streamlined user experience. </p>
-          <p>See <a href="/demo/demo1.jsp" target="_blank">API examples </a> for how to integrate BigBlueButton with your project.</p>
-        </div>
-				<div class="span one"></div>
-        <div class='span six'>
-          <div class='join-metting  pull-right'>
-            <h4>Try BigBlueButton</h4>
-            <p>Join a demo session on this server.</p>
-
-            <form name="form1" method="GET" onsubmit="return checkform(this);" action="/demo/demo1.jsp">
-              <input type="text" id="username" required="" name="username" placeholder="Enter Your Name" size="29" class="field input-default" autofocus>
-              <input type="submit" value="Join" class="submit_btn button success large"><br>
-              <input type="hidden" name="action" value="create">
-            </form>
-
-          <a class="watch" href="#video" class="pull-right">New to BigBlueButton?  Watch these videos.</a>
-
-          </div>
-
-        </div>
-      </div>
-
-      <hr class="featurette-divider">
-
-      <!-- BigBlueButton Features -->
-      <div class="bbb-features">
-	      <div class='row'>
-	        <div class='featurette-heading'>
-	          <h2>Features</h2>
-	        </div>
-
-	        <div class='span four first'>
-	          <i class="fa fa-play-circle-o"></i>
-
-	          <div class="bbb-features-content">
-	            <h3>Record and Playback</h3>
-	            <p>BigBlueButton can record your sessions for later playback by students.</p>
-	          </div>
-	        </div>
-
-	        <div class='span four'>
-	          <i class="fa fa-pencil-square-o"></i>
-
-	          <div class="bbb-features-content">
-	            <h3>Whiteboard</h3>
-	            <p>The whiteboard controls let you annotate key parts of your presentation.</p>
-	          </div>
-	        </div>
-
-	        <div class='span four last'>
-	          <i class="fa fa-desktop"></i>
-
-	          <div class="bbb-features-content">
-	            <h3><a href="https://youtu.be/xTFuEvmEqB0">Desktop Sharing</a></h3>
-	            <p>You can broadcast your desktop for all users to see (requires lastest version of Java for presenter only).</p>
-	          </div>
-	        </div>
-	      </div>
-
-
-	      <div class='row'>
-	        <div class='span four first'>
-	          <i class="fa fa-microphone"></i>
-
-	          <div class="bbb-features-content">
-	            <h3><a href="https://youtu.be/4Y__UsUrRx0">WebRTC Audio</a></h3>
-	            <p>Users of Chrome and FireFox browsers will benefit from high-quality, low-latency WebRTC audio. (Users of other browsers will seamlessly use Flash-based audio.)</p>
-	          </div>
-	        </div>
-
-	        <div class='span four'>
-	          <i class="fa fa-bar-chart-o"></i>
-
-	          <div class="bbb-features-content">
-	            <h3><a href="https://youtu.be/J9mbw00P9W0">Presentation</a></h3>
-	            <p>You can upload any PDF presentation or MS office document. BigBlueButton keeps everyone in sync with your current slide, zoom, pan, annotations, and mouse pointer.</p>
-	          </div>
-	        </div>
-
-	        <div class='span four last'>
-	          <i class="fa fa-video-camera"></i>
-
-	          <div class="bbb-features-content">
-	            <h3>Web Cam</h3>
-	            <p>Multiple users can share their webcam at the same time. There is no built-in limit on the number of simultaneously active webcams.</p>
-	          </div>
-	        </div>
-	      </div>
-
-              <div class='row'>
-                <div class='span four first'>
-                  <i class="fa fa-smile-o"></i>
-
-                  <div class="bbb-features-content">
-                    <h3>Emoji</h3>
-                    <p>Students can raise hand and use emoji icons for feedback.</p>
-                  </div>
-                </div>
-
-                <div class='span four'>
-                  <i class="fa fa-check-square-o"></i>
-
-                  <div class="bbb-features-content">
-                    <h3>Polling</h3>
-                    <p>You can poll students anytime to increase engagement.</p>
-                  </div>
-                </div>
-
-                <div class='span four last'>
-                  <i class="fa fa-comments-o"></i>
-
-                  <div class="bbb-features-content">
-                    <h3>Chat</h3>
-                    <p>You can interact with students through public and private chat.</p>
-                  </div>
-                </div>
-              </div>
-
-              <div class='row'>
-                <div class='span four first'>
-                  <i class="fa fa-cc"></i>
-
-                  <div class="bbb-features-content">
-                    <h3><a href="https://youtu.be/vDpurrMgal0">Live Captioning</a></h3>
-                    <p>You can enter live captions for students.  These captions will later appear as subtitles in recordings.</p>
-                  </div>
-                </div>
-
-                <div class='span four'>
-                  <i class="fa fa-users"></i>
-
-                  <div class="bbb-features-content">
-                    <h3><a href="https://youtu.be/q5N-lcocJss">Breakout Rooms</a></h3>
-                    <p>You can group and place students into breakout rooms (full BigBlueButton sessions) for give number of minutes for increased collaboration.</p>
-                  </div>
-                </div>
-
-                <div class='span four last'>
-                  <i class="fa fa-blind"></i>
-
-                  <div class="bbb-features-content">
-                    <h3>Screen Reader</h3>
-                    <p>Students with visual disabilities can use JAWS screen reader to interact with BigBlueButton.</p>
-                  </div>
-                </div>
-              </div>
-
-      </div>
-      <hr class="featurette-divider">
-
-      <!-- BigBlueButton Videos -->
-      <div id="video" class="bbb-videos">
-	      <div class='row'>
-	        <div class='featurette-heading'>
-	          <h2>Getting Started Quickly</h2>
-	        </div>
-
-	        <div class='span four first video-item'>
-	        	<a href="https://www.youtube.com/watch?v=4Y__UsUrRx0&feature=youtu.be" target="_blank">
-		        	<div class="video-btn"><i class="fa fa-play-circle-o"></i></div>
-		          <img src="images/bbb-setup-audio.jpg" alt="Setting Up Audio"/>
-	        	</a>
-	          <h3><a href="https://www.youtube.com/watch?v=4Y__UsUrRx0&feature=youtu.be" title="Setup Audio" target="_blank">Setting Up Audio</a></h3>
-	        </div>
-
-	        <div class='span four video-item'>
-	        	<a href="https://www.youtube.com/watch?v=oh0bEk3YSwI" target="_blank">
-		        	<div class="video-btn"><i class="fa fa-play-circle-o"></i></div>
-		          <img src="images/bbb-viewer-overview.jpg" alt="BigBlueButton Viewer Overview Video"/>
-	        	</a>
-	          <h3><a href="https://www.youtube.com/watch?v=oh0bEk3YSwI;feature=youtu.be" title="Student Overview" target="_blank">Viewer Overview</a></h3>
-	        </div>
-
-	        <div class='span four last video-item'>
-	        	<a href="https://www.youtube.com/watch?v=J9mbw00P9W0&feature=youtu.be" target="_blank">
-		        	<div class="video-btn"><i class="fa fa-play-circle-o"></i></div>
-		          <img  src="images/bbb-presenter-overview.jpg" alt="Moderator/Presenter Overview Video"/>
-	        	</a>
-	          <h3><a href="https://www.youtube.com/watch?v=J9mbw00P9W0&feature=youtu.be" title="Moderator/Presenter Overview" target="_blank">Moderator/Presenter Overview</a></h3>
-	        </div>
-	      </div>
-      </div>
-
-      </div>
-    </div>
-
-    <!--  Footer -->
-    <footer>
-      <div class='container'>
-
-	      <div class="row">
-	      	<div class="span six first">
-		        <p>BigBlueButton and the BigBlueButton logo are trademarks of <a href="http://bigbluebutton.org/">BigBlueButton Inc.</a></p>
-          </div>
-	      	<div class="span six last">
-						<ul>
-							<li>
-								Follow Us:
-							</li>
-							<li><a class="twitter" href="http://www.twitter.com/bigbluebutton" title="BigBlueButton Twitter Page" target="_blank"><i class="fa fa-twitter"></i></a></li>
-							<li><a class="facebook" href="http://www.facebook.com/bigbluebutton" title="BigBlueButton Facebook Page" target="_blank"><i class="fa fa-facebook"></i></a></li>
-							<li><a class="youtube" href="http://www.youtube.com/bigbluebuttonshare" title="BigBlueButton YouTube Page" target="_blank"><i class="fa fa-youtube"></i> </a></li>
-							<li><a class="google" href="http://google.com/+bigbluebutton" title="BigBlueButton Google Plus" target="_blank"><i class="fa fa-google-plus"></i></a></li>
-						</ul>
-	      	</div>
-	      </div> 
-
-
-	      <div class="row">
-	      	<div class="span twelve center">
-		        <p>Copyright &copy; 2016 BigBlueButton Inc.<br>
-		        <small>Version <a href="http://docs.bigbluebutton.org/">1.1-beta</a></small>		        
-		        </p>
-	      	</div>
-	      </div>
-      </div>
-    </footer>
-  </body>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script type="text/javascript">
+<!--
+window.location = "/demo/demo_mconf.jsp"
+//-->
+</script>
+</head>
+<body>
+</body>
 </html>
diff --git a/bigbluebutton-web/grails-app/conf/UrlMappings.groovy b/bigbluebutton-web/grails-app/conf/UrlMappings.groovy
index 41e12e122f2909cada1334862b7c4331d3b30d94..bd6740d2f4c32b4b8458131c851c6ded60ad5f8e 100755
--- a/bigbluebutton-web/grails-app/conf/UrlMappings.groovy
+++ b/bigbluebutton-web/grails-app/conf/UrlMappings.groovy
@@ -40,6 +40,10 @@ class UrlMappings {
 		"/presentation/$conference/$room/$presentation_name/textfiles/$id"(controller:"presentation") {
 			action = [GET:'showTextfile']
 		}
+
+		"/presentation/$conference/$room/$presentation_name/download"(controller:"presentation") {
+			action = [GET:'downloadFile']
+		}
       
 		"/api/setConfigXML"(controller:"api") {
 			action = [POST:'setConfigXML']
diff --git a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties
index 56eb9a4bd868e5382982f338ab80ac9a23740f14..301596b9695657fa2582ea708edba9258194334e 100644
--- a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties
+++ b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties
@@ -100,8 +100,8 @@ defaultDialAccessNumber=613-555-1234
 # Default welcome message to display when the participant joins the web
 # conference. This is only used for the old scheduling which will be
 # removed in the future. Use the API to create a conference.
-defaultWelcomeMessage=<br>Welcome to <b>%%CONFNAME%%</b>!<br><br>For help on using BigBlueButton see these (short) <a href="event:http://www.bigbluebutton.org/content/videos"><u>tutorial videos</u></a>.<br><br>To join the audio bridge click the headset icon (upper-left hand corner).  Use a headset to avoid causing background noise for others.<br>
-defaultWelcomeMessageFooter=This server is running <a href="http://docs.bigbluebutton.org/" target="_blank"><u>BigBlueButton</u></a>.
+defaultWelcomeMessage=<br>Welcome to <b>%%CONFNAME%%</b>!<br><br>To join the audio bridge click the headset icon (upper-left hand corner).  Use a headset to avoid causing background noise for others.<br>
+defaultWelcomeMessageFooter=
 
 # Default maximum number of users a meeting can have.
 # Current default is 0 (meeting doesn't have a user limit).
@@ -150,7 +150,7 @@ bigbluebutton.web.logoutURL=default
 
 # The url of the BigBlueButton client. User's will be redirected here when
 # successfully joining the meeting.
-defaultClientUrl=${bigbluebutton.web.serverURL}/client/BigBlueButton.html
+defaultClientUrl=${bigbluebutton.web.serverURL}/client/MconfLive.html
 #defaultClientUrl=http://192.168.0.235/3rd-party.html
 
 # The default avatar image to display if nothing is passed on the JOIN API (avatarURL)
diff --git a/bigbluebutton-web/grails-app/conf/spring/resources.xml b/bigbluebutton-web/grails-app/conf/spring/resources.xml
index 4c8319a9cd832726b83ae049900f790c06e0771c..2ee6f72989565b5de1d15b58c2abb5253eb50ee0 100755
--- a/bigbluebutton-web/grails-app/conf/spring/resources.xml
+++ b/bigbluebutton-web/grails-app/conf/spring/resources.xml
@@ -69,6 +69,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
     <property name="publishedDir" value="${publishedDir}"/>
     <property name="unpublishedDir" value="${unpublishedDir}"/>  
     <property name="recordingServiceHelper" ref="recordingServiceHelper"/>
+    <property name="messagingService" ref="messagingService"/>
   </bean>
   
   <bean id="configServiceHelper" class="org.bigbluebutton.api.ClientConfigServiceHelperImp"/>
diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
index 01e641cd98585163e011b320640b1f20eb256f61..752a42571455a8251fb1ebbe305e01840fe2e47d 100755
--- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
+++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy
@@ -249,6 +249,13 @@ class ApiController {
       errors.missingParamError("checksum");
     }
 
+    String guest;
+    if (!StringUtils.isEmpty(params.guest) && params.guest.equalsIgnoreCase("true")) {
+        guest = "true";
+    } else {
+        guest = "false";
+    }
+
     // Do we have a name for the user joining? If none, complain.
     if(!StringUtils.isEmpty(params.fullName)) {
       params.fullName = StringUtils.strip(params.fullName);
@@ -439,6 +446,7 @@ class ApiController {
     us.mode = "LIVE"
     us.record = meeting.isRecord()
     us.welcome = meeting.getWelcomeMessage()
+    us.guest = guest
     us.logoutUrl = meeting.getLogoutUrl();
     us.configXML = configxml;
 
@@ -456,7 +464,7 @@ class ApiController {
     meetingService.addUserSession(sessionToken, us);
 
     // Register user into the meeting.
-    meetingService.registerUser(us.meetingID, us.internalUserId, us.fullname, us.role, us.externUserID, us.authToken, us.avatarURL)
+    meetingService.registerUser(us.meetingID, us.internalUserId, us.fullname, us.role, us.externUserID, us.authToken, us.avatarURL, us.guest)
 
     // Validate if the maxParticipants limit has been reached based on registeredUsers. If so, complain.
     // when maxUsers is set to 0, the validation is ignored
@@ -1588,6 +1596,7 @@ class ApiController {
               internalUserID = newInternalUserID
               authToken = us.authToken
               role = us.role
+              guest = us.guest
               conference = us.conference
               room = us.room
               voicebridge = us.voicebridge
@@ -1609,6 +1618,11 @@ class ApiController {
                   custdata "$k" : v
                 }
               }
+              metadata = array {
+                meeting.getMetadata().each{ k, v ->
+                  metadata "$k" : v
+                }
+              }
             }
           }
         }
@@ -2188,10 +2202,17 @@ class ApiController {
                   userID() { mkp.yield("${att.externalUserId}") }
                   fullName() { mkp.yield("${att.fullname}") }
                   role("${att.role}")
+                  guest("${att.guest}")
+                  waitingForAcceptance("${att.waitingForAcceptance}")
                   isPresenter("${att.isPresenter()}")
                   isListeningOnly("${att.isListeningOnly()}")
                   hasJoinedVoice("${att.isVoiceJoined()}")
                   hasVideo("${att.hasVideo()}")
+                  videoStreams() {
+                    att.getStreams().each { s ->
+                      streamName("${s}")
+                    }
+                  }
                   customdata(){
                     meeting.getUserCustomData(att.externalUserId).each{ k,v ->
                       "$k"("$v")
diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy
index 5fbe9af222c34e9cd43f6339cf619be07a1d1d50..5ec325d6174adaf66f3c5f558947a32877a7ab13 100755
--- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy
+++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/PresentationController.groovy
@@ -60,10 +60,33 @@ class PresentationController {
          def pres = new File(uploadDir.absolutePath + File.separatorChar + newFilename )
          file.transferTo(pres)
          
+         def isDownloadable = params.boolean('is_downloadable') //instead of params.is_downloadable
+
+         if(isDownloadable) {
+           log.debug "@Creating download directory..."
+           File downloadDir = Util.downloadPresentationDirectory(uploadDir.absolutePath)
+           if (downloadDir != null) {
+             def notValidCharsRegExp = /[^0-9a-zA-Z_\.]/
+             def downloadableFileName = presFilename.replaceAll(notValidCharsRegExp, '-')
+             def downloadableFile = new File( downloadDir.absolutePath + File.separatorChar + downloadableFileName )
+             downloadableFile << pres.newInputStream()
+           }
+         }
+
          def presentationBaseUrl = presentationService.presentationBaseUrl
          UploadedPresentation uploadedPres = new UploadedPresentation(meetingId, presId, presFilename, presentationBaseUrl);
+
+         if(isDownloadable) {
+           log.debug "@Setting file to be downloadable..."
+           uploadedPres.setDownloadable();
+         }
+
          uploadedPres.setUploadedFile(pres);
          presentationService.processUploadedPresentation(uploadedPres)
+
+         response.addHeader("Cache-Control", "no-cache")
+         response.contentType = 'plain/text'
+         response.outputStream << 'upload-success';
       }
     } else {
       flash.message = 'file cannot be empty'
@@ -186,6 +209,33 @@ class PresentationController {
     return null;
   }
   
+  def downloadFile = {
+    def presentationName = params.presentation_name
+    def conf = params.conference
+    def rm = params.room
+    println "Controller: Download request for $presentationName"
+
+    InputStream is = null;
+    try {
+      def pres = presentationService.getFile(conf, rm, presentationName)
+      if (pres.exists()) {
+        println "Controller: Sending pdf reply for $presentationName"
+
+        def bytes = pres.readBytes()
+        def responseName = pres.getName();
+        response.addHeader("content-disposition", "filename=$responseName")
+        response.addHeader("Cache-Control", "no-cache")
+        response.outputStream << bytes;
+      } else {
+        println "$pres does not exist."
+      }
+    } catch (IOException e) {
+      println("Error reading file.\n" + e.getMessage());
+    }
+
+    return null;
+  }
+
   def thumbnail = {
     def filename = params.id.replace('###', '.')
     def presDir = confDir() + File.separatorChar + filename
diff --git a/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy b/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy
index 1cdd92c9255628213cdcb0a959aaf8192e78da2a..7eab66371f05ab7c8738489d73af0179f19d7012 100755
--- a/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy
+++ b/bigbluebutton-web/grails-app/services/org/bigbluebutton/web/services/PresentationService.groovy
@@ -158,6 +158,16 @@ class PresentationService {
 		}
 		
 	}
+
+	def getFile = {conf, room, presentationName ->
+		println "download request for $presentationName"
+		def fileDirectory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
+"download")
+		//list the files of the download directory ; it must have only 1 file to download
+		def list = fileDirectory.listFiles()
+		//new File(pdfFile)
+		list[0]
+	}
 }
 
 /*** Helper classes **/
diff --git a/bigbluebutton-web/src/groovy/org/bigbluebutton/api/RecordingServiceHelperImp.groovy b/bigbluebutton-web/src/groovy/org/bigbluebutton/api/RecordingServiceHelperImp.groovy
index a6f1fe96fbca99cb624b1e63a7e57307c4e5242a..f8e841199831aa2e1fb53d7692a6afe6de2610d3 100755
--- a/bigbluebutton-web/src/groovy/org/bigbluebutton/api/RecordingServiceHelperImp.groovy
+++ b/bigbluebutton-web/src/groovy/org/bigbluebutton/api/RecordingServiceHelperImp.groovy
@@ -79,6 +79,7 @@ public class RecordingServiceHelperImp implements RecordingServiceHelper {
             builder.published(info.isPublished())
             builder.start_time(info.getStartTime())
             builder.end_time(info.getEndTime())
+            builder.raw_size(info.getRawSize())
             if ( info.getPlaybackFormat() == null ) {
                 builder.playback()
             } else {
@@ -86,6 +87,8 @@ public class RecordingServiceHelperImp implements RecordingServiceHelper {
                     builder.format(info.getPlaybackFormat())
                     builder.link(info.getPlaybackLink())
                     builder.duration(info.getPlaybackDuration())
+                    builder.size(info.getPlaybackSize())
+                    builder.processing_time(info.getProcessingTime())
                     def extensions = info.getPlaybackExtensions()
                     if ( !extensions.isEmpty() ) {
                         builder.extensions {
@@ -99,6 +102,16 @@ public class RecordingServiceHelperImp implements RecordingServiceHelper {
                     }
                 }
             }
+            if ( info.getDownloadFormat() == null ) {
+                builder.download()
+            } else {
+                builder.download {
+                    builder.format(info.getDownloadFormat())
+                    builder.link(info.getDownloadLink())
+                    builder.md5(info.getDownloadMd5())
+                    builder.key(info.getDownloadKey())
+                }
+            }
             Map<String,String> metainfo = info.getMetadata();
             builder.meta{
                 metainfo.keySet().each { key ->
@@ -110,6 +123,12 @@ public class RecordingServiceHelperImp implements RecordingServiceHelper {
         xmlEventFile.write writer.toString()
     }
 
+    public Recording getRecordingInfo(String id, String recordingDir, String playbackFormat) {
+        String path = recordingDir + File.separatorChar + playbackFormat + File.separatorChar + id;
+        File dir = new File(path);
+        return getRecordingInfo(dir);
+    }
+
     public Recording getRecordingInfo(File dir) {
         if (dir.isDirectory()) {
             try {
@@ -135,10 +154,13 @@ public class RecordingServiceHelperImp implements RecordingServiceHelper {
         r.setPublished(Boolean.parseBoolean(rec.published.text()));
         r.setStartTime(rec.start_time.text());
         r.setEndTime(rec.end_time.text());
+        r.setRawSize(rec.raw_size.text());
         if ( !rec.playback.text().equals("") ) {
             r.setPlaybackFormat(rec.playback.format.text());
             r.setPlaybackLink(rec.playback.link.text());
             r.setPlaybackDuration(rec.playback.duration.text());
+            r.setPlaybackSize(rec.playback.size.text());
+            r.setProcessingTime(rec.playback.processing_time.text());
         }
 
         //Add extensions
@@ -148,6 +170,15 @@ public class RecordingServiceHelperImp implements RecordingServiceHelper {
         }
         r.setPlaybackExtensions(extensions)
 
+        //Add download
+        if ( !rec.download.text().equals("") ) {
+            r.setDownloadFormat(rec.download.format.text());
+            r.setDownloadLink(rec.download.link.text());
+            r.setDownloadMd5(rec.download.md5.text());
+            r.setDownloadKey(rec.download.key.text());
+            r.setDownloadSize(rec.download.size.text());
+        }
+
         //Add metadata
         Map<String, String> meta = new HashMap<String, String>();
         rec.meta.children().each { anode ->
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java
index 71c537bf24952f0446bf6a874b3a41e69a6e6fc7..bf8b419f46b272c1aed031d4e86d7f96a2f90263 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/MeetingService.java
@@ -37,12 +37,14 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.LinkedBlockingQueue;
+import org.bigbluebutton.api.domain.Download;
 import org.bigbluebutton.api.domain.Meeting;
 import org.bigbluebutton.api.domain.Playback;
 import org.bigbluebutton.api.domain.Recording;
 import org.bigbluebutton.api.domain.User;
 import org.bigbluebutton.api.domain.UserSession;
 import org.bigbluebutton.api.messaging.MessageListener;
+import org.bigbluebutton.api.messaging.MessagingConstants;
 import org.bigbluebutton.api.messaging.MessagingService;
 import org.bigbluebutton.api.messaging.messages.CreateBreakoutRoom;
 import org.bigbluebutton.api.messaging.messages.CreateMeeting;
@@ -59,6 +61,7 @@ import org.bigbluebutton.api.messaging.messages.UserJoinedVoice;
 import org.bigbluebutton.api.messaging.messages.UserLeft;
 import org.bigbluebutton.api.messaging.messages.UserLeftVoice;
 import org.bigbluebutton.api.messaging.messages.UserListeningOnly;
+import org.bigbluebutton.api.messaging.messages.UserRoleChanged;
 import org.bigbluebutton.api.messaging.messages.UserSharedWebcam;
 import org.bigbluebutton.api.messaging.messages.UserStatusChanged;
 import org.bigbluebutton.api.messaging.messages.UserUnsharedWebcam;
@@ -114,9 +117,9 @@ public class MeetingService implements MessageListener {
 
     public void registerUser(String meetingID, String internalUserId,
             String fullname, String role, String externUserID,
-            String authToken, String avatarURL) {
+            String authToken, String avatarURL, String guest) {
         handle(new RegisterUser(meetingID, internalUserId, fullname, role,
-                externUserID, authToken, avatarURL));
+                externUserID, authToken, avatarURL, guest));
     }
 
     public UserSession getUserSession(String token) {
@@ -336,7 +339,7 @@ public class MeetingService implements MessageListener {
                 m.getTelVoice(), m.getDuration(), m.getAutoStartRecording(),
                 m.getAllowStartStopRecording(), m.getModeratorPassword(),
                 m.getViewerPassword(), m.getCreateTime(),
-                formatPrettyDate(m.getCreateTime()), m.isBreakout(), m.getSequence());
+                formatPrettyDate(m.getCreateTime()), m.isBreakout(), m.getSequence(), m.getMetadata());
     }
 
     private String formatPrettyDate(Long timestamp) {
@@ -350,7 +353,7 @@ public class MeetingService implements MessageListener {
     private void processRegisterUser(RegisterUser message) {
         messagingService.registerUser(message.meetingID,
                 message.internalUserId, message.fullname, message.role,
-                message.externUserID, message.authToken, message.avatarURL);
+                message.externUserID, message.authToken, message.avatarURL, message.guest);
     }
 
     public String addSubscription(String meetingId, String event,
@@ -435,22 +438,43 @@ public class MeetingService implements MessageListener {
                 if (r.getPlaybackFormat() != null) {
                     plays.add(new Playback(r.getPlaybackFormat(), r.getPlaybackLink(),
                             getDurationRecording(r.getPlaybackDuration(), r.getEndTime(),
-                            r.getStartTime()), r.getPlaybackExtensions()));
+                            r.getStartTime()), r.getPlaybackSize(), r.getProcessingTime(), r.getPlaybackExtensions()));
                 }
 
                 r.setPlaybacks(plays);
+
+                ArrayList<Download> downloads = new ArrayList<Download>();
+
+                if (r.getDownloadFormat() != null) {
+                    downloads.add(new Download(r.getDownloadFormat(), r.getDownloadLink(),
+                            r.getDownloadMd5(), r.getDownloadKey(),
+                            r.getDownloadSize(),
+                            getDurationRecording(r.getEndTime(), r.getStartTime())));
+                }
+                r.setDownloads(downloads);
+
                 map.put(r.getId(), r);
             } else {
                 Recording rec = map.get(r.getId());
-                rec.getPlaybacks().add(new Playback(r.getPlaybackFormat(), r.getPlaybackLink(),
-                                    getDurationRecording(r.getPlaybackDuration(), r.getEndTime(),
-                                    r.getStartTime()), r.getPlaybackExtensions()));
+                if (r.getPlaybackFormat() != null) {
+                    rec.getPlaybacks().add(new Playback(r.getPlaybackFormat(), r.getPlaybackLink(),
+                                        getDurationRecording(r.getPlaybackDuration(), r.getEndTime(), r.getStartTime()),
+                                        r.getPlaybackSize(), r.getProcessingTime(), r.getPlaybackExtensions()));
+                }
+                if (r.getDownloadFormat() != null) {
+                    rec.getDownloads().add(new Download(r.getDownloadFormat(), r.getDownloadLink(), r.getDownloadMd5(),
+                                        r.getDownloadKey(), r.getDownloadSize(), getDurationRecording(r.getEndTime(), r.getStartTime())));
+                }
             }
         }
 
         return map;
     }
 
+    private int getDurationRecording(String end, String start) {
+        return getDurationRecording("", end, start);
+    }
+
     private int getDurationRecording(String playbackDuration, String end,
             String start) {
         int duration;
@@ -476,17 +500,24 @@ public class MeetingService implements MessageListener {
 
     public void setPublishRecording(List<String> idList, boolean publish) {
         for (String id : idList) {
+            boolean success = false;
             if (publish) {
-                recordingService.changeState(id, Recording.STATE_PUBLISHED);
+                success = recordingService.changeState(id, Recording.STATE_PUBLISHED);
             } else {
-                recordingService.changeState(id, Recording.STATE_UNPUBLISHED);
+                success = recordingService.changeState(id, Recording.STATE_UNPUBLISHED);
+            }
+            if (success) {
+                log.debug("Publish recording operation succeeded for meeting {}", id);
             }
         }
     }
 
     public void deleteRecordings(List<String> idList) {
         for (String id : idList) {
-            recordingService.changeState(id, Recording.STATE_DELETED);
+            boolean success = recordingService.changeState(id, Recording.STATE_DELETED);
+            if (success) {
+                log.debug("Delete recording operation succeeded for meeting {}", id);
+            }
         }
     }
 
@@ -568,7 +599,9 @@ public class MeetingService implements MessageListener {
 
     private void processEndMeeting(EndMeeting message) {
         messagingService.endMeeting(message.meetingId);
+    }
 
+    private void processRemoveEndedMeeting(MeetingEnded message) {
         Meeting m = getMeeting(message.meetingId);
         if (m != null) {
             m.setForciblyEnded(true);
@@ -680,6 +713,8 @@ public class MeetingService implements MessageListener {
 
             log.info("Meeting destroyed: data={}", logStr);
 
+            processRemoveEndedMeeting(message);
+
             return;
         }
     }
@@ -694,7 +729,7 @@ public class MeetingService implements MessageListener {
             }
 
             User user = new User(message.userId, message.externalUserId,
-                    message.name, message.role, message.avatarURL);
+                    message.name, message.role, message.avatarURL, message.guest, message.waitingForAcceptance);
             m.userJoined(user);
 
             Map<String, Object> logData = new HashMap<String, Object>();
@@ -705,8 +740,10 @@ public class MeetingService implements MessageListener {
             logData.put("externalUserId", user.getExternalUserId());
             logData.put("username", user.getFullname());
             logData.put("role", user.getRole());
-            logData.put("event", "user_joined_message");
-            logData.put("description", "User had joined the meeting.");
+            logData.put("guest", user.isGuest());
+            logData.put("waitingForAcceptance", user.isWaitingForAcceptance());
+            logData.put("event", MessagingConstants.USER_JOINED_EVENT);
+            logData.put("description", "User joined the meeting.");
 
             Gson gson = new Gson();
             String logStr = gson.toJson(logData);
@@ -731,8 +768,10 @@ public class MeetingService implements MessageListener {
                 logData.put("externalUserId", user.getExternalUserId());
                 logData.put("username", user.getFullname());
                 logData.put("role", user.getRole());
-                logData.put("event", "user_left_message");
-                logData.put("description", "User had left the meeting.");
+                logData.put("guest", user.isGuest());
+                logData.put("waitingForAcceptance", user.isWaitingForAcceptance());
+                logData.put("event", MessagingConstants.USER_LEFT_EVENT);
+                logData.put("description", "User left the meeting.");
 
                 Gson gson = new Gson();
                 String logStr = gson.toJson(logData);
@@ -863,6 +902,21 @@ public class MeetingService implements MessageListener {
         }
     }
 
+    private void userRoleChanged(UserRoleChanged message) {
+        Meeting m = getMeeting(message.meetingId);
+        if (m != null) {
+            User user = m.getUserById(message.userId);
+            if(user != null){
+                user.setRole(message.role);
+                log.debug("Setting new role in meeting " + message.meetingId + " for participant:" + user.getFullname());
+                return;
+            }
+            log.warn("The participant " + message.userId + " doesn't exist in the meeting " + message.meetingId);
+            return;
+        }
+        log.warn("The meeting " + message.meetingId + " doesn't exist");
+    }
+
     private void processMessage(final IMessage message) {
         Runnable task = new Runnable() {
             public void run() {
@@ -878,6 +932,8 @@ public class MeetingService implements MessageListener {
                     userLeft((UserLeft) message);
                 } else if (message instanceof UserStatusChanged) {
                     updatedStatus((UserStatusChanged) message);
+                } else if (message instanceof UserRoleChanged) {
+                    userRoleChanged((UserRoleChanged)message);
                 } else if (message instanceof UserJoinedVoice) {
                     userJoinedVoice((UserJoinedVoice) message);
                 } else if (message instanceof UserLeftVoice) {
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/ParamsProcessorUtil.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/ParamsProcessorUtil.java
index be29faa84fef1c75d9840b5546172c82ddb7e683..89398c145887f91791848519692beaf471394fae 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/ParamsProcessorUtil.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/ParamsProcessorUtil.java
@@ -74,11 +74,12 @@ public class ParamsProcessorUtil {
     private String substituteKeywords(String message, String dialNumber, String telVoice, String meetingName) {
         String welcomeMessage = message;
 
+        String SERVER_URL = "%%SERVERURL%%";
         String DIAL_NUM = "%%DIALNUM%%";
         String CONF_NUM = "%%CONFNUM%%";
         String CONF_NAME = "%%CONFNAME%%";
         ArrayList<String> keywordList = new ArrayList<String>();
-        keywordList.add(DIAL_NUM);keywordList.add(CONF_NUM);keywordList.add(CONF_NAME);
+        keywordList.add(DIAL_NUM);keywordList.add(CONF_NUM);keywordList.add(CONF_NAME);keywordList.add(SERVER_URL);
 
         Iterator<String> itr = keywordList.iterator();
         while(itr.hasNext()) {
@@ -89,6 +90,8 @@ public class ParamsProcessorUtil {
                 welcomeMessage = welcomeMessage.replaceAll(CONF_NUM, telVoice);
             } else if (keyword.equals(CONF_NAME)) {
                 welcomeMessage = welcomeMessage.replaceAll(CONF_NAME, meetingName);
+            } else if (keyword.equals(SERVER_URL)) {
+                welcomeMessage = welcomeMessage.replaceAll(SERVER_URL, defaultServerUrl);
             }
         }
         return  welcomeMessage;
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/RecordingService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/RecordingService.java
index 8f0a2162e24dd4f131289823d0d2db775a964f72..68e060fc5c06360e04f47f74b37f0d1896368f46 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/RecordingService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/RecordingService.java
@@ -34,6 +34,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.bigbluebutton.api.domain.Recording;
+import org.bigbluebutton.api.messaging.MessagingService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -45,6 +46,7 @@ public class RecordingService {
     private String unpublishedDir = "/var/bigbluebutton/unpublished";
     private String deletedDir = "/var/bigbluebutton/deleted";
     private RecordingServiceHelper recordingServiceHelper;
+    private MessagingService messagingService;
     private String recordStatusDir;
 
     public void startIngestAndProcessing(String meetingId) {
@@ -295,22 +297,25 @@ public class RecordingService {
         return r;
     }
 
-    public void changeState(String recordingId, String state) {
+    public boolean changeState(String recordingId, String state) {
+        boolean anyResult = false;
         if (state.equals(Recording.STATE_PUBLISHED)) {
             // It can only be published if it is unpublished
-            changeState(unpublishedDir, recordingId, state);
+            anyResult |= changeState(unpublishedDir, recordingId, state);
         } else if (state.equals(Recording.STATE_UNPUBLISHED)) {
             // It can only be unpublished if it is published
-            changeState(publishedDir, recordingId, state);
+            anyResult |= changeState(publishedDir, recordingId, state);
         } else if (state.equals(Recording.STATE_DELETED)) {
             // It can be deleted from any state
-            changeState(publishedDir, recordingId, state);
-            changeState(unpublishedDir, recordingId, state);
+            anyResult |= changeState(publishedDir, recordingId, state);
+            anyResult |= changeState(unpublishedDir, recordingId, state);
         }
+        return anyResult;
     }
 
-    private void changeState(String path, String recordingId, String state) {
+    private boolean changeState(String path, String recordingId, String state) {
         String[] format = getPlaybackFormats(path);
+        boolean anyResult = false;
         for (int i = 0; i < format.length; i++) {
             List<File> recordings = getDirectories(path + File.separatorChar + format[i]);
             for (int f = 0; f < recordings.size(); f++) {
@@ -326,7 +331,7 @@ public class RecordingService {
                             dest = new File(deletedDir + File.separatorChar + format[i]);
                         } else {
                             log.debug(String.format("State: %s, is not supported", state));
-                            return;
+                            return anyResult;
                         }
                         if (!dest.exists())
                             dest.mkdirs();
@@ -340,14 +345,30 @@ public class RecordingService {
                                 deleteRecording(recordingId, deletedDir);
                             }
                             recordingServiceHelper.writeRecordingInfo(dest.getAbsolutePath() + File.separatorChar + recordings.get(f).getName(), r);
+                            sendRedisEvent(r.getId(), r.getId(), r.getExternalMeetingId(), format[i], state);
                             log.debug(String.format("Recording successfully %s!", state));
                         } else {
                             log.debug("Recording was not moved");
                         }
+                        anyResult |= moved;
                     }
                 }
             }
         }
+        return anyResult;
+    }
+
+    private void sendRedisEvent(String recordId, String meetingId, String externalMeetingId, String format, String state) {
+        log.debug("Sending Redis event for meeting {} {}", meetingId, format);
+        if (state.equals(Recording.STATE_PUBLISHED)) {
+            messagingService.publishRecording(recordId, meetingId, externalMeetingId, format, true);
+        } else if (state.equals(Recording.STATE_UNPUBLISHED)) {
+            messagingService.publishRecording(recordId, meetingId, externalMeetingId, format, false);
+        } else if (state.equals(Recording.STATE_DELETED)) {
+            messagingService.deleteRecording(recordId, meetingId, externalMeetingId, format);
+        } else {
+            log.debug("No event for {}", state);
+        }
     }
 
     private List<File> getAllDirectories(String state) {
@@ -471,4 +492,7 @@ public class RecordingService {
         return baseDir;
     }
 
+    public void setMessagingService(MessagingService service) {
+        messagingService = service;
+    }
 }
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/Util.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/Util.java
index 3f6548afdfbff56075a0d904e86c0169e28c4dbf..0d7d543f68de83e7de6aa966778fee9436164982 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/Util.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/Util.java
@@ -23,4 +23,12 @@ public final class Util {
 		}
 		return null;
 	}
+
+	public static File downloadPresentationDirectory(String uploadDirectory) {
+		File dir = new File(uploadDirectory + File.separatorChar + "download");
+		if (dir.mkdirs()) {
+			return dir;
+		}
+		return null;
+	}
 }
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Download.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Download.java
new file mode 100755
index 0000000000000000000000000000000000000000..1ab2943824a356724285b1b3c003c94d9432f0e2
--- /dev/null
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Download.java
@@ -0,0 +1,55 @@
+package org.bigbluebutton.api.domain;
+
+public class Download {
+	private String format;
+	private String url;
+	private int length;
+	private String md5;
+	private String key;
+	private String size;
+	public Download(String format, String url, String md5, String key, String size, int length) {
+		this.format = format;
+		this.url = url;
+		this.length = length;
+		this.md5 = md5;
+		this.size = size;
+		this.key = key;
+	}
+	public String getFormat() {
+		return format;
+	}
+	public void setFormat(String format) {
+		this.format = format;
+	}
+	public String getUrl() {
+		return url;
+	}
+	public void setUrl(String url) {
+		this.url = url;
+	}
+	public int getLength() {
+		return length;
+	}
+	public void setLength(int length) {
+		this.length = length;
+	}
+	public void setMd5(String md5) {
+		this.md5 = md5;
+	}
+	public String getMd5() {
+		return md5;
+	}
+	public void setSize(String size) {
+		this.size = size;
+	}
+	public String getSize() {
+		return size;
+	}
+	public void setKey(String key) {
+		this.key = key;
+	}
+	public String getKey() {
+		return key;
+	}
+
+}
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Playback.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Playback.java
index 73f281ef389ed652045b534158a6a9bf977efd98..49823bc14086b06d0eb88deaf0ab12ac262e05c8 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Playback.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Playback.java
@@ -25,12 +25,16 @@ public class Playback {
 	private String format;
 	private String url;
 	private int length;
+	private String size;
+	private String processingTime;
 	private List<Extension> extensions;
 	
-	public Playback(String format, String url, int length, List<Extension> extensions) {
+	public Playback(String format, String url, int length, String size, String processingTime, List<Extension> extensions) {
 		this.format = format;
 		this.url = url;
 		this.length = length;
+		this.size = size;
+		this.processingTime = processingTime;
 		this.extensions = extensions;
 	}
 	public String getFormat() {
@@ -51,6 +55,18 @@ public class Playback {
 	public void setLength(int length) {
 		this.length = length;
 	}
+	public String getSize() {
+		return size;
+	}
+	public void setSize(String size) {
+		this.size = size;
+	}
+	public String getProcessingTime() {
+		return processingTime;
+	}
+	public void setProcessingTime(String processingTime) {
+		this.processingTime = processingTime;
+	}
 	public List<Extension> getExtensions() {
 		return extensions;
 	}
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Recording.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Recording.java
index a406111da09662269f9890fca2d69b08ca0ffac4..32498e388b127f7dada5b96da233659c4d25271c 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Recording.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/Recording.java
@@ -19,6 +19,7 @@
 
 package org.bigbluebutton.api.domain;
 
+import java.math.BigInteger;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -34,16 +35,26 @@ public class Recording {
 	private boolean published;
 	private String startTime;
 	private String endTime;
+	private String rawSize;
 	private Map<String, String> metadata = new TreeMap<String, String>();
 	private List<Playback> playbacks=new ArrayList<Playback>();
+	private ArrayList<Download> downloads=new ArrayList<Download>();
 	
 	//TODO: 
 	private String state;
 	private String playbackLink;
 	private String playbackFormat;
 	private String playbackDuration;
+	private String playbackSize;
+	private String processingTime;
 	private List<Extension> playbackExtensions;
 
+	private String downloadLink;
+	private String downloadFormat;
+	private String downloadMd5;
+	private String downloadKey;
+	private String downloadSize;
+
 	public static final String STATE_PROCESSING = "processing";
 	public static final String STATE_PROCESSED = "processed";
 	public static final String STATE_PUBLISING = "publishing";
@@ -97,6 +108,69 @@ public class Recording {
 		this.endTime = convertOldDateFormat(endTime);
 	}
 	
+	public String getSize() {
+		BigInteger size = BigInteger.ZERO;
+		for (Playback p: playbacks) {
+			if (p.getSize().length() > 0) {
+				size = size.add(new BigInteger(p.getSize()));
+			}
+		}
+		for (Download p: downloads) {
+			if (p.getSize().length() > 0) {
+				size = size.add(new BigInteger(p.getSize()));
+			}
+		}
+		return size.toString();
+	}
+
+	public String getRawSize() {
+		return rawSize;
+	}
+
+	public void setRawSize(String rawSize) {
+		this.rawSize = rawSize;
+	}
+
+	public String getDownloadLink() {
+		return downloadLink;
+	}
+
+	public void setDownloadLink(String downloadLink) {
+		this.downloadLink = downloadLink;
+	}
+
+	public String getDownloadFormat() {
+		return downloadFormat;
+	}
+
+	public void setDownloadFormat(String downloadFormat) {
+		this.downloadFormat = downloadFormat;
+	}
+
+	public String getDownloadMd5() {
+		return downloadMd5;
+	}
+
+	public void setDownloadMd5(String downloadMd5) {
+		this.downloadMd5 = downloadMd5;
+	}
+
+	public String getDownloadKey() {
+		return downloadKey;
+	}
+
+	public void setDownloadKey(String downloadKey) {
+		this.downloadKey = downloadKey;
+	}
+
+	public String getDownloadSize() {
+		return downloadSize;
+	}
+
+	public void setDownloadSize(String downloadSize) {
+		this.downloadSize = downloadSize;
+	}
+
 	public String getPlaybackLink() {
 		return playbackLink;
 	}
@@ -121,6 +195,22 @@ public class Recording {
 		this.playbackDuration = playbackDuration;
 	}
 
+	public String getPlaybackSize() {
+		return playbackSize;
+	}
+
+	public void setPlaybackSize(String playbackSize) {
+		this.playbackSize = playbackSize;
+	}
+
+	public String getProcessingTime() {
+		return processingTime;
+	}
+
+	public void setProcessingTime(String processingTime) {
+		this.processingTime = processingTime;
+	}
+
 	public List<Extension> getPlaybackExtensions() {
 		return playbackExtensions;
 	}
@@ -169,6 +259,14 @@ public class Recording {
 		this.name = name;
 	}
 
+	public ArrayList<Download> getDownloads() {
+		return downloads;
+	}
+
+	public void setDownloads(ArrayList<Download> downloads) {
+		this.downloads = downloads;
+	}
+
 	public List<Playback> getPlaybacks() {
 		return playbacks;
 	}
@@ -199,6 +297,18 @@ public class Recording {
 		return newdate;
 	}
 	
+	public String getExternalMeetingId() {
+		String externalMeetingId = null;
+		if (this.metadata != null) {
+			externalMeetingId = this.metadata.get("meetingId");
+		}
+
+		if (externalMeetingId != null) {
+			return externalMeetingId;
+		} else {
+			return "";
+		}
+	}
 }
 
 /*
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/User.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/User.java
index 3f022263aca21822415688d1d1ac212d77704a90..03b90f12d672582c5fb629d32de1e0453473cb42 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/User.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/User.java
@@ -32,16 +32,20 @@ public class User {
 	private String role;
 	private String avatarURL;
 	private Map<String,String> status;
+	private Boolean guest;
+	private Boolean waitingForAcceptance;
 	private Boolean listeningOnly = false;
 	private Boolean voiceJoined = false;
 	private List<String> streams;
 	
-	public User(String internalUserId, String externalUserId, String fullname, String role, String avatarURL) {
+	public User(String internalUserId, String externalUserId, String fullname, String role, String avatarURL, Boolean guest, Boolean waitingForAcceptance) {
 		this.internalUserId = internalUserId;
 		this.externalUserId = externalUserId;
 		this.fullname = fullname;
 		this.role = role;
 		this.avatarURL = avatarURL;
+		this.guest = guest;
+		this.waitingForAcceptance = waitingForAcceptance;
 		this.status = new ConcurrentHashMap<String, String>();
 		this.streams = Collections.synchronizedList(new ArrayList<String>());
 	}
@@ -60,6 +64,22 @@ public class User {
 	public void setExternalUserId(String externalUserId){
 		this.externalUserId = externalUserId;
 	}
+
+	public void setGuest(Boolean guest) {
+		this.guest = guest;
+	}
+
+	public Boolean isGuest() {
+		return this.guest;
+	}
+
+	public void setWaitingForAcceptance(Boolean waitingForAcceptance) {
+		this.waitingForAcceptance = waitingForAcceptance;
+	}
+
+	public Boolean isWaitingForAcceptance() {
+		return this.waitingForAcceptance;
+	}
 	
 	public String getFullname() {
 		return fullname;
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/UserSession.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/UserSession.java
index 346b9ecb95aa01e9365d158aaf2e766c7260c9a7..b642f0269e1eaace3da61978c1869d6b053d1ac8 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/UserSession.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/domain/UserSession.java
@@ -32,6 +32,7 @@ public class UserSession {
   public String role = null;
   public String conference = null;
   public String room = null;
+  public String guest = "false";
   public String voicebridge = null;
   public String webvoiceconf = null;
   public String mode = null;
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/Constants.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/Constants.java
index fed0e687c05c3553bd455e31ac2e8829721d0027..3d6d3cd84ff23d777d2a714455574f774f62cb41 100644
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/Constants.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/Constants.java
@@ -93,4 +93,9 @@ public class Constants {
   public static final String CREATE_TIME                     = "create_time";
   public static final String CREATE_DATE                     = "create_date";
   public static final String AVATAR_URL                      = "avatarURL";
+  public static final String GUEST                           = "guest";
+  public static final String WAITING_FOR_ACCEPTANCE          = "waiting_for_acceptance";
+  public static final String FORMAT                          = "format";
+  public static final String RECORD_ID                       = "record_id";
+  public static final String METADATA                        = "metadata";
 }
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java
index 9bfd168087ef0de3c6559bed909a0e07cc3ed8fc..de0a2f86add29e6a6e14334b81f72521c98cf084 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MeetingMessageHandler.java
@@ -14,6 +14,7 @@ import org.bigbluebutton.api.messaging.messages.UserJoinedVoice;
 import org.bigbluebutton.api.messaging.messages.UserLeft;
 import org.bigbluebutton.api.messaging.messages.UserLeftVoice;
 import org.bigbluebutton.api.messaging.messages.UserListeningOnly;
+import org.bigbluebutton.api.messaging.messages.UserRoleChanged;
 import org.bigbluebutton.api.messaging.messages.UserSharedWebcam;
 import org.bigbluebutton.api.messaging.messages.UserStatusChanged;
 import org.bigbluebutton.api.messaging.messages.UserUnsharedWebcam;
@@ -131,8 +132,10 @@ public class MeetingMessageHandler implements MessageHandler {
             String username = user.get("name").getAsString();
             String role = user.get("role").getAsString();
             String avatarURL = user.get("avatarURL").getAsString();
+            Boolean guest = user.get("guest").getAsBoolean();
+            Boolean waitingForAcceptance = user.get("waiting_for_acceptance").getAsBoolean();
             for (MessageListener listener : listeners) {
-              listener.handle(new UserJoined(meetingId, userid, externuserid, username, role, avatarURL));
+              listener.handle(new UserJoined(meetingId, userid, externuserid, username, role, avatarURL, guest, waitingForAcceptance));
             }
           } else if(MessagingConstants.USER_STATUS_CHANGE_EVENT.equalsIgnoreCase(messageName)) {
             String meetingId = payload.get("meeting_id").getAsString();
@@ -184,6 +187,13 @@ public class MeetingMessageHandler implements MessageHandler {
             for (MessageListener listener : listeners) {
               listener.handle(new UserUnsharedWebcam(meetingId, userid, stream));
             }
+          } else if (MessagingConstants.USER_ROLE_CHANGE_EVENT.equalsIgnoreCase(messageName)) {
+            String meetingId = payload.get("meeting_id").getAsString();
+            String userid = payload.get("userid").getAsString();
+            String role = payload.get("role").getAsString();
+            for (MessageListener listener : listeners) {
+              listener.handle(new UserRoleChanged(meetingId, userid, role));
+            }
           } else if (SendStunTurnInfoRequestMessage.SEND_STUN_TURN_INFO_REQUEST_MESSAGE.equalsIgnoreCase(messageName)) {
             String meetingId = payload.get(Constants.MEETING_ID).getAsString();
             String requesterId = payload.get(Constants.REQUESTER_ID).getAsString();
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessageToJson.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessageToJson.java
index 98649191b5de42c2eff49fd58c3ff82391e57d09..cd885190f5a3f0cc536398b29cc22e7b08c55767 100644
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessageToJson.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessageToJson.java
@@ -7,6 +7,9 @@ import org.bigbluebutton.api.messaging.converters.messages.DestroyMeetingMessage
 import org.bigbluebutton.api.messaging.converters.messages.EndMeetingMessage;
 import org.bigbluebutton.api.messaging.converters.messages.KeepAliveMessage;
 import org.bigbluebutton.api.messaging.converters.messages.RegisterUserMessage;
+import org.bigbluebutton.api.messaging.converters.messages.PublishRecordingMessage;
+import org.bigbluebutton.api.messaging.converters.messages.UnpublishRecordingMessage;
+import org.bigbluebutton.api.messaging.converters.messages.DeleteRecordingMessage;
 
 public class MessageToJson {
 
@@ -19,6 +22,7 @@ public class MessageToJson {
 		payload.put(Constants.EXT_USER_ID, message.externUserID);
 		payload.put(Constants.AUTH_TOKEN, message.authToken);
 		payload.put(Constants.AVATAR_URL, message.avatarURL);
+		payload.put(Constants.GUEST, message.guest);
 		
 		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(RegisterUserMessage.REGISTER_USER, message.VERSION, null);
 
@@ -39,6 +43,7 @@ public class MessageToJson {
 		payload.put(Constants.VIEWER_PASS, msg.viewerPass);
 		payload.put(Constants.CREATE_TIME, msg.createTime);
 		payload.put(Constants.CREATE_DATE, msg.createDate);
+		payload.put(Constants.METADATA, msg.metadata);
 		
 		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(CreateMeetingMessage.CREATE_MEETING_REQUEST_EVENT, CreateMeetingMessage.VERSION, null);
 		return MessageBuilder.buildJson(header, payload);				
@@ -68,5 +73,37 @@ public class MessageToJson {
 		return MessageBuilder.buildJson(header, payload);				
 	}	
 	
+	public static String publishRecordingMessageToJson(PublishRecordingMessage message) {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.RECORD_ID, message.recordId);
+		payload.put(Constants.MEETING_ID, message.meetingId);
+		payload.put(Constants.EXTERNAL_MEETING_ID, message.externalMeetingId);
+		payload.put(Constants.FORMAT, message.format);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(PublishRecordingMessage.PUBLISH_RECORDING, PublishRecordingMessage.VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static String unpublishRecordingMessageToJson(UnpublishRecordingMessage message) {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.RECORD_ID, message.recordId);
+		payload.put(Constants.MEETING_ID, message.meetingId);
+		payload.put(Constants.EXTERNAL_MEETING_ID, message.externalMeetingId);
+		payload.put(Constants.FORMAT, message.format);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(UnpublishRecordingMessage.UNPUBLISH_RECORDING, UnpublishRecordingMessage.VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
+
+	public static String deleteRecordingMessageToJson(DeleteRecordingMessage message) {
+		HashMap<String, Object> payload = new HashMap<String, Object>();
+		payload.put(Constants.RECORD_ID, message.recordId);
+		payload.put(Constants.MEETING_ID, message.meetingId);
+		payload.put(Constants.EXTERNAL_MEETING_ID, message.externalMeetingId);
+		payload.put(Constants.FORMAT, message.format);
+
+		java.util.HashMap<String, Object> header = MessageBuilder.buildHeader(DeleteRecordingMessage.DELETE_RECORDING, DeleteRecordingMessage.VERSION, null);
+		return MessageBuilder.buildJson(header, payload);
+	}
 	
 }
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java
index a57cf06c6dd4be4d87531ae8610766b0eab8dac0..bc6d736956efb18b797c4d20e6b1510f992e7da2 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingConstants.java
@@ -52,6 +52,7 @@ public class MessagingConstants {
 	public static final String USER_LISTEN_ONLY_EVENT        = "user_listening_only";
 	public static final String USER_SHARE_WEBCAM_EVENT       = "user_shared_webcam_message";
 	public static final String USER_UNSHARE_WEBCAM_EVENT     = "user_unshared_webcam_message";
+	public static final String USER_ROLE_CHANGE_EVENT        = "user_role_changed_message";
 			
 	public static final String SEND_POLLS_EVENT = "SendPollsEvent";
 	public static final String KEEP_ALIVE_REPLY = "keep_alive_reply";
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingService.java
index b665c9b3984642d28a63d84d3070d5ea48e99779..40f93f0139dab454df95922088207641bf95a341 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/MessagingService.java
@@ -34,14 +34,13 @@ public interface MessagingService {
             String voiceBridge, Integer duration, Boolean autoStartRecording,
             Boolean allowStartStopRecording, String moderatorPass,
             String viewerPass, Long createTime, String createDate,
-            Boolean isBreakout, Integer sequence);
+            Boolean isBreakout, Integer sequence, Map<String, String> metadata);
 	void endMeeting(String meetingId);
 	void send(String channel, String message);
 	void sendPolls(String meetingId, String title, String question, String questionType, List<String> answers);
-	String storeSubscription(String meetingId, String externalMeetingID, String callbackURL);
-	boolean removeSubscription(String meetingId, String subscriptionId);
-	List<Map<String,String>> listSubscriptions(String meetingId);
-	void registerUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken, String avatarURL);
+	void registerUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken, String avatarURL, String guest);
 	void sendKeepAlive(String system, Long timestamp);
 	void sendStunTurnInfo(String meetingId, String internalUserId, Set<StunServer> stuns, Set<TurnEntry> turns);
+	void publishRecording(String recordId, String meetingId, String externalMeetingId, String format, boolean publish);
+	void deleteRecording(String recordId, String meetingId, String externalMeetingId, String format);
 }
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisMessagingService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisMessagingService.java
index 4d4d4e75d66b700e74c449d5a3382446f2ab1303..5c35d7fe2731901cfea671d3818d7bd9ad686371 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisMessagingService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisMessagingService.java
@@ -29,6 +29,9 @@ import java.util.Set;
 import org.bigbluebutton.api.messaging.converters.messages.DestroyMeetingMessage;
 import org.bigbluebutton.api.messaging.converters.messages.EndMeetingMessage;
 import org.bigbluebutton.api.messaging.converters.messages.RegisterUserMessage;
+import org.bigbluebutton.api.messaging.converters.messages.PublishRecordingMessage;
+import org.bigbluebutton.api.messaging.converters.messages.UnpublishRecordingMessage;
+import org.bigbluebutton.api.messaging.converters.messages.DeleteRecordingMessage;
 import org.bigbluebutton.common.converters.ToJsonEncoder;
 import org.bigbluebutton.common.messages.Constants;
 import org.bigbluebutton.common.messages.MessagingConstants;
@@ -60,8 +63,8 @@ public class RedisMessagingService implements MessagingService {
 		sender.send(MessagingConstants.TO_MEETING_CHANNEL, json);	
 	}
 	
-	public void registerUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken, String avatarURL) {
-		RegisterUserMessage msg = new RegisterUserMessage(meetingID, internalUserId, fullname, role, externUserID, authToken, avatarURL);
+	public void registerUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken, String avatarURL, String guest) {
+		RegisterUserMessage msg = new RegisterUserMessage(meetingID, internalUserId, fullname, role, externUserID, authToken, avatarURL, guest);
 		String json = MessageToJson.registerUserToJson(msg);
 		log.info("Sending register user message to bbb-apps:[{}]", json);
 		sender.send(MessagingConstants.TO_MEETING_CHANNEL, json);		
@@ -72,12 +75,12 @@ public class RedisMessagingService implements MessagingService {
             String voiceBridge, Integer duration, Boolean autoStartRecording,
             Boolean allowStartStopRecording, String moderatorPass,
             String viewerPass, Long createTime, String createDate,
-            Boolean isBreakout, Integer sequence) {
+            Boolean isBreakout, Integer sequence, Map<String, String> metadata) {
         CreateMeetingRequestPayload payload = new CreateMeetingRequestPayload(
                 meetingID, externalMeetingID, parentMeetingID, meetingName,
                 recorded, voiceBridge, duration, autoStartRecording,
                 allowStartStopRecording, moderatorPass, viewerPass, createTime,
-                createDate, isBreakout, sequence);
+                createDate, isBreakout, sequence, metadata);
         CreateMeetingRequest msg = new CreateMeetingRequest(payload);
 
         Gson gson = new Gson();
@@ -124,20 +127,34 @@ public class RedisMessagingService implements MessagingService {
   	this.storeService = storeService;
   }
   
-	public String storeSubscription(String meetingId, String externalMeetingID, String callbackURL){
-		return storeService.storeSubscription(meetingId, externalMeetingID, callbackURL);
+	public void removeMeeting(String meetingId){
+		storeService.removeMeeting(meetingId);
 	}
 
-	public boolean removeSubscription(String meetingId, String subscriptionId){
-		return storeService.removeSubscription(meetingId, subscriptionId);
+	private void publishRecording(String recordId, String meetingId, String externalMeetingId, String format) {
+		PublishRecordingMessage msg = new PublishRecordingMessage(recordId, meetingId, externalMeetingId, format);
+		String json = MessageToJson.publishRecordingMessageToJson(msg);
+		sender.send(MessagingConstants.FROM_BBB_RECORDING_CHANNEL, json);
 	}
 
-	public List<Map<String,String>> listSubscriptions(String meetingId){
-		return storeService.listSubscriptions(meetingId);	
-	}	
+	private void unpublishRecording(String recordId, String meetingId, String externalMeetingId, String format) {
+		UnpublishRecordingMessage msg = new UnpublishRecordingMessage(recordId, meetingId, externalMeetingId, format);
+		String json = MessageToJson.unpublishRecordingMessageToJson(msg);
+		sender.send(MessagingConstants.FROM_BBB_RECORDING_CHANNEL, json);
+	}
 
-	public void removeMeeting(String meetingId){
-		storeService.removeMeeting(meetingId);
+	public void publishRecording(String recordId, String meetingId, String externalMeetingId, String format, boolean publish) {
+		if (publish) {
+			publishRecording(recordId, meetingId, externalMeetingId, format);
+		} else {
+			unpublishRecording(recordId, meetingId, externalMeetingId, format);
+		}
+	}
+
+	public void deleteRecording(String recordId, String meetingId, String externalMeetingId, String format) {
+		DeleteRecordingMessage msg = new DeleteRecordingMessage(recordId, meetingId, externalMeetingId, format);
+		String json = MessageToJson.deleteRecordingMessageToJson(msg);
+		sender.send(MessagingConstants.FROM_BBB_RECORDING_CHANNEL, json);
 	}
 
 	public void sendStunTurnInfo(String meetingId, String internalUserId, Set<StunServer> stuns, Set<TurnEntry> turns) {
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisStorageService.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisStorageService.java
index f27a34d9b928dfee9f95f22d1e0935f1de55b33d..4971af07ad5fc42322dea0ab79f0ae5f82f3d091 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisStorageService.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/RedisStorageService.java
@@ -65,65 +65,6 @@ public class RedisStorageService {
 		}
 	}
 	
-	public List<Map<String,String>> listSubscriptions(String meetingId){
-		List<Map<String,String>> list = new ArrayList<Map<String,String>>();
-		Jedis jedis = redisPool.getResource();
-		try {
-			List<String> sids = jedis.lrange("meeting:" + meetingId + ":subscriptions", 0 , -1);
-			for(int i=0; i<sids.size(); i++){
-				Map<String,String> props = jedis.hgetAll("meeting:" + meetingId + ":subscription:" + sids.get(i));
-				list.add(props);	
-			}
-				
-		} catch (Exception e){
-			log.warn("Cannot list subscriptions:" + meetingId, e);
-		} finally {
-			jedis.close();
-		}
-
-		return list;	
-	}	
-	
-	public boolean removeSubscription(String meetingId, String subscriptionId){
-		boolean unsubscribed = true;
-		Jedis jedis = redisPool.getResource();
-		try {
-			jedis.hset("meeting:" + meetingId + ":subscription:" + subscriptionId, "active", "false");	
-		} catch (Exception e){
-			log.warn("Cannot rmove subscription:" + meetingId, e);
-			unsubscribed = false;
-		} finally {
-			jedis.close();
-		}
-
-		return unsubscribed; 	
-	}
-	
-	public String storeSubscription(String meetingId, String externalMeetingID, String callbackURL){
-		String sid = "";
-		Jedis jedis = redisPool.getResource();
-		try {
-			sid = Long.toString(jedis.incr("meeting:" + meetingId + ":nextSubscription"));
-
-			HashMap<String,String> props = new HashMap<String,String>();
-			props.put("subscriptionID", sid);
-			props.put("meetingId", meetingId);
-			props.put("externalMeetingID", externalMeetingID);
-			props.put("callbackURL", callbackURL);
-			props.put("active", "true");
-
-			jedis.hmset("meeting:" + meetingId + ":subscription:" + sid, props);
-			jedis.rpush("meeting:" + meetingId + ":subscriptions", sid);
-			
-		} catch (Exception e){
-			log.warn("Cannot store subscription:" + meetingId, e);
-		} finally {
-			jedis.close();
-		}
-
-		return sid; 	
-	}
-	
 	public void setHost(String host){
 		this.host = host;
 	}
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/CreateMeetingMessage.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/CreateMeetingMessage.java
index 7c747034e50785b1765e553bc128cb7b7b856bc8..7e3aaa7b6e8631194bb29799d5f003f2900f98f5 100644
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/CreateMeetingMessage.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/CreateMeetingMessage.java
@@ -1,5 +1,6 @@
 package org.bigbluebutton.api.messaging.converters.messages;
 
+import java.util.Map;
 
 public class CreateMeetingMessage {
 	public static final String CREATE_MEETING_REQUEST_EVENT  = "create_meeting_request";
@@ -17,12 +18,13 @@ public class CreateMeetingMessage {
 	public final String viewerPass;
 	public final Long createTime;
 	public final String createDate;
+	public final Map<String, String> metadata;
 	
 	public CreateMeetingMessage(String id, String externalId, String name, Boolean record, 
 						String voiceBridge, Long duration, 
 						Boolean autoStartRecording, Boolean allowStartStopRecording,
 						String moderatorPass, String viewerPass, Long createTime,
-						String createDate) {
+						String createDate, Map<String, String> metadata) {
 		this.id = id;
 		this.externalId = externalId;
 		this.name = name;
@@ -35,5 +37,6 @@ public class CreateMeetingMessage {
 		this.viewerPass = viewerPass;
 		this.createTime = createTime;
 		this.createDate = createDate;
+		this.metadata = metadata;
 	}
 }
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/DeleteRecordingMessage.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/DeleteRecordingMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc79d97e64b6c49f5fa1bf0d862e2d09a01261d3
--- /dev/null
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/DeleteRecordingMessage.java
@@ -0,0 +1,18 @@
+package org.bigbluebutton.api.messaging.converters.messages;
+
+public class DeleteRecordingMessage {
+	public static final String DELETE_RECORDING = "deleted";
+	public static final String VERSION = "0.0.1";
+
+	public final String recordId;
+	public final String meetingId;
+	public final String externalMeetingId;
+	public final String format;
+
+	public DeleteRecordingMessage(String recordId, String meetingId, String externalMeetingId, String format) {
+		this.recordId = recordId;
+		this.meetingId = meetingId;
+		this.externalMeetingId = externalMeetingId;
+		this.format = format;
+	}
+}
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/PublishRecordingMessage.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/PublishRecordingMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..509679ea7ef30cbb9b0cf02600a4b6180e4e79dd
--- /dev/null
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/PublishRecordingMessage.java
@@ -0,0 +1,18 @@
+package org.bigbluebutton.api.messaging.converters.messages;
+
+public class PublishRecordingMessage {
+	public static final String PUBLISH_RECORDING = "published";
+	public static final String VERSION = "0.0.1";
+
+	public final String recordId;
+	public final String meetingId;
+	public final String externalMeetingId;
+	public final String format;
+
+	public PublishRecordingMessage(String recordId, String meetingId, String externalMeetingId, String format) {
+		this.recordId = recordId;
+		this.meetingId = meetingId;
+		this.externalMeetingId = externalMeetingId;
+		this.format = format;
+	}
+}
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/RegisterUserMessage.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/RegisterUserMessage.java
index c1bfa9c085d3f76e7854bb90a8561a92f267158a..2ad05059409588407327a92e2e4e9d36844212eb 100644
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/RegisterUserMessage.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/RegisterUserMessage.java
@@ -11,8 +11,9 @@ public class RegisterUserMessage {
 	public final String externUserID;
 	public final String authToken;
 	public final String avatarURL;
+	public final String guest;
 	
-	public RegisterUserMessage(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken, String avatarURL) {
+	public RegisterUserMessage(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken, String avatarURL, String guest) {
 		this.meetingID = meetingID;
 		this.internalUserId = internalUserId;
 		this.fullname = fullname;
@@ -20,5 +21,6 @@ public class RegisterUserMessage {
 		this.externUserID = externUserID;	
 		this.authToken = authToken;
 		this.avatarURL = avatarURL;
+		this.guest = guest;
 	}
 }
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/UnpublishRecordingMessage.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/UnpublishRecordingMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..822104657d6ed02d5e8f542bccc315fc0349967b
--- /dev/null
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/converters/messages/UnpublishRecordingMessage.java
@@ -0,0 +1,18 @@
+package org.bigbluebutton.api.messaging.converters.messages;
+
+public class UnpublishRecordingMessage {
+	public static final String UNPUBLISH_RECORDING = "unpublished";
+	public static final String VERSION = "0.0.1";
+
+	public final String recordId;
+	public final String meetingId;
+	public final String externalMeetingId;
+	public final String format;
+
+	public UnpublishRecordingMessage(String recordId, String meetingId, String externalMeetingId, String format) {
+		this.recordId = recordId;
+		this.meetingId = meetingId;
+		this.externalMeetingId = externalMeetingId;
+		this.format = format;
+	}
+}
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/RegisterUser.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/RegisterUser.java
index 3c3451297cbb4e709d32ec3ad35f05ad155669fb..0b1b80cc49257c28ffbb27dbe2b11ceec73fb453 100644
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/RegisterUser.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/RegisterUser.java
@@ -9,8 +9,9 @@ public class RegisterUser implements IMessage {
 	public final String externUserID;
 	public final String authToken;
 	public final String avatarURL;
+	public final String guest;
 	
-	public RegisterUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken, String avatarURL) {
+	public RegisterUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken, String avatarURL, String guest) {
 		this.meetingID = meetingID;
 		this.internalUserId = internalUserId;
 		this.fullname = fullname;
@@ -18,5 +19,6 @@ public class RegisterUser implements IMessage {
 		this.externUserID = externUserID;
 		this.authToken = authToken;		
 		this.avatarURL = avatarURL;		
+		this.guest = guest;
 	}
 }
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/UserJoined.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/UserJoined.java
index cad1acb397fa0aba229edc39161f97112024977d..63173526a76e90ce8a19e409f07421baf8cf4d66 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/UserJoined.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/UserJoined.java
@@ -7,13 +7,17 @@ public class UserJoined implements IMessage {
   public final String name;
   public final String role;
   public final String avatarURL;
+  public final Boolean guest;
+  public final Boolean waitingForAcceptance;
   
-  public UserJoined(String meetingId, String userId, String externalUserId, String name, String role, String avatarURL) {
+  public UserJoined(String meetingId, String userId, String externalUserId, String name, String role, String avatarURL, Boolean guest, Boolean waitingForAcceptance) {
   	this.meetingId = meetingId;
   	this.userId = userId;
   	this.externalUserId = externalUserId;
   	this.name = name;
   	this.role = role;
   	this.avatarURL = avatarURL;
+  	this.guest = guest;
+  	this.waitingForAcceptance = waitingForAcceptance;
   }
 }
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/UserRoleChanged.java b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/UserRoleChanged.java
new file mode 100644
index 0000000000000000000000000000000000000000..1373dc9e5ef6c733b8486c3a4cca2c1c87be14e8
--- /dev/null
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/api/messaging/messages/UserRoleChanged.java
@@ -0,0 +1,13 @@
+package org.bigbluebutton.api.messaging.messages;
+
+public class UserRoleChanged implements IMessage {
+	public final String meetingId;
+	public final String userId;
+	public final String role;
+
+	public UserRoleChanged(String meetingId, String userId, String role) {
+		this.meetingId = meetingId;
+		this.userId = userId;
+		this.role = role;
+	}
+}
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/presentation/ConversionUpdateMessage.java b/bigbluebutton-web/src/java/org/bigbluebutton/presentation/ConversionUpdateMessage.java
index 126d1db12d114bdb57f09686fe77746a599ded56..a354515c40cb60faedc6cbeab63a3a96a40e19c0 100644
--- a/bigbluebutton-web/src/java/org/bigbluebutton/presentation/ConversionUpdateMessage.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/presentation/ConversionUpdateMessage.java
@@ -44,6 +44,7 @@ public class ConversionUpdateMessage {
 			message.put("presentationName", pres.getId());
 			message.put("presentationId", pres.getId());
 			message.put("filename", pres.getName());
+			message.put("downloadable", pres.isDownloadable());
     	}
 		
 		public MessageBuilder entry(String key, Object value) {
diff --git a/bigbluebutton-web/src/java/org/bigbluebutton/presentation/UploadedPresentation.java b/bigbluebutton-web/src/java/org/bigbluebutton/presentation/UploadedPresentation.java
index ffa5da576c38d1d509f1c4e85c0c260b175bd160..742236fb1b94ba0cfcb69cf6302369d13325ca15 100755
--- a/bigbluebutton-web/src/java/org/bigbluebutton/presentation/UploadedPresentation.java
+++ b/bigbluebutton-web/src/java/org/bigbluebutton/presentation/UploadedPresentation.java
@@ -30,6 +30,7 @@ public final class UploadedPresentation {
 	private int numberOfPages = 0;
 	private boolean lastStepSuccessful = false;
 	private final String baseUrl;
+	private boolean isDownloadable = false;
 	
 	public UploadedPresentation(String meetingId, String id, 
 			                    String name, 
@@ -38,6 +39,15 @@ public final class UploadedPresentation {
 		this.id = id;
 		this.name = name;
 		this.baseUrl = baseUrl;
+		this.isDownloadable = false;
+	}
+
+	public boolean isDownloadable() {
+		return isDownloadable;
+	}
+
+	public void setDownloadable() {
+		this.isDownloadable = true;
 	}
 
 	public File getUploadedFile() {
diff --git a/bigbluebutton-web/test/unit/org/bigbluebutton/api/messaging/NullMessagingService.java b/bigbluebutton-web/test/unit/org/bigbluebutton/api/messaging/NullMessagingService.java
index 23ad693a62dd68a7890c9b89caa5f7abeeb9de9b..8c12f4d2d9130c88bef4b42509c1ecfbbeb75e9e 100644
--- a/bigbluebutton-web/test/unit/org/bigbluebutton/api/messaging/NullMessagingService.java
+++ b/bigbluebutton-web/test/unit/org/bigbluebutton/api/messaging/NullMessagingService.java
@@ -67,22 +67,6 @@ public class NullMessagingService implements MessagingService {
 	  
   }
 
-  public String storeSubscription(String meetingId, String externalMeetingID,
-      String callbackURL) {
-	  // TODO Auto-generated method stub
-	  return null;
-  }
-
-  public boolean removeSubscription(String meetingId, String subscriptionId) {
-	  // TODO Auto-generated method stub
-	  return false;
-  }
-
-  public List<Map<String, String>> listSubscriptions(String meetingId) {
-	  // TODO Auto-generated method stub
-	  return null;
-  }
-
 	@Override
   public void registerUser(String meetingID, String internalUserId,
       String fullname, String role, String externUserID, String authToken, String avatarURL) {
diff --git a/bigbluebutton-web/web-app/WEB-INF/freemarker/get-recordings.ftl b/bigbluebutton-web/web-app/WEB-INF/freemarker/get-recordings.ftl
index 4433d9b99f377345fabf35d1e5e8708bafceaaa8..8eda5a204b568f7cfe7c3f26706595e46f580604 100644
--- a/bigbluebutton-web/web-app/WEB-INF/freemarker/get-recordings.ftl
+++ b/bigbluebutton-web/web-app/WEB-INF/freemarker/get-recordings.ftl
@@ -14,6 +14,8 @@
       <state>${r.getState()?string}</state>
       <startTime><#if r.getStartTime()?? && r.getStartTime() != "">${r.getStartTime()}</#if></startTime>
       <endTime><#if r.getEndTime()?? && r.getEndTime() != "">${r.getEndTime()}</#if></endTime>
+      <size><#if r.getSize()?? && r.getSize() != "">${r.getSize()}</#if></size>
+      <rawSize><#if r.getRawSize()?? && r.getRawSize() != "">${r.getRawSize()}</#if></rawSize>
       <#assign m = r.getMetadata()>
       <metadata>
       <#list m?keys as prop>
@@ -28,6 +30,8 @@
             <type>${p.getFormat()}</type>
             <url>${p.getUrl()}</url>
             <length>${p.getLength()}</length>
+            <size>${p.getSize()}</size>
+            <processingTime>${p.getProcessingTime()}</processingTime>
             <#if p.getExtensions()??>
             <#list p.getExtensions() as extension>
               <${extension.getType()}>
@@ -58,6 +62,22 @@
         </#list>
         </#if>
       </playback>
+      <download>
+        <#if r.getDownloads()??>
+        <#list r.getDownloads() as p>
+          <#if p?? && p.getFormat()??>
+          <format>
+            <type>${p.getFormat()}</type>
+            <url>${p.getUrl()}</url>
+            <md5>${p.getMd5()}</md5>
+            <key>${p.getKey()}</key>
+            <length>${p.getLength()}</length>
+            <size>${p.getSize()}</size>
+          </format>
+          </#if>
+        </#list>
+        </#if>
+      </download>
     </recording>
   </#list>
   </recordings>
diff --git a/clients/flash/web-client/src/main/resources/lib/bbb_deskshare.js b/clients/flash/web-client/src/main/resources/lib/bbb_deskshare.js
index 38afed12af0b23f575d26e02e298edafaba93910..07d73014c17119a4ea2ae8479cd87f415c74834b 100755
--- a/clients/flash/web-client/src/main/resources/lib/bbb_deskshare.js
+++ b/clients/flash/web-client/src/main/resources/lib/bbb_deskshare.js
@@ -91,8 +91,8 @@ function getHighestJavaVersion(javas) {
       highestJava = java;
       console.log(highestJava);
     } else if (parseInt(iter[0]) == parseInt(highest[0]) && parseInt(iter[1]) == parseInt(highest[1])) {
-      var iterMinor  = parseInt((iter[2]).split("_")[1]);
-      var highestMinor = parseInt((highest[2]).split("_")[1]);
+      var iterMinor  = iter.length > 2? parseInt((iter[2]).split("_")[1]): 0;
+      var highestMinor = highest.length > 2? parseInt((highest[2]).split("_")[1]): 0;
       if (iterMinor > highestMinor) {
         highestJava = java;
         console.log(highestJava);
diff --git a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/red5/DeskshareApplication.scala b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/red5/DeskshareApplication.scala
index 054905ea1897daa36c97bd6bfe322d5658cf6f8f..bae1803c4d9fa3e708ff6f9e91efac5f9f2253ee 100755
--- a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/red5/DeskshareApplication.scala
+++ b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/red5/DeskshareApplication.scala
@@ -208,4 +208,38 @@ class DeskshareApplication(streamManager: StreamManager, deskShareServer: DeskSh
     
 	   return Some(broadcastStream)
 	}
+
+	def destroyScreenVideoBroadcastStream(name: String):Boolean = {
+		logger.debug("DeskshareApplication: Destroying ScreenVideoBroadcastStream")
+		getRoomSharedObject(appScope, name) match {
+			case None => logger.error("Failed to get shared object for room %s", name)
+			case Some(deskSO) => {
+				logger.debug("DeskshareApplication: Destroying Broadcast Stream for room [ %s ]", name)
+				return destroyBroadcastStream(name, appScope)
+			}
+		}
+		return false
+	}
+
+	private def destroyBroadcastStream(name:String, roomScope:IScope):Boolean = {
+		if (name == null || roomScope == null) {
+			logger.error("Cannot destroy broadcast stream. Invalid parameter")
+			return false
+		}
+
+		val context: IContext  = roomScope.getContext()
+
+		logger.debug("DeskshareApplication: Getting provider service for room [ %s ]", name)
+		val providerService: IProviderService  = context.getBean(IProviderService.BEAN_NAME).asInstanceOf[IProviderService]
+
+		logger.debug("DeskshareApplication: Unregistering broadcast stream for room [ %s ]", name)
+		if (providerService.unregisterBroadcastStream(roomScope, name)) {
+			// Do nothing. Successfully unregistered a live broadcast stream
+		} else {
+			logger.error("DeskShareStream: Could not unregister broadcast stream")
+			return false
+		}
+
+		return true
+	}
 }
diff --git a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerSVC.scala b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerSVC.scala
index e8d3ba7d4208c30bec7561841fd613190dbf7ee2..e77ca7884dad56bdef1890c51f8bcf9dcf3f34df 100644
--- a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerSVC.scala
+++ b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionManagerSVC.scala
@@ -25,6 +25,7 @@ import scala.collection.mutable.HashMap
 import org.bigbluebutton.deskshare.server.svc1.Dimension
 import org.bigbluebutton.deskshare.server.stream.StreamManager
 import java.awt.Point
+import java.io.{PrintWriter, StringWriter}
 
 case class CreateSession(room: String, screenDim: Dimension, blockDim: Dimension, seqNum: Int, useSVC2: Boolean)
 case class RemoveSession(room: String)
@@ -41,6 +42,15 @@ class SessionManagerSVC(streamManager: StreamManager, keyFrameInterval: Int, int
  	private val sessions = new HashMap[String, SessionSVC]
  	private val stoppedSessions = new HashMap[String, String]
 	
+	override def exceptionHandler() = {
+	  case e: Exception => {
+	    val sw:StringWriter = new StringWriter()
+	    sw.write("An exception has been thrown on SessionManagerSVC, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+	    e.printStackTrace(new PrintWriter(sw))
+	    log.error(sw.toString())
+	  }
+	}
+
 	def act() = {
 	  loop {
 	    react {
diff --git a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionSVC.scala b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionSVC.scala
index 304f098bfff0c28d605af3d4c8d298d27600ac9d..a82efeafb1d3d45dd7bd1506a95b63bf6c16d0f5 100755
--- a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionSVC.scala
+++ b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/sessions/SessionSVC.scala
@@ -26,6 +26,7 @@ import scala.actors.Actor
 import scala.actors.Actor._
 import net.lag.logging.Logger
 import java.awt.Point
+import java.io.{PrintWriter, StringWriter}
 
 case object StartSession
 case class UpdateSessionBlock(position: Int, blockData: Array[Byte], keyframe: Boolean, seqNum: Int)
@@ -50,6 +51,15 @@ class SessionSVC(sessionManager:SessionManagerSVC, room: String, screenDim: Dime
   private var streamStartedOn = 0L
   private var streamStarted = false
   
+	override def exceptionHandler() = {
+		case e: Exception => {
+			val sw:StringWriter = new StringWriter()
+			sw.write("An exception has been thrown on SessionSVC, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+			e.printStackTrace(new PrintWriter(sw))
+			log.error(sw.toString())
+		}
+	}
+
 	/*
 	 * Schedule to generate a key frame after 30seconds of a request.
 	 * This prevents us from generating unnecessary key frames when
diff --git a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/stream/DeskshareStream.scala b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/stream/DeskshareStream.scala
index c846afc59af479300322b467b23fcb25b8c93f1f..4f15be3c7bd01a243b509d3a9afde25f32ef516d 100755
--- a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/stream/DeskshareStream.scala
+++ b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/stream/DeskshareStream.scala
@@ -29,6 +29,7 @@ import org.red5.server.net.rtmp.event.VideoData;
 import org.red5.server.stream.IProviderService
 import org.red5.server.net.rtmp.message.Constants;
 import org.apache.mina.core.buffer.IoBuffer
+import java.io.{PrintWriter, StringWriter}
 import java.util.ArrayList
 import scala.actors.Actor
 import scala.actors.Actor._
@@ -41,6 +42,15 @@ class DeskshareStream(app: DeskshareApplication, name: String, val width: Int, v
 	private var dsClient:RtmpClientAdapter = null
 		
 	var startTimestamp: Long = System.currentTimeMillis()
+
+	override def exceptionHandler() = {
+	  case e: Exception => {
+	    val sw:StringWriter = new StringWriter()
+	    sw.write("An exception has been thrown on DeskshareStream, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+	    e.printStackTrace(new PrintWriter(sw))
+	    log.error(sw.toString())
+	  }
+	}
  
 	def act() = {
 	  loop {
@@ -71,6 +81,10 @@ class DeskshareStream(app: DeskshareApplication, name: String, val width: Int, v
 	   } 
 	   return false
 	}
+
+	def destroyStream():Boolean = {
+		return app.destroyScreenVideoBroadcastStream(name)
+	}
  
 	private def stopStream() = {
 		log.debug("DeskShareStream: Stopping stream %s", name)
diff --git a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/stream/StreamManager.scala b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/stream/StreamManager.scala
index 99df1c58024df8b096b7b05863af9538ac610050..b5be9320b35ddc38a8443a9e8f655bc8d42b6a0b 100755
--- a/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/stream/StreamManager.scala
+++ b/deskshare/app/src/main/scala/org/bigbluebutton/deskshare/server/stream/StreamManager.scala
@@ -22,6 +22,7 @@ import org.bigbluebutton.deskshare.server.red5.DeskshareApplication
 import org.red5.server.api.scope.IScope
 import org.red5.server.api.so.ISharedObject
 
+import java.io.{PrintWriter, StringWriter}
 import java.util.ArrayList
 
 import scala.actors.Actor
@@ -48,6 +49,14 @@ class StreamManager(record:Boolean, recordingService:RecordingService) extends A
 
 	private val streams = new HashMap[String, DeskshareStream]
  
+	override def exceptionHandler() = {
+	  case e: Exception => {
+	    val sw:StringWriter = new StringWriter()
+	    sw.write("An exception has been thrown on StreamManager, exception message [" + e.getMessage() + "] (full stacktrace below)\n")
+	    e.printStackTrace(new PrintWriter(sw))
+	    log.error(sw.toString())
+	  }
+	}
 
 	def act() = {
 	  loop {
@@ -95,9 +104,13 @@ class StreamManager(record:Boolean, recordingService:RecordingService) extends A
 	  }
 	}
  
-  	def destroyStream(room: String) {
-  		this ! new RemoveStream(room)
-  	}  	
+	def destroyStream(room: String) {
+		streams.get(room) match {
+			case Some(stream) => stream.destroyStream()
+			case None => log.info("Tried to destroy, but could not find deskshare stream for room [ %s ]", room)
+		}
+		this ! new RemoveStream(room)
+	}
    
   	override def exit() : Nothing = {
 	  log.warning("StreamManager: **** Exiting  Actor")
diff --git a/deskshare/applet/build.gradle b/deskshare/applet/build.gradle
index 2f5b4608be7859da3a18d8a6c869cae033de88a5..149b1e346a763c4c3b3a4a95a6050147d427e7dd 100755
--- a/deskshare/applet/build.gradle
+++ b/deskshare/applet/build.gradle
@@ -32,7 +32,7 @@ jar.doFirst {
 jar {
    manifest.mainAttributes("Permissions": "all-permissions")
    manifest.mainAttributes("Codebase": "*")
-   manifest.mainAttributes("Application-Name": "BigBlueButton Deskshare Applet")
+   manifest.mainAttributes("Application-Name": "Mconf Deskshare Applet")
    manifest.mainAttributes("Application-Library-Allowable-Codebase": "*")
    manifest.mainAttributes("Caller-Allowable-Codebase": "*")
    manifest.mainAttributes("Trusted-Only": "true")
diff --git a/record-and-playback/core/Gemfile b/record-and-playback/core/Gemfile
index 00ad88a9a076112d3c95de839131ef0b37835690..13924f205f88cc413081a3dcd9c1e2c616c5d2b0 100644
--- a/record-and-playback/core/Gemfile
+++ b/record-and-playback/core/Gemfile
@@ -22,7 +22,8 @@ source "http://rubygems.org"
 gem "redis"
 gem "nokogiri"
 gem "resque"
-gem "mime-types"
+gem "mime-types", "2.99.2"
+gem "streamio-ffmpeg", "2.1.0"
 gem "rubyzip"
 gem "curb"
 gem "builder"
diff --git a/record-and-playback/core/Gemfile.lock b/record-and-playback/core/Gemfile.lock
index c708d7d2f809817332301df0c40978d97a9fbb57..6a507fcf74ac4f17d0501f45e16de365025f46b0 100644
--- a/record-and-playback/core/Gemfile.lock
+++ b/record-and-playback/core/Gemfile.lock
@@ -7,7 +7,7 @@ GEM
     curb (0.9.3)
     fastimage (2.0.0)
       addressable (~> 2)
-    mime-types (2.6.2)
+    mime-types (2.99.2)
     mini_portile2 (2.1.0)
     mono_logger (1.1.0)
     multi_json (1.12.1)
@@ -48,13 +48,13 @@ DEPENDENCIES
   builder
   curb
   fastimage
-  mime-types (= 2.6.2)
+  mime-types (= 2.99.2)
   nokogiri
   open4
   redis
   resque
   rubyzip
-  streamio-ffmpeg
+  streamio-ffmpeg (= 2.1.0)
   trollop
 
 BUNDLED WITH
diff --git a/record-and-playback/core/lib/custom_hash.rb b/record-and-playback/core/lib/custom_hash.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e1e85c664b20f8cd0dd35eb97948206c5467c790
--- /dev/null
+++ b/record-and-playback/core/lib/custom_hash.rb
@@ -0,0 +1,82 @@
+# Set encoding to utf-8
+# encoding: UTF-8
+
+#
+# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+#
+# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+#
+# This program is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 3.0 of the License, or (at your option) any later
+# version.
+#
+# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+#
+
+require 'nokogiri'
+
+# modified from http://stackoverflow.com/questions/1230741/convert-a-nokogiri-document-to-a-ruby-hash/1231297#1231297
+class Hash
+  class << self
+    def from_xml(xml_io)
+      begin
+        result = Nokogiri::XML(xml_io)
+        return { result.root.name.to_sym => xml_node_to_hash(result.root)}
+      rescue Exception => e
+        # raise your custom exception here
+      end
+    end
+
+    def xml_node_to_hash(node)
+      # If we are at the root of the document, start the hash
+      if node.element?
+        result_hash = {}
+        if node.attributes != {}
+          result_hash[:attributes] = {}
+          node.attributes.keys.each do |key|
+            result_hash[:attributes][node.attributes[key].name.to_sym] = prepare(node.attributes[key].value)
+          end
+        end
+        if node.children.size > 0
+          node.children.each do |child|
+            result = xml_node_to_hash(child)
+
+            if child.name == "text"
+              unless child.next_sibling || child.previous_sibling
+                return prepare(result)
+              end
+            elsif result_hash[child.name.to_sym]
+              if result_hash[child.name.to_sym].is_a?(Object::Array)
+                result_hash[child.name.to_sym] << prepare(result)
+              else
+                result_hash[child.name.to_sym] = [result_hash[child.name.to_sym]] << prepare(result)
+              end
+            else
+              result_hash[child.name.to_sym] = prepare(result)
+            end
+          end
+
+          return result_hash
+        else
+          return result_hash
+        end
+      else
+        return prepare(node.content.to_s)
+      end
+    end
+
+    def prepare(data)
+      (data.class == String && data.to_i.to_s == data) ? data.to_i : data
+    end
+  end
+
+  def to_struct(struct_name)
+      Struct.new(struct_name,*keys).new(*values)
+  end
+end
diff --git a/record-and-playback/core/lib/recordandplayback.rb b/record-and-playback/core/lib/recordandplayback.rb
index ce3184b86d2ac40f1584809128166107efa44c5d..329a14126423a7b4790fa7d71e420d89b8e122ea 100755
--- a/record-and-playback/core/lib/recordandplayback.rb
+++ b/record-and-playback/core/lib/recordandplayback.rb
@@ -33,10 +33,13 @@ require 'recordandplayback/generators/audio'
 require 'recordandplayback/generators/video'
 require 'recordandplayback/generators/audio_processor'
 require 'recordandplayback/generators/presentation'
+require 'custom_hash'
 require 'open4'
 require 'pp'
 require 'absolute_time'
 require 'logger'
+require 'find'
+require 'rubygems'
 
 module BigBlueButton
   class MissingDirectoryException < RuntimeError
@@ -155,4 +158,45 @@ module BigBlueButton
   def self.monotonic_clock()
     return (AbsoluteTime.now * 1000).to_i
   end
+
+  def self.get_dir_size(dir_name)
+    size = 0
+    if FileTest.directory?(dir_name)
+      Find.find(dir_name) { |f| size += File.size(f) }
+    end
+    size.to_s
+  end
+
+  def self.add_tag_to_xml(xml_filename, parent_xpath, tag, content)
+    if File.exist? xml_filename
+      doc = Nokogiri::XML(File.open(xml_filename)) { |x| x.noblanks }
+
+      node = doc.at_xpath("#{parent_xpath}/#{tag}")
+      node.remove if not node.nil?
+
+      node = Nokogiri::XML::Node.new tag, doc
+      node.content = content
+
+      doc.at(parent_xpath) << node
+
+      xml_file = File.new(xml_filename, "w")
+      xml_file.write(doc.to_xml(:indent => 2))
+      xml_file.close
+    end
+  end
+
+  def self.add_raw_size_to_metadata(dir_name, raw_dir_name)
+    size = BigBlueButton.get_dir_size(raw_dir_name)
+    BigBlueButton.add_tag_to_xml("#{dir_name}/metadata.xml", "//recording", "raw_size", size)
+  end
+
+  def self.add_playback_size_to_metadata(dir_name)
+    size = BigBlueButton.get_dir_size(dir_name)
+    BigBlueButton.add_tag_to_xml("#{dir_name}/metadata.xml", "//recording/playback", "size", size)
+  end
+
+  def self.add_download_size_to_metadata(dir_name)
+    size = BigBlueButton.get_dir_size(dir_name)
+    BigBlueButton.add_tag_to_xml("#{dir_name}/metadata.xml", "//recording/download", "size", size)
+  end
 end
diff --git a/record-and-playback/core/lib/recordandplayback/events_archiver.rb b/record-and-playback/core/lib/recordandplayback/events_archiver.rb
index f384e1baf61148d0084506b6881c827ece1f573d..e53336b9071fc6c108f22772699e66343c7767b1 100755
--- a/record-and-playback/core/lib/recordandplayback/events_archiver.rb
+++ b/record-and-playback/core/lib/recordandplayback/events_archiver.rb
@@ -26,6 +26,10 @@ require 'builder'
 require 'yaml'
 
 module BigBlueButton  
+  $bbb_props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml'))
+  $recording_dir = $bbb_props['recording_dir']
+  $raw_recording_dir = "#{$recording_dir}/raw"
+
   # Class to wrap Redis so we can mock
   # for testing
   class RedisWrapper
@@ -101,7 +105,15 @@ module BigBlueButton
     RECORDINGS_CHANNEL = "bigbluebutton:from-rap"
 
     def put_message(message_type, meeting_id, additional_payload = {})
+      events_xml = "#{$raw_recording_dir}/#{meeting_id}/events.xml"
+      if File.exist?(events_xml)
+        additional_payload.merge!({
+          "external_meeting_id" => BigBlueButton::Events.get_external_meeting_id(events_xml)
+        })
+      end
+
       msg = build_message build_header(message_type), additional_payload.merge({
+        "record_id" => meeting_id,
         "meeting_id" => meeting_id
       })
       @redis.publish RECORDINGS_CHANNEL, msg.to_json
diff --git a/record-and-playback/core/lib/recordandplayback/generators/events.rb b/record-and-playback/core/lib/recordandplayback/generators/events.rb
index 23b7c2fa113b705c80f9c3ddc1b9dc1fed64baff..ca93ec2125072fc1b5f028bb560b90c4ce675550 100755
--- a/record-and-playback/core/lib/recordandplayback/generators/events.rb
+++ b/record-and-playback/core/lib/recordandplayback/generators/events.rb
@@ -38,6 +38,15 @@ module BigBlueButton
       end  
       metadata
     end
+
+    # Get the external meeting id
+    def self.get_external_meeting_id(events_xml)
+      BigBlueButton.logger.info("Task: Getting external meeting id")
+      metadata = get_meeting_metadata(events_xml)
+      external_meeting_id = {}
+      external_meeting_id = metadata['meetingId'] if !metadata['meetingId'].nil?
+      external_meeting_id
+    end
     
     # Get the timestamp of the first event.
     def self.first_event_timestamp(events_xml)
diff --git a/record-and-playback/core/scripts/bbb-0.9-recording-size b/record-and-playback/core/scripts/bbb-0.9-recording-size
new file mode 100755
index 0000000000000000000000000000000000000000..2f879ca893a08c0d7e4bac71e4658ebc977baedf
--- /dev/null
+++ b/record-and-playback/core/scripts/bbb-0.9-recording-size
@@ -0,0 +1,82 @@
+#!/usr/bin/ruby1.9.1
+
+require File.expand_path('../../lib/recordandplayback', __FILE__)
+require 'trollop'
+
+props = YAML::load(File.open(File.expand_path('../bigbluebutton.yml', __FILE__)))
+log_dir = props['log_dir']
+raw_recording_dir = "#{props['recording_dir']}/raw"
+published_dir = props['published_dir']
+unpublished_dir = "#{published_dir}/../unpublished"
+
+opts = Trollop::options do
+  opt(:force, "Run script even if it has previously been run",
+              :default => false)
+  opt(:quiet, "Minimal output mode, for automated use",
+              :default => false)
+end
+
+log_file = "#{log_dir}/bbb-0.9-recording-size.log"
+done_file = "#{props['recording_dir']}/status/bbb-0.9-recording-size.done"
+
+logger = Logger.new(log_file)
+logger.level = Logger::INFO
+BigBlueButton.logger = logger
+
+if File.exist?(done_file) and !opts.force
+  if !opts.quiet
+    puts "Script has previously been run, doing nothing"
+    puts "Use the --force option to override"
+  end
+  exit 0
+end
+
+def do_recording_size_update(recording_dir, raw_recording_dir, format_dir)
+  match = /([^\/]*)$/.match(recording_dir)
+  meeting_id = match[1]
+
+  match = /([^\/]*)$/.match(format_dir)
+  format = match[1]
+
+  BigBlueButton.logger.info("Processing #{format} recording #{meeting_id}")
+  BigBlueButton.logger.info("Adding raw size to recording #{meeting_id}")
+  raw_dir = "#{raw_recording_dir}/#{meeting_id}"
+  BigBlueButton.add_raw_size_to_metadata(recording_dir, raw_dir)
+  if format == "mconf_encrypted"
+    BigBlueButton.add_download_size_to_metadata(recording_dir)
+  else
+    BigBlueButton.add_playback_size_to_metadata(recording_dir)
+  end
+end
+
+BigBlueButton.logger.info("Updating size of 0.9.0 recordings")
+
+puts "Updating recording size for 0.9.0..."
+
+num_recordings = 0
+
+BigBlueButton.logger.info("Checking recordings in #{published_dir}")
+Dir.glob("#{published_dir}/*").each do |format_dir|
+  Dir.glob("#{format_dir}/*-*").each do |recording_dir|
+    print '.' if num_recordings % 10 == 0
+    num_recordings += 1
+    do_recording_size_update(recording_dir, raw_recording_dir, format_dir)
+  end
+end
+
+BigBlueButton.logger.info("Checking recordings in #{unpublished_dir}")
+Dir.glob("#{unpublished_dir}/*").each do |format_dir|
+  Dir.glob("#{format_dir}/*-*").each do |recording_dir|
+    print '.' if num_recordings % 10 == 0
+    num_recordings += 1
+    do_recording_size_update(recording_dir, raw_recording_dir, format_dir)
+  end
+end
+
+puts "done"
+
+puts "See the output in #{log_file} for details"
+
+BigBlueButton.logger.info("Processed #{num_recordings} recordings")
+
+IO.write(done_file, Time.now)
diff --git a/record-and-playback/core/scripts/rap-worker.rb b/record-and-playback/core/scripts/rap-worker.rb
index 5e995d31c6d42382466c5550341799dec05a61c2..d8e3f5bed3fa1bbf35a37cd1a51d578790239c28 100755
--- a/record-and-playback/core/scripts/rap-worker.rb
+++ b/record-and-playback/core/scripts/rap-worker.rb
@@ -123,7 +123,7 @@ def process_archived_meeting(recording_dir)
     match = /([^\/]*).done$/.match(sanity_done)
     meeting_id = match[1]
 
-    step_succeeded = true
+    phase_succeeded = true
 
     # Iterate over the list of recording processing scripts to find available types
     # For now, we look for the ".rb" extension - TODO other scripting languages?
@@ -136,7 +136,7 @@ def process_archived_meeting(recording_dir)
 
       processed_fail = "#{recording_dir}/status/processed/#{meeting_id}-#{process_type}.fail"
       if File.exists?(processed_fail)
-        step_succeeded = false
+        phase_succeeded = false
         next
       end
 
@@ -150,7 +150,9 @@ def process_archived_meeting(recording_dir)
       step_stop_time = BigBlueButton.monotonic_clock
       step_time = step_stop_time - step_start_time
 
-      IO.write("#{recording_dir}/process/#{process_type}/#{meeting_id}/processing_time", step_time)
+      if BigBlueButton.dir_exists? "#{recording_dir}/process/#{process_type}/#{meeting_id}"
+        IO.write("#{recording_dir}/process/#{process_type}/#{meeting_id}/processing_time", step_time)
+      end
 
       step_succeeded = (ret == 0 and File.exists?(processed_done))
 
@@ -162,15 +164,20 @@ def process_archived_meeting(recording_dir)
       if step_succeeded
         BigBlueButton.logger.info("Process format #{process_type} succeeded for #{meeting_id}")
         BigBlueButton.logger.info("Process took #{step_time}ms")
+
+        # when it succeeds to process a recording, publish it immediately instead
+        # of continue processing the next recordings
+        # the side-effect is that the publish phase will occur before the post_process phase
+        publish_processed_meeting(recording_dir)
       else
         BigBlueButton.logger.info("Process format #{process_type} failed for #{meeting_id}")
         BigBlueButton.logger.info("Process took #{step_time}ms")
         FileUtils.touch(processed_fail)
-        step_succeeded = false
+        phase_succeeded = false
       end
     end
 
-    if step_succeeded
+    if phase_succeeded
       post_process(meeting_id)
       FileUtils.rm(sanity_done)
     end
@@ -199,6 +206,13 @@ def publish_processed_meeting(recording_dir)
       match2 = /([^\/]*).rb$/.match(publish_script)
       publish_type = match2[1]
 
+      # Do not try to publish a format that failed in the process phase
+      processed_done = "#{recording_dir}/status/processed/#{meeting_id}-#{publish_type}.done"
+      if !File.exists?(processed_done)
+        publish_succeeded = false
+        next
+      end
+
       published_done = "#{recording_dir}/status/published/#{meeting_id}-#{publish_type}.done"
       next if File.exists?(published_done)
 
@@ -222,9 +236,45 @@ def publish_processed_meeting(recording_dir)
 
       step_succeeded = (ret == 0 and File.exists?(published_done))
 
+      props = YAML::load(File.open('bigbluebutton.yml'))
+      published_dir = props['published_dir']
+
+      playback = {}
+      metadata = {}
+      download = {}
+      raw_size = {}
+      start_time = {}
+      end_time = {}
+      metadata_xml_path = "#{published_dir}/#{publish_type}/#{meeting_id}/metadata.xml"
+      if File.exists? metadata_xml_path
+        begin
+          doc = Hash.from_xml(File.open(metadata_xml_path))
+          playback = doc[:recording][:playback] if !doc[:recording][:playback].nil?
+          metadata = doc[:recording][:meta] if !doc[:recording][:meta].nil?
+          download = doc[:recording][:download] if !doc[:recording][:download].nil?
+          raw_size = doc[:recording][:raw_size] if !doc[:recording][:raw_size].nil?
+          start_time = doc[:recording][:start_time] if !doc[:recording][:start_time].nil?
+          end_time = doc[:recording][:end_time] if !doc[:recording][:end_time].nil?
+        rescue Exception => e
+          BigBlueButton.logger.warn "An exception occurred while loading the extra information for the publish event"
+          BigBlueButton.logger.warn e.message
+          e.backtrace.each do |traceline|
+            BigBlueButton.logger.warn traceline
+          end
+        end
+      else
+        BigBlueButton.logger.warn "Couldn't find the metadata file at #{metadata_xml_path}"
+      end
+
       BigBlueButton.redis_publisher.put_publish_ended publish_type, meeting_id, {
         "success" => step_succeeded,
-        "step_time" => step_time
+        "step_time" => step_time,
+        "playback" => playback,
+        "metadata" => metadata,
+        "download" => download,
+        "raw_size" => raw_size,
+        "start_time" => start_time,
+        "end_time" => end_time
       }
 
       if step_succeeded
@@ -257,6 +307,24 @@ def publish_processed_meeting(recording_dir)
   end
 end
 
+def clean_presentation_dependents(recording_dir)
+  # clean workspace so the formats that depend on the presentation format to be
+  # published will run
+  [ "presentation_export" ].each do |dependent_format|
+    presentation_published_done_files = Dir.glob("#{recording_dir}/status/published/*-presentation.done")
+    presentation_published_done_files.each do |published_done|
+      match = /([^\/]*)-([^\/-]*).done$/.match(published_done)
+      meeting_id = match[1]
+      process_type = match[2]
+      processed_fail = "#{recording_dir}/status/processed/#{meeting_id}-#{dependent_format}.fail"
+      if File.exists? processed_fail
+        BigBlueButton.logger.info "Removing #{processed_fail} so #{dependent_format} can execute in the next run of rap-worker"
+        FileUtils.rm processed_fail
+      end
+    end
+  end
+end
+
 def post_archive(meeting_id)
   Dir.glob("post_archive/*.rb").sort.each do |post_archive_script|
     match = /([^\/]*).rb$/.match(post_archive_script)
@@ -351,6 +419,7 @@ begin
   sanity_archived_meeting(recording_dir)
   process_archived_meeting(recording_dir)
   publish_processed_meeting(recording_dir)
+  clean_presentation_dependents(recording_dir)
 
   BigBlueButton.logger.debug("rap-worker done")
 
diff --git a/record-and-playback/deploy.sh b/record-and-playback/deploy.sh
index 064af82a413411d5a2f62c7bd1308029cb686dac..4e8fe016bdc1a97b65dc435190a6070d7cf90b99 100755
--- a/record-and-playback/deploy.sh
+++ b/record-and-playback/deploy.sh
@@ -38,7 +38,16 @@ function deploy_format() {
 	done
 }
 
-deploy_format "presentation"
+RECORDING_SERVER=true
+if $RECORDING_SERVER ; then
+	deploy_format "presentation"
+	deploy_format "presentation_export"
+	deploy_format "mconf_decrypter"
+	sudo mv /usr/local/bigbluebutton/core/scripts/mconf-recording-decrypter.initd /etc/init.d/mconf-recording-decrypter
+	sudo mv /usr/local/bigbluebutton/core/scripts/mconf-recording-decrypter.monit /etc/monit/conf.d/mconf-recording-decrypter
+else
+	deploy_format "mconf_encrypted"
+fi
 
 sudo mkdir -p /var/bigbluebutton/playback/
 sudo mkdir -p /var/bigbluebutton/recording/raw/
diff --git a/record-and-playback/mconf_decrypter/scripts/mconf-decrypter.rb b/record-and-playback/mconf_decrypter/scripts/mconf-decrypter.rb
new file mode 100755
index 0000000000000000000000000000000000000000..8e6026b7fc6c02e92c38f581e68d5746a927f743
--- /dev/null
+++ b/record-and-playback/mconf_decrypter/scripts/mconf-decrypter.rb
@@ -0,0 +1,183 @@
+#!/usr/bin/ruby
+# Set encoding to utf-8
+# encoding: UTF-8
+#
+# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+#
+# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+#
+# This program is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 3.0 of the License, or (at your option) any later
+# version.
+#
+# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+#
+
+require '../../core/lib/recordandplayback'
+require 'rubygems'
+require 'yaml'
+require 'net/http'
+require 'net/https'
+require 'rexml/document'
+require 'open-uri'
+require 'digest/md5'
+
+BigBlueButton.logger = Logger.new("/var/log/bigbluebutton/mconf_decrypter.log",'daily' )
+#BigBlueButton.logger = Logger.new(STDOUT)
+
+bbb_props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml'))
+mconf_props = YAML::load(File.open('mconf-decrypter.yml'))
+
+# these properties must be global variables (starting with $)
+$private_key = mconf_props['private_key']
+$get_recordings_url = mconf_props['get_recordings_url']
+$verify_ssl_certificate = mconf_props['verify_ssl_certificate']
+$recording_dir = bbb_props['recording_dir']
+$raw_dir = "#{$recording_dir}/raw"
+$archived_dir = "#{$recording_dir}/status/archived"
+
+def getRequest(url)
+  BigBlueButton.logger.debug("Fetching #{url}")
+  url_parsed = URI.parse(url)
+  http = Net::HTTP.new(url_parsed.host, url_parsed.port)
+  http.use_ssl = (url_parsed.scheme.downcase == "https")
+  http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl? && ! $verify_ssl_certificate
+  http.get(url_parsed.request_uri)
+end
+
+def fetchRecordings(url)
+  doc = nil
+  begin
+    response = getRequest(url)
+    # follow redirects once only
+    if response.kind_of?(Net::HTTPRedirection)
+      BigBlueButton.logger.debug("Received a redirect, will make a new request")
+      response = getRequest(response['location'])
+    end
+
+    doc = Nokogiri::XML(response.body)
+    returncode = doc.xpath("//returncode")
+    if returncode.empty? or returncode.text != "SUCCESS"
+      BigBlueButton.logger.error "getRecordings didn't return success:\n#{doc.to_xml(:indent => 2)}"
+      return false
+    end
+  rescue
+    BigBlueButton.logger.error("Exception occurred: #{$!}")
+    return false
+  end
+
+  doc.xpath("//recording").each do |recording|
+    record_id = recording.xpath(".//recordID").text
+    recording.xpath(".//download/format").each do |format|
+      type = format.xpath(".//type").text
+      if type == "encrypted"
+        meeting_id = record_id
+        file_url = format.xpath(".//url").text
+        key_file_url = format.xpath(".//key").text
+        md5_value = format.xpath(".//md5").text
+
+        encrypted_file = file_url.split("/").last
+        decrypted_file = File.basename(encrypted_file, '.*') + ".tar.gz"
+        # can't check only for archived.done because when the file is published, the archived flag is removed
+        # so we check for any .done file
+        if Dir.glob("#{$recording_dir}/status/**/#{record_id}*.done").empty? then
+          Dir.chdir($raw_dir) do
+            BigBlueButton.logger.info("Next recording to be processed is #{meeting_id}")
+
+            BigBlueButton.logger.debug("Removing any file previously downloaded related to this recording")
+            FileUtils.rm_r Dir.glob("#{$raw_dir}/#{record_id}*"), :force => true
+
+            BigBlueButton.logger.debug("recordID = #{record_id}")
+            BigBlueButton.logger.debug("file_url = #{file_url}")
+            BigBlueButton.logger.debug("key_file_url = #{key_file_url}")
+            BigBlueButton.logger.debug("md5_value = #{md5_value}")
+
+            BigBlueButton.logger.info("Downloading the encrypted file to #{encrypted_file}")
+
+            `wget --output-document "#{encrypted_file}" "#{file_url}"`
+
+            md5_calculated = Digest::MD5.file(encrypted_file)
+
+            if md5_calculated == md5_value
+              BigBlueButton.logger.info("The calculated MD5 matches the expected value")
+              key_file = key_file_url.split("/").last
+              decrypted_key_file = File.basename(key_file, '.*') + ".txt"
+
+              BigBlueButton.logger.info("Downloading the key file to #{key_file}")
+              writeOut = open(key_file, "wb")
+              writeOut.write(open(key_file_url).read)
+              writeOut.close
+
+              if key_file != decrypted_key_file
+                BigBlueButton.logger.debug("Locating private key")
+                if not File.exists?("#{$private_key}")
+                  BigBlueButton.logger.error "Couldn't find the private key on #{$private_key}"
+                  next
+                end
+                BigBlueButton.logger.debug("Decrypting recording key")
+                command = "openssl rsautl -decrypt -inkey #{$private_key} < #{key_file} > #{decrypted_key_file}"
+                status = BigBlueButton.execute(command, false)
+                if not status.success?
+                  BigBlueButton.logger.error "Couldn't decrypt the random key with the server private key"
+                  next
+                end
+                FileUtils.rm_r "#{key_file}"
+              else
+                BigBlueButton.logger.info("No public key was used to encrypt the random key")
+              end
+
+              BigBlueButton.logger.debug("Decrypting the recording file")
+              command = "openssl enc -aes-256-cbc -d -pass file:#{decrypted_key_file} < #{encrypted_file} > #{decrypted_file}"
+              status = BigBlueButton.execute(command, false)
+              if not status.success?
+                BigBlueButton.logger.error "Couldn't decrypt the recording file using the random key"
+                next
+              end
+
+              command = "tar -xf #{decrypted_file}"
+              status = BigBlueButton.execute(command, false)
+              if not status.success?
+                BigBlueButton.logger.error "Couldn't extract the raw files"
+                next
+              end
+
+              archived_done = File.new("#{$archived_dir}/#{meeting_id}.done", "w")
+              archived_done.write("Archived #{meeting_id}")
+              archived_done.close
+
+              [ "#{encrypted_file}", "#{decrypted_file}", "#{decrypted_key_file}" ].each { |file|
+                BigBlueButton.logger.info("Removing #{file}")
+                FileUtils.rm_r "#{file}"
+              }
+
+              BigBlueButton.logger.info("Recording #{record_id} decrypted successfully")
+
+            else
+              BigBlueButton.logger.error("The calculated MD5 doesn't match the expected value")
+              FileUtils.rm_f(encrypted_file)
+            end
+          end
+        end
+      end
+    end
+  end
+  return true
+end
+
+def processGetRecordingsUrlInput(input)
+  if input.respond_to? "each"
+    input.each do |url|
+      processGetRecordingsUrlInput url
+    end
+  else
+    fetchRecordings input
+  end
+end
+
+processGetRecordingsUrlInput $get_recordings_url if !$get_recordings_url.nil? and !$get_recordings_url.empty?
diff --git a/record-and-playback/mconf_decrypter/scripts/mconf-decrypter.yml b/record-and-playback/mconf_decrypter/scripts/mconf-decrypter.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0aa9a706a8a26083a1ac9bab3e5de5afdd722f61
--- /dev/null
+++ b/record-and-playback/mconf_decrypter/scripts/mconf-decrypter.yml
@@ -0,0 +1,3 @@
+get_recordings_url:
+private_key: /usr/local/bigbluebutton/core/scripts/private.pem
+verify_ssl_certificate: true
diff --git a/record-and-playback/mconf_decrypter/scripts/mconf-recording-decrypter.initd b/record-and-playback/mconf_decrypter/scripts/mconf-recording-decrypter.initd
new file mode 100755
index 0000000000000000000000000000000000000000..276f08e05daa14b6a78a3eba690897be82babac2
--- /dev/null
+++ b/record-and-playback/mconf_decrypter/scripts/mconf-recording-decrypter.initd
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides:          mconf-recording-decrypter
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Description:       Starts the foo service
+### END INIT INFO
+
+NAME=mconf-recording-decrypter
+PID_FILE=/var/run/mconf-recording-decrypter.pid
+DIR=/usr/local/bigbluebutton/core/scripts
+EXEC=mconf-decrypter.rb
+RUN_AS=tomcat7
+
+if [ ! -f $DIR/$EXEC ]; then
+        echo "$DIR/$EXEC not found."
+        exit
+fi
+
+case "$1" in
+  start)
+        echo "Starting $NAME"
+        cd $DIR
+        start-stop-daemon -d $DIR --start --background --pidfile $PID_FILE --chuid $RUN_AS:$RUN_AS --make-pidfile --exec $EXEC --quiet
+        ;;
+  stop)
+        echo "Stopping $NAME"
+        start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE --exec $EXEC
+        ;;
+  force-reload|restart)
+        $0 stop
+        $0 start
+        ;;
+
+  *)
+        echo "Use: /etc/init.d/$NAME {start|stop|restart|force-reload}"
+        exit 1
+        ;;
+esac
+
+exit 0
diff --git a/record-and-playback/mconf_decrypter/scripts/mconf-recording-decrypter.monit b/record-and-playback/mconf_decrypter/scripts/mconf-recording-decrypter.monit
new file mode 100644
index 0000000000000000000000000000000000000000..d977722e417fb883c09171369f0b4fce8a3f991d
--- /dev/null
+++ b/record-and-playback/mconf_decrypter/scripts/mconf-recording-decrypter.monit
@@ -0,0 +1,3 @@
+check process mconf-recording-decrypter with pidfile /var/run/mconf-recording-decrypter.pid
+    start program = "/etc/init.d/mconf-recording-decrypter start" with timeout 60 seconds
+    stop program  = "/etc/init.d/mconf-recording-decrypter stop"
diff --git a/record-and-playback/mconf_encrypted/scripts/mconf_encrypted.nginx b/record-and-playback/mconf_encrypted/scripts/mconf_encrypted.nginx
new file mode 100644
index 0000000000000000000000000000000000000000..bd531918b29798c1f2042c28c269306e29653ed9
--- /dev/null
+++ b/record-and-playback/mconf_encrypted/scripts/mconf_encrypted.nginx
@@ -0,0 +1,22 @@
+
+#
+# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+#
+# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+#
+# This program is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 3.0 of the License, or (at your option) any later
+# version.
+#
+# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+#
+        location /mconf_encrypted {
+                root    /var/bigbluebutton/published;
+                index  index.html index.htm;
+        }
diff --git a/record-and-playback/mconf_encrypted/scripts/process/mconf_encrypted.rb b/record-and-playback/mconf_encrypted/scripts/process/mconf_encrypted.rb
new file mode 100755
index 0000000000000000000000000000000000000000..b354aee192613b68fa97291487753651bdce8b1e
--- /dev/null
+++ b/record-and-playback/mconf_encrypted/scripts/process/mconf_encrypted.rb
@@ -0,0 +1,57 @@
+# Set encoding to utf-8
+# encoding: UTF-8
+#
+# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+#
+# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+#
+# This program is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 3.0 of the License, or (at your option) any later
+# version.
+#
+# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+#
+
+
+require '../../core/lib/recordandplayback'
+require 'rubygems'
+require 'trollop'
+require 'yaml'
+
+opts = Trollop::options do
+  opt :meeting_id, "Meeting id to archive", :default => '58f4a6b3-cd07-444d-8564-59116cb53974', :type => String
+end
+
+meeting_id = opts[:meeting_id]
+
+#Mconf process log file
+logger = Logger.new("/var/log/bigbluebutton/mconf_encrypted/process-#{meeting_id}.log", 'daily' )
+BigBlueButton.logger = logger
+
+# This script lives in scripts/archive/steps while bigbluebutton.yml lives in scripts/
+props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml'))
+
+recording_dir = props['recording_dir']
+raw_presentation_src = props['raw_presentation_src']
+
+meeting_raw_dir = "#{recording_dir}/raw/#{meeting_id}"
+meeting_raw_presentation_dir = "#{raw_presentation_src}/#{meeting_id}"
+meeting_process_dir = "#{recording_dir}/process/mconf_encrypted/#{meeting_id}"
+
+if not FileTest.directory?(meeting_process_dir)
+  FileUtils.mkdir_p "#{meeting_process_dir}"
+
+  # We used to copy the raw files to the process directory, but it takes extra
+  # unnecessary disk space, so we create the process dir but leave it empty. The
+  # publish phase will use the data from the raw dir
+
+  process_done = File.new("#{recording_dir}/status/processed/#{meeting_id}-mconf_encrypted.done", "w")
+  process_done.write("Processed #{meeting_id}")
+  process_done.close
+end
diff --git a/record-and-playback/mconf_encrypted/scripts/publish/mconf_encrypted.rb b/record-and-playback/mconf_encrypted/scripts/publish/mconf_encrypted.rb
new file mode 100755
index 0000000000000000000000000000000000000000..dd1ab80e2b9e6bc6becdd8e7d923354452d5e65f
--- /dev/null
+++ b/record-and-playback/mconf_encrypted/scripts/publish/mconf_encrypted.rb
@@ -0,0 +1,160 @@
+# Set encoding to utf-8
+# encoding: UTF-8
+#
+# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+#
+# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+#
+# This program is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 3.0 of the License, or (at your option) any later
+# version.
+#
+# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+#
+
+require '../../core/lib/recordandplayback'
+require 'rubygems'
+require 'yaml'
+require 'cgi'
+require 'digest/md5'
+
+bbb_props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml'))
+
+recording_dir = bbb_props['recording_dir']
+playback_host = bbb_props['playback_host']
+published_dir = bbb_props['published_dir']
+raw_presentation_src = bbb_props['raw_presentation_src']
+
+done_files = Dir.glob("#{recording_dir}/status/processed/*.done")
+done_files.each do |df|
+  match = /(.*)-(.*).done/.match df.sub(/.+\//, "")
+  meeting_id = match[1]
+  if (match[2] == "mconf_encrypted")
+    BigBlueButton.logger = Logger.new("/var/log/bigbluebutton/mconf_encrypted/publish-#{meeting_id}.log", 'daily' )
+
+    meeting_publish_dir = "#{recording_dir}/publish/mconf_encrypted/#{meeting_id}"
+    meeting_published_dir = "#{recording_dir}/published/mconf_encrypted/#{meeting_id}"
+    meeting_raw_dir = "#{recording_dir}/raw/#{meeting_id}"
+    meeting_raw_presentation_dir = "#{raw_presentation_src}/#{meeting_id}"
+
+    if not FileTest.directory?(meeting_publish_dir)
+      FileUtils.mkdir_p meeting_publish_dir
+
+      Dir.chdir("#{recording_dir}/raw") do
+        command = "tar -czf #{meeting_publish_dir}/#{meeting_id}.tar.gz #{meeting_id}"
+        status = BigBlueButton.execute(command)
+        if not status.success?
+          raise "Couldn't compress the raw files"
+        end
+      end
+
+      Dir.chdir(meeting_publish_dir) do
+        metadata = BigBlueButton::Events.get_meeting_metadata("#{meeting_raw_dir}/events.xml")
+
+        length = 16
+        chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
+        password = ''
+        length.times { password << chars[rand(chars.size)] }
+
+        passfile = File.new("#{meeting_id}.txt", "w")
+        passfile.write "#{password}"
+        passfile.close
+
+        # encrypt files
+        command = "openssl enc -aes-256-cbc -pass file:#{meeting_id}.txt < #{meeting_id}.tar.gz > #{meeting_id}.dat"
+        status = BigBlueButton.execute(command)
+        if not status.success?
+          raise "Couldn't encrypt the recording file using the random key"
+        end
+
+        FileUtils.rm_f "#{meeting_id}.tar.gz"
+
+        key_filename = ""
+        if metadata.has_key?('mconflb-rec-server-key') and not metadata['mconflb-rec-server-key'].to_s.empty?
+          key_filename = "#{meeting_id}.enc"
+          # the key is already unescaped in the metadata
+          public_key_decoded = "#{metadata['mconflb-rec-server-key'].to_s}"
+          public_key_filename = "public-key.pem"
+          public_key = File.new("#{public_key_filename}", "w")
+          public_key.write "#{public_key_decoded}"
+          public_key.close
+
+          command = "openssl rsautl -encrypt -pubin -inkey #{public_key_filename} < #{meeting_id}.txt > #{meeting_id}.enc"
+          status = BigBlueButton.execute(command)
+          if not status.success?
+            raise "Couldn't encrypt the random key using the server public key passed as metadata"
+          end
+
+          FileUtils.rm_f ["#{meeting_id}.txt", "#{public_key_filename}"]
+        else
+          key_filename = "#{meeting_id}.txt"
+          BigBlueButton.logger.warn "No public key was found in the meeting's metadata"
+        end
+
+        # generate md5 checksum
+        md5sum = Digest::MD5.file("#{meeting_id}.dat")
+
+        BigBlueButton.logger.info("Creating metadata.xml")
+
+        # Get the real-time start and end timestamp
+        meeting_start = BigBlueButton::Events.first_event_timestamp("#{meeting_raw_dir}/events.xml")
+        meeting_end = BigBlueButton::Events.last_event_timestamp("#{meeting_raw_dir}/events.xml")
+        match = /.*-(\d+)$/.match(meeting_id)
+        real_start_time = match[1]
+        real_end_time = (real_start_time.to_i + (meeting_end.to_i - meeting_start.to_i)).to_s
+
+        # Create metadata.xml
+        b = Builder::XmlMarkup.new(:indent => 2)
+        metaxml = b.recording {
+          b.id(meeting_id)
+          b.state("available")
+          b.published(true)
+          # Date Format for recordings: Thu Mar 04 14:05:56 UTC 2010
+          b.start_time(real_start_time)
+          b.end_time(real_end_time)
+          b.download {
+            b.format("encrypted")
+            b.link("http://#{playback_host}/mconf_encrypted/#{meeting_id}/#{meeting_id}.dat")
+            b.md5(md5sum)
+            b.key("http://#{playback_host}/mconf_encrypted/#{meeting_id}/#{key_filename}")
+          }
+          b.meta {
+            BigBlueButton::Events.get_meeting_metadata("#{meeting_raw_dir}/events.xml").each { |k,v| b.method_missing(k,v) }
+          }
+        }
+
+        metadata_xml = File.new("metadata.xml","w")
+        metadata_xml.write(metaxml)
+        metadata_xml.close
+
+        # After all the processing we'll add the published format and raw sizes to the metadata file
+        BigBlueButton.add_raw_size_to_metadata(meeting_publish_dir, meeting_raw_dir)
+        BigBlueButton.add_download_size_to_metadata(meeting_publish_dir)
+
+        BigBlueButton.logger.info("Publishing mconf_encrypted")
+
+        # Now publish this recording
+        if not FileTest.directory?("#{published_dir}/mconf_encrypted")
+          FileUtils.mkdir_p "#{published_dir}/mconf_encrypted"
+        end
+        BigBlueButton.logger.info("Publishing files")
+        FileUtils.mv(meeting_publish_dir, "#{published_dir}/mconf_encrypted")
+
+        BigBlueButton.logger.info("Removing the recording raw files: #{meeting_raw_dir}")
+        FileUtils.rm_r meeting_raw_dir, :force => true
+        BigBlueButton.logger.info("Removing the recording presentation: #{meeting_raw_presentation_dir}")
+        FileUtils.rm_r meeting_raw_presentation_dir, :force => true
+
+        publish_done = File.new("#{recording_dir}/status/published/#{meeting_id}-mconf_encrypted.done", "w")
+        publish_done.write("Published #{meeting_id}")
+        publish_done.close
+      end
+    end
+  end
+end
diff --git a/record-and-playback/presentation/playback/presentation/0.81/logo.png b/record-and-playback/presentation/playback/presentation/0.81/logo.png
index 8f181420c325b665b8a49972f137e1471c305410..ce4ab709dbe496ea387b0ff14164adad7a60a947 100755
Binary files a/record-and-playback/presentation/playback/presentation/0.81/logo.png and b/record-and-playback/presentation/playback/presentation/0.81/logo.png differ
diff --git a/record-and-playback/presentation/playback/presentation/0.81/playback.html b/record-and-playback/presentation/playback/presentation/0.81/playback.html
index e9824c538b1603b35bbb914769a1d02f4b12676e..ef51674823d038740d06463bde36881c589027b6 100755
--- a/record-and-playback/presentation/playback/presentation/0.81/playback.html
+++ b/record-and-playback/presentation/playback/presentation/0.81/playback.html
@@ -18,7 +18,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 -->
 <html>
 <head>
-  <title>BigBlueButton Playback</title>
+  <title>Recording Playback</title>
   <link rel="stylesheet" href="css/bbb.playback.css">
   <script type="text/javascript" src="lib/jquery.min.js"></script>
   <script type="text/javascript" src="lib/jquery-ui.min.js"></script>
@@ -46,7 +46,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
   </style>
 </head>
 <body>
-	<h1 class="visually-hidden">BigBlueButton Playback</h1>
+	<h1 class="visually-hidden">Recording Playback</h1>
 	<div id="playbackArea" class="clearfix" role="main">
 		<h2 class="visually-hidden">Slide Thumbnails</h2>
 		<div id="thumbnails" role="region" aria-label="Slide thumbnails"></div>
@@ -90,7 +90,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 	</div>
 	-->
 	<div id="footer">
-                <p>Recorded with <a target="_blank" href="http://bigbluebutton.org/">BigBlueButton</a>. </p>
+                <p>Recorded with <a target="_blank" href="http://mconf.org/">Mconf</a>. </p>
                 <p>Use <a target="_blank" href="http://mozilla.org/firefox">Mozilla Firefox</a> or
                    <a target="_blank" href="http://google.com/chrome/">Google Chrome</a> to play this recording.
                 </p>
diff --git a/record-and-playback/presentation/playback/presentation/0.9.0/lib/writing.js b/record-and-playback/presentation/playback/presentation/0.9.0/lib/writing.js
index 80fcb462f2b670678a40447eaed03b84367c40c5..9b2710d34a491091299211036fb5ba3fe452caf3 100755
--- a/record-and-playback/presentation/playback/presentation/0.9.0/lib/writing.js
+++ b/record-and-playback/presentation/playback/presentation/0.9.0/lib/writing.js
@@ -122,6 +122,36 @@ function removeSlideChangeAttribute() {
 	Popcorn('#video').unlisten(Popcorn.play, 'removeSlideChangeAttribute');
 }
 
+function hideWhiteboardIfDeskshare(time) {
+  var num_current = current_image.substr(5);
+  var wbcanvas;
+
+  if(svgobj.contentDocument)
+    wbcanvas = svgobj.contentDocument.getElementById("canvas" + num_current);
+  else
+    wbcanvas = svgobj.getSVGDocument('svgfile').getElementById("canvas" + num_current);
+
+  if(wbcanvas !== null) {
+    var sharing = false;
+
+    for (var m = 0; m < deskshareTimes.length; m++) {
+      var start_timestamp = deskshareTimes[m][0];
+      var stop_timestamp = deskshareTimes[m][1];
+
+      if(time >= start_timestamp && time <= stop_timestamp)
+        sharing = true;
+    }
+
+    if(sharing) {
+      wbcanvas.setAttribute("display", "none");
+      document.getElementById("cursor").style.display = 'none';
+    } else {
+      wbcanvas.setAttribute("display", "");
+      document.getElementById("cursor").style.display = '';
+    }
+  }
+}
+
 // - - - END OF JAVASCRIPT FUNCTIONS - - - //
 
 
@@ -258,6 +288,23 @@ function runPopcorn() {
   }
 
 
+  // PROCESS DESKSHARE.XML
+  console.log("** Getting deskshare.xml");
+  xmlhttp.open("GET", deskshare_xml, false);
+  xmlhttp.send();
+  xmlDoc = xmlhttp.responseXML;
+  //getting all the event tags
+  console.log("** Processing deskshare.xml");
+  var deskelements = xmlDoc.getElementsByTagName("recording");
+  var deskshareArray = deskelements[0].getElementsByTagName("event");
+
+  if(deskshareArray != null && deskshareArray.length != 0) {
+    for (var m = 0; m < deskshareArray.length; m++) {
+      var deskTimes = [parseFloat(deskshareArray[m].getAttribute("start_timestamp")),parseFloat(deskshareArray[m].getAttribute("stop_timestamp"))];
+      deskshareTimes[m] = deskTimes;
+    }
+  }
+
   svgobj.style.left = document.getElementById("slide").offsetLeft + "px";
   svgobj.style.top = "0px";
   var next_shape;
@@ -428,6 +475,7 @@ function runPopcorn() {
             currentImage = thisimg;
             resizeSlides();
           }
+          hideWhiteboardIfDeskshare(t);
        }
     }
   });
@@ -502,6 +550,7 @@ var imageAtTime = {};
 var slidePlainText = {}; //holds slide plain text for retrieval
 var cursorStyle;
 var cursorShownAt = 0;
+var deskshareTimes = [];
 
 var params = getUrlParameters();
 var MEETINGID = params.meetingId;
@@ -512,6 +561,7 @@ var shapes_svg = url + '/shapes.svg';
 var events_xml = url + '/panzooms.xml';
 var cursor_xml = url + '/cursor.xml';
 var metadata_xml = url + '/metadata.xml';
+var deskshare_xml = url + '/deskshare.xml';
 
 var firstLoad = true;
 var svjobjLoaded = false;
diff --git a/record-and-playback/presentation/playback/presentation/0.9.0/logo.png b/record-and-playback/presentation/playback/presentation/0.9.0/logo.png
index 4e4e97c4cd72da35001ebd90e34b7be06eb7db3c..395446fcb9f6df10a87b1d16c396ab47a6379ce9 100644
Binary files a/record-and-playback/presentation/playback/presentation/0.9.0/logo.png and b/record-and-playback/presentation/playback/presentation/0.9.0/logo.png differ
diff --git a/record-and-playback/presentation/playback/presentation/0.9.0/playback.html b/record-and-playback/presentation/playback/presentation/0.9.0/playback.html
index 54aae44f05d65c27167b225e8f8526d2445edfef..bf4c743d970327c12919810629ead5cb4d777e9e 100755
--- a/record-and-playback/presentation/playback/presentation/0.9.0/playback.html
+++ b/record-and-playback/presentation/playback/presentation/0.9.0/playback.html
@@ -21,7 +21,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>BigBlueButton Playback</title>
+  <title>Recording Playback</title>
 
   <link rel="stylesheet" type="text/css" href="acornmediaplayer/acornmediaplayer.base.css" />
   <link rel="stylesheet" type="text/css" href="acornmediaplayer/themes/access/acorn.access.css" />
@@ -45,7 +45,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
         <a class="left-off-canvas-toggle menu-icon" href="#">
           <i class="sidebar-icon fi-list"></i>
         </a>
-        <h1 id="recording-title">BigBlueButton Playback</h1>
+        <h1 id="recording-title">Recording Playback</h1>
       </div>
 
       <aside class="left-off-canvas-menu">
@@ -67,7 +67,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
           </div>
 
           <div id="copyright">
-            Recorded with <a target="_blank" href="http://bigbluebutton.org/">BigBlueButton</a>.
+            Recorded with <a target="_blank" href="http://mconf.org/">Mconf</a>.
             Use <a target="_blank" href="http://mozilla.org/firefox">Mozilla Firefox</a> or
             <a target="_blank" href="http://google.com/chrome/">Google Chrome</a> to play this recording.
           </div>
diff --git a/record-and-playback/presentation/scripts/publish/presentation.rb b/record-and-playback/presentation/scripts/publish/presentation.rb
index 3335020ae06fa0bb5ae4e7be478ad589a6e3a1d8..fc337937950a848ca68db05f7ad60018c0200969 100755
--- a/record-and-playback/presentation/scripts/publish/presentation.rb
+++ b/record-and-playback/presentation/scripts/publish/presentation.rb
@@ -858,7 +858,15 @@ def processChatMessages
             chat_sender = node.xpath(".//sender")[0].text()
             chat_message =  BigBlueButton::Events.linkify(node.xpath(".//message")[0].text())
             chat_start = ( translateTimestamp(chat_timestamp) / 1000).to_i
-            $xml.chattimeline(:in => chat_start, :direction => :down,  :name => chat_sender, :message => chat_message, :target => :chat )
+            # Creates a list of the clear timestamps that matter for this message
+            next_clear_timestamps = $clear_chat_timestamps.select{ |e| e >= node[:timestamp] }
+            # If there is none we skip it, or else we add the out time that will remove a message
+            if next_clear_timestamps.empty?
+              $xml.chattimeline(:in => chat_start, :direction => :down,  :name => chat_sender, :message => chat_message, :target => :chat )
+            else
+              chat_end = ( translateTimestamp( next_clear_timestamps.first ) / 1000).to_i
+              $xml.chattimeline(:in => chat_start, :out => chat_end, :direction => :down,  :name => chat_sender, :message => chat_message, :target => :chat )
+            end
           end
         end
         current_time += re[:stop_timestamp] - re[:start_timestamp]
@@ -867,6 +875,34 @@ def processChatMessages
   end
 end
 
+def processDeskshareEvents
+  BigBlueButton.logger.info("Processing deskshare events on presentation.rb")
+
+  BigBlueButton.logger.info("Getting deskshare events in #{$process_dir}/events.xml" );
+  deskshare_start_evts = BigBlueButton::Events.get_start_deskshare_events("#{$process_dir}/events.xml")
+  deskshare_stop_evts = BigBlueButton::Events.get_stop_deskshare_events("#{$process_dir}/events.xml")
+  deskshare_matched_evts = BigBlueButton::Events.match_start_and_stop_video_events(deskshare_start_evts, deskshare_stop_evts)
+
+  $deskshare_xml = Nokogiri::XML::Builder.new do |xml|
+    $xml = xml
+    $xml.recording('id' => 'deskshare_events') do
+      if(!deskshare_matched_evts.empty?)
+        deskshare_matched_evts.each do |start_evt|
+          start_timestamp_orig = start_evt[:start_timestamp].to_f
+          stop_timestamp_orig = start_evt[:stop_timestamp].to_f
+
+          start_timestamp = ( translateTimestamp(start_timestamp_orig) / 1000 ).round(1)
+          stop_timestamp = ( translateTimestamp(stop_timestamp_orig) / 1000 ).round(1)
+          BigBlueButton.logger.info("start_timestamp = #{start_timestamp}, stop_timestamp = #{stop_timestamp}")
+
+          $xml.event(:start_timestamp => start_timestamp, :stop_timestamp => stop_timestamp)
+        end
+      end
+    end
+  end
+  BigBlueButton.logger.info("Finished processing deskshare events on presentation.rb")
+end
+
 $vbox_width = 1600
 $vbox_height = 1200
 $magic_mystery_number = 2
@@ -874,6 +910,7 @@ $shapesold_svg_filename = 'shapes_old.svg'
 $shapes_svg_filename = 'shapes.svg'
 $panzooms_xml_filename = 'panzooms.xml'
 $cursor_xml_filename = 'cursor.xml'
+$deskshare_xml_filename = 'deskshare.xml'
 
 $originX = "NaN"
 $originY = "NaN"
@@ -1064,6 +1101,12 @@ begin
         $join_time = $meeting_start.to_f
         $end_time = $meeting_end.to_f
 
+        # Create a list of timestamps when the moderator cleared the public chat
+		$clear_chat_timestamps = [ ]
+		clear_chat_events = @doc.xpath("//event[@eventname='ClearPublicChatEvent']")
+		clear_chat_events.each { |clear| $clear_chat_timestamps << clear[:timestamp] }
+		$clear_chat_timestamps.sort!
+
         calculateRecordEventsOffset()
 
         first_presentation_start_node = @doc.xpath("//event[@eventname='SharePresentationEvent']")
@@ -1081,6 +1124,8 @@ begin
 
         processCursorEvents()
 
+        processDeskshareEvents()
+
         # Write slides.xml to file
         File.open("#{package_dir}/slides_new.xml", 'w') { |f| f.puts $slides_doc.to_xml }
         # Write shapes.svg to file
@@ -1092,6 +1137,9 @@ begin
         # Write panzooms.xml to file
         File.open("#{package_dir}/#{$cursor_xml_filename}", 'w') { |f| f.puts $cursor_xml.to_xml }
 
+        # Write deskshare.xml to file
+        File.open("#{package_dir}/#{$deskshare_xml_filename}", 'w') { |f| f.puts $deskshare_xml.to_xml }
+
         BigBlueButton.logger.info("Copying files to package dir")
         FileUtils.cp_r("#{$process_dir}/presentation", package_dir)
         BigBlueButton.logger.info("Copied files to package dir")
@@ -1101,6 +1149,13 @@ begin
         if not FileTest.directory?(publish_dir)
           FileUtils.mkdir_p publish_dir
         end
+
+        # Get raw size of presentation files
+        raw_dir = "#{recording_dir}/raw/#{$meeting_id}"
+        # After all the processing we'll add the published format and raw sizes to the metadata file
+        BigBlueButton.add_raw_size_to_metadata(package_dir, raw_dir)
+        BigBlueButton.add_playback_size_to_metadata(package_dir)
+
         FileUtils.cp_r(package_dir, publish_dir) # Copy all the files.
         BigBlueButton.logger.info("Finished publishing script presentation.rb successfully.")
 
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/acornmediaplayer.base.css b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/acornmediaplayer.base.css
new file mode 100755
index 0000000000000000000000000000000000000000..06378fdfb078be972aad5f31a57e7542d971ecde
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/acornmediaplayer.base.css
@@ -0,0 +1,222 @@
+/*
+ * Acorn Media Player - jQuery plugin 1.0
+ *
+ * Copyright (C) 2010 Cristian I. Colceriu
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * www.ghinda.net
+ * contact@ghinda.net
+ *
+ * Base stylesheet
+ *
+ */
+
+/* Main elements */
+.acorn-player, .acorn-controls {
+	position: relative;
+}
+.acorn-timer {
+	cursor: default;
+}
+.acorn-buffer {
+	width: 0px;
+}
+/* <video> */
+.acorn-player video {
+	background-color: #000;
+}
+/* <audio> */
+.acorn-player.audio-player {
+	width: 500px;
+}
+.acorn-player.audio-player audio {
+	display: none;
+}
+/* Captions and Transcript */
+.acorn-transcript {	
+	clear: both;
+	display: none;
+	
+	overflow: auto;
+	height: 15em;
+}
+.acorn-transcript-button {
+	display: none;
+}
+/* 
+ * Show the timings in square brackets before each "subtitle" in the transcript.
+ * Borrowed and adapted from Bruce Lawson's “Accessible HTML5 Video with JavaScripted captions”
+ * http://dev.opera.com/articles/view/accessible-html5-video-with-javascripted-captions/
+ */
+.acorn-transcript span {
+	display: block;
+	float: left;
+	width: 100%;
+	line-height: 1.5em;
+	
+	-moz-border-radius: 5px;
+	-webkit-border-radius: 5px;
+	border-radius: 5px;
+}
+.acorn-transcript span:hover {
+	background-color: #cadde7 !important;
+	
+	font-weight: bold;
+}
+.acorn-transcript span:nth-of-type(even) {
+	background-color: #efefef;
+}
+.acorn-transcript [data-begin]:before {
+	display: block;
+	float: left;
+	content: " [" attr(data-begin) "s-" attr(data-end)"s]   ";
+	width: 15%;
+	padding: 0.2em 1.5em 0.2em 0.2em;	
+}
+.acorn-caption {
+	display: none;
+	position: absolute;
+	bottom: 75px;
+	width: 100%;
+	
+	text-align: center;
+}
+.acorn-caption-button {
+	display: none;
+}
+.acorn-caption-selector {
+	position: absolute;
+	display: none;
+	width: 170px;
+	padding: 5px;
+	height: 75px;
+	margin-bottom: 10px;
+	overflow: auto;
+	
+	background-color: #000;
+	border: 3px solid #fff;
+
+	z-index: 3;
+	
+	-moz-border-radius: 5px;
+	-webkit-border-radius: 5px;
+	border-radius: 5px;
+	
+	-moz-box-shadow: 0px 1px 5px #000;
+	-webkit-box-shadow: 0px 1px 5px #000;
+	box-shadow: 0px 1px 5px #000;
+}
+.acorn-caption-selector label {
+	display: block;
+	
+	font-weight: bold;
+	color: #fff;
+}
+.acorn-caption-selector ul, .acorn-caption-selector li {
+	list-style-type: none;
+	margin: 0px;
+	padding: 0px;
+}
+/* Fullscreen Mode */
+.fullscreen-video {
+	position: fixed !important;
+	top: 0px;
+	left: 0px;
+	z-index: 99999 !important;
+	
+	background-color: #000;
+}
+.acorn-controls.fullscreen-controls {
+	position: fixed !important;
+	z-index: 100000 !important;
+}
+/* Loading */
+.show-loading .loading-media {
+	visibility: visible;
+}
+
+.loading-media {
+	visibility: hidden;
+	position: absolute;
+	left: 25%;
+	top: 50%;
+	width: 20px;
+	height: 20px;
+	margin-top: -10px;
+	margin-lefT: -10px;
+	
+	background-color: #000;
+	border: 5px solid #fff;
+	border-top: 5px solid rgba(0,0,0,0);
+	border-left: 5px solid rgba(0,0,0,0);
+	border-radius: 20px;
+	
+	animation: spin 1s infinite linear;
+	-o-animation: spin 1s infinite linear;
+	-moz-animation: spin 1s infinite linear;
+	-webkit-animation: spin 1s infinite linear;
+}
+
+@-o-keyframes spin {
+	0% { -o-transform:rotate(0deg); }
+	100% { -o-transform:rotate(360deg); }
+}
+@-ms-keyframes spin {
+	0% { -ms-transform:rotate(0deg); }
+	100% { -ms-transform:rotate(360deg); }
+}
+@-moz-keyframes spin {
+	0% { -moz-transform:rotate(0deg); }
+	100% { -moz-transform:rotate(360deg); }
+}
+@-webkit-keyframes spin {
+	0% { -webkit-transform:rotate(0deg); }
+	100% { -webkit-transform:rotate(360deg); }
+}
+@keyframes spin {
+	0% { transform:rotate(0deg); }
+	100% { transform:rotate(360deg); }
+}
+
+/* Controls overlay while loading */
+.show-loading .acorn-controls:after {
+	content: '';
+	position: absolute;
+	top: -2px; /* Slider handle goes above */
+	padding-bottom: 2px;
+	left: 0;
+	z-index: 10;
+	width: 100%;
+	height: 100%;
+	
+	background: #000;
+	opacity: 0.9;
+}
+
+/* Styles needed for the jQuery UI slider
+ * We're declaring these so we don't have to use jQuery UI's stylesheet
+ */
+a.ui-slider-handle {
+	position: absolute;
+	display: block;
+	margin-left: -0.6em;
+	z-index: 2;
+	cursor: default;
+	outline: none;
+}
+.ui-slider {
+	position: relative;
+}
+.ui-slider-range {
+	position: absolute;
+	display: block;
+	width: 100%;
+	height: 100%;
+	left: 0;
+	bottom: 0;
+	border: none;
+	z-index: 1;
+}
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/jquery.acornmediaplayer.js b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/jquery.acornmediaplayer.js
new file mode 100755
index 0000000000000000000000000000000000000000..22f941b1d225be42049c500df15a628cfbba9d5b
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/jquery.acornmediaplayer.js
@@ -0,0 +1,1067 @@
+/*
+ * Acorn Media Player - jQuery plugin 1.6
+ *
+ * Copyright (C) 2012 Ionut Cristian Colceriu
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * www.ghinda.net
+ * contact@ghinda.net
+ *
+ */
+ 
+(function($) {
+	$.fn.acornMediaPlayer = function(options) {
+		/*
+		 * Define default plugin options
+		 */
+		var defaults = {
+			theme: 'access',
+			nativeSliders: false,
+			volumeSlider: 'horizontal',
+			captionsOn: false
+		};
+		options = $.extend(defaults, options);
+		
+		/* 
+		 * Function for generating a unique identifier using the current date and time
+		 * Used for generating an ID for the media elmenet when none is available
+		 */
+		var uniqueID = function() {
+			var currentDate = new Date();
+			return currentDate.getTime();
+		};
+		
+		/* 
+		 * Detect support for localStorage
+		 */
+		function supports_local_storage() {
+			try {
+				return 'localStorage' in window && window.localStorage !== null;
+			} catch(e){
+				return false;
+			}
+		}
+		
+		/* Detect Touch support
+		 */
+		var is_touch_device = 'ontouchstart' in document.documentElement;
+		
+		/*
+		 * Get the volume value from localStorage
+		 * If no value is present, define as maximum
+		 */
+		var volume = (supports_local_storage) ? localStorage.getItem('acornvolume') : 1;
+		if(!volume) {
+			volume = 1;
+		}
+		
+		/* 
+		 * Main plugin function
+		 * It will be called on each element in the matched set
+		 */
+		var acornPlayer = function() {
+			// set the acorn object, will contain the needed DOM nodes and others
+			var acorn = {
+				$self: $(this)
+			};
+			
+			var loadedMetadata; // Is the metadata loaded
+			var seeking; // The user is seeking the media
+			var wasPlaying; // Media was playing when the seeking started
+			var fullscreenMode; // The media is in fullscreen mode
+			var captionsActive; // Captions are active
+			
+			/* Define all the texts used
+			 * This makes it easier to maintain, make translations, etc.
+			*/
+			var text = {
+				play: 'Play',
+				playTitle: 'Start the playback',
+				pause: 'Pause',
+				pauseTitle: 'Pause the playback',
+				mute: 'Mute',
+				unmute: 'Unmute',
+				fullscreen: 'Fullscreen',
+				fullscreenTitle: 'Toggle fullscreen mode',
+				swap: 'Swap',
+				swapTitle: 'Toggle video and presention swap',
+				volumeTitle: 'Volume control',
+				seekTitle: 'Video seek control',
+				captions: 'Captions',
+				captionsTitle: 'Show captions',
+				captionsChoose: 'Choose caption',
+				transcript: 'Transcript',
+				transcriptTitle: 'Show transcript'
+			};
+			
+			// main wrapper element
+			var $wrapper = $('<div class="acorn-player" role="application"></div>').addClass(options.theme);
+
+			/*
+			 * Define attribute tabindex on the main element to make it readchable by keyboard
+			 * Useful when "aria-describedby" is present
+			 *
+			 * It makes more sense for screen reader users to first reach the actual <video> or <audio> elment and read of description of it,
+			 * than directly reach the Media Player controls, without knowing what they control.
+			 */
+			acorn.$self.attr('tabindex', '0');		
+			
+			/*
+			 * Check if the main element has an ID attribute
+			 * If not present, generate one
+			 */
+			acorn.id = acorn.$self.attr('id');
+			if(!acorn.id) {
+				acorn.id = 'acorn' + uniqueID();
+				acorn.$self.attr('id', acorn.id);
+			}
+			
+			/* 
+			 * Markup for the fullscreen button
+			 * If the element is not <video> we leave if blank, as the button if useless on <audio> elements
+			 */
+			var fullscreenBtnMarkup = (acorn.$self.is('video')) ? '<button class="acorn-fullscreen-button" title="' + text.fullscreenTitle + '" aria-controls="' + acorn.id + '" tabindex="3">' + text.fullscreen + '</button>' : '';
+			
+			/* 
+			 * Markup for the swap button
+			 * If the element is not <video> we leave if blank, as the button if useless on <audio> elements
+			 */
+			var swapBtnMarkup = (acorn.$self.is('video')) ? '<button class="acorn-swap-button" title="' + text.swapTitle + '" aria-controls="' + acorn.id + '" tabindex="4" >' + text.swap + '</button>' : '';
+			
+
+			/*
+			 * Complete markup
+			 */
+			var template = '<div class="acorn-controls">' +
+								'<button class="acorn-play-button" title="' + text.playTitle + '" aria-controls="' + acorn.id + '" tabindex="1">' + text.play + '</button>' +
+								'<input type="range" class="acorn-seek-slider" title="' + text.seekTitle + '" value="0" min="0" max="150" step="0.1" aria-controls="' + acorn.id + '" tabindex="2" />' +
+								'<span class="acorn-timer">00:00</span>' +
+								'<div class="acorn-volume-box">' +
+									'<button class="acorn-volume-button" title="' + text.mute + '" aria-controls="' + acorn.id + '" tabindex="5" >' + text.mute + '</button>' +
+									'<input type="range" class="acorn-volume-slider" title="' + text.volumeTitle + '" value="1" min="0" max="1" step="0.05" aria-controls="' + acorn.id + '" tabindex="6" />' +
+								'</div>' +
+								swapBtnMarkup +
+								fullscreenBtnMarkup +
+								'<button class="acorn-caption-button" title="' + text.captionsTitle + '"  aria-controls="' + acorn.id + '">' + text.captions + '</button>' +
+								'<div class="acorn-caption-selector"></div>' +
+								'<button class="acorn-transcript-button" title="' + text.transcriptTitle + '">' + text.transcript + '</button>' +
+							'</div>';
+
+			var captionMarkup = '<div class="acorn-caption"></div>';
+			var transcriptMarkup = '<div class="acorn-transcript" role="region" aria-live="assertive"></div>';				
+			
+			/*
+			 * Append the HTML markup
+			 */
+			
+			// append the wrapper
+			acorn.$self.after($wrapper);
+			
+			// For iOS support, I have to clone the node, remove the original, and get a reference to the new one.
+			// This is because iOS doesn't want to play videos that have just been `moved around`.
+			// More details on the issue: http://bugs.jquery.com/ticket/8015
+			$wrapper[0].appendChild( acorn.$self[0].cloneNode(true) );
+			
+			acorn.$self.trigger('pause');
+			acorn.$self.remove();
+			acorn.$self = $wrapper.find('video, audio');
+			
+			// append the controls and loading mask
+			acorn.$self.after(template).after('<div class="loading-media"></div>');
+			
+			/*
+			 * Define the newly created DOM nodes
+			 */
+			acorn.$container = acorn.$self.parent('.acorn-player');
+			
+			acorn.$controls = $('.acorn-controls', acorn.$container);
+			acorn.$playBtn = $('.acorn-play-button', acorn.$container);
+			acorn.$seek = $('.acorn-seek-slider', acorn.$container);
+			acorn.$timer = $('.acorn-timer', acorn.$container);
+			acorn.$volume = $('.acorn-volume-slider', acorn.$container);
+			acorn.$volumeBtn = $('.acorn-volume-button', acorn.$container);
+			acorn.$fullscreenBtn = $('.acorn-fullscreen-button', acorn.$container);				
+			acorn.$swapBtn = $('.acorn-swap-button', acorn.$container);	
+			/*
+			 * Append the markup for the Captions and Transcript
+			 * and define newly created DOM nodes for these
+			 */
+			acorn.$controls.after(captionMarkup);
+			acorn.$container.after(transcriptMarkup);
+			
+			acorn.$transcript = acorn.$container.next('.acorn-transcript');
+			acorn.$transcriptBtn = $('.acorn-transcript-button', acorn.$container);
+		
+			acorn.$caption = $('.acorn-caption', acorn.$container);
+			acorn.$captionBtn = $('.acorn-caption-button', acorn.$container);
+			acorn.$captionSelector = $('.acorn-caption-selector', acorn.$container);
+			
+			/*
+			 * Use HTML5 "data-" attributes to set the original Width&Height for the <video>
+			 * These are used when returning from Fullscreen Mode
+			 */
+			acorn.$self.attr('data-width', acorn.$self.width());
+			acorn.$self.attr('data-height', acorn.$self.height());
+			
+			/*
+			 * Time formatting function
+			 * Takes the number of seconds as a parameter and return a readable format "minutes:seconds"
+			 * Used with the number of seconds returned by "currentTime"
+			 */
+			var timeFormat = function(sec) {
+				var m = Math.floor(sec/60)<10?"0" + Math.floor(sec/60):Math.floor(sec/60);
+				var s = Math.floor(sec-(m*60))<10?"0" + Math.floor(sec-(m*60)):Math.floor(sec-(m*60));
+				return m + ":" + s;
+			};
+			
+			/*
+			 * PLAY/PAUSE Behaviour			 
+			 *
+			 * Function for the Play button
+			 * It triggers the native Play or Pause events
+			 */
+			var playMedia = function() {
+				if(!acorn.$self.prop('paused')) {
+					acorn.$self.trigger('pause');
+				} else {
+					//acorn.$self.trigger('play');
+					acorn.$self[0].play();
+				}
+			};
+			
+			/* 
+			 * Functions for native playback events (Play, Pause, Ended)
+			 * These are attached to the native media events.
+			 *
+			 * Even if the user is still using some form of native playback control (such as using the Context Menu)
+			 * it will not break the behviour of our player.
+			 */
+			var startPlayback = function() {
+				acorn.$playBtn.text(text.pause).attr('title', text.pauseTitle);
+				acorn.$playBtn.addClass('acorn-paused-button');
+
+				// if the metadata is not loaded yet, add the loading class
+				if (!loadedMetadata) $wrapper.addClass('show-loading');
+			};
+			
+			var stopPlayback = function() {
+				acorn.$playBtn.text(text.play).attr('title', text.playTitle);
+				acorn.$playBtn.removeClass('acorn-paused-button');
+			};
+			
+			/*
+			 * SEEK SLIDER Behaviour
+			 * 
+			 * Updates the Timer and Seek Slider values
+			 * Is called on each "timeupdate"
+			 */
+			var seekUpdate = function() {
+				var currenttime = acorn.$self.prop('currentTime');
+				acorn.$timer.text(timeFormat(currenttime));	
+				
+				// If the user is not manualy seeking
+				if(!seeking) {
+					// Check type of sliders (Range <input> or jQuery UI)
+					if(options.nativeSliders) {
+						acorn.$seek.attr('value', currenttime);
+					} else {
+						acorn.$seek.slider('value', currenttime);
+					}
+				}
+				
+				// If captions are active, update them
+				if(captionsActive) { 
+					updateCaption(); 
+				}
+			};
+			
+			/*
+			 * Time formatting function
+			 * Takes the number of seconds as a paramenter
+			 * 
+			 * Used with "aria-valuetext" on the Seek Slider to provide a human readable time format to AT
+			 * Returns "X minutes Y seconds"
+			 */
+			var ariaTimeFormat = function(sec) {
+				var m = Math.floor(sec/60)<10?"" + Math.floor(sec/60):Math.floor(sec/60);
+				var s = Math.floor(sec-(m*60))<10?"" + Math.floor(sec-(m*60)):Math.floor(sec-(m*60));
+				var formatedTime;
+									
+				var mins = 'minutes';
+				var secs = 'seconds';
+				
+				if(m == 1) {
+					min = 'minute';
+				}
+				if(s == 1) {
+					sec = 'second';
+				}
+				
+				if(m === 0) {
+					formatedTime = s + ' ' + secs;
+				} else {						
+					formatedTime = m + ' ' + mins + ' ' + s + ' ' + secs;
+				}				
+				
+				return formatedTime;
+			};
+			
+			/* 
+			 * jQuery UI slider uses preventDefault when clicking any element
+			 * so it stops the Blur event from being fired.
+			 * This causes problems with the Caption Selector.
+			 * We trigger the Blur event manually.
+			 */
+			var blurCaptionBtn = function() {
+				acorn.$captionBtn.trigger('blur');				
+			};
+			
+			/*
+			 * Triggered when the user starts to seek manually
+			 * Pauses the media during seek and changes the "currentTime" to the slider's value
+			 */
+			var startSeek = function(e, ui) {					
+				if(!acorn.$self.attr('paused')) {
+					wasPlaying = true;
+				}
+				acorn.$self.trigger('pause');
+				seeking = true;
+				
+				var seekLocation;
+				if(options.nativeSliders) {
+					seekLocation = acorn.$seek.val();
+				} else {
+					seekLocation = ui.value;
+				}
+				
+				acorn.$self[0].currentTime = seekLocation;
+				
+				// manually blur the Caption Button
+				blurCaptionBtn();
+			};
+			
+			/*
+			 * Triggered when user stoped manual seek
+			 * If the media was playing when seek started, it triggeres the playback,
+			 * and updates ARIA attributes
+			 */
+			var endSeek = function(e, ui) {
+				if(wasPlaying) {
+					acorn.$self.trigger('play');
+					wasPlaying = false;
+				}
+				seeking = false;			
+				var sliderUI = $(ui.handle);
+				sliderUI.attr("aria-valuenow", parseInt(ui.value, 10));
+				sliderUI.attr("aria-valuetext", ariaTimeFormat(ui.value));
+			};
+			
+			/*
+			 * Transforms element into ARIA Slider adding attributes and "tabindex"
+			 * Used on jQuery UI sliders
+			 * 
+			 * Will not needed once the jQuery UI slider gets built-in ARIA 
+			 */ 
+			var initSliderAccess = function (elem, opts) {
+				var accessDefaults = {
+				 'role': 'slider',
+				 'aria-valuenow': parseInt(opts.value, 10),
+				 'aria-valuemin': parseInt(opts.min, 10),
+				 'aria-valuemax': parseInt(opts.max, 10),
+				 'aria-valuetext': opts.valuetext
+				};
+				elem.attr(accessDefaults);        
+			};
+			
+			/*
+			 * Init jQuery UI slider
+			 */
+			var initSeek = function() {
+				
+				// get existing classes
+				var seekClass = acorn.$seek.attr('class');
+				
+				// create the new markup
+				var	divSeek = '<div class="' + seekClass + '" title="' + text.seekTitle + '"></div>';
+				acorn.$seek.after(divSeek).remove();
+				
+				// get the newly created DOM node
+				acorn.$seek = $('.' + seekClass, acorn.$container);
+				
+				// create the buffer element
+				var bufferBar = '<div class="ui-slider-range acorn-buffer"></div>';
+				acorn.$seek.append(bufferBar);
+				
+				// get the buffer element DOM node
+				acorn.$buffer = $('.acorn-buffer', acorn.$container);					
+				
+				// set up the slider options for the jQuery UI slider
+				var sliderOptions = {
+					value: 0,
+					step: 1,
+					orientation: 'horizontal',
+					range: 'min',
+					min: 0,
+					max: 100
+				}; 
+				// init the jQuery UI slider
+				acorn.$seek.slider(sliderOptions);
+			
+			};
+			 
+			/*
+			 * Seek slider update, after metadata is loaded
+			 * Attach events, add the "duration" attribute and generate the jQuery UI Seek Slider
+			 */
+			var updateSeek = function() {
+				// Get the duration of the media
+				var duration = acorn.$self[0].duration;			
+				
+				// Check for the nativeSliders option
+				if(options.nativeSliders) {
+					acorn.$seek.attr('max', duration);
+					acorn.$seek.bind('change', startSeek);
+					
+					acorn.$seek.bind('mousedown', startSeek);						
+					acorn.$seek.bind('mouseup', endSeek);
+					
+				} else {
+					
+					// set up the slider options for the jQuery UI slider
+					var sliderOptions = {
+						value: 0,
+						step: 1,
+						orientation: 'horizontal',
+						range: 'min',
+						min: 0,
+						max: duration,
+						slide: startSeek,
+						stop: endSeek
+					}; 
+					// init the jQuery UI slider
+					acorn.$seek.slider('option', sliderOptions);
+					
+					// add valuetext value to the slider options for better ARIA values
+					sliderOptions.valuetext = ariaTimeFormat(sliderOptions.value);
+					// accessify the slider
+					initSliderAccess(acorn.$seek.find('.ui-slider-handle'), sliderOptions);
+					
+					// manully blur the Caption Button when clicking the handle
+					$('.ui-slider-handle', acorn.$seek).click(blurCaptionBtn);
+					
+					// set the tab index
+					$('.ui-slider-handle', acorn.$seek).attr("tabindex", "2");
+
+					// show buffering progress on progress
+					acorn.$self.bind('progress', showBuffer);
+				}
+				
+
+				$wrapper.removeClass('show-loading');
+				// remove the loading element
+				//acorn.$self.next('.loading-media').remove();
+				
+			};
+			
+			/*
+			 * Show buffering progress
+			 */
+			var showBuffer = function(e) {
+				var max = parseInt(acorn.$self.prop('duration'), 10);
+				var tr = this.buffered;
+				if(tr && tr.length) {
+					var buffer = parseInt(this.buffered.end(0)-this.buffered.start(0), 10);
+					var bufferWidth = (buffer*100)/max;
+					
+					acorn.$buffer.css('width', bufferWidth + '%');
+				}				
+			};
+			
+			/*
+			 * VOLUME BUTTON and SLIDER Behaviour
+			 *
+			 * Change volume using the Volume Slider
+			 * Also update ARIA attributes and set the volume value as a localStorage item
+			 */
+			var changeVolume = function(e, ui) {
+				// get the slider value
+				volume = ui.value;
+				// set the value as a localStorage item
+				localStorage.setItem('acornvolume', volume);
+				
+				// check if the volume was muted before
+				if(acorn.$self.prop('muted')) {
+					acorn.$self.prop('muted', false);
+					acorn.$volumeBtn.removeClass('acorn-volume-mute');
+					acorn.$volumeBtn.text(text.mute).attr('title', text.mute);
+				}
+				
+				// set the new volume on the media
+				acorn.$self.prop('volume', volume);
+				
+				// set the ARIA attributes
+				acorn.$volume.$handle.attr("aria-valuenow", Math.round(volume*100));
+				acorn.$volume.$handle.attr("aria-valuetext", Math.round(volume*100) + ' percent');
+				// manually trigger the Blur event on the Caption Button
+				blurCaptionBtn();
+			};
+			
+			/*
+			 * Mute and Unmute volume
+			 * Also add classes and change label on the Volume Button
+			 */
+			var muteVolume = function() {					
+				if(acorn.$self.prop('muted') === true) {						
+					acorn.$self.prop('muted', false);
+					if(options.nativeSliders) {
+						acorn.$volume.val(volume);
+					} else {
+						acorn.$volume.slider('value', volume);
+					}
+					
+					acorn.$volumeBtn.removeClass('acorn-volume-mute');
+					acorn.$volumeBtn.text(text.mute).attr('title', text.mute);
+				} else {
+					acorn.$self.prop('muted', true);
+					
+					if(options.nativeSliders) {
+						acorn.$volume.val('0');
+					} else {
+						acorn.$volume.slider('value', '0');
+					}
+					
+					acorn.$volumeBtn.addClass('acorn-volume-mute');
+					acorn.$volumeBtn.text(text.unmute).attr('title', text.unmute);
+				}
+			};
+			
+			/*
+			 * Init the Volume Button and Slider
+			 *
+			 * Attach events, create the jQuery UI Slider for the Volume Slider and add ARIA support
+			 */
+			var initVolume = function() {
+				if(options.nativeSliders) {
+					acorn.$volume.bind('change', function() {
+						acorn.$self.prop('muted',false);
+						volume = acorn.$volume.val();
+						acorn.$self.prop('volume', volume);
+					});
+				} else {
+					var volumeClass = acorn.$volume.attr('class');
+				
+					var	divVolume = '<div class="' + volumeClass + '" title="' + text.volumeTitle + '"></div>';
+					acorn.$volume.after(divVolume).remove();
+					
+					acorn.$volume = $('.' + volumeClass, acorn.$container);
+					
+					var volumeSliderOptions = {
+						value: volume,
+						orientation: options.volumeSlider,
+						range: "min",
+						max: 1,
+						min: 0,
+						step: 0.1,
+						animate: false,
+						slide: changeVolume
+					};
+					
+					acorn.$volume.slider(volumeSliderOptions);
+					
+					acorn.$volume.$handle = acorn.$volume.find('.ui-slider-handle');
+					
+					// change and add values to volumeSliderOptions for better values in the ARIA attributes
+					volumeSliderOptions.max = 100;
+					volumeSliderOptions.value = volumeSliderOptions.value * 100;
+					volumeSliderOptions.valuetext = volumeSliderOptions.value + ' percent';
+					initSliderAccess(acorn.$volume.$handle, volumeSliderOptions);
+					acorn.$volume.$handle.attr("tabindex", "6");
+					
+					// show the volume slider when it is tabbed into
+					acorn.$volume.$handle.focus(function(){
+						if (!acorn.$volume.parent().is(":hover")) {
+							acorn.$volume.addClass("handle-focused");
+						}
+					});
+					acorn.$volume.$handle.blur(function(){
+						acorn.$volume.removeClass("handle-focused");
+					});
+					// manully blur the Caption Button when clicking the handle
+					$('.ui-slider-handle', acorn.$volume).click(blurCaptionBtn);
+				}
+				
+				acorn.$volumeBtn.click(muteVolume);
+			};
+			
+			/*
+			 * FULLSCREEN Behviour
+			 * 
+			 * Resize the video while in Fullscreen Mode
+			 * Attached to window.resize 
+			 */
+			var resizeFullscreenVideo = function() {
+				acorn.$self.attr({
+					'width': $(window).width(),
+					'height': $(window).height()
+				});
+			};
+			
+			/* 
+			 * Enter and exit Fullscreen Mode
+			 * 
+			 * Resizes the Width & Height of the <video> element
+			 * and add classes to the controls and wrapper
+			 */
+			var goFullscreen = function() {
+				if(fullscreenMode) {
+					if(acorn.$self[0].webkitSupportsFullscreen) {
+						acorn.$self[0].webkitExitFullScreen();
+					} else {
+						$('body').css('overflow', 'auto');
+					
+						var w = acorn.$self.attr('data-width');
+						var h = acorn.$self.attr('data-height');
+					
+						acorn.$self.removeClass('fullscreen-video').attr({
+							'width': w,
+							'height': h
+						});
+						
+						$(window).unbind('resize');
+						
+						acorn.$controls.removeClass('fullscreen-controls');
+					}
+					
+					fullscreenMode = false;
+					
+				} else {						
+					if(acorn.$self[0].webkitSupportsFullscreen) {
+						acorn.$self[0].webkitEnterFullScreen();
+					} else if (acorn.$self[0].mozRequestFullScreen) {
+						acorn.$self[0].mozRequestFullScreen();
+						acorn.$self.attr('controls', 'controls');
+						document.addEventListener('mozfullscreenchange', function() {
+							console.log('screenchange event found');
+							if (!document.mozFullScreenElement) {
+								acorn.$self.removeAttr('controls');
+								//document.removeEventListener('mozfullscreenchange');
+							}
+						});
+					} else {
+						$('body').css('overflow', 'hidden');
+					
+						acorn.$self.addClass('fullscreen-video').attr({
+							width: $(window).width(),
+							height: $(window).height()
+						});
+						
+						$(window).resize(resizeFullscreenVideo);
+						
+						acorn.$controls.addClass('fullscreen-controls');
+					}
+					
+					fullscreenMode = true;
+					
+				}
+			};	
+			
+			/* 
+			 * Swap the video and presentation areas
+			 * 
+			 * Resizes and moves based on hard coded numbers
+			 * Uses css to move it 
+			 */
+
+			var goSwap = function() {
+                                acorn.$self.trigger('swap');
+			}
+
+			/* 
+			 * CAPTIONS Behaviour
+			 *		
+			 * Turning off the captions
+			 * When selecting "None" from the Caption Selector or when the caption fails to load
+			 */			
+			var captionBtnActiveClass = 'acorn-caption-active';
+			var captionBtnLoadingClass = 'acorn-caption-loading';
+			var transcriptBtnActiveClass = 'acorn-transcript-active';
+			
+			var captionRadioName = 'acornCaptions' + uniqueID();
+			 
+			var captionOff = function() {
+				captions = '';
+				acorn.$caption.hide();
+				activeCaptions = false;
+
+				acorn.$transcriptBtn.removeClass(transcriptBtnActiveClass).hide();
+				acorn.$transcript.hide();
+				
+				acorn.$captionBtn.removeClass(captionBtnActiveClass);
+			};
+			
+			/*
+			 * Update caption based on "currentTime"
+			 * Borrowed and adapted from Bruce Lawson's “Accessible HTML5 Video with JavaScripted captions”
+			 * http://dev.opera.com/articles/view/accessible-html5-video-with-javascripted-captions/
+			 */
+			var updateCaption = function() {			
+				var now = acorn.$self[0].currentTime; // how soon is now?
+				var text = "";
+				for (var i = 0; i < captions.length; i++) {
+					if (now >= captions[i].start && now <= captions[i].end) {
+						text = captions[i].content; // yes? then load it into a variable called text
+						break;
+					}
+				}
+				acorn.$caption.html(text); // and put contents of text into caption div
+			};
+			
+			/*
+			 * Initialize the Caption Selector
+			 * Used when multiple <track>s are present
+			 */
+			var initCaptionSelector = function() {
+				// calculate the position relative to the parent controls element
+				var setUpCaptionSelector = function() {
+					var pos = acorn.$captionBtn.offset();
+					var top = pos.top - acorn.$captionSelector.outerHeight(true);
+					var left = pos.left - ((acorn.$captionSelector.outerWidth(true) - acorn.$captionBtn.outerWidth(true))/2);
+					
+					var parentPos = acorn.$controls.offset();
+					
+					left = left - parentPos.left;
+					top = top - parentPos.top;
+					
+					acorn.$captionSelector.css({
+							'top': top,
+							'left': left
+						});
+				};
+				
+				acorn.$fullscreenBtn.click(setUpCaptionSelector);
+				$(window).resize(function() {
+					setUpCaptionSelector();		
+				});
+				
+				setUpCaptionSelector();
+				
+				/*
+				 * Show and hide the caption selector based on focus rather than hover.
+				 * This benefits both touchscreen and AT users.
+				 */
+				var hideSelector; // timeout for hiding the Caption Selector				
+				var showCaptionSelector = function() {
+					if(hideSelector) {
+						clearTimeout(hideSelector);
+					}
+					acorn.$captionSelector.show();
+				};
+				var hideCaptionSelector = function() {
+					hideSelector = setTimeout(function() {
+						acorn.$captionSelector.hide();						
+					}, 200);
+				};
+				
+				/* Little TEMPORARY hack to focus the caption button on click
+				   This is because Webkit does not focus the button on click */
+				acorn.$captionBtn.click(function() {
+					$(this).focus();
+				});
+				
+				acorn.$captionBtn.bind('focus', showCaptionSelector);
+				acorn.$captionBtn.bind('blur', hideCaptionSelector);
+				
+				$('input[name=' + captionRadioName + ']', acorn.$container).bind('focus', showCaptionSelector);
+				$('input[name=' + captionRadioName + ']', acorn.$container).bind('blur', hideCaptionSelector);
+				
+				/*
+				 * Make the Caption Selector focusable and attach events to it
+				 * If we wouldn't do this, when we'd use the scroll on the Caption Selector, it would dissapear
+				 */
+				acorn.$captionSelector.attr('tabindex', '-1');
+				acorn.$captionSelector.bind('focus', showCaptionSelector);
+				acorn.$captionSelector.bind('blur', hideCaptionSelector);
+			};
+			
+			/*
+			 * Current caption loader
+			 * Loads a SRT file and uses it as captions
+			 * Takes the url as a parameter
+			 */
+			var loadCaption = function(url) {
+				// add a loading class to the Caption Button when starting to load the caption
+				acorn.$captionBtn.addClass(captionBtnLoadingClass);
+				// make an AJAX request to load the file
+				$.ajax({
+					url: url,
+					success: function(data) {
+						/*
+						 * On success use a SRT parser on the loaded data
+						 * Using JavaScript SRT parser by Silvia Pfeiffer <silvia@siliva-pfeiffer.de>
+						 * parseSrt included at the end of this file
+						 */
+						captions = parseSrt(data);
+						
+						// show the Transcript Button						
+						acorn.$transcriptBtn.show();
+						
+						/* 
+						 * Generate the markup for the transcript
+						 * Markup based on Bruce Lawson's “Accessible HTML5 Video with JavaScripted captions”
+						 * http://dev.opera.com/articles/view/accessible-html5-video-with-javascripted-captions/
+						 */
+						var transcriptText = '';
+						$(captions).each(function() {
+							transcriptText += '<span data-begin="' + parseInt(this.start, 10) + '" data-end=' + parseInt(this.end, 10) + '>' + this.content.replace("'","") + '</span>';
+						});
+						// append the generated markup
+						acorn.$transcript.html(transcriptText);
+						
+						// show caption
+						acorn.$caption.show();
+						captionsActive = true;
+						
+						// in case the media is paused and timeUpdate is not triggered, trigger it
+						if(acorn.$self.prop('paused')) {
+							updateCaption();
+						}
+						
+						acorn.$captionBtn.addClass(captionBtnActiveClass).removeClass(captionBtnLoadingClass);
+					},
+					error: function() {
+						// if an error occurs while loading the caption, turn captions off
+						captionOff();
+						// if a console is available, log error
+						if(console) {
+							console.log('Error loading captions');
+						}
+					}
+				});
+			};
+			
+			/*			 
+			 * Show or hide the Transcript based on the presence of the active class
+			 */
+			var showTranscript = function() {
+				if($(this).hasClass(transcriptBtnActiveClass)) {
+					acorn.$transcript.hide();						
+				} else {
+					acorn.$transcript.show();
+				}
+				$(this).toggleClass(transcriptBtnActiveClass);
+			};
+
+			/*
+			 * Caption loading and initialization
+			 */
+			var initCaption = function() {
+				// get all <track> elements
+				acorn.$track = $('track', acorn.$self);
+				
+				// if there is at least one <track> element, show the Caption Button
+				if(acorn.$track.length) {
+					acorn.$captionBtn.show();
+				}
+				
+				// check if there is more than one <track> element
+				// if there is more than one track element we'll create the Caption Selector
+				if(acorn.$track.length>1) {
+					// set a different "title" attribute
+					acorn.$captionBtn.attr('title', text.captionsChoose);
+					
+					// markup for the Caption Selector
+					var captionList = '<ul><li><label><input type="radio" name="' + captionRadioName + '" checked="true" />None</label></li>';					
+					acorn.$track.each(function() {
+						var tracksrc = $(this).attr('src');
+						captionList += '<li><label><input type="radio" name="' + captionRadioName + '" data-url="' + $(this).attr('src') + '" />' + $(this).attr('label') + '</label></li>';
+					});
+					captionList += '</ul>';
+					
+					// append the generated markup
+					acorn.$captionSelector.html(captionList);
+					
+					// change selected caption
+					var changeCaption = function() {
+						// get the original <track> "src" attribute from the custom "data-url" attribute of the radio input
+						var tracksrc = $(this).attr('data-url');
+						if(tracksrc) {
+							loadCaption(tracksrc);						
+						} else {
+							// if there's not "data-url" attribute, turn off the caption
+							captionOff();
+						}
+					};
+					
+					// attach event handler
+					$('input[name=' + captionRadioName + ']', acorn.$container).change(changeCaption);
+				
+					// initialize Caption Selector
+					initCaptionSelector();
+					
+					// load first caption if captionsOn is true
+					var firstCaption = acorn.$track.first().attr('src');
+					if(options.captionsOn) {
+						loadCaption(firstCaption);
+						$('input[name=' + captionRadioName + ']', acorn.$container).removeAttr('checked');
+						$('input[name=' + captionRadioName + ']:eq(1)', acorn.$container).attr('checked', 'true');
+					};
+				} else if(acorn.$track.length) {
+					// if there's only one <track> element
+					// load the specific caption when activating the Caption Button
+					var tracksrc = acorn.$track.attr('src');
+					
+					acorn.$captionBtn.bind('click', function() {		
+						if($(this).hasClass(captionBtnActiveClass)) {
+							captionOff();
+						} else {
+							loadCaption(tracksrc);
+						}
+						$(this).toggleClass(captionBtnActiveClass);
+					});
+
+					// load default caption if captionsOn is true
+					if(options.captionsOn) loadCaption(tracksrc);					
+				}
+				
+				// attach event to Transcript Button
+				acorn.$transcriptBtn.bind('click', showTranscript);
+			};
+			
+			/*
+			 * Initialization self-invoking function
+			 * Runs other initialization functions, attaches events, removes native controls
+			 */
+			var init = function() {
+				// attach playback handlers
+				acorn.$playBtn.bind( (is_touch_device) ? 'touchstart' : 'click', playMedia);
+				acorn.$self.bind( (is_touch_device) ? 'touchstart' : 'click' , playMedia);
+
+				acorn.$self.bind('play', startPlayback);
+				acorn.$self.bind('pause', stopPlayback);
+				acorn.$self.bind('ended', stopPlayback);
+				
+				// update the Seek Slider when timeupdate is triggered
+				acorn.$self.bind('timeupdate', seekUpdate);
+				
+				// bind Fullscreen Button
+				acorn.$fullscreenBtn.click(goFullscreen);
+				
+				// bind Swap Button
+				acorn.$swapBtn.click(goSwap);
+
+				// initialize volume controls
+				initVolume();				
+				
+				// add the loading class
+				$wrapper.addClass('');
+				
+				if(!options.nativeSliders) initSeek();
+				
+				// once the metadata has loaded
+				acorn.$self.bind('loadedmetadata', function() {
+					/* I use an interval to make sure the video has the right readyState
+					 * to bypass a known webkit bug that causes loadedmetadata to be triggered
+					 * before the duration is available
+					 */
+
+					var t = window.setInterval(function() {
+								if (acorn.$self[0].readyState > 0) {
+									loadedMetadata = true;
+									updateSeek();
+									
+									clearInterval(t);
+								}
+							}, 500);
+					
+					initCaption();					
+				});
+			
+				// trigger update seek manualy for the first time, for iOS support
+				updateSeek();
+				
+				// remove the native controls
+				acorn.$self.removeAttr('controls');
+				
+				if(acorn.$self.is('audio')) {
+					/*
+					 * If the media is <audio>, we're adding the 'audio-player' class to the element.
+					 * This is because Opera 10.62 does not allow the <audio> element to be targeted by CSS
+					 * and this can cause problems with themeing.
+					 */
+					acorn.$container.addClass('audio-player');
+				}
+			}();
+		
+		};
+		
+		// iterate and reformat each matched element
+		return this.each(acornPlayer);
+	};
+
+})(jQuery);
+
+/* 
+ * parseSrt function
+ * JavaScript SRT parser by Silvia Pfeiffer <silvia@siliva-pfeiffer.de>
+ * http://silvia-pfeiffer.de/ 
+ * 
+ * Tri-licensed under MPL 1.1/GPL 2.0/LGPL 2.1
+ *  http://www.gnu.org/licenses/gpl.html  
+ *  http://www.gnu.org/licenses/lgpl.html
+ *  http://www.mozilla.org/MPL/
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Silvia Pfeiffer <silvia@siliva-pfeiffer.de>
+ *
+ *
+ */
+function parseSrt(data) {
+    var srt = data.replace(/\r+/g, ''); // remove dos newlines
+    srt = srt.replace(/^\s+|\s+$/g, ''); // trim white space start and end
+    srt = srt.replace(/<[a-zA-Z\/][^>]*>/g, ''); // remove all html tags for security reasons
+
+    // get captions
+    var captions = [];
+    var caplist = srt.split('\n\n');
+    for (var i = 0; i < caplist.length; i=i+1) {
+        var caption = "";
+        var content, start, end, s;
+        caption = caplist[i];
+        s = caption.split(/\n/);
+        if (s[0].match(/^\d+$/) && s[1].match(/\d+:\d+:\d+/)) {
+            // ignore caption number in s[0]
+            // parse time string
+            var m = s[1].match(/(\d+):(\d+):(\d+)(?:,(\d+))?\s*--?>\s*(\d+):(\d+):(\d+)(?:,(\d+))?/);
+            if (m) {
+                start =
+                  (parseInt(m[1], 10) * 60 * 60) +
+                  (parseInt(m[2], 10) * 60) +
+                  (parseInt(m[3], 10)) +
+                  (parseInt(m[4], 10) / 1000);
+                end =
+                  (parseInt(m[5], 10) * 60 * 60) +
+                  (parseInt(m[6], 10) * 60) +
+                  (parseInt(m[7], 10)) +
+                  (parseInt(m[8], 10) / 1000);
+            } else {
+                // Unrecognized timestring
+                continue;
+            }
+            // concatenate text lines to html text
+            content = s.slice(2).join("<br>");
+        } else {
+            // file format error or comment lines
+            continue;
+        }
+        captions.push({start: start, end: end, content: content});
+    }
+
+    return captions;
+}
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-captions-dark.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-captions-dark.png
new file mode 100755
index 0000000000000000000000000000000000000000..f4a244a436a53c4ec4e4bee00ba400eef9af6d60
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-captions-dark.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-captions.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-captions.png
new file mode 100755
index 0000000000000000000000000000000000000000..93f11096297b248273dfef200a56c7a29bebe144
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-captions.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-exit-fullscreen-dark.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-exit-fullscreen-dark.png
new file mode 100755
index 0000000000000000000000000000000000000000..ee211f809e8c3518cb8b1fc590e578dce09246a8
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-exit-fullscreen-dark.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-exit-fullscreen.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-exit-fullscreen.png
new file mode 100755
index 0000000000000000000000000000000000000000..aaa0893de804099069e5309cc982db329ad7bff8
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-exit-fullscreen.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-fullscreen-dark.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-fullscreen-dark.png
new file mode 100755
index 0000000000000000000000000000000000000000..ea0a9ad23d31030ea4c49baae2bc9029a1a84560
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-fullscreen-dark.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-fullscreen.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-fullscreen.png
new file mode 100755
index 0000000000000000000000000000000000000000..f15827a3f7e2ec5b316fc0537c4443669639d7dc
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-fullscreen.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-pause-dark.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-pause-dark.png
new file mode 100755
index 0000000000000000000000000000000000000000..95975c91d54bde8f4365f6fc61d6d48cc87fc338
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-pause-dark.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-pause.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-pause.png
new file mode 100755
index 0000000000000000000000000000000000000000..241593c84fdf4bba9a4f4df97b67091e1ae9ead6
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-pause.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-play-dark.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-play-dark.png
new file mode 100755
index 0000000000000000000000000000000000000000..3db3f26cf0c78f61180aa1da02928e3ec1661894
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-play-dark.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-play.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-play.png
new file mode 100755
index 0000000000000000000000000000000000000000..28f84741ac14f602634476ad0bd2722a1f09b0b2
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-play.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-transcript-dark.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-transcript-dark.png
new file mode 100755
index 0000000000000000000000000000000000000000..1c5d6eadd3ffb25be420eb8e5bfd6de7395c5c3e
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-transcript-dark.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-transcript.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-transcript.png
new file mode 100755
index 0000000000000000000000000000000000000000..6c63973a6a3132bfa89cfaba2a29abba715961aa
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-transcript.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume-dark.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume-dark.png
new file mode 100755
index 0000000000000000000000000000000000000000..c2a34cdc4f34b709bbbd45e22ef9485e752b3e6f
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume-dark.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume-full-dark.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume-full-dark.png
new file mode 100755
index 0000000000000000000000000000000000000000..4caea2f3f765c99b931013ac49e92b0f5c5fae3b
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume-full-dark.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume-full.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume-full.png
new file mode 100755
index 0000000000000000000000000000000000000000..f4d4030d984f69fdc521ed63d567f30b66e31c4b
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume-full.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume.png
new file mode 100755
index 0000000000000000000000000000000000000000..088c13204c789837cac92dcb0b178076af808793
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/access-volume.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/acorn.access.css b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/acorn.access.css
new file mode 100755
index 0000000000000000000000000000000000000000..3a2356e2356b21506244bf089f970e95951c8386
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/acorn.access.css
@@ -0,0 +1,314 @@
+/*
+ * acccess - Accessible Theme for Acorn Media Player
+ * accesslight - Child theme of access
+ *
+ * To be used with the horizontal volume slider.
+ *
+ * Copyright (C) 2010 Cristian I. Colceriu
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * www.ghinda.net
+ * contact@ghinda.net
+ *
+ */
+ 
+/* Start of access theme */
+.acorn-player.access {
+	float: left;
+	position: relative;
+	overflow: hidden;
+	
+	font-family: Arial, Helvetica, sans-serif;
+}
+/* <video> element */
+.acorn-player.access video {
+	float: left;
+	clear: both;
+	background-color: #000;
+}
+/* Player Controls */
+.acorn-player.access .acorn-controls {
+	position: relative;	
+	float: left;
+	clear: both;
+	width: 100%;
+	padding-top: 15px;
+		
+	background-image: url(controls-background-dark.png);
+	background-position: bottom left;
+}
+/* <button>s */
+.acorn-player.access button {
+	position: relative;	
+	margin: 0;
+	padding-left: 25px;
+	height: 35px;
+	border: 1px solid #333;
+	background-color: #3F3F3F;
+	background-position: 5px center, top left;
+	background-repeat: no-repeat, repeat-x;	
+	
+	font-weight: bold;
+	color: #fff;
+	text-shadow: 0px -1px 1px #000;
+	
+	cursor: pointer;
+}
+.acorn-player.access button:hover, .acorn-player.access button:focus {
+	background-color: #044293;
+	background-position: 5px center, left -33px;
+}
+.acorn-player.access button:active {
+	top: 1px;	
+	box-shadow: inset 1px 1px 10px #000;
+}
+/* Playback Controls(Play, Pause) */
+.acorn-player.access .acorn-play-button {
+	float: left;
+	display: block;
+	width: 75px;
+	background-image: url(access-play.png), url(button-background-dark.png);
+}
+.acorn-player.access .acorn-paused-button {
+	background-image: url(access-pause.png), url(button-background-dark.png);
+}
+/* Seek Slider */
+.acorn-player.access .acorn-seek-slider {
+	position:absolute;
+	top: 0px;
+	display: block;
+	width: 100%;
+	height: 15px;
+		
+	background: #7289A8;
+	z-index: 2;
+}
+.acorn-player.access .acorn-seek-slider .ui-slider-handle {
+	display: block;
+	position: absolute;
+	width: 13px;
+	height: 13px;
+	border: 3px solid #fff;
+	top: -2px;
+
+	-moz-border-radius: 10px;
+	-webkit-border-radius: 10px;
+	border-radius: 10px;
+	
+	-moz-box-shadow: 0px 2px 8px #000;
+	-webkit-box-shadow: 0px 2px 8px #000;
+	box-shadow: 0px 2px 8px #000;
+	
+	background: #888;
+}
+.acorn-player.access .acorn-seek-slider .ui-slider-range {	
+	background: #0750B2;	
+}
+.acorn-player.access .acorn-buffer {	
+	background: #8E9DAF !important;	
+}
+.acorn-player.access .acorn-seek-slider .ui-state-focus, .acorn-player.access .acorn-seek-slider .ui-slider-handle.ui-state-hover {
+	background: #0750B2 !important;
+	
+	-moz-box-shadow: 0px 2px 15px #000;
+	-webkit-box-shadow: 0px 2px 15px #000;
+	box-shadow: 0px 2px 15px #000;
+}
+/* Timer */
+.acorn-player.access .acorn-timer {
+	position: absolute;
+	top: 25px;
+	left: 260px;
+	
+	color: #efefef;
+	font-size: 14px;
+	font-weight: bold;
+	text-shadow: 0px -1px 2px #000;
+}
+/* Volume Container */
+.acorn-player.access .acorn-volume-box {
+	float: left;
+	overflow: hidden;
+	padding-right: 10px;
+	
+	-moz-box-shadow: 2px 0px 5px #111;
+	-webkit-box-shadow: 2px 0px 5px #111;
+	box-shadow: 2px 0px 5px #111;
+}
+/* Volume Button */
+.acorn-player.access .acorn-volume-button {
+	float: left;
+	width: 85px;
+	border-left: none;
+	background-image: url(access-volume-full.png), url(button-background-dark.png);
+	
+	-moz-box-shadow: 2px 0px 5px #111;
+	-webkit-box-shadow: 2px 0px 5px #111;
+	box-shadow: 2px 0px 5px #111;
+}
+.acorn-player.access .acorn-volume-mute {
+	background-image: url(access-volume.png), url(button-background-dark.png);
+}
+/* Volume Slider */
+.acorn-player.access .acorn-volume-slider {
+	float: left;
+	height: 5px;
+	width: 70px;
+	margin-left: 10px;
+	margin-top: 15px;		
+	border: 1px solid #333;	
+	
+	background: #111;
+	
+	-moz-box-shadow: 0px 1px 1px #777;
+	-webkit-box-shadow: 0px 1px 1px #777;
+	box-shadow: 0px 1px 1px #777;
+}
+.acorn-player.access .acorn-volume-slider .ui-slider-handle {
+	width: 5px;
+	height: 15px;	
+	margin-top: -5px;
+	margin-left: -5px;
+	
+	border: 1px solid #333;
+	background: #BCBCBC;
+		
+	-moz-box-shadow: 0px 0px 5px #000;
+	-webkit-box-shadow: 0px 0px 5px #000;
+	box-shadow: 0px 0px 5px #000;
+}
+.acorn-player.access .acorn-volume-slider .ui-slider-handle.ui-state-hover, .acorn-player.access .acorn-volume-slider .ui-slider-handle.ui-state-focus {
+	background: #fff !important;
+}
+.acorn-player.access .acorn-volume-slider .ui-slider-range {	
+	background: #636F7C;
+}
+/* Fullscreen Button */
+.acorn-player.access .acorn-fullscreen-button {
+	float: right;
+	background-image: url(access-fullscreen.png), url(button-background-dark.png);
+	
+	-moz-box-shadow: -2px 0px 5px #111;
+	-webkit-box-shadow: -2px 0px 5px #111;
+	box-shadow: -2px 0px 5px #111;
+}
+/* Fullscreen Mode */
+.acorn-player.access .fullscreen-controls {	
+	left: 0px;
+	bottom: 0px;
+}
+.acorn-player.access .fullscreen-controls .acorn-fullscreen-button {
+	background-image: url(access-exit-fullscreen.png), url(button-background-dark.png);
+}
+/* Caption Button */
+.acorn-player.access .acorn-caption-button {
+	float: right;
+	border-right: none;
+	background-image: url(access-captions.png), url(button-background-dark.png);
+	
+	-moz-box-shadow: -2px 0px 5px #111;
+	-webkit-box-shadow: -2px 0px 5px #111;
+	box-shadow: -2px 0px 5px #111;
+}
+.acorn-player.access .acorn-caption {
+	font-size: 14px;
+	font-weight: bold;
+	color: #fff;
+	
+	text-shadow: 0px 1px 5px #000;
+}
+/* Transcript */
+.acorn-player.access .acorn-transcript-button {
+	float: right;
+	border-right: none;
+	background-image: url(access-transcript.png), url(button-background-dark.png);
+	
+	-moz-box-shadow: -2px 0px 5px #111;
+	-webkit-box-shadow: -2px 0px 5px #111;
+	box-shadow: -2px 0px 5px #111;
+}
+.acorn-player.access .acorn-caption-active, .acorn-player.access .acorn-transcript-active {
+	background-position: 5px center, left bottom;
+}
+/* 
+ * acesslight Child Theme
+ */
+.acorn-player.access.accesslight .acorn-controls {
+	background-image: url(controls-background-light.png);
+}
+/* <button>s */
+.acorn-player.access.accesslight button {
+	border: 1px solid #bdbdbd;
+		
+	color: #333;
+	text-shadow: 0px 1px 0px #fff;
+}
+/* Playback Controls(Play, Pause) */
+.acorn-player.access.accesslight .acorn-play-button {
+	background-image: url(access-play-dark.png), url(button-background-light.png);
+}
+.acorn-player.access.accesslight .acorn-paused-button {
+	background-image: url(access-pause-dark.png), url(button-background-light.png);
+}
+/* Volume Button */
+.acorn-player.access.accesslight .acorn-volume-button {
+	background-image: url(access-volume-full-dark.png), url(button-background-light.png);
+	
+	-moz-box-shadow: 2px 0px 5px #8c8c8c;
+	-webkit-box-shadow: 2px 0px 5px #8c8c8c;
+	box-shadow: 2px 0px 5px #8c8c8c;
+}
+.acorn-player.access.accesslight .acorn-volume-mute {
+	background-image: url(access-volume-dark.png), url(button-background-light.png);
+}
+/* Caption Buttton */
+.acorn-player.access.accesslight .acorn-caption-button {
+	background-image: url(access-captions-dark.png), url(button-background-light.png);
+	
+	-moz-box-shadow: -2px 0px 5px #8c8c8c;
+	-webkit-box-shadow: -2px 0px 5px #8c8c8c;
+	box-shadow: -2px 0px 5px #8c8c8c;
+}
+/* Transcript */
+.acorn-player.access.accesslight .acorn-transcript-button {
+	background-image: url(access-transcript-dark.png), url(button-background-light.png);
+	
+	-moz-box-shadow: -2px 0px 5px #8c8c8c;
+	-webkit-box-shadow: -2px 0px 5px #8c8c8c;
+	box-shadow: -2px 0px 5px #8c8c8c;
+}
+.acorn-player.access.accesslight .acorn-caption-active, .acorn-player.access.accesslight .acorn-transcript-active {
+	color: #000;
+	text-shadow: none;
+}
+/* Fullscreen Button */
+.acorn-player.access.accesslight .acorn-fullscreen-button {	
+	background-image: url(access-fullscreen-dark.png), url(button-background-light.png);
+	
+	-moz-box-shadow: -2px 0px 5px #8c8c8c;
+	-webkit-box-shadow: -2px 0px 5px #8c8c8c;
+	box-shadow: -2px 0px 5px #8c8c8c;
+}
+/* Volume Container */
+.acorn-player.access.accesslight .acorn-volume-box {
+	-moz-box-shadow: 2px 0px 5px #8c8c8c;
+	-webkit-box-shadow: 2px 0px 5px #8c8c8c;
+	box-shadow: 2px 0px 5px #8c8c8c;
+}
+/* Timer */
+.acorn-player.access.accesslight .acorn-timer {	
+	color: #333;
+	text-shadow: 0px 1px 2px #fff;
+}
+/* Volume Slider */
+.acorn-player.access.accesslight .acorn-volume-slider {
+	border: 1px solid #333;	
+	background: #c1c1c1;
+	
+	-moz-box-shadow: 0px 1px 1px #fff;
+	-webkit-box-shadow: 0px 1px 1px #fff;
+	box-shadow: 0px 1px 1px #fff;
+}
\ No newline at end of file
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/deskshare_icon.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/button-background-dark.png
old mode 100644
new mode 100755
similarity index 81%
rename from bigbluebutton-client/src/org/bigbluebutton/common/assets/images/deskshare_icon.png
rename to record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/button-background-dark.png
index e9065faaf077a4032e50c4455f2e0e10a349c2af..eb3ac270b7cffa473db459a8743b6cde71c93cc7
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/deskshare_icon.png and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/button-background-dark.png differ
diff --git a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/page_white_get.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/button-background-light.png
similarity index 78%
rename from bigbluebutton-client/src/org/bigbluebutton/common/assets/images/page_white_get.png
rename to record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/button-background-light.png
index 5e3c3db49266205ada109139fb5c13a4c2bd6ade..952c285996aa7020655731fc468d580f3305cca9 100755
Binary files a/bigbluebutton-client/src/org/bigbluebutton/common/assets/images/page_white_get.png and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/button-background-light.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/controls-background-dark.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/controls-background-dark.png
new file mode 100755
index 0000000000000000000000000000000000000000..88443bf0626331bec2a018df9800bf6d99be0e84
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/controls-background-dark.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/controls-background-light.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/controls-background-light.png
new file mode 100755
index 0000000000000000000000000000000000000000..7e4c85aa5c0aac77f5fb335032f77b39e0ef0741
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/access/controls-background-light.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/barebones/acorn.barebones.css b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/barebones/acorn.barebones.css
new file mode 100755
index 0000000000000000000000000000000000000000..60471b604eb1f10122d8e1b234ba47619203fe7f
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/barebones/acorn.barebones.css
@@ -0,0 +1,143 @@
+/*
+ * barebones - Theme for Acorn Media Player 
+ * 
+ * To be used with the horizontal volume slider.
+ *
+ * Copyright (C) 2010 Cristian I. Colceriu
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * www.ghinda.net
+ * contact@ghinda.net
+ *
+ */
+ 
+/* Start of barebones theme */
+.acorn-player.barebones {
+	float: left;
+	position: relative;
+	
+	font-family: Arial, Helvetica, sans-serif;
+}
+/* <video> element */
+.acorn-player.barebones video {
+	float: left;
+	clear: both;
+	
+	margin-bottom: 5px;
+}
+/* Player Controls */
+.acorn-player.barebones .acorn-controls {
+	position: relative;
+	float: left;
+	clear: both;
+	
+	width: 100%;	
+}
+/* <button>s */
+.acorn-player.barebones button {	
+}
+/* Playback controls(Play, Pause) */
+.acorn-player.barebones .acorn-play-button {
+	float: left;
+}
+.acorn-player.barebones .acorn-paused-button {	
+}
+/* Seek Slider */
+.acorn-player.barebones .acorn-seek-slider {
+	position: relative;
+	display: block;
+	float: left;
+	width: 40%;
+	height: 10px;
+	margin: 6px 0px 0px 10px;
+	background: #ADADAD;
+}
+.acorn-player.barebones .acorn-seek-slider .ui-slider-handle {
+	display: block;
+	position: absolute;	
+	width: 15px;
+	height: 15px;	
+	top: -3px;
+	background: #e6e6e6;
+	border: 1px solid #000;
+}
+.acorn-player.barebones .acorn-seek-slider .ui-slider-range {		
+	background: #4cbae8;
+}
+.acorn-player.barebones .acorn-buffer {
+	background: #939393 !important;
+}
+.acorn-player.barebones .acorn-seek-slider .ui-state-focus, .acorn-player.barebones .acorn-seek-slider .ui-slider-handle.ui-state-hover {
+	background: #fff !important;
+}
+/* Timer */
+.acorn-player.barebones .acorn-timer {
+	float: left;
+	margin: 2px 0px 0px 5px;
+}
+/* Volume Box */
+.acorn-player.barebones .acorn-volume-box {	
+	float: left;
+	margin-left: 10px;
+}
+/* Volume Slider */
+.acorn-player.barebones .acorn-volume-slider {
+	float: left;
+	height: 10px;
+	width: 50px;
+	left: 4px;
+	margin: 6px 0px 0px 10px;
+	
+	background: #535353;
+}
+.acorn-player.barebones .acorn-volume-slider .ui-slider-handle {
+	width: 12px;
+	height: 12px;
+	left: -4px;
+	top: -2px;	
+	border: 1px solid #000;
+	background: #e6e6e6;
+}
+.acorn-player.barebones .acorn-volume-slider .ui-slider-handle.ui-state-hover {
+	background: #fff;
+}
+.acorn-player.barebones .acorn-volume-slider .ui-slider-range {	
+	background: #e6e6e6;
+}
+/* Volume Button */
+.acorn-player.barebones .acorn-volume-button {
+	float: left;
+}
+.acorn-player.barebones .acorn-volume-mute {
+}
+/* Fullscreen Button */
+.acorn-player.barebones .acorn-fullscreen-button {
+	float: right;
+}
+/* Fullscreen Mode */
+.acorn-player.barebones .fullscreen-controls {	
+	left: 0px;
+	bottom: 0px;
+}
+/* Caption Button */
+.acorn-player.barebones .acorn-caption-button {
+	float: right;
+}
+.acorn-player.barebones .acorn-caption {
+	font-size: 14px;
+	font-weight: bold;
+	color: #fff;
+}
+.acorn-player.barebones .acorn-caption-active {
+	border: 2px solid #8F0000 !important;
+}
+.acorn-player.barebones .acorn-transcript-active {
+	border: 2px solid #8F0000 !important;
+}
+/* Transcript Button */
+.acorn-player.barebones .acorn-transcript-button {
+	float: right;
+}
\ No newline at end of file
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/acorn.bigbluebutton.css b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/acorn.bigbluebutton.css
new file mode 100755
index 0000000000000000000000000000000000000000..322db7724c607d10da76a6bec84cd60d82bc8228
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/acorn.bigbluebutton.css
@@ -0,0 +1,337 @@
+/*
+ * bigbluebutton - Theme for Acorn Media Player
+ * bigbluebuttonsmall - Child theme of bigbluebutton
+ *
+ * To be used with the vertical volume slider.
+ *
+ * Copyright (C) 2010 Cristian I. Colceriu
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * www.ghinda.net
+ * contact@ghinda.net
+ *
+ */
+
+/* Start of bigbluebutton theme */
+.acorn-player.bigbluebutton {
+  float: left;
+  position: relative;
+  padding: 0;
+  margin: 0;
+  font-family: Arial, Helvetica, sans-serif;
+}
+/* <video> element */
+.acorn-player.bigbluebutton video {
+  float: left;
+  clear: both;
+  margin: 0;
+  cursor: pointer;
+}
+/* Player Controls */
+.acorn-player.bigbluebutton .acorn-controls {
+  position: relative;
+  float: left;
+  clear: both;
+  width: 95%;
+  padding: 5px 40px 5px 5px;
+  border: 0;
+  background: #2a2d34; /* #314b5d; */
+}
+/* <button>s */
+.acorn-player.bigbluebutton button {
+  position: relative;
+  width: 35px;
+  margin: 0 6px;
+  padding: 0px;
+  border: none;
+  background-color: transparent;
+  background-repeat: no-repeat;
+  background-position: center center;
+  background-size: auto 100%;
+
+  opacity: 0.6;
+  -moz-transition: all 0.2s ease-in-out;
+  -webkit-transition: all 0.2s ease-in-out;
+  -o-transition: all 0.2s ease-in-out;
+  transition: all 0.2s ease-in-out;
+
+  -moz-border-radius: 2px;
+  -webkit-border-radius: 2px;
+  border-radius: 2px;
+
+  cursor: pointer;
+  text-indent: -9999px;
+}
+.acorn-player.bigbluebutton button:hover, .acorn-player.bigbluebutton button:focus {
+  opacity: 1;
+}
+.acorn-player.bigbluebutton button:active {
+  top: 1px;
+}
+/* Playback controls(Play, Pause) */
+.acorn-player.bigbluebutton .acorn-play-button {
+  float: left;
+  display: block;
+  background-image: url(bigbluebutton-play.png);
+}
+.acorn-player.bigbluebutton .acorn-paused-button {
+  background-image: url(bigbluebutton-pause.png);
+}
+/* Seek Slider */
+.acorn-player.bigbluebutton .acorn-seek-slider {
+  position: relative;
+  display: block;
+  float: left;
+  width: 70%;
+  height: 12px;
+  margin: 5px 10px 5px 10px;
+  background: #8E9DAF;
+}
+.acorn-player.bigbluebutton .acorn-seek-slider .ui-slider-handle {
+  display: block;
+  position: absolute;
+  width: 12px;
+  height: 16px;
+  border-left: 1px solid #333;
+  border-right: 1px solid #333;
+  top: -2px;
+  background: #e6e6e6;
+  cursor: pointer;
+  border-radius: 3px;
+}
+.acorn-player.bigbluebutton .acorn-seek-slider .ui-slider-handle:hover {
+  /* height: 18px; */
+  /* top: -4px; */
+}
+.acorn-player.bigbluebutton .acorn-seek-slider .ui-slider-range {
+  background: #289ad6;
+}
+.acorn-player.bigbluebutton .acorn-buffer {
+  background: #8E9DAF !important;
+}
+.acorn-player.bigbluebutton .acorn-seek-slider .ui-state-focus, .acorn-player.bigbluebutton .acorn-seek-slider .ui-slider-handle.ui-state-hover {
+  background: #fff !important;
+
+  -moz-box-shadow: 0px 2px 15px #289ad6;
+  -webkit-box-shadow: 0px 2px 15px #289ad6;
+  box-shadow: 0px 2px 15px #289ad6;
+}
+/* Timer */
+.acorn-player.bigbluebutton .acorn-timer {
+  float: left;
+  width: 6%;
+  overflow: hidden;
+  margin-top: 1px;
+  color: #eee;
+  font-size: 0.9em;
+  font-weight: bold;
+  min-width: 40px;
+}
+/* Volume Box */
+.acorn-player.bigbluebutton .acorn-volume-box {
+  position: absolute;
+  float: left;
+  bottom: 6px;
+  right: 0;
+  overflow: visible;
+  color: #fff;
+  transition: all 0.1s ease-in-out 0s;
+  margin: 0 6px;
+  width: 35px;/* 5%; */
+}
+.acorn-player.bigbluebutton .acorn-volume-box:hover {
+  height: 135px;
+}
+.acorn-player.bigbluebutton .acorn-volume-slider.handle-focused {
+  position: relative;
+  visibility: visible;
+  height: 100px;
+  opacity: 1;
+  top: -100px;
+}
+.acorn-player.bigbluebutton .acorn-volume-box:hover .acorn-volume-slider {
+  position: relative;
+  visibility: visible;
+  height: 100px;
+  opacity: 1;
+  top: 0px;
+}
+/* Volume Slider */
+.acorn-player.bigbluebutton .acorn-volume-slider {
+  position: relative;
+  height: 1px;
+  width: 12px;
+  margin: 0 auto;
+  visibility: visible;
+  opacity: 0;
+  border: 1px solid #666;
+  background: #ddd; /* #8E9DAF; */
+}
+.acorn-player.bigbluebutton .acorn-volume-slider .ui-slider-handle {
+  width: 18px;
+  height: 8px;
+  left: -4px;
+  margin-bottom:-0.6em;
+  margin-left:0;
+  border: 1px solid #666;
+  border-radius: 3px;
+  background: #e6e6e6;
+
+  -moz-transition: all 0.1s ease-in-out;
+  -webkit-transition: all 0.1s ease-in-out;
+  -o-transition: all 0.1s ease-in-out;
+  transition: all 0.1s ease-in-out;
+}
+.acorn-player.bigbluebutton .acorn-volume-slider .ui-slider-handle:hover, .acorn-player.bigbluebutton .acorn-volume-slider.handle-focused .ui-slider-handle {
+  background: #fff;
+
+  -moz-box-shadow: 0px 2px 15px #289ad6;
+  -webkit-box-shadow: 0px 2px 15px #289ad6;
+  box-shadow: 0px 2px 15px #289ad6;
+}
+.acorn-player.bigbluebutton .acorn-volume-slider .ui-slider-range {
+  background: #289ad6;
+  box-shadow: inset 0 3px 3px #d5d5d5;
+  margin-top: 15px;
+}
+/* Volume Button */
+.acorn-player.bigbluebutton .acorn-volume-button {
+  position: absolute;
+  bottom: 0px;
+  width: 100%;
+  display: block;
+  background: url(bigbluebutton-volume-full.png) no-repeat;
+  background-size: contain;
+  text-indent: -9999px;
+  margin: 0;
+  opacity: 0.6;
+}
+.acorn-player.bigbluebutton .acorn-volume-button:active {
+  top: auto;
+}
+.acorn-player.bigbluebutton .acorn-volume-mute {
+  background-image: url(bigbluebutton-volume.png);
+}
+/* Swap Button */
+.acorn-player.bigbluebutton .acorn-swap-button {
+  float: right;
+  background-image: url(bigbluebutton-swap.png);
+}
+/* Fullscreen Button */
+.acorn-player.bigbluebutton .acorn-fullscreen-button {
+  float: right;
+  background-image: url(bigbluebutton-fullscreen.png);
+}
+/* Fullscreen Mode */
+.acorn-player.bigbluebutton .fullscreen-controls {
+  left: 0px;
+  bottom: 0px;
+}
+.acorn-player.bigbluebutton .fullscreen-controls button {
+  height: 35px;
+}
+.acorn-player.bigbluebutton .fullscreen-controls .acorn-fullscreen-button {
+  background-image: url(bigbluebutton-exit-fullscreen.png);
+}
+.acorn-player.bigbluebutton .fullscreen-controls .acorn-seek-slider {
+  margin-top: 10px;
+}
+/* Caption Button */
+.acorn-player.bigbluebutton .acorn-caption-button {
+  float: right;
+  background-image: url(bigbluebutton-caption.png);
+}
+.acorn-player.bigbluebutton .acorn-caption {
+  font-size: 14px;
+  font-weight: bold;
+  color: #fff;
+
+  text-shadow: 0px 1px 5px #000;
+}
+.acorn-player.bigbluebutton .acorn-caption-active {
+  background-color: #8F0000 !important;
+}
+.acorn-player.bigbluebutton .acorn-transcript-active {
+  background-color: #8F0000 !important;
+}
+/* Transcript Button */
+.acorn-player.bigbluebutton .acorn-transcript-button {
+  float: right;
+  background-image: url(bigbluebutton-transcript.png);
+}
+
+.acorn-player .loading-media {
+  left: auto;
+  right: auto;
+  top: auto;
+  bottom: auto;
+  margin: 0 auto;
+  background: none;
+  z-index: 999;
+  position: relative;
+  margin-top: 6px;
+}
+/* Controls overlay while loading */
+.show-loading .acorn-controls:after {
+  content: '';
+  position: absolute;
+  top: -2px; /* Slider handle goes above */
+  left: 0;
+  z-index: 10;
+  width: 100%;
+  height: 100%;
+  background: #2a2d34;
+  opacity: 0.85;
+}
+
+/* Very small screens only */
+@media only screen and (max-width: 21em) {
+  .acorn-player.bigbluebutton .acorn-seek-slider {
+    width: 20%;
+  }
+  .acorn-player.bigbluebutton .acorn-controls {
+    padding-right: 35px;
+  }
+  .acorn-player.bigbluebutton button {
+    width: 25px;
+  }
+  .acorn-player.bigbluebutton .acorn-volume-box {
+    width: 25px;
+  }
+}
+
+/* Small screens only */
+@media only screen and (min-width: 21.063em) {
+/* @media only screen and (max-width: 40em) { -- this is used by foundation */
+  .acorn-player.bigbluebutton .acorn-seek-slider {
+    width: 40%;
+  }
+  .acorn-player.bigbluebutton .acorn-controls {
+    padding-right: 35px;
+  }
+  .acorn-player.bigbluebutton button {
+    position: relative;
+    width: 25px;
+  }
+  .acorn-player.bigbluebutton .acorn-volume-box {
+    width: 25px;
+    right: 0px;
+  }
+}
+
+/* Medium screens up */
+@media only screen and (min-width: 40.063em) {
+  .acorn-player.bigbluebutton .acorn-seek-slider {
+    width: 65%;
+  }
+}
+
+/* Large screens up */
+@media only screen and (min-width: 64.063em) {
+  .acorn-player.bigbluebutton .acorn-seek-slider {
+    width: 70%;
+  }
+}
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-caption.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-caption.png
new file mode 100755
index 0000000000000000000000000000000000000000..9c814ec7547919896fac5df9ccbff0988c784b4e
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-caption.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-exit-fullscreen.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-exit-fullscreen.png
new file mode 100755
index 0000000000000000000000000000000000000000..3df3bf468cc385d8a39a7e6e427fbe4d8d1a1dee
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-exit-fullscreen.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-fullscreen.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-fullscreen.png
new file mode 100755
index 0000000000000000000000000000000000000000..c70fb08ee7ce2ae3253151d978c353b33b049311
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-fullscreen.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-pause.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-pause.png
new file mode 100755
index 0000000000000000000000000000000000000000..26462e66f6ed8522650890f93de8a7861cc35b49
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-pause.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-play.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-play.png
new file mode 100755
index 0000000000000000000000000000000000000000..5d5aacae17c9e7ff391b1fcefec296943f074a1e
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-play.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-swap.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-swap.png
new file mode 100755
index 0000000000000000000000000000000000000000..055dacceac1cc04d28cdd69f4dd2995fe6ebeaa0
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-swap.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-transcript.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-transcript.png
new file mode 100755
index 0000000000000000000000000000000000000000..e6d6dac51651d27e804eccdcca62087276aeff02
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-transcript.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-volume-full.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-volume-full.png
new file mode 100755
index 0000000000000000000000000000000000000000..485a1133d82ef535b98f118893cd1575df3cdcb7
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-volume-full.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-volume.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-volume.png
new file mode 100755
index 0000000000000000000000000000000000000000..d4bdcbf622ee54121870c17e9763c76eb8569d00
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/bigbluebutton/bigbluebutton-volume.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/acorn.darkglass.css b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/acorn.darkglass.css
new file mode 100755
index 0000000000000000000000000000000000000000..907e253c706c135f86051ecabf4cb8c9e66bea39
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/acorn.darkglass.css
@@ -0,0 +1,363 @@
+/*
+ * darkglass - Theme for Acorn Media Player
+ * darkglasssmall - Child theme of darkglass
+ *
+ * To be used with the vertical volume slider.
+ *
+ * Copyright (C) 2010 Cristian I. Colceriu
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * www.ghinda.net
+ * contact@ghinda.net
+ *
+ */
+ 
+/* Start of darkglass theme */
+.acorn-player.darkglass {
+	float: left;
+	position: relative;	
+	padding: 2px;
+	font-family: Arial, Helvetica, sans-serif;
+}
+/* <video> element */
+.acorn-player.darkglass video {
+	float: left;
+	clear: both;
+	margin-bottom: 5px;	
+}
+/* Audio player */
+/* 
+ * If you're playing <audio>, we're assigning a Width larger by 10%, because we're missing two buttons(Captions and Transcript)
+ * each with a 5% Width
+ */
+.acorn-player.darkglass.audio-player .acorn-seek-slider {
+	width: 82%;
+}
+/* Player Controls */
+.acorn-player.darkglass .acorn-controls {
+	position: relative;
+	float: left;
+	clear: both;
+	width: 95%;
+	padding-right: 5%;
+	padding-left: 1%;
+	border: 2px solid #61625d;	
+	-moz-border-radius: 5px;
+	-webkit-border-radius: 5px;
+	border-radius: 5px;
+	background: #000000;
+	background-image: -moz-linear-gradient(top, #313131, #000000);
+	background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #313131),color-stop(1, #000000));		
+}
+/* <button>s */
+.acorn-player.darkglass button {
+	position: relative;
+	height: 22px;	
+	width: 4%;
+	margin-right: 1%;
+	padding: 0px;
+	border: none;
+	background-color: transparent;
+	background-repeat: no-repeat;
+	background-position: center center;
+	background-size: auto 100%;
+	
+	opacity: 0.7;
+	-moz-transition: all 0.2s ease-in-out;
+	-webkit-transition: all 0.2s ease-in-out;
+	-o-transition: all 0.2s ease-in-out;
+	transition: all 0.2s ease-in-out;
+	
+	-moz-border-radius: 2px;
+	-webkit-border-radius: 2px;
+	border-radius: 2px;
+	
+	cursor: pointer;
+	text-indent: -9999px;
+}
+.acorn-player.darkglass button:hover, .acorn-player.darkglass button:focus {
+	opacity: 1;
+}
+.acorn-player.darkglass button:active {
+	top: 1px;	
+}
+/* Playback controls(Play, Pause) */
+.acorn-player.darkglass .acorn-play-button {
+	float: left;
+	display: block;
+	background-image: url(darkglass-play.png);
+}
+.acorn-player.darkglass .acorn-paused-button {
+	background-image: url(darkglass-pause.png);
+}
+/* Seek Slider */
+.acorn-player.darkglass .acorn-seek-slider {
+	position: relative;
+	display: block;
+	float: left;
+	width: 72%;
+	height: 10px;
+	margin: 5px 1% 0px 1%;
+	background: #7289A8;
+	-moz-border-radius: 15px;
+	-webkit-border-radius: 15px;
+	border-radius: 15px;	
+}
+.acorn-player.darkglass .acorn-seek-slider .ui-slider-handle {
+	display: block;
+	position: absolute;	
+	width: 15px;
+	height: 15px;
+	border: 1px solid #333;
+	top: -4px;
+	background: #e6e6e6;	
+
+	-moz-border-radius: 10px;
+	-webkit-border-radius: 10px;
+	border-radius: 10px;
+}
+.acorn-player.darkglass .acorn-seek-slider .ui-slider-range {		
+	background: #0750B2;
+	
+	-moz-border-radius:10px;
+	-webkit-border-radius:10px;
+	border-radius:10px;
+}
+.acorn-player.darkglass .acorn-buffer {
+	background: #8E9DAF !important;
+}
+.acorn-player.darkglass .acorn-seek-slider .ui-state-focus, .acorn-player.darkglass .acorn-seek-slider .ui-slider-handle.ui-state-hover {
+	background: #fff !important;
+	
+	-moz-box-shadow: 0px 2px 15px #ff0000;
+	-webkit-box-shadow: 0px 2px 15px #ff0000;
+	box-shadow: 0px 2px 15px #ff0000;
+}
+/* Timer */
+.acorn-player.darkglass .acorn-timer {
+	float: left;
+	width: 6%;
+	overflow: hidden;
+	margin-top: 5px;	
+	
+	color: #999;
+	font-size: 0.7em;
+	font-weight: bold;
+}
+/* Volume Box */
+.acorn-player.darkglass .acorn-volume-box {
+	position: absolute;
+	float: left;
+	bottom: 0px;
+	right: 0px;
+	overflow: visible;
+	width: 5%;
+	height: 35px;
+	color: #fff;	
+	
+	-moz-transition: all 0.1s ease-in-out;
+	-webkit-transition: all 0.1s ease-in-out;
+	-o-transition: all 0.2s ease-in-out;
+	transition: all 0.1s ease-in-out;
+}
+.acorn-player.darkglass .acorn-volume-box:hover {
+	height: 135px;
+}
+.acorn-player.darkglass .acorn-volume-slider.handle-focused {
+	position: relative;
+	visibility: visible;
+	height: 100px;
+	opacity: 1;
+	top: -100px;
+}
+.acorn-player.darkglass .acorn-volume-box:hover .acorn-volume-slider {
+	position: relative;
+	visibility: visible;
+	height: 100px;
+	opacity: 1;
+	top: 0px;
+}
+/* Volume Slider */
+.acorn-player.darkglass .acorn-volume-slider {
+	position: relative;
+	height: 1px;
+	width: 7px;
+	left: 4px;
+	
+	visibility: visible;
+	opacity: 0;
+	
+	border: 1px solid #444;
+
+	-moz-border-radius: 15px;
+	-webkit-border-radius: 15px;
+	border-radius: 15px;
+	
+	background: #535353;
+	background-image: -moz-linear-gradient(top, #535353, #333333);
+	background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #535353),color-stop(1, #333333));
+	
+	box-shadow: inset 0 3px 3px #333333;
+	
+	-moz-transition: all 0.1s ease-in-out;
+	-webkit-transition: all 0.1s ease-in-out;
+	-o-transition: all 0.1s ease-in-out;
+	transition: all 0.1s ease-in-out; 
+}
+.acorn-player.darkglass .acorn-volume-slider .ui-slider-handle {
+	width: 12px;
+	height: 12px;
+	left: -4px;
+	margin-bottom:-0.6em;
+	margin-left:0;
+	border: 1px solid #333;	
+
+	-moz-border-radius:10px;
+	-webkit-border-radius:10px;
+	border-radius:10px;	
+	
+	background: #e6e6e6;
+	background-image: -moz-linear-gradient(top, #e6e6e6, #d5d5d5);
+	background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #e6e6e6),color-stop(1, #d5d5d5));
+	
+	box-shadow: inset 0 3px 3px #d5d5d5;	
+}
+.acorn-player.darkglass .acorn-volume-slider .ui-slider-handle:hover, .acorn-player.darkglass .acorn-volume-slider.handle-focused .ui-slider-handle {
+	background: #fff;
+
+	-moz-box-shadow: 0px 2px 15px #ff0000;
+	-webkit-box-shadow: 0px 2px 15px #ff0000;
+	box-shadow: 0px 2px 15px #ff0000;
+}
+.acorn-player.darkglass .acorn-volume-slider .ui-slider-range {
+	-moz-border-radius: 15px;
+	-webkit-border-radius: 15px;
+	border-radius: 15px;
+	
+	background: #e6e6e6;
+	background-image: -moz-linear-gradient(top, #e6e6e6, #d5d5d5);
+	background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #e6e6e6),color-stop(1, #d5d5d5));
+	
+	box-shadow: inset 0 3px 3px #d5d5d5;
+}
+/* Volume Button */
+.acorn-player.darkglass .acorn-volume-button {
+	position: absolute;	
+	bottom: 0px;
+	width: 100%;
+	display: block;	
+	background: url(darkglass-volume-full.png) no-repeat;
+	text-indent: -9999px;
+	
+	opacity: 0.8;
+}
+.acorn-player.darkglass .acorn-volume-button:active {
+	top: auto;
+}
+.acorn-player.darkglass .acorn-volume-mute {
+	background-image: url(darkglass-volume.png);
+}
+/* Swap Button */
+.acorn-player.darkglass .acorn-swap-button {
+	float: right;
+	background-image: url(darkglass-swap.png);
+}
+/* Fullscreen Button */
+.acorn-player.darkglass .acorn-fullscreen-button {
+	float: right;
+	background-image: url(darkglass-fullscreen.png);
+}
+/* Fullscreen Mode */
+.acorn-player.darkglass .fullscreen-controls {	
+	left: 0px;
+	bottom: 0px;
+}
+.acorn-player.darkglass .fullscreen-controls button {
+	height: 35px;
+}
+.acorn-player.darkglass .fullscreen-controls .acorn-fullscreen-button {
+	background-image: url(darkglass-exit-fullscreen.png);
+}
+.acorn-player.darkglass .fullscreen-controls .acorn-seek-slider {
+	margin-top: 10px;
+}
+/* Caption Button */
+.acorn-player.darkglass .acorn-caption-button {
+	float: right;
+	background-image: url(darkglass-caption.png);
+}
+.acorn-player.darkglass .acorn-caption {
+	font-size: 14px;
+	font-weight: bold;
+	color: #fff;
+	
+	text-shadow: 0px 1px 5px #000;
+}
+.acorn-player.darkglass .acorn-caption-active {
+	background-color: #8F0000 !important;
+}
+.acorn-player.darkglass .acorn-transcript-active {
+	background-color: #8F0000 !important;
+}
+/* Transcript Button */
+.acorn-player.darkglass .acorn-transcript-button {
+	float: right;
+	background-image: url(darkglass-transcript.png);
+}
+/* 
+ * darkglasssmall Child Theme
+ */
+.acorn-player.darkglasssmall {
+	padding: 0px;
+}
+.acorn-player.darkglasssmall video:hover + .acorn-controls {
+	visibility: visible;
+	opacity: 0.7;
+}
+.acorn-player.darkglasssmall .acorn-controls:hover {
+	visibility: visible;
+	opacity: 0.7;
+}
+.acorn-player.darkglasssmall .acorn-controls {
+	position: absolute;	
+	bottom: 5%;
+	width: 87%;
+	margin-left: 2%;
+	padding: 2% 7% 2% 2%;
+	
+	border: 1px solid #2E2E2E;
+	
+	-moz-border-radius: 5px;
+	-webkit-border-radius: 5px;
+	border-radius: 5px;
+	
+	background: #000000;
+	background-image: -moz-linear-gradient(top, #313131, #000000);
+	background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #313131),color-stop(1, #000000));
+	
+	opacity: 0;
+	visibility: hidden;	
+	
+	-moz-transition: all 0.1s ease-in-out;
+	-webkit-transition: all 0.1s ease-in-out;
+	-o-transition: all 0.1s ease-in-out;
+	transition: all 0.1s ease-in-out;
+}
+.acorn-player.darkglasssmall .acorn-volume-box {
+	margin-right: 2%;
+	margin-bottom: 2%;
+}
+/* Audio player */
+.acorn-player.darkglasssmall.audio-player .acorn-controls {
+	display: block;
+	position: relative;
+	visibility: visible;
+	opacity: 1;
+	margin-left: 0px;
+	width: 91%;
+	
+	border: none;
+}
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-caption.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-caption.png
new file mode 100755
index 0000000000000000000000000000000000000000..9c814ec7547919896fac5df9ccbff0988c784b4e
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-caption.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-exit-fullscreen.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-exit-fullscreen.png
new file mode 100755
index 0000000000000000000000000000000000000000..3df3bf468cc385d8a39a7e6e427fbe4d8d1a1dee
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-exit-fullscreen.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-fullscreen.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-fullscreen.png
new file mode 100755
index 0000000000000000000000000000000000000000..c70fb08ee7ce2ae3253151d978c353b33b049311
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-fullscreen.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-pause.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-pause.png
new file mode 100755
index 0000000000000000000000000000000000000000..26462e66f6ed8522650890f93de8a7861cc35b49
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-pause.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-play.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-play.png
new file mode 100755
index 0000000000000000000000000000000000000000..5d5aacae17c9e7ff391b1fcefec296943f074a1e
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-play.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-swap.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-swap.png
new file mode 100755
index 0000000000000000000000000000000000000000..055dacceac1cc04d28cdd69f4dd2995fe6ebeaa0
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-swap.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-transcript.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-transcript.png
new file mode 100755
index 0000000000000000000000000000000000000000..e6d6dac51651d27e804eccdcca62087276aeff02
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-transcript.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-volume-full.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-volume-full.png
new file mode 100755
index 0000000000000000000000000000000000000000..485a1133d82ef535b98f118893cd1575df3cdcb7
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-volume-full.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-volume.png b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-volume.png
new file mode 100755
index 0000000000000000000000000000000000000000..d4bdcbf622ee54121870c17e9763c76eb8569d00
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/acornmediaplayer/themes/darkglass/darkglass-volume.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/css/bbb.playback.css b/record-and-playback/presentation_export/playback/presentation_export/css/bbb.playback.css
new file mode 100755
index 0000000000000000000000000000000000000000..4364dbb9e2cac1f1fb4a9ff7ed0470eea4a3975b
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/css/bbb.playback.css
@@ -0,0 +1,256 @@
+/*
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+html{
+}
+body {
+	font-family: Verdana;
+	background: #fff;
+	padding-top: 30px;
+}
+h1 {
+	text-align:center
+}
+br{
+	display:none
+}
+
+/*
+ * clearfix
+ * see: http://css-tricks.com/snippets/css/clear-fix/
+ */
+.clearfix:after {
+	visibility: hidden;
+	display: block;
+	font-size: 0;
+	content: " ";
+	clear: both;
+	height: 0;
+}
+* html .clearfix             { zoom: 1; } /* IE6 */
+*:first-child+html .clearfix { zoom: 1; } /* IE7 */
+
+#playbackArea {
+	width: 1360px; /* #slide.width + #chat.width + #audioRecording.width */
+	height: 650px;
+	margin: 0 auto;
+	overflow: hidden;
+}
+
+#audioRecordingWrapper{
+	float: left;
+	width: 800px;
+}
+
+#audioRecording{
+	display: block;
+	margin-left: auto;
+	margin-right: auto;
+	width: 100%;
+}
+
+#audioRecordingWrapper .acorn-controls, #videoRecordingWrapper .acorn-controls{
+	position: relative;
+	top: 0;
+	left: -810px;
+	width: 730px;
+}
+
+#playbackControls{
+	width: 1360px;
+	margin: 0 auto;
+	margin-top: -50px;
+}
+
+#autoscrollWrapper{
+	float: left;
+	margin-left: 10px;
+	margin-top: 8px;
+	font-size: 14px;
+}
+
+.webcam{
+  width: 402px;
+  height: 300px;
+}
+
+#video{
+  width: 402px;
+  background: white;
+}
+
+/* To remove the white space on top of the audio tag in Firefox
+ * See: http://stackoverflow.com/questions/9527453/firefox-and-html5-audio-element-dont-play-well-together
+ */
+@-moz-document url-prefix() {
+	#audioRecordingWrapper{
+		position: relative;
+		height: 28px;
+	}
+	#audioRecording {
+		position: absolute;
+		bottom: 0;
+	}
+}
+
+#presentation {
+	float: left;
+	position: relative;
+	height: 600px;
+}
+
+#slide {
+	background-image: url('../logo.png');
+	text-align: center;
+	border: 0px solid #ccc;
+	width: 800px;
+	height: 600px; /* same as slide images */
+	position: relative;
+	top: -12px;
+}
+
+/* Visually hides text
+ * see: yaccessibilityblog.com/library/css-clip-hidden-content.html
+ */
+.visually-hidden {
+	position: absolute !important;
+	clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
+	clip: rect(1px, 1px, 1px, 1px);
+	padding: 0 !important;
+	border: 0 !important;
+	height: 1px !important;
+	width: 1px !important;
+	overflow: hidden;
+}
+
+#mediaArea {
+	float: right;
+	background: white;
+	width: 402px;
+}
+
+#chatAndMediaArea{
+	float: right;
+	background: white;
+	height: 600px;
+	width: 402px;
+}
+#chat{
+	margin: 0 auto;
+	padding: 0 10px;
+	border: 0px solid #ccc;
+	height: 300px;
+	overflow: auto;
+}
+#chat div{
+	padding:0px;
+	font-size:13px;
+}
+#big {display:none}
+#mid {display:none}
+
+#thumbnails {
+	float: left;
+	width: 130px;
+	height: 600px; /* same as #slide */
+	background: #fff;
+	border: 0px solid #bbb;
+	margin-right: 10px;
+	overflow-y: scroll;
+	overflow-x: hidden;
+}
+
+#thumbnails img.thumbnail {
+	width: 100px;
+	height: auto;
+	border: 0px solid #eee;
+	margin: 5px;
+	cursor: pointer;
+	vertical-align: bottom;
+}
+
+#thumbnails .thumbnail-wrapper {
+	position: relative;
+	margin: 0;
+	padding: 0;
+}
+
+#thumbnails .thumbnail-wrapper.active {
+	background-color: #D9EDF7;
+}
+
+#thumbnails .thumbnail-wrapper.active img.thumbnail {
+	border-color: #3A87AD;
+}
+
+#thumbnails .thumbnail-label {
+	color: #fff;
+	background: #3A87AD;
+	font-weight: bold;
+	font-size: 12px;
+	position: absolute;
+	bottom: 5px;
+	left: 5px;
+	max-width: 90px;
+	text-align: center;
+	display: none;
+	padding: 2px 5px;
+	cursor: pointer;
+}
+
+#accInfo{
+        margin: 20px auto;
+        font-size:0.75em;
+        text-align: center;
+        clear: both;
+	padding-top: 75px;
+}
+
+#footer{
+        margin: 20px auto;
+        font-size:0.75em;
+        color: #666;
+        text-align: center;
+        clear: both;
+	padding-top: 35px;
+}
+
+.circle {
+	height: 12px;
+	width: 12px;
+	border-radius: 50%;
+}
+
+
+#cursor {
+	position: relative;
+	background: red;
+	z-index: 10;
+}
+
+#load-recording-msg {
+	text-align: center;
+	height: 50px;
+	width: 200px;
+	position: absolute;
+	left: 50%;
+	margin-left: -100px;
+	top:60%;
+}
\ No newline at end of file
diff --git a/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.css b/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.css
new file mode 100644
index 0000000000000000000000000000000000000000..d866a73352494020724b8868a05c474ae0937148
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.css
@@ -0,0 +1,594 @@
+/* 
+ * Foundation Icons v 3.0
+ * Made by ZURB 2013 http://zurb.com/playground/foundation-icon-fonts-3
+ * MIT License
+ */
+
+@font-face {
+  font-family: "foundation-icons";
+  src: url("foundation-icons.eot");
+  src: url("foundation-icons.eot?#iefix") format("embedded-opentype"),
+       url("foundation-icons.woff") format("woff"),
+       url("foundation-icons.ttf") format("truetype"),
+       url("foundation-icons.svg#fontcustom") format("svg");
+  font-weight: normal;
+  font-style: normal;
+}
+
+.fi-address-book:before,
+.fi-alert:before,
+.fi-align-center:before,
+.fi-align-justify:before,
+.fi-align-left:before,
+.fi-align-right:before,
+.fi-anchor:before,
+.fi-annotate:before,
+.fi-archive:before,
+.fi-arrow-down:before,
+.fi-arrow-left:before,
+.fi-arrow-right:before,
+.fi-arrow-up:before,
+.fi-arrows-compress:before,
+.fi-arrows-expand:before,
+.fi-arrows-in:before,
+.fi-arrows-out:before,
+.fi-asl:before,
+.fi-asterisk:before,
+.fi-at-sign:before,
+.fi-background-color:before,
+.fi-battery-empty:before,
+.fi-battery-full:before,
+.fi-battery-half:before,
+.fi-bitcoin-circle:before,
+.fi-bitcoin:before,
+.fi-blind:before,
+.fi-bluetooth:before,
+.fi-bold:before,
+.fi-book-bookmark:before,
+.fi-book:before,
+.fi-bookmark:before,
+.fi-braille:before,
+.fi-burst-new:before,
+.fi-burst-sale:before,
+.fi-burst:before,
+.fi-calendar:before,
+.fi-camera:before,
+.fi-check:before,
+.fi-checkbox:before,
+.fi-clipboard-notes:before,
+.fi-clipboard-pencil:before,
+.fi-clipboard:before,
+.fi-clock:before,
+.fi-closed-caption:before,
+.fi-cloud:before,
+.fi-comment-minus:before,
+.fi-comment-quotes:before,
+.fi-comment-video:before,
+.fi-comment:before,
+.fi-comments:before,
+.fi-compass:before,
+.fi-contrast:before,
+.fi-credit-card:before,
+.fi-crop:before,
+.fi-crown:before,
+.fi-css3:before,
+.fi-database:before,
+.fi-die-five:before,
+.fi-die-four:before,
+.fi-die-one:before,
+.fi-die-six:before,
+.fi-die-three:before,
+.fi-die-two:before,
+.fi-dislike:before,
+.fi-dollar-bill:before,
+.fi-dollar:before,
+.fi-download:before,
+.fi-eject:before,
+.fi-elevator:before,
+.fi-euro:before,
+.fi-eye:before,
+.fi-fast-forward:before,
+.fi-female-symbol:before,
+.fi-female:before,
+.fi-filter:before,
+.fi-first-aid:before,
+.fi-flag:before,
+.fi-folder-add:before,
+.fi-folder-lock:before,
+.fi-folder:before,
+.fi-foot:before,
+.fi-foundation:before,
+.fi-graph-bar:before,
+.fi-graph-horizontal:before,
+.fi-graph-pie:before,
+.fi-graph-trend:before,
+.fi-guide-dog:before,
+.fi-hearing-aid:before,
+.fi-heart:before,
+.fi-home:before,
+.fi-html5:before,
+.fi-indent-less:before,
+.fi-indent-more:before,
+.fi-info:before,
+.fi-italic:before,
+.fi-key:before,
+.fi-laptop:before,
+.fi-layout:before,
+.fi-lightbulb:before,
+.fi-like:before,
+.fi-link:before,
+.fi-list-bullet:before,
+.fi-list-number:before,
+.fi-list-thumbnails:before,
+.fi-list:before,
+.fi-lock:before,
+.fi-loop:before,
+.fi-magnifying-glass:before,
+.fi-mail:before,
+.fi-male-female:before,
+.fi-male-symbol:before,
+.fi-male:before,
+.fi-map:before,
+.fi-marker:before,
+.fi-megaphone:before,
+.fi-microphone:before,
+.fi-minus-circle:before,
+.fi-minus:before,
+.fi-mobile-signal:before,
+.fi-mobile:before,
+.fi-monitor:before,
+.fi-mountains:before,
+.fi-music:before,
+.fi-next:before,
+.fi-no-dogs:before,
+.fi-no-smoking:before,
+.fi-page-add:before,
+.fi-page-copy:before,
+.fi-page-csv:before,
+.fi-page-delete:before,
+.fi-page-doc:before,
+.fi-page-edit:before,
+.fi-page-export-csv:before,
+.fi-page-export-doc:before,
+.fi-page-export-pdf:before,
+.fi-page-export:before,
+.fi-page-filled:before,
+.fi-page-multiple:before,
+.fi-page-pdf:before,
+.fi-page-remove:before,
+.fi-page-search:before,
+.fi-page:before,
+.fi-paint-bucket:before,
+.fi-paperclip:before,
+.fi-pause:before,
+.fi-paw:before,
+.fi-paypal:before,
+.fi-pencil:before,
+.fi-photo:before,
+.fi-play-circle:before,
+.fi-play-video:before,
+.fi-play:before,
+.fi-plus:before,
+.fi-pound:before,
+.fi-power:before,
+.fi-previous:before,
+.fi-price-tag:before,
+.fi-pricetag-multiple:before,
+.fi-print:before,
+.fi-prohibited:before,
+.fi-projection-screen:before,
+.fi-puzzle:before,
+.fi-quote:before,
+.fi-record:before,
+.fi-refresh:before,
+.fi-results-demographics:before,
+.fi-results:before,
+.fi-rewind-ten:before,
+.fi-rewind:before,
+.fi-rss:before,
+.fi-safety-cone:before,
+.fi-save:before,
+.fi-share:before,
+.fi-sheriff-badge:before,
+.fi-shield:before,
+.fi-shopping-bag:before,
+.fi-shopping-cart:before,
+.fi-shuffle:before,
+.fi-skull:before,
+.fi-social-500px:before,
+.fi-social-adobe:before,
+.fi-social-amazon:before,
+.fi-social-android:before,
+.fi-social-apple:before,
+.fi-social-behance:before,
+.fi-social-bing:before,
+.fi-social-blogger:before,
+.fi-social-delicious:before,
+.fi-social-designer-news:before,
+.fi-social-deviant-art:before,
+.fi-social-digg:before,
+.fi-social-dribbble:before,
+.fi-social-drive:before,
+.fi-social-dropbox:before,
+.fi-social-evernote:before,
+.fi-social-facebook:before,
+.fi-social-flickr:before,
+.fi-social-forrst:before,
+.fi-social-foursquare:before,
+.fi-social-game-center:before,
+.fi-social-github:before,
+.fi-social-google-plus:before,
+.fi-social-hacker-news:before,
+.fi-social-hi5:before,
+.fi-social-instagram:before,
+.fi-social-joomla:before,
+.fi-social-lastfm:before,
+.fi-social-linkedin:before,
+.fi-social-medium:before,
+.fi-social-myspace:before,
+.fi-social-orkut:before,
+.fi-social-path:before,
+.fi-social-picasa:before,
+.fi-social-pinterest:before,
+.fi-social-rdio:before,
+.fi-social-reddit:before,
+.fi-social-skillshare:before,
+.fi-social-skype:before,
+.fi-social-smashing-mag:before,
+.fi-social-snapchat:before,
+.fi-social-spotify:before,
+.fi-social-squidoo:before,
+.fi-social-stack-overflow:before,
+.fi-social-steam:before,
+.fi-social-stumbleupon:before,
+.fi-social-treehouse:before,
+.fi-social-tumblr:before,
+.fi-social-twitter:before,
+.fi-social-vimeo:before,
+.fi-social-windows:before,
+.fi-social-xbox:before,
+.fi-social-yahoo:before,
+.fi-social-yelp:before,
+.fi-social-youtube:before,
+.fi-social-zerply:before,
+.fi-social-zurb:before,
+.fi-sound:before,
+.fi-star:before,
+.fi-stop:before,
+.fi-strikethrough:before,
+.fi-subscript:before,
+.fi-superscript:before,
+.fi-tablet-landscape:before,
+.fi-tablet-portrait:before,
+.fi-target-two:before,
+.fi-target:before,
+.fi-telephone-accessible:before,
+.fi-telephone:before,
+.fi-text-color:before,
+.fi-thumbnails:before,
+.fi-ticket:before,
+.fi-torso-business:before,
+.fi-torso-female:before,
+.fi-torso:before,
+.fi-torsos-all-female:before,
+.fi-torsos-all:before,
+.fi-torsos-female-male:before,
+.fi-torsos-male-female:before,
+.fi-torsos:before,
+.fi-trash:before,
+.fi-trees:before,
+.fi-trophy:before,
+.fi-underline:before,
+.fi-universal-access:before,
+.fi-unlink:before,
+.fi-unlock:before,
+.fi-upload-cloud:before,
+.fi-upload:before,
+.fi-usb:before,
+.fi-video:before,
+.fi-volume-none:before,
+.fi-volume-strike:before,
+.fi-volume:before,
+.fi-web:before,
+.fi-wheelchair:before,
+.fi-widget:before,
+.fi-wrench:before,
+.fi-x-circle:before,
+.fi-x:before,
+.fi-yen:before,
+.fi-zoom-in:before,
+.fi-zoom-out:before {
+  font-family: "foundation-icons";
+  font-style: normal;
+  font-weight: normal;
+  font-variant: normal;
+  text-transform: none;
+  line-height: 1;
+  -webkit-font-smoothing: antialiased;
+  display: inline-block;
+  text-decoration: inherit;
+}
+
+.fi-address-book:before { content: "\f100"; }
+.fi-alert:before { content: "\f101"; }
+.fi-align-center:before { content: "\f102"; }
+.fi-align-justify:before { content: "\f103"; }
+.fi-align-left:before { content: "\f104"; }
+.fi-align-right:before { content: "\f105"; }
+.fi-anchor:before { content: "\f106"; }
+.fi-annotate:before { content: "\f107"; }
+.fi-archive:before { content: "\f108"; }
+.fi-arrow-down:before { content: "\f109"; }
+.fi-arrow-left:before { content: "\f10a"; }
+.fi-arrow-right:before { content: "\f10b"; }
+.fi-arrow-up:before { content: "\f10c"; }
+.fi-arrows-compress:before { content: "\f10d"; }
+.fi-arrows-expand:before { content: "\f10e"; }
+.fi-arrows-in:before { content: "\f10f"; }
+.fi-arrows-out:before { content: "\f110"; }
+.fi-asl:before { content: "\f111"; }
+.fi-asterisk:before { content: "\f112"; }
+.fi-at-sign:before { content: "\f113"; }
+.fi-background-color:before { content: "\f114"; }
+.fi-battery-empty:before { content: "\f115"; }
+.fi-battery-full:before { content: "\f116"; }
+.fi-battery-half:before { content: "\f117"; }
+.fi-bitcoin-circle:before { content: "\f118"; }
+.fi-bitcoin:before { content: "\f119"; }
+.fi-blind:before { content: "\f11a"; }
+.fi-bluetooth:before { content: "\f11b"; }
+.fi-bold:before { content: "\f11c"; }
+.fi-book-bookmark:before { content: "\f11d"; }
+.fi-book:before { content: "\f11e"; }
+.fi-bookmark:before { content: "\f11f"; }
+.fi-braille:before { content: "\f120"; }
+.fi-burst-new:before { content: "\f121"; }
+.fi-burst-sale:before { content: "\f122"; }
+.fi-burst:before { content: "\f123"; }
+.fi-calendar:before { content: "\f124"; }
+.fi-camera:before { content: "\f125"; }
+.fi-check:before { content: "\f126"; }
+.fi-checkbox:before { content: "\f127"; }
+.fi-clipboard-notes:before { content: "\f128"; }
+.fi-clipboard-pencil:before { content: "\f129"; }
+.fi-clipboard:before { content: "\f12a"; }
+.fi-clock:before { content: "\f12b"; }
+.fi-closed-caption:before { content: "\f12c"; }
+.fi-cloud:before { content: "\f12d"; }
+.fi-comment-minus:before { content: "\f12e"; }
+.fi-comment-quotes:before { content: "\f12f"; }
+.fi-comment-video:before { content: "\f130"; }
+.fi-comment:before { content: "\f131"; }
+.fi-comments:before { content: "\f132"; }
+.fi-compass:before { content: "\f133"; }
+.fi-contrast:before { content: "\f134"; }
+.fi-credit-card:before { content: "\f135"; }
+.fi-crop:before { content: "\f136"; }
+.fi-crown:before { content: "\f137"; }
+.fi-css3:before { content: "\f138"; }
+.fi-database:before { content: "\f139"; }
+.fi-die-five:before { content: "\f13a"; }
+.fi-die-four:before { content: "\f13b"; }
+.fi-die-one:before { content: "\f13c"; }
+.fi-die-six:before { content: "\f13d"; }
+.fi-die-three:before { content: "\f13e"; }
+.fi-die-two:before { content: "\f13f"; }
+.fi-dislike:before { content: "\f140"; }
+.fi-dollar-bill:before { content: "\f141"; }
+.fi-dollar:before { content: "\f142"; }
+.fi-download:before { content: "\f143"; }
+.fi-eject:before { content: "\f144"; }
+.fi-elevator:before { content: "\f145"; }
+.fi-euro:before { content: "\f146"; }
+.fi-eye:before { content: "\f147"; }
+.fi-fast-forward:before { content: "\f148"; }
+.fi-female-symbol:before { content: "\f149"; }
+.fi-female:before { content: "\f14a"; }
+.fi-filter:before { content: "\f14b"; }
+.fi-first-aid:before { content: "\f14c"; }
+.fi-flag:before { content: "\f14d"; }
+.fi-folder-add:before { content: "\f14e"; }
+.fi-folder-lock:before { content: "\f14f"; }
+.fi-folder:before { content: "\f150"; }
+.fi-foot:before { content: "\f151"; }
+.fi-foundation:before { content: "\f152"; }
+.fi-graph-bar:before { content: "\f153"; }
+.fi-graph-horizontal:before { content: "\f154"; }
+.fi-graph-pie:before { content: "\f155"; }
+.fi-graph-trend:before { content: "\f156"; }
+.fi-guide-dog:before { content: "\f157"; }
+.fi-hearing-aid:before { content: "\f158"; }
+.fi-heart:before { content: "\f159"; }
+.fi-home:before { content: "\f15a"; }
+.fi-html5:before { content: "\f15b"; }
+.fi-indent-less:before { content: "\f15c"; }
+.fi-indent-more:before { content: "\f15d"; }
+.fi-info:before { content: "\f15e"; }
+.fi-italic:before { content: "\f15f"; }
+.fi-key:before { content: "\f160"; }
+.fi-laptop:before { content: "\f161"; }
+.fi-layout:before { content: "\f162"; }
+.fi-lightbulb:before { content: "\f163"; }
+.fi-like:before { content: "\f164"; }
+.fi-link:before { content: "\f165"; }
+.fi-list-bullet:before { content: "\f166"; }
+.fi-list-number:before { content: "\f167"; }
+.fi-list-thumbnails:before { content: "\f168"; }
+.fi-list:before { content: "\f169"; }
+.fi-lock:before { content: "\f16a"; }
+.fi-loop:before { content: "\f16b"; }
+.fi-magnifying-glass:before { content: "\f16c"; }
+.fi-mail:before { content: "\f16d"; }
+.fi-male-female:before { content: "\f16e"; }
+.fi-male-symbol:before { content: "\f16f"; }
+.fi-male:before { content: "\f170"; }
+.fi-map:before { content: "\f171"; }
+.fi-marker:before { content: "\f172"; }
+.fi-megaphone:before { content: "\f173"; }
+.fi-microphone:before { content: "\f174"; }
+.fi-minus-circle:before { content: "\f175"; }
+.fi-minus:before { content: "\f176"; }
+.fi-mobile-signal:before { content: "\f177"; }
+.fi-mobile:before { content: "\f178"; }
+.fi-monitor:before { content: "\f179"; }
+.fi-mountains:before { content: "\f17a"; }
+.fi-music:before { content: "\f17b"; }
+.fi-next:before { content: "\f17c"; }
+.fi-no-dogs:before { content: "\f17d"; }
+.fi-no-smoking:before { content: "\f17e"; }
+.fi-page-add:before { content: "\f17f"; }
+.fi-page-copy:before { content: "\f180"; }
+.fi-page-csv:before { content: "\f181"; }
+.fi-page-delete:before { content: "\f182"; }
+.fi-page-doc:before { content: "\f183"; }
+.fi-page-edit:before { content: "\f184"; }
+.fi-page-export-csv:before { content: "\f185"; }
+.fi-page-export-doc:before { content: "\f186"; }
+.fi-page-export-pdf:before { content: "\f187"; }
+.fi-page-export:before { content: "\f188"; }
+.fi-page-filled:before { content: "\f189"; }
+.fi-page-multiple:before { content: "\f18a"; }
+.fi-page-pdf:before { content: "\f18b"; }
+.fi-page-remove:before { content: "\f18c"; }
+.fi-page-search:before { content: "\f18d"; }
+.fi-page:before { content: "\f18e"; }
+.fi-paint-bucket:before { content: "\f18f"; }
+.fi-paperclip:before { content: "\f190"; }
+.fi-pause:before { content: "\f191"; }
+.fi-paw:before { content: "\f192"; }
+.fi-paypal:before { content: "\f193"; }
+.fi-pencil:before { content: "\f194"; }
+.fi-photo:before { content: "\f195"; }
+.fi-play-circle:before { content: "\f196"; }
+.fi-play-video:before { content: "\f197"; }
+.fi-play:before { content: "\f198"; }
+.fi-plus:before { content: "\f199"; }
+.fi-pound:before { content: "\f19a"; }
+.fi-power:before { content: "\f19b"; }
+.fi-previous:before { content: "\f19c"; }
+.fi-price-tag:before { content: "\f19d"; }
+.fi-pricetag-multiple:before { content: "\f19e"; }
+.fi-print:before { content: "\f19f"; }
+.fi-prohibited:before { content: "\f1a0"; }
+.fi-projection-screen:before { content: "\f1a1"; }
+.fi-puzzle:before { content: "\f1a2"; }
+.fi-quote:before { content: "\f1a3"; }
+.fi-record:before { content: "\f1a4"; }
+.fi-refresh:before { content: "\f1a5"; }
+.fi-results-demographics:before { content: "\f1a6"; }
+.fi-results:before { content: "\f1a7"; }
+.fi-rewind-ten:before { content: "\f1a8"; }
+.fi-rewind:before { content: "\f1a9"; }
+.fi-rss:before { content: "\f1aa"; }
+.fi-safety-cone:before { content: "\f1ab"; }
+.fi-save:before { content: "\f1ac"; }
+.fi-share:before { content: "\f1ad"; }
+.fi-sheriff-badge:before { content: "\f1ae"; }
+.fi-shield:before { content: "\f1af"; }
+.fi-shopping-bag:before { content: "\f1b0"; }
+.fi-shopping-cart:before { content: "\f1b1"; }
+.fi-shuffle:before { content: "\f1b2"; }
+.fi-skull:before { content: "\f1b3"; }
+.fi-social-500px:before { content: "\f1b4"; }
+.fi-social-adobe:before { content: "\f1b5"; }
+.fi-social-amazon:before { content: "\f1b6"; }
+.fi-social-android:before { content: "\f1b7"; }
+.fi-social-apple:before { content: "\f1b8"; }
+.fi-social-behance:before { content: "\f1b9"; }
+.fi-social-bing:before { content: "\f1ba"; }
+.fi-social-blogger:before { content: "\f1bb"; }
+.fi-social-delicious:before { content: "\f1bc"; }
+.fi-social-designer-news:before { content: "\f1bd"; }
+.fi-social-deviant-art:before { content: "\f1be"; }
+.fi-social-digg:before { content: "\f1bf"; }
+.fi-social-dribbble:before { content: "\f1c0"; }
+.fi-social-drive:before { content: "\f1c1"; }
+.fi-social-dropbox:before { content: "\f1c2"; }
+.fi-social-evernote:before { content: "\f1c3"; }
+.fi-social-facebook:before { content: "\f1c4"; }
+.fi-social-flickr:before { content: "\f1c5"; }
+.fi-social-forrst:before { content: "\f1c6"; }
+.fi-social-foursquare:before { content: "\f1c7"; }
+.fi-social-game-center:before { content: "\f1c8"; }
+.fi-social-github:before { content: "\f1c9"; }
+.fi-social-google-plus:before { content: "\f1ca"; }
+.fi-social-hacker-news:before { content: "\f1cb"; }
+.fi-social-hi5:before { content: "\f1cc"; }
+.fi-social-instagram:before { content: "\f1cd"; }
+.fi-social-joomla:before { content: "\f1ce"; }
+.fi-social-lastfm:before { content: "\f1cf"; }
+.fi-social-linkedin:before { content: "\f1d0"; }
+.fi-social-medium:before { content: "\f1d1"; }
+.fi-social-myspace:before { content: "\f1d2"; }
+.fi-social-orkut:before { content: "\f1d3"; }
+.fi-social-path:before { content: "\f1d4"; }
+.fi-social-picasa:before { content: "\f1d5"; }
+.fi-social-pinterest:before { content: "\f1d6"; }
+.fi-social-rdio:before { content: "\f1d7"; }
+.fi-social-reddit:before { content: "\f1d8"; }
+.fi-social-skillshare:before { content: "\f1d9"; }
+.fi-social-skype:before { content: "\f1da"; }
+.fi-social-smashing-mag:before { content: "\f1db"; }
+.fi-social-snapchat:before { content: "\f1dc"; }
+.fi-social-spotify:before { content: "\f1dd"; }
+.fi-social-squidoo:before { content: "\f1de"; }
+.fi-social-stack-overflow:before { content: "\f1df"; }
+.fi-social-steam:before { content: "\f1e0"; }
+.fi-social-stumbleupon:before { content: "\f1e1"; }
+.fi-social-treehouse:before { content: "\f1e2"; }
+.fi-social-tumblr:before { content: "\f1e3"; }
+.fi-social-twitter:before { content: "\f1e4"; }
+.fi-social-vimeo:before { content: "\f1e5"; }
+.fi-social-windows:before { content: "\f1e6"; }
+.fi-social-xbox:before { content: "\f1e7"; }
+.fi-social-yahoo:before { content: "\f1e8"; }
+.fi-social-yelp:before { content: "\f1e9"; }
+.fi-social-youtube:before { content: "\f1ea"; }
+.fi-social-zerply:before { content: "\f1eb"; }
+.fi-social-zurb:before { content: "\f1ec"; }
+.fi-sound:before { content: "\f1ed"; }
+.fi-star:before { content: "\f1ee"; }
+.fi-stop:before { content: "\f1ef"; }
+.fi-strikethrough:before { content: "\f1f0"; }
+.fi-subscript:before { content: "\f1f1"; }
+.fi-superscript:before { content: "\f1f2"; }
+.fi-tablet-landscape:before { content: "\f1f3"; }
+.fi-tablet-portrait:before { content: "\f1f4"; }
+.fi-target-two:before { content: "\f1f5"; }
+.fi-target:before { content: "\f1f6"; }
+.fi-telephone-accessible:before { content: "\f1f7"; }
+.fi-telephone:before { content: "\f1f8"; }
+.fi-text-color:before { content: "\f1f9"; }
+.fi-thumbnails:before { content: "\f1fa"; }
+.fi-ticket:before { content: "\f1fb"; }
+.fi-torso-business:before { content: "\f1fc"; }
+.fi-torso-female:before { content: "\f1fd"; }
+.fi-torso:before { content: "\f1fe"; }
+.fi-torsos-all-female:before { content: "\f1ff"; }
+.fi-torsos-all:before { content: "\f200"; }
+.fi-torsos-female-male:before { content: "\f201"; }
+.fi-torsos-male-female:before { content: "\f202"; }
+.fi-torsos:before { content: "\f203"; }
+.fi-trash:before { content: "\f204"; }
+.fi-trees:before { content: "\f205"; }
+.fi-trophy:before { content: "\f206"; }
+.fi-underline:before { content: "\f207"; }
+.fi-universal-access:before { content: "\f208"; }
+.fi-unlink:before { content: "\f209"; }
+.fi-unlock:before { content: "\f20a"; }
+.fi-upload-cloud:before { content: "\f20b"; }
+.fi-upload:before { content: "\f20c"; }
+.fi-usb:before { content: "\f20d"; }
+.fi-video:before { content: "\f20e"; }
+.fi-volume-none:before { content: "\f20f"; }
+.fi-volume-strike:before { content: "\f210"; }
+.fi-volume:before { content: "\f211"; }
+.fi-web:before { content: "\f212"; }
+.fi-wheelchair:before { content: "\f213"; }
+.fi-widget:before { content: "\f214"; }
+.fi-wrench:before { content: "\f215"; }
+.fi-x-circle:before { content: "\f216"; }
+.fi-x:before { content: "\f217"; }
+.fi-yen:before { content: "\f218"; }
+.fi-zoom-in:before { content: "\f219"; }
+.fi-zoom-out:before { content: "\f21a"; }
diff --git a/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.eot b/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.eot
new file mode 100644
index 0000000000000000000000000000000000000000..1746ad407fecf570ead54e216dc4bd7c79271206
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.eot differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.ttf b/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..6cce217ddc2efe3411dc9fa34e294e48e4cdf4f5
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.ttf differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.woff b/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.woff
new file mode 100644
index 0000000000000000000000000000000000000000..e2cfe25dd392203f910d5deadd19beebe7e99984
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/css/foundation-icons.woff differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/css/foundation.css b/record-and-playback/presentation_export/playback/presentation_export/css/foundation.css
new file mode 100644
index 0000000000000000000000000000000000000000..837fbe3da5ca65b6daa12e0a7a205d920b073054
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/css/foundation.css
@@ -0,0 +1,6579 @@
+meta.foundation-version {
+  font-family: "/5.5.3/"; }
+
+meta.foundation-mq-small {
+  font-family: "/only screen/";
+  width: 0; }
+
+meta.foundation-mq-small-only {
+  font-family: "/only screen and (max-width: 40em)/";
+  width: 0; }
+
+meta.foundation-mq-medium {
+  font-family: "/only screen and (min-width:40.0625em)/";
+  width: 40.0625em; }
+
+meta.foundation-mq-medium-only {
+  font-family: "/only screen and (min-width:40.0625em) and (max-width:64em)/";
+  width: 40.0625em; }
+
+meta.foundation-mq-large {
+  font-family: "/only screen and (min-width:64.0625em)/";
+  width: 64.0625em; }
+
+meta.foundation-mq-large-only {
+  font-family: "/only screen and (min-width:64.0625em) and (max-width:90em)/";
+  width: 64.0625em; }
+
+meta.foundation-mq-xlarge {
+  font-family: "/only screen and (min-width:90.0625em)/";
+  width: 90.0625em; }
+
+meta.foundation-mq-xlarge-only {
+  font-family: "/only screen and (min-width:90.0625em) and (max-width:120em)/";
+  width: 90.0625em; }
+
+meta.foundation-mq-xxlarge {
+  font-family: "/only screen and (min-width:120.0625em)/";
+  width: 120.0625em; }
+
+meta.foundation-data-attribute-namespace {
+  font-family: false; }
+
+html, body {
+  height: 100%; }
+
+*,
+*:before,
+*:after {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box; }
+
+html,
+body {
+  font-size: 100%; }
+
+body {
+  background: #fff;
+  color: #222;
+  cursor: auto;
+  font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1.5;
+  margin: 0;
+  padding: 0;
+  position: relative; }
+
+a:hover {
+  cursor: pointer; }
+
+img {
+  max-width: 100%;
+  height: auto; }
+
+img {
+  -ms-interpolation-mode: bicubic; }
+
+#map_canvas img,
+#map_canvas embed,
+#map_canvas object,
+.map_canvas img,
+.map_canvas embed,
+.map_canvas object,
+.mqa-display img,
+.mqa-display embed,
+.mqa-display object {
+  max-width: none !important; }
+
+.left {
+  float: left !important; }
+
+.right {
+  float: right !important; }
+
+.clearfix:before, .clearfix:after {
+  content: " ";
+  display: table; }
+.clearfix:after {
+  clear: both; }
+
+.hide {
+  display: none; }
+
+.invisible {
+  visibility: hidden; }
+
+.antialiased {
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale; }
+
+img {
+  display: inline-block;
+  vertical-align: middle; }
+
+textarea {
+  height: auto;
+  min-height: 50px; }
+
+select {
+  width: 100%; }
+
+.row {
+  margin: 0 auto;
+  max-width: 62.5rem;
+  width: 100%; }
+  .row:before, .row:after {
+    content: " ";
+    display: table; }
+  .row:after {
+    clear: both; }
+  .row.collapse > .column,
+  .row.collapse > .columns {
+    padding-left: 0;
+    padding-right: 0; }
+  .row.collapse .row {
+    margin-left: 0;
+    margin-right: 0; }
+  .row .row {
+    margin: 0 -0.9375rem;
+    max-width: none;
+    width: auto; }
+    .row .row:before, .row .row:after {
+      content: " ";
+      display: table; }
+    .row .row:after {
+      clear: both; }
+    .row .row.collapse {
+      margin: 0;
+      max-width: none;
+      width: auto; }
+      .row .row.collapse:before, .row .row.collapse:after {
+        content: " ";
+        display: table; }
+      .row .row.collapse:after {
+        clear: both; }
+
+.column,
+.columns {
+  padding-left: 0.9375rem;
+  padding-right: 0.9375rem;
+  width: 100%;
+  float: left; }
+
+.column + .column:last-child,
+.columns + .column:last-child, .column +
+.columns:last-child,
+.columns +
+.columns:last-child {
+  float: right; }
+.column + .column.end,
+.columns + .column.end, .column +
+.columns.end,
+.columns +
+.columns.end {
+  float: left; }
+
+@media only screen {
+  .small-push-0 {
+    position: relative;
+    left: 0;
+    right: auto; }
+
+  .small-pull-0 {
+    position: relative;
+    right: 0;
+    left: auto; }
+
+  .small-push-1 {
+    position: relative;
+    left: 8.33333%;
+    right: auto; }
+
+  .small-pull-1 {
+    position: relative;
+    right: 8.33333%;
+    left: auto; }
+
+  .small-push-2 {
+    position: relative;
+    left: 16.66667%;
+    right: auto; }
+
+  .small-pull-2 {
+    position: relative;
+    right: 16.66667%;
+    left: auto; }
+
+  .small-push-3 {
+    position: relative;
+    left: 25%;
+    right: auto; }
+
+  .small-pull-3 {
+    position: relative;
+    right: 25%;
+    left: auto; }
+
+  .small-push-4 {
+    position: relative;
+    left: 33.33333%;
+    right: auto; }
+
+  .small-pull-4 {
+    position: relative;
+    right: 33.33333%;
+    left: auto; }
+
+  .small-push-5 {
+    position: relative;
+    left: 41.66667%;
+    right: auto; }
+
+  .small-pull-5 {
+    position: relative;
+    right: 41.66667%;
+    left: auto; }
+
+  .small-push-6 {
+    position: relative;
+    left: 50%;
+    right: auto; }
+
+  .small-pull-6 {
+    position: relative;
+    right: 50%;
+    left: auto; }
+
+  .small-push-7 {
+    position: relative;
+    left: 58.33333%;
+    right: auto; }
+
+  .small-pull-7 {
+    position: relative;
+    right: 58.33333%;
+    left: auto; }
+
+  .small-push-8 {
+    position: relative;
+    left: 66.66667%;
+    right: auto; }
+
+  .small-pull-8 {
+    position: relative;
+    right: 66.66667%;
+    left: auto; }
+
+  .small-push-9 {
+    position: relative;
+    left: 75%;
+    right: auto; }
+
+  .small-pull-9 {
+    position: relative;
+    right: 75%;
+    left: auto; }
+
+  .small-push-10 {
+    position: relative;
+    left: 83.33333%;
+    right: auto; }
+
+  .small-pull-10 {
+    position: relative;
+    right: 83.33333%;
+    left: auto; }
+
+  .small-push-11 {
+    position: relative;
+    left: 91.66667%;
+    right: auto; }
+
+  .small-pull-11 {
+    position: relative;
+    right: 91.66667%;
+    left: auto; }
+
+  .column,
+  .columns {
+    position: relative;
+    padding-left: 0.9375rem;
+    padding-right: 0.9375rem;
+    float: left; }
+
+  .small-1 {
+    width: 8.33333%; }
+
+  .small-2 {
+    width: 16.66667%; }
+
+  .small-3 {
+    width: 25%; }
+
+  .small-4 {
+    width: 33.33333%; }
+
+  .small-5 {
+    width: 41.66667%; }
+
+  .small-6 {
+    width: 50%; }
+
+  .small-7 {
+    width: 58.33333%; }
+
+  .small-8 {
+    width: 66.66667%; }
+
+  .small-9 {
+    width: 75%; }
+
+  .small-10 {
+    width: 83.33333%; }
+
+  .small-11 {
+    width: 91.66667%; }
+
+  .small-12 {
+    width: 100%; }
+
+  .small-offset-0 {
+    margin-left: 0 !important; }
+
+  .small-offset-1 {
+    margin-left: 8.33333% !important; }
+
+  .small-offset-2 {
+    margin-left: 16.66667% !important; }
+
+  .small-offset-3 {
+    margin-left: 25% !important; }
+
+  .small-offset-4 {
+    margin-left: 33.33333% !important; }
+
+  .small-offset-5 {
+    margin-left: 41.66667% !important; }
+
+  .small-offset-6 {
+    margin-left: 50% !important; }
+
+  .small-offset-7 {
+    margin-left: 58.33333% !important; }
+
+  .small-offset-8 {
+    margin-left: 66.66667% !important; }
+
+  .small-offset-9 {
+    margin-left: 75% !important; }
+
+  .small-offset-10 {
+    margin-left: 83.33333% !important; }
+
+  .small-offset-11 {
+    margin-left: 91.66667% !important; }
+
+  .small-reset-order {
+    float: left;
+    left: auto;
+    margin-left: 0;
+    margin-right: 0;
+    right: auto; }
+
+  .column.small-centered,
+  .columns.small-centered {
+    margin-left: auto;
+    margin-right: auto;
+    float: none; }
+
+  .column.small-uncentered,
+  .columns.small-uncentered {
+    float: left;
+    margin-left: 0;
+    margin-right: 0; }
+
+  .column.small-centered:last-child,
+  .columns.small-centered:last-child {
+    float: none; }
+
+  .column.small-uncentered:last-child,
+  .columns.small-uncentered:last-child {
+    float: left; }
+
+  .column.small-uncentered.opposite,
+  .columns.small-uncentered.opposite {
+    float: right; }
+
+  .row.small-collapse > .column,
+  .row.small-collapse > .columns {
+    padding-left: 0;
+    padding-right: 0; }
+  .row.small-collapse .row {
+    margin-left: 0;
+    margin-right: 0; }
+  .row.small-uncollapse > .column,
+  .row.small-uncollapse > .columns {
+    padding-left: 0.9375rem;
+    padding-right: 0.9375rem;
+    float: left; } }
+@media only screen and (min-width: 40.0625em) {
+  .medium-push-0 {
+    position: relative;
+    left: 0;
+    right: auto; }
+
+  .medium-pull-0 {
+    position: relative;
+    right: 0;
+    left: auto; }
+
+  .medium-push-1 {
+    position: relative;
+    left: 8.33333%;
+    right: auto; }
+
+  .medium-pull-1 {
+    position: relative;
+    right: 8.33333%;
+    left: auto; }
+
+  .medium-push-2 {
+    position: relative;
+    left: 16.66667%;
+    right: auto; }
+
+  .medium-pull-2 {
+    position: relative;
+    right: 16.66667%;
+    left: auto; }
+
+  .medium-push-3 {
+    position: relative;
+    left: 25%;
+    right: auto; }
+
+  .medium-pull-3 {
+    position: relative;
+    right: 25%;
+    left: auto; }
+
+  .medium-push-4 {
+    position: relative;
+    left: 33.33333%;
+    right: auto; }
+
+  .medium-pull-4 {
+    position: relative;
+    right: 33.33333%;
+    left: auto; }
+
+  .medium-push-5 {
+    position: relative;
+    left: 41.66667%;
+    right: auto; }
+
+  .medium-pull-5 {
+    position: relative;
+    right: 41.66667%;
+    left: auto; }
+
+  .medium-push-6 {
+    position: relative;
+    left: 50%;
+    right: auto; }
+
+  .medium-pull-6 {
+    position: relative;
+    right: 50%;
+    left: auto; }
+
+  .medium-push-7 {
+    position: relative;
+    left: 58.33333%;
+    right: auto; }
+
+  .medium-pull-7 {
+    position: relative;
+    right: 58.33333%;
+    left: auto; }
+
+  .medium-push-8 {
+    position: relative;
+    left: 66.66667%;
+    right: auto; }
+
+  .medium-pull-8 {
+    position: relative;
+    right: 66.66667%;
+    left: auto; }
+
+  .medium-push-9 {
+    position: relative;
+    left: 75%;
+    right: auto; }
+
+  .medium-pull-9 {
+    position: relative;
+    right: 75%;
+    left: auto; }
+
+  .medium-push-10 {
+    position: relative;
+    left: 83.33333%;
+    right: auto; }
+
+  .medium-pull-10 {
+    position: relative;
+    right: 83.33333%;
+    left: auto; }
+
+  .medium-push-11 {
+    position: relative;
+    left: 91.66667%;
+    right: auto; }
+
+  .medium-pull-11 {
+    position: relative;
+    right: 91.66667%;
+    left: auto; }
+
+  .column,
+  .columns {
+    position: relative;
+    padding-left: 0.9375rem;
+    padding-right: 0.9375rem;
+    float: left; }
+
+  .medium-1 {
+    width: 8.33333%; }
+
+  .medium-2 {
+    width: 16.66667%; }
+
+  .medium-3 {
+    width: 25%; }
+
+  .medium-4 {
+    width: 33.33333%; }
+
+  .medium-5 {
+    width: 41.66667%; }
+
+  .medium-6 {
+    width: 50%; }
+
+  .medium-7 {
+    width: 58.33333%; }
+
+  .medium-8 {
+    width: 66.66667%; }
+
+  .medium-9 {
+    width: 75%; }
+
+  .medium-10 {
+    width: 83.33333%; }
+
+  .medium-11 {
+    width: 91.66667%; }
+
+  .medium-12 {
+    width: 100%; }
+
+  .medium-offset-0 {
+    margin-left: 0 !important; }
+
+  .medium-offset-1 {
+    margin-left: 8.33333% !important; }
+
+  .medium-offset-2 {
+    margin-left: 16.66667% !important; }
+
+  .medium-offset-3 {
+    margin-left: 25% !important; }
+
+  .medium-offset-4 {
+    margin-left: 33.33333% !important; }
+
+  .medium-offset-5 {
+    margin-left: 41.66667% !important; }
+
+  .medium-offset-6 {
+    margin-left: 50% !important; }
+
+  .medium-offset-7 {
+    margin-left: 58.33333% !important; }
+
+  .medium-offset-8 {
+    margin-left: 66.66667% !important; }
+
+  .medium-offset-9 {
+    margin-left: 75% !important; }
+
+  .medium-offset-10 {
+    margin-left: 83.33333% !important; }
+
+  .medium-offset-11 {
+    margin-left: 91.66667% !important; }
+
+  .medium-reset-order {
+    float: left;
+    left: auto;
+    margin-left: 0;
+    margin-right: 0;
+    right: auto; }
+
+  .column.medium-centered,
+  .columns.medium-centered {
+    margin-left: auto;
+    margin-right: auto;
+    float: none; }
+
+  .column.medium-uncentered,
+  .columns.medium-uncentered {
+    float: left;
+    margin-left: 0;
+    margin-right: 0; }
+
+  .column.medium-centered:last-child,
+  .columns.medium-centered:last-child {
+    float: none; }
+
+  .column.medium-uncentered:last-child,
+  .columns.medium-uncentered:last-child {
+    float: left; }
+
+  .column.medium-uncentered.opposite,
+  .columns.medium-uncentered.opposite {
+    float: right; }
+
+  .row.medium-collapse > .column,
+  .row.medium-collapse > .columns {
+    padding-left: 0;
+    padding-right: 0; }
+  .row.medium-collapse .row {
+    margin-left: 0;
+    margin-right: 0; }
+  .row.medium-uncollapse > .column,
+  .row.medium-uncollapse > .columns {
+    padding-left: 0.9375rem;
+    padding-right: 0.9375rem;
+    float: left; }
+
+  .push-0 {
+    position: relative;
+    left: 0;
+    right: auto; }
+
+  .pull-0 {
+    position: relative;
+    right: 0;
+    left: auto; }
+
+  .push-1 {
+    position: relative;
+    left: 8.33333%;
+    right: auto; }
+
+  .pull-1 {
+    position: relative;
+    right: 8.33333%;
+    left: auto; }
+
+  .push-2 {
+    position: relative;
+    left: 16.66667%;
+    right: auto; }
+
+  .pull-2 {
+    position: relative;
+    right: 16.66667%;
+    left: auto; }
+
+  .push-3 {
+    position: relative;
+    left: 25%;
+    right: auto; }
+
+  .pull-3 {
+    position: relative;
+    right: 25%;
+    left: auto; }
+
+  .push-4 {
+    position: relative;
+    left: 33.33333%;
+    right: auto; }
+
+  .pull-4 {
+    position: relative;
+    right: 33.33333%;
+    left: auto; }
+
+  .push-5 {
+    position: relative;
+    left: 41.66667%;
+    right: auto; }
+
+  .pull-5 {
+    position: relative;
+    right: 41.66667%;
+    left: auto; }
+
+  .push-6 {
+    position: relative;
+    left: 50%;
+    right: auto; }
+
+  .pull-6 {
+    position: relative;
+    right: 50%;
+    left: auto; }
+
+  .push-7 {
+    position: relative;
+    left: 58.33333%;
+    right: auto; }
+
+  .pull-7 {
+    position: relative;
+    right: 58.33333%;
+    left: auto; }
+
+  .push-8 {
+    position: relative;
+    left: 66.66667%;
+    right: auto; }
+
+  .pull-8 {
+    position: relative;
+    right: 66.66667%;
+    left: auto; }
+
+  .push-9 {
+    position: relative;
+    left: 75%;
+    right: auto; }
+
+  .pull-9 {
+    position: relative;
+    right: 75%;
+    left: auto; }
+
+  .push-10 {
+    position: relative;
+    left: 83.33333%;
+    right: auto; }
+
+  .pull-10 {
+    position: relative;
+    right: 83.33333%;
+    left: auto; }
+
+  .push-11 {
+    position: relative;
+    left: 91.66667%;
+    right: auto; }
+
+  .pull-11 {
+    position: relative;
+    right: 91.66667%;
+    left: auto; } }
+@media only screen and (min-width: 64.0625em) {
+  .large-push-0 {
+    position: relative;
+    left: 0;
+    right: auto; }
+
+  .large-pull-0 {
+    position: relative;
+    right: 0;
+    left: auto; }
+
+  .large-push-1 {
+    position: relative;
+    left: 8.33333%;
+    right: auto; }
+
+  .large-pull-1 {
+    position: relative;
+    right: 8.33333%;
+    left: auto; }
+
+  .large-push-2 {
+    position: relative;
+    left: 16.66667%;
+    right: auto; }
+
+  .large-pull-2 {
+    position: relative;
+    right: 16.66667%;
+    left: auto; }
+
+  .large-push-3 {
+    position: relative;
+    left: 25%;
+    right: auto; }
+
+  .large-pull-3 {
+    position: relative;
+    right: 25%;
+    left: auto; }
+
+  .large-push-4 {
+    position: relative;
+    left: 33.33333%;
+    right: auto; }
+
+  .large-pull-4 {
+    position: relative;
+    right: 33.33333%;
+    left: auto; }
+
+  .large-push-5 {
+    position: relative;
+    left: 41.66667%;
+    right: auto; }
+
+  .large-pull-5 {
+    position: relative;
+    right: 41.66667%;
+    left: auto; }
+
+  .large-push-6 {
+    position: relative;
+    left: 50%;
+    right: auto; }
+
+  .large-pull-6 {
+    position: relative;
+    right: 50%;
+    left: auto; }
+
+  .large-push-7 {
+    position: relative;
+    left: 58.33333%;
+    right: auto; }
+
+  .large-pull-7 {
+    position: relative;
+    right: 58.33333%;
+    left: auto; }
+
+  .large-push-8 {
+    position: relative;
+    left: 66.66667%;
+    right: auto; }
+
+  .large-pull-8 {
+    position: relative;
+    right: 66.66667%;
+    left: auto; }
+
+  .large-push-9 {
+    position: relative;
+    left: 75%;
+    right: auto; }
+
+  .large-pull-9 {
+    position: relative;
+    right: 75%;
+    left: auto; }
+
+  .large-push-10 {
+    position: relative;
+    left: 83.33333%;
+    right: auto; }
+
+  .large-pull-10 {
+    position: relative;
+    right: 83.33333%;
+    left: auto; }
+
+  .large-push-11 {
+    position: relative;
+    left: 91.66667%;
+    right: auto; }
+
+  .large-pull-11 {
+    position: relative;
+    right: 91.66667%;
+    left: auto; }
+
+  .column,
+  .columns {
+    position: relative;
+    padding-left: 0.9375rem;
+    padding-right: 0.9375rem;
+    float: left; }
+
+  .large-1 {
+    width: 8.33333%; }
+
+  .large-2 {
+    width: 16.66667%; }
+
+  .large-3 {
+    width: 25%; }
+
+  .large-4 {
+    width: 33.33333%; }
+
+  .large-5 {
+    width: 41.66667%; }
+
+  .large-6 {
+    width: 50%; }
+
+  .large-7 {
+    width: 58.33333%; }
+
+  .large-8 {
+    width: 66.66667%; }
+
+  .large-9 {
+    width: 75%; }
+
+  .large-10 {
+    width: 83.33333%; }
+
+  .large-11 {
+    width: 91.66667%; }
+
+  .large-12 {
+    width: 100%; }
+
+  .large-offset-0 {
+    margin-left: 0 !important; }
+
+  .large-offset-1 {
+    margin-left: 8.33333% !important; }
+
+  .large-offset-2 {
+    margin-left: 16.66667% !important; }
+
+  .large-offset-3 {
+    margin-left: 25% !important; }
+
+  .large-offset-4 {
+    margin-left: 33.33333% !important; }
+
+  .large-offset-5 {
+    margin-left: 41.66667% !important; }
+
+  .large-offset-6 {
+    margin-left: 50% !important; }
+
+  .large-offset-7 {
+    margin-left: 58.33333% !important; }
+
+  .large-offset-8 {
+    margin-left: 66.66667% !important; }
+
+  .large-offset-9 {
+    margin-left: 75% !important; }
+
+  .large-offset-10 {
+    margin-left: 83.33333% !important; }
+
+  .large-offset-11 {
+    margin-left: 91.66667% !important; }
+
+  .large-reset-order {
+    float: left;
+    left: auto;
+    margin-left: 0;
+    margin-right: 0;
+    right: auto; }
+
+  .column.large-centered,
+  .columns.large-centered {
+    margin-left: auto;
+    margin-right: auto;
+    float: none; }
+
+  .column.large-uncentered,
+  .columns.large-uncentered {
+    float: left;
+    margin-left: 0;
+    margin-right: 0; }
+
+  .column.large-centered:last-child,
+  .columns.large-centered:last-child {
+    float: none; }
+
+  .column.large-uncentered:last-child,
+  .columns.large-uncentered:last-child {
+    float: left; }
+
+  .column.large-uncentered.opposite,
+  .columns.large-uncentered.opposite {
+    float: right; }
+
+  .row.large-collapse > .column,
+  .row.large-collapse > .columns {
+    padding-left: 0;
+    padding-right: 0; }
+  .row.large-collapse .row {
+    margin-left: 0;
+    margin-right: 0; }
+  .row.large-uncollapse > .column,
+  .row.large-uncollapse > .columns {
+    padding-left: 0.9375rem;
+    padding-right: 0.9375rem;
+    float: left; }
+
+  .push-0 {
+    position: relative;
+    left: 0;
+    right: auto; }
+
+  .pull-0 {
+    position: relative;
+    right: 0;
+    left: auto; }
+
+  .push-1 {
+    position: relative;
+    left: 8.33333%;
+    right: auto; }
+
+  .pull-1 {
+    position: relative;
+    right: 8.33333%;
+    left: auto; }
+
+  .push-2 {
+    position: relative;
+    left: 16.66667%;
+    right: auto; }
+
+  .pull-2 {
+    position: relative;
+    right: 16.66667%;
+    left: auto; }
+
+  .push-3 {
+    position: relative;
+    left: 25%;
+    right: auto; }
+
+  .pull-3 {
+    position: relative;
+    right: 25%;
+    left: auto; }
+
+  .push-4 {
+    position: relative;
+    left: 33.33333%;
+    right: auto; }
+
+  .pull-4 {
+    position: relative;
+    right: 33.33333%;
+    left: auto; }
+
+  .push-5 {
+    position: relative;
+    left: 41.66667%;
+    right: auto; }
+
+  .pull-5 {
+    position: relative;
+    right: 41.66667%;
+    left: auto; }
+
+  .push-6 {
+    position: relative;
+    left: 50%;
+    right: auto; }
+
+  .pull-6 {
+    position: relative;
+    right: 50%;
+    left: auto; }
+
+  .push-7 {
+    position: relative;
+    left: 58.33333%;
+    right: auto; }
+
+  .pull-7 {
+    position: relative;
+    right: 58.33333%;
+    left: auto; }
+
+  .push-8 {
+    position: relative;
+    left: 66.66667%;
+    right: auto; }
+
+  .pull-8 {
+    position: relative;
+    right: 66.66667%;
+    left: auto; }
+
+  .push-9 {
+    position: relative;
+    left: 75%;
+    right: auto; }
+
+  .pull-9 {
+    position: relative;
+    right: 75%;
+    left: auto; }
+
+  .push-10 {
+    position: relative;
+    left: 83.33333%;
+    right: auto; }
+
+  .pull-10 {
+    position: relative;
+    right: 83.33333%;
+    left: auto; }
+
+  .push-11 {
+    position: relative;
+    left: 91.66667%;
+    right: auto; }
+
+  .pull-11 {
+    position: relative;
+    right: 91.66667%;
+    left: auto; } }
+button, .button {
+  -webkit-appearance: none;
+  -moz-appearance: none;
+  border-radius: 0;
+  border-style: solid;
+  border-width: 0;
+  cursor: pointer;
+  font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+  font-weight: normal;
+  line-height: normal;
+  margin: 0 0 1.25rem;
+  position: relative;
+  text-align: center;
+  text-decoration: none;
+  display: inline-block;
+  padding: 1rem 2rem 1.0625rem 2rem;
+  font-size: 1rem;
+  background-color: #008CBA;
+  border-color: #007095;
+  color: #FFFFFF;
+  transition: background-color 300ms ease-out; }
+  button:hover, button:focus, .button:hover, .button:focus {
+    background-color: #007095; }
+  button:hover, button:focus, .button:hover, .button:focus {
+    color: #FFFFFF; }
+  button.secondary, .button.secondary {
+    background-color: #e7e7e7;
+    border-color: #b9b9b9;
+    color: #333333; }
+    button.secondary:hover, button.secondary:focus, .button.secondary:hover, .button.secondary:focus {
+      background-color: #b9b9b9; }
+    button.secondary:hover, button.secondary:focus, .button.secondary:hover, .button.secondary:focus {
+      color: #333333; }
+  button.success, .button.success {
+    background-color: #43AC6A;
+    border-color: #368a55;
+    color: #FFFFFF; }
+    button.success:hover, button.success:focus, .button.success:hover, .button.success:focus {
+      background-color: #368a55; }
+    button.success:hover, button.success:focus, .button.success:hover, .button.success:focus {
+      color: #FFFFFF; }
+  button.alert, .button.alert {
+    background-color: #f04124;
+    border-color: #cf2a0e;
+    color: #FFFFFF; }
+    button.alert:hover, button.alert:focus, .button.alert:hover, .button.alert:focus {
+      background-color: #cf2a0e; }
+    button.alert:hover, button.alert:focus, .button.alert:hover, .button.alert:focus {
+      color: #FFFFFF; }
+  button.warning, .button.warning {
+    background-color: #f08a24;
+    border-color: #cf6e0e;
+    color: #FFFFFF; }
+    button.warning:hover, button.warning:focus, .button.warning:hover, .button.warning:focus {
+      background-color: #cf6e0e; }
+    button.warning:hover, button.warning:focus, .button.warning:hover, .button.warning:focus {
+      color: #FFFFFF; }
+  button.info, .button.info {
+    background-color: #a0d3e8;
+    border-color: #61b6d9;
+    color: #333333; }
+    button.info:hover, button.info:focus, .button.info:hover, .button.info:focus {
+      background-color: #61b6d9; }
+    button.info:hover, button.info:focus, .button.info:hover, .button.info:focus {
+      color: #FFFFFF; }
+  button.large, .button.large {
+    padding: 1.125rem 2.25rem 1.1875rem 2.25rem;
+    font-size: 1.25rem; }
+  button.small, .button.small {
+    padding: 0.875rem 1.75rem 0.9375rem 1.75rem;
+    font-size: 0.8125rem; }
+  button.tiny, .button.tiny {
+    padding: 0.625rem 1.25rem 0.6875rem 1.25rem;
+    font-size: 0.6875rem; }
+  button.expand, .button.expand {
+    padding: 1rem 2rem 1.0625rem 2rem;
+    font-size: 1rem;
+    padding-bottom: 1.0625rem;
+    padding-top: 1rem;
+    padding-left: 1rem;
+    padding-right: 1rem;
+    width: 100%; }
+  button.left-align, .button.left-align {
+    text-align: left;
+    text-indent: 0.75rem; }
+  button.right-align, .button.right-align {
+    text-align: right;
+    padding-right: 0.75rem; }
+  button.radius, .button.radius {
+    border-radius: 3px; }
+  button.round, .button.round {
+    border-radius: 1000px; }
+  button.disabled, button[disabled], .button.disabled, .button[disabled] {
+    background-color: #008CBA;
+    border-color: #007095;
+    color: #FFFFFF;
+    box-shadow: none;
+    cursor: default;
+    opacity: 0.7; }
+    button.disabled:hover, button.disabled:focus, button[disabled]:hover, button[disabled]:focus, .button.disabled:hover, .button.disabled:focus, .button[disabled]:hover, .button[disabled]:focus {
+      background-color: #007095; }
+    button.disabled:hover, button.disabled:focus, button[disabled]:hover, button[disabled]:focus, .button.disabled:hover, .button.disabled:focus, .button[disabled]:hover, .button[disabled]:focus {
+      color: #FFFFFF; }
+    button.disabled:hover, button.disabled:focus, button[disabled]:hover, button[disabled]:focus, .button.disabled:hover, .button.disabled:focus, .button[disabled]:hover, .button[disabled]:focus {
+      background-color: #008CBA; }
+    button.disabled.secondary, button[disabled].secondary, .button.disabled.secondary, .button[disabled].secondary {
+      background-color: #e7e7e7;
+      border-color: #b9b9b9;
+      color: #333333;
+      box-shadow: none;
+      cursor: default;
+      opacity: 0.7; }
+      button.disabled.secondary:hover, button.disabled.secondary:focus, button[disabled].secondary:hover, button[disabled].secondary:focus, .button.disabled.secondary:hover, .button.disabled.secondary:focus, .button[disabled].secondary:hover, .button[disabled].secondary:focus {
+        background-color: #b9b9b9; }
+      button.disabled.secondary:hover, button.disabled.secondary:focus, button[disabled].secondary:hover, button[disabled].secondary:focus, .button.disabled.secondary:hover, .button.disabled.secondary:focus, .button[disabled].secondary:hover, .button[disabled].secondary:focus {
+        color: #333333; }
+      button.disabled.secondary:hover, button.disabled.secondary:focus, button[disabled].secondary:hover, button[disabled].secondary:focus, .button.disabled.secondary:hover, .button.disabled.secondary:focus, .button[disabled].secondary:hover, .button[disabled].secondary:focus {
+        background-color: #e7e7e7; }
+    button.disabled.success, button[disabled].success, .button.disabled.success, .button[disabled].success {
+      background-color: #43AC6A;
+      border-color: #368a55;
+      color: #FFFFFF;
+      box-shadow: none;
+      cursor: default;
+      opacity: 0.7; }
+      button.disabled.success:hover, button.disabled.success:focus, button[disabled].success:hover, button[disabled].success:focus, .button.disabled.success:hover, .button.disabled.success:focus, .button[disabled].success:hover, .button[disabled].success:focus {
+        background-color: #368a55; }
+      button.disabled.success:hover, button.disabled.success:focus, button[disabled].success:hover, button[disabled].success:focus, .button.disabled.success:hover, .button.disabled.success:focus, .button[disabled].success:hover, .button[disabled].success:focus {
+        color: #FFFFFF; }
+      button.disabled.success:hover, button.disabled.success:focus, button[disabled].success:hover, button[disabled].success:focus, .button.disabled.success:hover, .button.disabled.success:focus, .button[disabled].success:hover, .button[disabled].success:focus {
+        background-color: #43AC6A; }
+    button.disabled.alert, button[disabled].alert, .button.disabled.alert, .button[disabled].alert {
+      background-color: #f04124;
+      border-color: #cf2a0e;
+      color: #FFFFFF;
+      box-shadow: none;
+      cursor: default;
+      opacity: 0.7; }
+      button.disabled.alert:hover, button.disabled.alert:focus, button[disabled].alert:hover, button[disabled].alert:focus, .button.disabled.alert:hover, .button.disabled.alert:focus, .button[disabled].alert:hover, .button[disabled].alert:focus {
+        background-color: #cf2a0e; }
+      button.disabled.alert:hover, button.disabled.alert:focus, button[disabled].alert:hover, button[disabled].alert:focus, .button.disabled.alert:hover, .button.disabled.alert:focus, .button[disabled].alert:hover, .button[disabled].alert:focus {
+        color: #FFFFFF; }
+      button.disabled.alert:hover, button.disabled.alert:focus, button[disabled].alert:hover, button[disabled].alert:focus, .button.disabled.alert:hover, .button.disabled.alert:focus, .button[disabled].alert:hover, .button[disabled].alert:focus {
+        background-color: #f04124; }
+    button.disabled.warning, button[disabled].warning, .button.disabled.warning, .button[disabled].warning {
+      background-color: #f08a24;
+      border-color: #cf6e0e;
+      color: #FFFFFF;
+      box-shadow: none;
+      cursor: default;
+      opacity: 0.7; }
+      button.disabled.warning:hover, button.disabled.warning:focus, button[disabled].warning:hover, button[disabled].warning:focus, .button.disabled.warning:hover, .button.disabled.warning:focus, .button[disabled].warning:hover, .button[disabled].warning:focus {
+        background-color: #cf6e0e; }
+      button.disabled.warning:hover, button.disabled.warning:focus, button[disabled].warning:hover, button[disabled].warning:focus, .button.disabled.warning:hover, .button.disabled.warning:focus, .button[disabled].warning:hover, .button[disabled].warning:focus {
+        color: #FFFFFF; }
+      button.disabled.warning:hover, button.disabled.warning:focus, button[disabled].warning:hover, button[disabled].warning:focus, .button.disabled.warning:hover, .button.disabled.warning:focus, .button[disabled].warning:hover, .button[disabled].warning:focus {
+        background-color: #f08a24; }
+    button.disabled.info, button[disabled].info, .button.disabled.info, .button[disabled].info {
+      background-color: #a0d3e8;
+      border-color: #61b6d9;
+      color: #333333;
+      box-shadow: none;
+      cursor: default;
+      opacity: 0.7; }
+      button.disabled.info:hover, button.disabled.info:focus, button[disabled].info:hover, button[disabled].info:focus, .button.disabled.info:hover, .button.disabled.info:focus, .button[disabled].info:hover, .button[disabled].info:focus {
+        background-color: #61b6d9; }
+      button.disabled.info:hover, button.disabled.info:focus, button[disabled].info:hover, button[disabled].info:focus, .button.disabled.info:hover, .button.disabled.info:focus, .button[disabled].info:hover, .button[disabled].info:focus {
+        color: #FFFFFF; }
+      button.disabled.info:hover, button.disabled.info:focus, button[disabled].info:hover, button[disabled].info:focus, .button.disabled.info:hover, .button.disabled.info:focus, .button[disabled].info:hover, .button[disabled].info:focus {
+        background-color: #a0d3e8; }
+
+button::-moz-focus-inner {
+  border: 0;
+  padding: 0; }
+
+@media only screen and (min-width: 40.0625em) {
+  button, .button {
+    display: inline-block; } }
+/* Standard Forms */
+form {
+  margin: 0 0 1rem; }
+
+/* Using forms within rows, we need to set some defaults */
+form .row .row {
+  margin: 0 -0.5rem; }
+  form .row .row .column,
+  form .row .row .columns {
+    padding: 0 0.5rem; }
+  form .row .row.collapse {
+    margin: 0; }
+    form .row .row.collapse .column,
+    form .row .row.collapse .columns {
+      padding: 0; }
+    form .row .row.collapse input {
+      -webkit-border-bottom-right-radius: 0;
+      -webkit-border-top-right-radius: 0;
+      border-bottom-right-radius: 0;
+      border-top-right-radius: 0; }
+form .row input.column,
+form .row input.columns,
+form .row textarea.column,
+form .row textarea.columns {
+  padding-left: 0.5rem; }
+
+/* Label Styles */
+label {
+  color: #4d4d4d;
+  cursor: pointer;
+  display: block;
+  font-size: 0.875rem;
+  font-weight: normal;
+  line-height: 1.5;
+  margin-bottom: 0;
+  /* Styles for required inputs */ }
+  label.right {
+    float: none !important;
+    text-align: right; }
+  label.inline {
+    margin: 0 0 1rem 0;
+    padding: 0.5625rem 0; }
+  label small {
+    text-transform: capitalize;
+    color: #676767; }
+
+/* Attach elements to the beginning or end of an input */
+.prefix,
+.postfix {
+  border-style: solid;
+  border-width: 1px;
+  display: block;
+  font-size: 0.875rem;
+  height: 2.3125rem;
+  line-height: 2.3125rem;
+  overflow: visible;
+  padding-bottom: 0;
+  padding-top: 0;
+  position: relative;
+  text-align: center;
+  width: 100%;
+  z-index: 2; }
+
+/* Adjust padding, alignment and radius if pre/post element is a button */
+.postfix.button {
+  border: none;
+  padding-left: 0;
+  padding-right: 0;
+  padding-bottom: 0;
+  padding-top: 0;
+  text-align: center; }
+
+.prefix.button {
+  border: none;
+  padding-left: 0;
+  padding-right: 0;
+  padding-bottom: 0;
+  padding-top: 0;
+  text-align: center; }
+
+.prefix.button.radius {
+  border-radius: 0;
+  -webkit-border-bottom-left-radius: 3px;
+  -webkit-border-top-left-radius: 3px;
+  border-bottom-left-radius: 3px;
+  border-top-left-radius: 3px; }
+
+.postfix.button.radius {
+  border-radius: 0;
+  -webkit-border-bottom-right-radius: 3px;
+  -webkit-border-top-right-radius: 3px;
+  border-bottom-right-radius: 3px;
+  border-top-right-radius: 3px; }
+
+.prefix.button.round {
+  border-radius: 0;
+  -webkit-border-bottom-left-radius: 1000px;
+  -webkit-border-top-left-radius: 1000px;
+  border-bottom-left-radius: 1000px;
+  border-top-left-radius: 1000px; }
+
+.postfix.button.round {
+  border-radius: 0;
+  -webkit-border-bottom-right-radius: 1000px;
+  -webkit-border-top-right-radius: 1000px;
+  border-bottom-right-radius: 1000px;
+  border-top-right-radius: 1000px; }
+
+/* Separate prefix and postfix styles when on span or label so buttons keep their own */
+span.prefix, label.prefix {
+  background: #f2f2f2;
+  border-right: none;
+  color: #333333;
+  border-color: #cccccc; }
+
+span.postfix, label.postfix {
+  background: #f2f2f2;
+  border-left: none;
+  color: #333333;
+  border-color: #cccccc; }
+
+/* We use this to get basic styling on all basic form elements */
+input:not([type]), input[type="text"], input[type="password"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="month"], input[type="week"], input[type="email"], input[type="number"], input[type="search"], input[type="tel"], input[type="time"], input[type="url"], input[type="color"], textarea {
+  -webkit-appearance: none;
+  -moz-appearance: none;
+  border-radius: 0;
+  background-color: #FFFFFF;
+  border-style: solid;
+  border-width: 1px;
+  border-color: #cccccc;
+  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+  color: rgba(0, 0, 0, 0.75);
+  display: block;
+  font-family: inherit;
+  font-size: 0.875rem;
+  height: 2.3125rem;
+  margin: 0 0 1rem 0;
+  padding: 0.5rem;
+  width: 100%;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  -webkit-transition: border-color 0.15s linear, background 0.15s linear;
+  -moz-transition: border-color 0.15s linear, background 0.15s linear;
+  -ms-transition: border-color 0.15s linear, background 0.15s linear;
+  -o-transition: border-color 0.15s linear, background 0.15s linear;
+  transition: border-color 0.15s linear, background 0.15s linear; }
+  input:not([type]):focus, input[type="text"]:focus, input[type="password"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="week"]:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="time"]:focus, input[type="url"]:focus, input[type="color"]:focus, textarea:focus {
+    background: #fafafa;
+    border-color: #999999;
+    outline: none; }
+  input:not([type]):disabled, input[type="text"]:disabled, input[type="password"]:disabled, input[type="date"]:disabled, input[type="datetime"]:disabled, input[type="datetime-local"]:disabled, input[type="month"]:disabled, input[type="week"]:disabled, input[type="email"]:disabled, input[type="number"]:disabled, input[type="search"]:disabled, input[type="tel"]:disabled, input[type="time"]:disabled, input[type="url"]:disabled, input[type="color"]:disabled, textarea:disabled {
+    background-color: #DDDDDD;
+    cursor: default; }
+  input:not([type])[disabled], input:not([type])[readonly], fieldset[disabled] input:not([type]), input[type="text"][disabled], input[type="text"][readonly], fieldset[disabled] input[type="text"], input[type="password"][disabled], input[type="password"][readonly], fieldset[disabled] input[type="password"], input[type="date"][disabled], input[type="date"][readonly], fieldset[disabled] input[type="date"], input[type="datetime"][disabled], input[type="datetime"][readonly], fieldset[disabled] input[type="datetime"], input[type="datetime-local"][disabled], input[type="datetime-local"][readonly], fieldset[disabled] input[type="datetime-local"], input[type="month"][disabled], input[type="month"][readonly], fieldset[disabled] input[type="month"], input[type="week"][disabled], input[type="week"][readonly], fieldset[disabled] input[type="week"], input[type="email"][disabled], input[type="email"][readonly], fieldset[disabled] input[type="email"], input[type="number"][disabled], input[type="number"][readonly], fieldset[disabled] input[type="number"], input[type="search"][disabled], input[type="search"][readonly], fieldset[disabled] input[type="search"], input[type="tel"][disabled], input[type="tel"][readonly], fieldset[disabled] input[type="tel"], input[type="time"][disabled], input[type="time"][readonly], fieldset[disabled] input[type="time"], input[type="url"][disabled], input[type="url"][readonly], fieldset[disabled] input[type="url"], input[type="color"][disabled], input[type="color"][readonly], fieldset[disabled] input[type="color"], textarea[disabled], textarea[readonly], fieldset[disabled] textarea {
+    background-color: #DDDDDD;
+    cursor: default; }
+  input:not([type]).radius, input[type="text"].radius, input[type="password"].radius, input[type="date"].radius, input[type="datetime"].radius, input[type="datetime-local"].radius, input[type="month"].radius, input[type="week"].radius, input[type="email"].radius, input[type="number"].radius, input[type="search"].radius, input[type="tel"].radius, input[type="time"].radius, input[type="url"].radius, input[type="color"].radius, textarea.radius {
+    border-radius: 3px; }
+
+form .row .prefix-radius.row.collapse input,
+form .row .prefix-radius.row.collapse textarea,
+form .row .prefix-radius.row.collapse select,
+form .row .prefix-radius.row.collapse button {
+  border-radius: 0;
+  -webkit-border-bottom-right-radius: 3px;
+  -webkit-border-top-right-radius: 3px;
+  border-bottom-right-radius: 3px;
+  border-top-right-radius: 3px; }
+form .row .prefix-radius.row.collapse .prefix {
+  border-radius: 0;
+  -webkit-border-bottom-left-radius: 3px;
+  -webkit-border-top-left-radius: 3px;
+  border-bottom-left-radius: 3px;
+  border-top-left-radius: 3px; }
+form .row .postfix-radius.row.collapse input,
+form .row .postfix-radius.row.collapse textarea,
+form .row .postfix-radius.row.collapse select,
+form .row .postfix-radius.row.collapse button {
+  border-radius: 0;
+  -webkit-border-bottom-left-radius: 3px;
+  -webkit-border-top-left-radius: 3px;
+  border-bottom-left-radius: 3px;
+  border-top-left-radius: 3px; }
+form .row .postfix-radius.row.collapse .postfix {
+  border-radius: 0;
+  -webkit-border-bottom-right-radius: 3px;
+  -webkit-border-top-right-radius: 3px;
+  border-bottom-right-radius: 3px;
+  border-top-right-radius: 3px; }
+form .row .prefix-round.row.collapse input,
+form .row .prefix-round.row.collapse textarea,
+form .row .prefix-round.row.collapse select,
+form .row .prefix-round.row.collapse button {
+  border-radius: 0;
+  -webkit-border-bottom-right-radius: 1000px;
+  -webkit-border-top-right-radius: 1000px;
+  border-bottom-right-radius: 1000px;
+  border-top-right-radius: 1000px; }
+form .row .prefix-round.row.collapse .prefix {
+  border-radius: 0;
+  -webkit-border-bottom-left-radius: 1000px;
+  -webkit-border-top-left-radius: 1000px;
+  border-bottom-left-radius: 1000px;
+  border-top-left-radius: 1000px; }
+form .row .postfix-round.row.collapse input,
+form .row .postfix-round.row.collapse textarea,
+form .row .postfix-round.row.collapse select,
+form .row .postfix-round.row.collapse button {
+  border-radius: 0;
+  -webkit-border-bottom-left-radius: 1000px;
+  -webkit-border-top-left-radius: 1000px;
+  border-bottom-left-radius: 1000px;
+  border-top-left-radius: 1000px; }
+form .row .postfix-round.row.collapse .postfix {
+  border-radius: 0;
+  -webkit-border-bottom-right-radius: 1000px;
+  -webkit-border-top-right-radius: 1000px;
+  border-bottom-right-radius: 1000px;
+  border-top-right-radius: 1000px; }
+
+input[type="submit"] {
+  -webkit-appearance: none;
+  -moz-appearance: none;
+  border-radius: 0; }
+
+/* Respect enforced amount of rows for textarea */
+textarea[rows] {
+  height: auto; }
+
+/* Not allow resize out of parent */
+textarea {
+  max-width: 100%; }
+
+::-webkit-input-placeholder {
+  color: #666666; }
+
+:-moz-placeholder {
+  /* Firefox 18- */
+  color: #666666; }
+
+::-moz-placeholder {
+  /* Firefox 19+ */
+  color: #666666; }
+
+:-ms-input-placeholder {
+  color: #666666; }
+
+/* Add height value for select elements to match text input height */
+select {
+  -webkit-appearance: none !important;
+  -moz-appearance: none !important;
+  background-color: #FAFAFA;
+  border-radius: 0;
+  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeD0iMTJweCIgeT0iMHB4IiB3aWR0aD0iMjRweCIgaGVpZ2h0PSIzcHgiIHZpZXdCb3g9IjAgMCA2IDMiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDYgMyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHBvbHlnb24gcG9pbnRzPSI1Ljk5MiwwIDIuOTkyLDMgLTAuMDA4LDAgIi8+PC9zdmc+");
+  background-position: 100% center;
+  background-repeat: no-repeat;
+  border-style: solid;
+  border-width: 1px;
+  border-color: #cccccc;
+  color: rgba(0, 0, 0, 0.75);
+  font-family: inherit;
+  font-size: 0.875rem;
+  line-height: normal;
+  padding: 0.5rem;
+  border-radius: 0;
+  height: 2.3125rem; }
+  select::-ms-expand {
+    display: none; }
+  select.radius {
+    border-radius: 3px; }
+  select:focus {
+    background-color: #f3f3f3;
+    border-color: #999999; }
+  select:disabled {
+    background-color: #DDDDDD;
+    cursor: default; }
+  select[multiple] {
+    height: auto; }
+
+/* Adjust margin for form elements below */
+input[type="file"],
+input[type="checkbox"],
+input[type="radio"],
+select {
+  margin: 0 0 1rem 0; }
+
+input[type="checkbox"] + label,
+input[type="radio"] + label {
+  display: inline-block;
+  margin-left: 0.5rem;
+  margin-right: 1rem;
+  margin-bottom: 0;
+  vertical-align: baseline; }
+
+/* Normalize file input width */
+input[type="file"] {
+  width: 100%; }
+
+/* HTML5 Number spinners settings */
+/* We add basic fieldset styling */
+fieldset {
+  border: 1px solid #DDDDDD;
+  margin: 1.125rem 0;
+  padding: 1.25rem; }
+  fieldset legend {
+    font-weight: bold;
+    margin: 0;
+    margin-left: -0.1875rem;
+    padding: 0 0.1875rem; }
+
+/* Error Handling */
+[data-abide] .error small.error, [data-abide] .error span.error, [data-abide] span.error, [data-abide] small.error {
+  display: block;
+  font-size: 0.75rem;
+  font-style: italic;
+  font-weight: normal;
+  margin-bottom: 1rem;
+  margin-top: -1px;
+  padding: 0.375rem 0.5625rem 0.5625rem;
+  background: #f04124;
+  color: #FFFFFF; }
+[data-abide] span.error, [data-abide] small.error {
+  display: none; }
+
+span.error, small.error {
+  display: block;
+  font-size: 0.75rem;
+  font-style: italic;
+  font-weight: normal;
+  margin-bottom: 1rem;
+  margin-top: -1px;
+  padding: 0.375rem 0.5625rem 0.5625rem;
+  background: #f04124;
+  color: #FFFFFF; }
+
+.error input,
+.error textarea,
+.error select {
+  margin-bottom: 0; }
+.error input[type="checkbox"],
+.error input[type="radio"] {
+  margin-bottom: 1rem; }
+.error label,
+.error label.error {
+  color: #f04124; }
+.error small.error {
+  display: block;
+  font-size: 0.75rem;
+  font-style: italic;
+  font-weight: normal;
+  margin-bottom: 1rem;
+  margin-top: -1px;
+  padding: 0.375rem 0.5625rem 0.5625rem;
+  background: #f04124;
+  color: #FFFFFF; }
+.error > label > small {
+  background: transparent;
+  color: #676767;
+  display: inline;
+  font-size: 60%;
+  font-style: normal;
+  margin: 0;
+  padding: 0;
+  text-transform: capitalize; }
+.error span.error-message {
+  display: block; }
+
+input.error,
+textarea.error,
+select.error {
+  margin-bottom: 0; }
+
+label.error {
+  color: #f04124; }
+
+meta.foundation-mq-topbar {
+  font-family: "/only screen and (min-width:40.0625em)/";
+  width: 40.0625em; }
+
+/* Wrapped around .top-bar to contain to grid width */
+.contain-to-grid {
+  width: 100%;
+  background: #333333; }
+  .contain-to-grid .top-bar {
+    margin-bottom: 0; }
+
+.fixed {
+  position: fixed;
+  top: 0;
+  width: 100%;
+  z-index: 99;
+  left: 0; }
+  .fixed.expanded:not(.top-bar) {
+    height: auto;
+    max-height: 100%;
+    overflow-y: auto;
+    width: 100%; }
+    .fixed.expanded:not(.top-bar) .title-area {
+      position: fixed;
+      width: 100%;
+      z-index: 99; }
+    .fixed.expanded:not(.top-bar) .top-bar-section {
+      margin-top: 2.8125rem;
+      z-index: 98; }
+
+.top-bar {
+  background: #333333;
+  height: 2.8125rem;
+  line-height: 2.8125rem;
+  margin-bottom: 0;
+  overflow: hidden;
+  position: relative; }
+  .top-bar ul {
+    list-style: none;
+    margin-bottom: 0; }
+  .top-bar .row {
+    max-width: none; }
+  .top-bar form,
+  .top-bar input,
+  .top-bar select {
+    margin-bottom: 0; }
+  .top-bar input,
+  .top-bar select {
+    font-size: 0.75rem;
+    height: 1.75rem;
+    padding-bottom: .35rem;
+    padding-top: .35rem; }
+  .top-bar .button, .top-bar button {
+    font-size: 0.75rem;
+    margin-bottom: 0;
+    padding-bottom: 0.4125rem;
+    padding-top: 0.4125rem; }
+    @media only screen and (max-width: 40em) {
+      .top-bar .button, .top-bar button {
+        position: relative;
+        top: -1px; } }
+  .top-bar .title-area {
+    margin: 0;
+    position: relative; }
+  .top-bar .name {
+    font-size: 16px;
+    height: 2.8125rem;
+    margin: 0; }
+    .top-bar .name h1, .top-bar .name h2, .top-bar .name h3, .top-bar .name h4, .top-bar .name p, .top-bar .name span {
+      font-size: 1.0625rem;
+      line-height: 2.8125rem;
+      margin: 0; }
+      .top-bar .name h1 a, .top-bar .name h2 a, .top-bar .name h3 a, .top-bar .name h4 a, .top-bar .name p a, .top-bar .name span a {
+        color: #FFFFFF;
+        display: block;
+        font-weight: normal;
+        padding: 0 0.9375rem;
+        width: 75%; }
+  .top-bar .toggle-topbar {
+    position: absolute;
+    right: 0;
+    top: 0; }
+    .top-bar .toggle-topbar a {
+      color: #FFFFFF;
+      display: block;
+      font-size: 0.8125rem;
+      font-weight: bold;
+      height: 2.8125rem;
+      line-height: 2.8125rem;
+      padding: 0 0.9375rem;
+      position: relative;
+      text-transform: uppercase; }
+    .top-bar .toggle-topbar.menu-icon {
+      margin-top: -16px;
+      top: 50%; }
+      .top-bar .toggle-topbar.menu-icon a {
+        color: #FFFFFF;
+        height: 34px;
+        line-height: 33px;
+        padding: 0 2.5rem 0 0.9375rem;
+        position: relative; }
+        .top-bar .toggle-topbar.menu-icon a span::after {
+          content: "";
+          display: block;
+          height: 0;
+          position: absolute;
+          margin-top: -8px;
+          top: 50%;
+          right: 0.9375rem;
+          box-shadow: 0 0 0 1px #FFFFFF, 0 7px 0 1px #FFFFFF, 0 14px 0 1px #FFFFFF;
+          width: 16px; }
+        .top-bar .toggle-topbar.menu-icon a span:hover:after {
+          box-shadow: 0 0 0 1px "", 0 7px 0 1px "", 0 14px 0 1px ""; }
+  .top-bar.expanded {
+    background: transparent;
+    height: auto; }
+    .top-bar.expanded .title-area {
+      background: #333333; }
+    .top-bar.expanded .toggle-topbar a {
+      color: #888888; }
+      .top-bar.expanded .toggle-topbar a span::after {
+        box-shadow: 0 0 0 1px #888888, 0 7px 0 1px #888888, 0 14px 0 1px #888888; }
+    @media screen and (-webkit-min-device-pixel-ratio: 0) {
+      .top-bar.expanded .top-bar-section .has-dropdown.moved > .dropdown,
+      .top-bar.expanded .top-bar-section .dropdown {
+        clip: initial; }
+      .top-bar.expanded .top-bar-section .has-dropdown:not(.moved) > ul {
+        padding: 0; } }
+
+.top-bar-section {
+  left: 0;
+  position: relative;
+  width: auto;
+  transition: left 300ms ease-out; }
+  .top-bar-section ul {
+    display: block;
+    font-size: 16px;
+    height: auto;
+    margin: 0;
+    padding: 0;
+    width: 100%; }
+  .top-bar-section .divider,
+  .top-bar-section [role="separator"] {
+    border-top: solid 1px #1a1a1a;
+    clear: both;
+    height: 1px;
+    width: 100%; }
+  .top-bar-section ul li {
+    background: #333333; }
+    .top-bar-section ul li > a {
+      color: #FFFFFF;
+      display: block;
+      font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+      font-size: 0.8125rem;
+      font-weight: normal;
+      padding-left: 0.9375rem;
+      padding: 12px 0 12px 0.9375rem;
+      text-transform: none;
+      width: 100%; }
+      .top-bar-section ul li > a.button {
+        font-size: 0.8125rem;
+        padding-left: 0.9375rem;
+        padding-right: 0.9375rem;
+        background-color: #008CBA;
+        border-color: #007095;
+        color: #FFFFFF; }
+        .top-bar-section ul li > a.button:hover, .top-bar-section ul li > a.button:focus {
+          background-color: #007095; }
+        .top-bar-section ul li > a.button:hover, .top-bar-section ul li > a.button:focus {
+          color: #FFFFFF; }
+      .top-bar-section ul li > a.button.secondary {
+        background-color: #e7e7e7;
+        border-color: #b9b9b9;
+        color: #333333; }
+        .top-bar-section ul li > a.button.secondary:hover, .top-bar-section ul li > a.button.secondary:focus {
+          background-color: #b9b9b9; }
+        .top-bar-section ul li > a.button.secondary:hover, .top-bar-section ul li > a.button.secondary:focus {
+          color: #333333; }
+      .top-bar-section ul li > a.button.success {
+        background-color: #43AC6A;
+        border-color: #368a55;
+        color: #FFFFFF; }
+        .top-bar-section ul li > a.button.success:hover, .top-bar-section ul li > a.button.success:focus {
+          background-color: #368a55; }
+        .top-bar-section ul li > a.button.success:hover, .top-bar-section ul li > a.button.success:focus {
+          color: #FFFFFF; }
+      .top-bar-section ul li > a.button.alert {
+        background-color: #f04124;
+        border-color: #cf2a0e;
+        color: #FFFFFF; }
+        .top-bar-section ul li > a.button.alert:hover, .top-bar-section ul li > a.button.alert:focus {
+          background-color: #cf2a0e; }
+        .top-bar-section ul li > a.button.alert:hover, .top-bar-section ul li > a.button.alert:focus {
+          color: #FFFFFF; }
+      .top-bar-section ul li > a.button.warning {
+        background-color: #f08a24;
+        border-color: #cf6e0e;
+        color: #FFFFFF; }
+        .top-bar-section ul li > a.button.warning:hover, .top-bar-section ul li > a.button.warning:focus {
+          background-color: #cf6e0e; }
+        .top-bar-section ul li > a.button.warning:hover, .top-bar-section ul li > a.button.warning:focus {
+          color: #FFFFFF; }
+      .top-bar-section ul li > a.button.info {
+        background-color: #a0d3e8;
+        border-color: #61b6d9;
+        color: #333333; }
+        .top-bar-section ul li > a.button.info:hover, .top-bar-section ul li > a.button.info:focus {
+          background-color: #61b6d9; }
+        .top-bar-section ul li > a.button.info:hover, .top-bar-section ul li > a.button.info:focus {
+          color: #FFFFFF; }
+    .top-bar-section ul li > button {
+      font-size: 0.8125rem;
+      padding-left: 0.9375rem;
+      padding-right: 0.9375rem;
+      background-color: #008CBA;
+      border-color: #007095;
+      color: #FFFFFF; }
+      .top-bar-section ul li > button:hover, .top-bar-section ul li > button:focus {
+        background-color: #007095; }
+      .top-bar-section ul li > button:hover, .top-bar-section ul li > button:focus {
+        color: #FFFFFF; }
+      .top-bar-section ul li > button.secondary {
+        background-color: #e7e7e7;
+        border-color: #b9b9b9;
+        color: #333333; }
+        .top-bar-section ul li > button.secondary:hover, .top-bar-section ul li > button.secondary:focus {
+          background-color: #b9b9b9; }
+        .top-bar-section ul li > button.secondary:hover, .top-bar-section ul li > button.secondary:focus {
+          color: #333333; }
+      .top-bar-section ul li > button.success {
+        background-color: #43AC6A;
+        border-color: #368a55;
+        color: #FFFFFF; }
+        .top-bar-section ul li > button.success:hover, .top-bar-section ul li > button.success:focus {
+          background-color: #368a55; }
+        .top-bar-section ul li > button.success:hover, .top-bar-section ul li > button.success:focus {
+          color: #FFFFFF; }
+      .top-bar-section ul li > button.alert {
+        background-color: #f04124;
+        border-color: #cf2a0e;
+        color: #FFFFFF; }
+        .top-bar-section ul li > button.alert:hover, .top-bar-section ul li > button.alert:focus {
+          background-color: #cf2a0e; }
+        .top-bar-section ul li > button.alert:hover, .top-bar-section ul li > button.alert:focus {
+          color: #FFFFFF; }
+      .top-bar-section ul li > button.warning {
+        background-color: #f08a24;
+        border-color: #cf6e0e;
+        color: #FFFFFF; }
+        .top-bar-section ul li > button.warning:hover, .top-bar-section ul li > button.warning:focus {
+          background-color: #cf6e0e; }
+        .top-bar-section ul li > button.warning:hover, .top-bar-section ul li > button.warning:focus {
+          color: #FFFFFF; }
+      .top-bar-section ul li > button.info {
+        background-color: #a0d3e8;
+        border-color: #61b6d9;
+        color: #333333; }
+        .top-bar-section ul li > button.info:hover, .top-bar-section ul li > button.info:focus {
+          background-color: #61b6d9; }
+        .top-bar-section ul li > button.info:hover, .top-bar-section ul li > button.info:focus {
+          color: #FFFFFF; }
+    .top-bar-section ul li:hover:not(.has-form) > a {
+      background-color: #555555;
+      color: #FFFFFF;
+      background: #222222; }
+    .top-bar-section ul li.active > a {
+      background: #008CBA;
+      color: #FFFFFF; }
+      .top-bar-section ul li.active > a:hover {
+        background: #0078a0;
+        color: #FFFFFF; }
+  .top-bar-section .has-form {
+    padding: 0.9375rem; }
+  .top-bar-section .has-dropdown {
+    position: relative; }
+    .top-bar-section .has-dropdown > a:after {
+      border: inset 5px;
+      content: "";
+      display: block;
+      height: 0;
+      width: 0;
+      border-color: transparent transparent transparent rgba(255, 255, 255, 0.4);
+      border-left-style: solid;
+      margin-right: 0.9375rem;
+      margin-top: -4.5px;
+      position: absolute;
+      top: 50%;
+      right: 0; }
+    .top-bar-section .has-dropdown.moved {
+      position: static; }
+      .top-bar-section .has-dropdown.moved > .dropdown {
+        position: static !important;
+        height: auto;
+        width: auto;
+        overflow: visible;
+        clip: auto;
+        display: block;
+        position: absolute !important;
+        width: 100%; }
+      .top-bar-section .has-dropdown.moved > a:after {
+        display: none; }
+  .top-bar-section .dropdown {
+    clip: rect(1px, 1px, 1px, 1px);
+    height: 1px;
+    overflow: hidden;
+    position: absolute !important;
+    width: 1px;
+    display: block;
+    padding: 0;
+    position: absolute;
+    top: 0;
+    z-index: 99;
+    left: 100%; }
+    .top-bar-section .dropdown li {
+      height: auto;
+      width: 100%; }
+      .top-bar-section .dropdown li a {
+        font-weight: normal;
+        padding: 8px 0.9375rem; }
+        .top-bar-section .dropdown li a.parent-link {
+          font-weight: normal; }
+      .top-bar-section .dropdown li.title h5, .top-bar-section .dropdown li.parent-link {
+        margin-bottom: 0;
+        margin-top: 0;
+        font-size: 1.125rem; }
+        .top-bar-section .dropdown li.title h5 a, .top-bar-section .dropdown li.parent-link a {
+          color: #FFFFFF;
+          display: block; }
+          .top-bar-section .dropdown li.title h5 a:hover, .top-bar-section .dropdown li.parent-link a:hover {
+            background: none; }
+      .top-bar-section .dropdown li.has-form {
+        padding: 8px 0.9375rem; }
+      .top-bar-section .dropdown li .button,
+      .top-bar-section .dropdown li button {
+        top: auto; }
+    .top-bar-section .dropdown label {
+      color: #777777;
+      font-size: 0.625rem;
+      font-weight: bold;
+      margin-bottom: 0;
+      padding: 8px 0.9375rem 2px;
+      text-transform: uppercase; }
+
+.js-generated {
+  display: block; }
+
+@media only screen and (min-width: 40.0625em) {
+  .top-bar {
+    background: #333333;
+    overflow: visible; }
+    .top-bar:before, .top-bar:after {
+      content: " ";
+      display: table; }
+    .top-bar:after {
+      clear: both; }
+    .top-bar .toggle-topbar {
+      display: none; }
+    .top-bar .title-area {
+      float: left; }
+    .top-bar .name h1 a,
+    .top-bar .name h2 a,
+    .top-bar .name h3 a,
+    .top-bar .name h4 a,
+    .top-bar .name h5 a,
+    .top-bar .name h6 a {
+      width: auto; }
+    .top-bar input,
+    .top-bar select,
+    .top-bar .button,
+    .top-bar button {
+      font-size: 0.875rem;
+      height: 1.75rem;
+      position: relative;
+      top: 0.53125rem; }
+    .top-bar .has-form > .button,
+    .top-bar .has-form > button {
+      font-size: 0.875rem;
+      height: 1.75rem;
+      position: relative;
+      top: 0.53125rem; }
+    .top-bar.expanded {
+      background: #333333; }
+
+  .contain-to-grid .top-bar {
+    margin: 0 auto;
+    margin-bottom: 0;
+    max-width: 62.5rem; }
+
+  .top-bar-section {
+    transition: none 0 0;
+    left: 0 !important; }
+    .top-bar-section ul {
+      display: inline;
+      height: auto !important;
+      width: auto; }
+      .top-bar-section ul li {
+        float: left; }
+        .top-bar-section ul li .js-generated {
+          display: none; }
+    .top-bar-section li.hover > a:not(.button) {
+      background-color: #555555;
+      background: #222222;
+      color: #FFFFFF; }
+    .top-bar-section li:not(.has-form) a:not(.button) {
+      background: #333333;
+      line-height: 2.8125rem;
+      padding: 0 0.9375rem; }
+      .top-bar-section li:not(.has-form) a:not(.button):hover {
+        background-color: #555555;
+        background: #222222; }
+    .top-bar-section li.active:not(.has-form) a:not(.button) {
+      background: #008CBA;
+      color: #FFFFFF;
+      line-height: 2.8125rem;
+      padding: 0 0.9375rem; }
+      .top-bar-section li.active:not(.has-form) a:not(.button):hover {
+        background: #0078a0;
+        color: #FFFFFF; }
+    .top-bar-section .has-dropdown > a {
+      padding-right: 2.1875rem !important; }
+      .top-bar-section .has-dropdown > a:after {
+        border: inset 5px;
+        content: "";
+        display: block;
+        height: 0;
+        width: 0;
+        border-color: rgba(255, 255, 255, 0.4) transparent transparent transparent;
+        border-top-style: solid;
+        margin-top: -2.5px;
+        top: 1.40625rem; }
+    .top-bar-section .has-dropdown.moved {
+      position: relative; }
+      .top-bar-section .has-dropdown.moved > .dropdown {
+        clip: rect(1px, 1px, 1px, 1px);
+        height: 1px;
+        overflow: hidden;
+        position: absolute !important;
+        width: 1px;
+        display: block; }
+    .top-bar-section .has-dropdown.hover > .dropdown, .top-bar-section .has-dropdown.not-click:hover > .dropdown {
+      position: static !important;
+      height: auto;
+      width: auto;
+      overflow: visible;
+      clip: auto;
+      display: block;
+      position: absolute !important; }
+    .top-bar-section .has-dropdown > a:focus + .dropdown {
+      position: static !important;
+      height: auto;
+      width: auto;
+      overflow: visible;
+      clip: auto;
+      display: block;
+      position: absolute !important; }
+    .top-bar-section .has-dropdown .dropdown li.has-dropdown > a:after {
+      border: none;
+      content: "\00bb";
+      top: 0.1875rem;
+      right: 5px; }
+    .top-bar-section .dropdown {
+      left: 0;
+      background: transparent;
+      min-width: 100%;
+      top: auto; }
+      .top-bar-section .dropdown li a {
+        background: #333333;
+        color: #FFFFFF;
+        line-height: 2.8125rem;
+        padding: 12px 0.9375rem;
+        white-space: nowrap; }
+      .top-bar-section .dropdown li:not(.has-form):not(.active) > a:not(.button) {
+        background: #333333;
+        color: #FFFFFF; }
+      .top-bar-section .dropdown li:not(.has-form):not(.active):hover > a:not(.button) {
+        background-color: #555555;
+        color: #FFFFFF;
+        background: #222222; }
+      .top-bar-section .dropdown li label {
+        background: #333333;
+        white-space: nowrap; }
+      .top-bar-section .dropdown li .dropdown {
+        left: 100%;
+        top: 0; }
+    .top-bar-section > ul > .divider,
+    .top-bar-section > ul > [role="separator"] {
+      border-right: solid 1px #4e4e4e;
+      border-bottom: none;
+      border-top: none;
+      clear: none;
+      height: 2.8125rem;
+      width: 0; }
+    .top-bar-section .has-form {
+      background: #333333;
+      height: 2.8125rem;
+      padding: 0 0.9375rem; }
+    .top-bar-section .right li .dropdown {
+      left: auto;
+      right: 0; }
+      .top-bar-section .right li .dropdown li .dropdown {
+        right: 100%; }
+    .top-bar-section .left li .dropdown {
+      right: auto;
+      left: 0; }
+      .top-bar-section .left li .dropdown li .dropdown {
+        left: 100%; }
+
+  .no-js .top-bar-section ul li:hover > a {
+    background-color: #555555;
+    background: #222222;
+    color: #FFFFFF; }
+  .no-js .top-bar-section ul li:active > a {
+    background: #008CBA;
+    color: #FFFFFF; }
+  .no-js .top-bar-section .has-dropdown:hover > .dropdown {
+    position: static !important;
+    height: auto;
+    width: auto;
+    overflow: visible;
+    clip: auto;
+    display: block;
+    position: absolute !important; }
+  .no-js .top-bar-section .has-dropdown > a:focus + .dropdown {
+    position: static !important;
+    height: auto;
+    width: auto;
+    overflow: visible;
+    clip: auto;
+    display: block;
+    position: absolute !important; } }
+.breadcrumbs {
+  border-style: solid;
+  border-width: 1px;
+  display: block;
+  list-style: none;
+  margin-left: 0;
+  overflow: hidden;
+  padding: 0.5625rem 0.875rem 0.5625rem;
+  background-color: #f4f4f4;
+  border-color: gainsboro;
+  border-radius: 3px; }
+  .breadcrumbs > * {
+    color: #008CBA;
+    float: left;
+    font-size: 0.6875rem;
+    line-height: 0.6875rem;
+    margin: 0;
+    text-transform: uppercase; }
+    .breadcrumbs > *:hover a, .breadcrumbs > *:focus a {
+      text-decoration: underline; }
+    .breadcrumbs > * a {
+      color: #008CBA; }
+    .breadcrumbs > *.current {
+      color: #333333;
+      cursor: default; }
+      .breadcrumbs > *.current a {
+        color: #333333;
+        cursor: default; }
+      .breadcrumbs > *.current:hover, .breadcrumbs > *.current:hover a, .breadcrumbs > *.current:focus, .breadcrumbs > *.current:focus a {
+        text-decoration: none; }
+    .breadcrumbs > *.unavailable {
+      color: #999999; }
+      .breadcrumbs > *.unavailable a {
+        color: #999999; }
+      .breadcrumbs > *.unavailable:hover, .breadcrumbs > *.unavailable:hover a, .breadcrumbs > *.unavailable:focus,
+      .breadcrumbs > *.unavailable a:focus {
+        color: #999999;
+        cursor: not-allowed;
+        text-decoration: none; }
+    .breadcrumbs > *:before {
+      color: #AAAAAA;
+      content: "/";
+      margin: 0 0.75rem;
+      position: relative;
+      top: 1px; }
+    .breadcrumbs > *:first-child:before {
+      content: " ";
+      margin: 0; }
+
+/* Accessibility - hides the forward slash */
+[aria-label="breadcrumbs"] [aria-hidden="true"]:after {
+  content: "/"; }
+
+.alert-box {
+  border-style: solid;
+  border-width: 1px;
+  display: block;
+  font-size: 0.8125rem;
+  font-weight: normal;
+  margin-bottom: 1.25rem;
+  padding: 0.875rem 1.5rem 0.875rem 0.875rem;
+  position: relative;
+  transition: opacity 300ms ease-out;
+  background-color: #008CBA;
+  border-color: #0078a0;
+  color: #FFFFFF; }
+  .alert-box .close {
+    right: 0.25rem;
+    background: inherit;
+    color: #333333;
+    font-size: 1.375rem;
+    line-height: .9;
+    margin-top: -0.6875rem;
+    opacity: 0.3;
+    padding: 0 6px 4px;
+    position: absolute;
+    top: 50%; }
+    .alert-box .close:hover, .alert-box .close:focus {
+      opacity: 0.5; }
+  .alert-box.radius {
+    border-radius: 3px; }
+  .alert-box.round {
+    border-radius: 1000px; }
+  .alert-box.success {
+    background-color: #43AC6A;
+    border-color: #3a945b;
+    color: #FFFFFF; }
+  .alert-box.alert {
+    background-color: #f04124;
+    border-color: #de2d0f;
+    color: #FFFFFF; }
+  .alert-box.secondary {
+    background-color: #e7e7e7;
+    border-color: #c7c7c7;
+    color: #4f4f4f; }
+  .alert-box.warning {
+    background-color: #f08a24;
+    border-color: #de770f;
+    color: #FFFFFF; }
+  .alert-box.info {
+    background-color: #a0d3e8;
+    border-color: #74bfdd;
+    color: #4f4f4f; }
+  .alert-box.alert-close {
+    opacity: 0; }
+
+.inline-list {
+  list-style: none;
+  margin-top: 0;
+  margin-bottom: 1.0625rem;
+  margin-left: -1.375rem;
+  margin-right: 0;
+  overflow: hidden;
+  padding: 0; }
+  .inline-list > li {
+    display: block;
+    float: left;
+    list-style: none;
+    margin-left: 1.375rem; }
+    .inline-list > li > * {
+      display: block; }
+
+.button-group {
+  list-style: none;
+  margin: 0;
+  left: 0; }
+  .button-group:before, .button-group:after {
+    content: " ";
+    display: table; }
+  .button-group:after {
+    clear: both; }
+  .button-group.even-2 li {
+    display: inline-block;
+    margin: 0 -2px;
+    width: 50%; }
+    .button-group.even-2 li > button, .button-group.even-2 li .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.even-2 li:first-child button, .button-group.even-2 li:first-child .button {
+      border-left: 0; }
+    .button-group.even-2 li button, .button-group.even-2 li .button {
+      width: 100%; }
+  .button-group.even-3 li {
+    display: inline-block;
+    margin: 0 -2px;
+    width: 33.33333%; }
+    .button-group.even-3 li > button, .button-group.even-3 li .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.even-3 li:first-child button, .button-group.even-3 li:first-child .button {
+      border-left: 0; }
+    .button-group.even-3 li button, .button-group.even-3 li .button {
+      width: 100%; }
+  .button-group.even-4 li {
+    display: inline-block;
+    margin: 0 -2px;
+    width: 25%; }
+    .button-group.even-4 li > button, .button-group.even-4 li .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.even-4 li:first-child button, .button-group.even-4 li:first-child .button {
+      border-left: 0; }
+    .button-group.even-4 li button, .button-group.even-4 li .button {
+      width: 100%; }
+  .button-group.even-5 li {
+    display: inline-block;
+    margin: 0 -2px;
+    width: 20%; }
+    .button-group.even-5 li > button, .button-group.even-5 li .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.even-5 li:first-child button, .button-group.even-5 li:first-child .button {
+      border-left: 0; }
+    .button-group.even-5 li button, .button-group.even-5 li .button {
+      width: 100%; }
+  .button-group.even-6 li {
+    display: inline-block;
+    margin: 0 -2px;
+    width: 16.66667%; }
+    .button-group.even-6 li > button, .button-group.even-6 li .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.even-6 li:first-child button, .button-group.even-6 li:first-child .button {
+      border-left: 0; }
+    .button-group.even-6 li button, .button-group.even-6 li .button {
+      width: 100%; }
+  .button-group.even-7 li {
+    display: inline-block;
+    margin: 0 -2px;
+    width: 14.28571%; }
+    .button-group.even-7 li > button, .button-group.even-7 li .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.even-7 li:first-child button, .button-group.even-7 li:first-child .button {
+      border-left: 0; }
+    .button-group.even-7 li button, .button-group.even-7 li .button {
+      width: 100%; }
+  .button-group.even-8 li {
+    display: inline-block;
+    margin: 0 -2px;
+    width: 12.5%; }
+    .button-group.even-8 li > button, .button-group.even-8 li .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.even-8 li:first-child button, .button-group.even-8 li:first-child .button {
+      border-left: 0; }
+    .button-group.even-8 li button, .button-group.even-8 li .button {
+      width: 100%; }
+  .button-group > li {
+    display: inline-block;
+    margin: 0 -2px; }
+    .button-group > li > button, .button-group > li .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group > li:first-child button, .button-group > li:first-child .button {
+      border-left: 0; }
+  .button-group.stack > li {
+    display: block;
+    margin: 0;
+    float: none; }
+    .button-group.stack > li > button, .button-group.stack > li .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.stack > li:first-child button, .button-group.stack > li:first-child .button {
+      border-left: 0; }
+    .button-group.stack > li > button, .button-group.stack > li .button {
+      border-color: rgba(255, 255, 255, 0.5);
+      border-left-width: 0;
+      border-top: 1px solid;
+      display: block;
+      margin: 0; }
+    .button-group.stack > li > button {
+      width: 100%; }
+    .button-group.stack > li:first-child button, .button-group.stack > li:first-child .button {
+      border-top: 0; }
+  .button-group.stack-for-small > li {
+    display: inline-block;
+    margin: 0 -2px; }
+    .button-group.stack-for-small > li > button, .button-group.stack-for-small > li .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.stack-for-small > li:first-child button, .button-group.stack-for-small > li:first-child .button {
+      border-left: 0; }
+    @media only screen and (max-width: 40em) {
+      .button-group.stack-for-small > li {
+        display: block;
+        margin: 0;
+        width: 100%; }
+        .button-group.stack-for-small > li > button, .button-group.stack-for-small > li .button {
+          border-left: 1px solid;
+          border-color: rgba(255, 255, 255, 0.5); }
+        .button-group.stack-for-small > li:first-child button, .button-group.stack-for-small > li:first-child .button {
+          border-left: 0; }
+        .button-group.stack-for-small > li > button, .button-group.stack-for-small > li .button {
+          border-color: rgba(255, 255, 255, 0.5);
+          border-left-width: 0;
+          border-top: 1px solid;
+          display: block;
+          margin: 0; }
+        .button-group.stack-for-small > li > button {
+          width: 100%; }
+        .button-group.stack-for-small > li:first-child button, .button-group.stack-for-small > li:first-child .button {
+          border-top: 0; } }
+  .button-group.radius > * {
+    display: inline-block;
+    margin: 0 -2px; }
+    .button-group.radius > * > button, .button-group.radius > * .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.radius > *:first-child button, .button-group.radius > *:first-child .button {
+      border-left: 0; }
+    .button-group.radius > *,
+    .button-group.radius > * > a,
+    .button-group.radius > * > button,
+    .button-group.radius > * > .button {
+      border-radius: 0; }
+    .button-group.radius > *:first-child, .button-group.radius > *:first-child > a, .button-group.radius > *:first-child > button, .button-group.radius > *:first-child > .button {
+      -webkit-border-bottom-left-radius: 3px;
+      -webkit-border-top-left-radius: 3px;
+      border-bottom-left-radius: 3px;
+      border-top-left-radius: 3px; }
+    .button-group.radius > *:last-child, .button-group.radius > *:last-child > a, .button-group.radius > *:last-child > button, .button-group.radius > *:last-child > .button {
+      -webkit-border-bottom-right-radius: 3px;
+      -webkit-border-top-right-radius: 3px;
+      border-bottom-right-radius: 3px;
+      border-top-right-radius: 3px; }
+  .button-group.radius.stack > * {
+    display: block;
+    margin: 0; }
+    .button-group.radius.stack > * > button, .button-group.radius.stack > * .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.radius.stack > *:first-child button, .button-group.radius.stack > *:first-child .button {
+      border-left: 0; }
+    .button-group.radius.stack > * > button, .button-group.radius.stack > * .button {
+      border-color: rgba(255, 255, 255, 0.5);
+      border-left-width: 0;
+      border-top: 1px solid;
+      display: block;
+      margin: 0; }
+    .button-group.radius.stack > * > button {
+      width: 100%; }
+    .button-group.radius.stack > *:first-child button, .button-group.radius.stack > *:first-child .button {
+      border-top: 0; }
+    .button-group.radius.stack > *,
+    .button-group.radius.stack > * > a,
+    .button-group.radius.stack > * > button,
+    .button-group.radius.stack > * > .button {
+      border-radius: 0; }
+    .button-group.radius.stack > *:first-child, .button-group.radius.stack > *:first-child > a, .button-group.radius.stack > *:first-child > button, .button-group.radius.stack > *:first-child > .button {
+      -webkit-top-left-radius: 3px;
+      -webkit-top-right-radius: 3px;
+      border-top-left-radius: 3px;
+      border-top-right-radius: 3px; }
+    .button-group.radius.stack > *:last-child, .button-group.radius.stack > *:last-child > a, .button-group.radius.stack > *:last-child > button, .button-group.radius.stack > *:last-child > .button {
+      -webkit-bottom-left-radius: 3px;
+      -webkit-bottom-right-radius: 3px;
+      border-bottom-left-radius: 3px;
+      border-bottom-right-radius: 3px; }
+  @media only screen and (min-width: 40.0625em) {
+    .button-group.radius.stack-for-small > * {
+      display: inline-block;
+      margin: 0 -2px; }
+      .button-group.radius.stack-for-small > * > button, .button-group.radius.stack-for-small > * .button {
+        border-left: 1px solid;
+        border-color: rgba(255, 255, 255, 0.5); }
+      .button-group.radius.stack-for-small > *:first-child button, .button-group.radius.stack-for-small > *:first-child .button {
+        border-left: 0; }
+      .button-group.radius.stack-for-small > *,
+      .button-group.radius.stack-for-small > * > a,
+      .button-group.radius.stack-for-small > * > button,
+      .button-group.radius.stack-for-small > * > .button {
+        border-radius: 0; }
+      .button-group.radius.stack-for-small > *:first-child, .button-group.radius.stack-for-small > *:first-child > a, .button-group.radius.stack-for-small > *:first-child > button, .button-group.radius.stack-for-small > *:first-child > .button {
+        -webkit-border-bottom-left-radius: 3px;
+        -webkit-border-top-left-radius: 3px;
+        border-bottom-left-radius: 3px;
+        border-top-left-radius: 3px; }
+      .button-group.radius.stack-for-small > *:last-child, .button-group.radius.stack-for-small > *:last-child > a, .button-group.radius.stack-for-small > *:last-child > button, .button-group.radius.stack-for-small > *:last-child > .button {
+        -webkit-border-bottom-right-radius: 3px;
+        -webkit-border-top-right-radius: 3px;
+        border-bottom-right-radius: 3px;
+        border-top-right-radius: 3px; } }
+  @media only screen and (max-width: 40em) {
+    .button-group.radius.stack-for-small > * {
+      display: block;
+      margin: 0; }
+      .button-group.radius.stack-for-small > * > button, .button-group.radius.stack-for-small > * .button {
+        border-left: 1px solid;
+        border-color: rgba(255, 255, 255, 0.5); }
+      .button-group.radius.stack-for-small > *:first-child button, .button-group.radius.stack-for-small > *:first-child .button {
+        border-left: 0; }
+      .button-group.radius.stack-for-small > * > button, .button-group.radius.stack-for-small > * .button {
+        border-color: rgba(255, 255, 255, 0.5);
+        border-left-width: 0;
+        border-top: 1px solid;
+        display: block;
+        margin: 0; }
+      .button-group.radius.stack-for-small > * > button {
+        width: 100%; }
+      .button-group.radius.stack-for-small > *:first-child button, .button-group.radius.stack-for-small > *:first-child .button {
+        border-top: 0; }
+      .button-group.radius.stack-for-small > *,
+      .button-group.radius.stack-for-small > * > a,
+      .button-group.radius.stack-for-small > * > button,
+      .button-group.radius.stack-for-small > * > .button {
+        border-radius: 0; }
+      .button-group.radius.stack-for-small > *:first-child, .button-group.radius.stack-for-small > *:first-child > a, .button-group.radius.stack-for-small > *:first-child > button, .button-group.radius.stack-for-small > *:first-child > .button {
+        -webkit-top-left-radius: 3px;
+        -webkit-top-right-radius: 3px;
+        border-top-left-radius: 3px;
+        border-top-right-radius: 3px; }
+      .button-group.radius.stack-for-small > *:last-child, .button-group.radius.stack-for-small > *:last-child > a, .button-group.radius.stack-for-small > *:last-child > button, .button-group.radius.stack-for-small > *:last-child > .button {
+        -webkit-bottom-left-radius: 3px;
+        -webkit-bottom-right-radius: 3px;
+        border-bottom-left-radius: 3px;
+        border-bottom-right-radius: 3px; } }
+  .button-group.round > * {
+    display: inline-block;
+    margin: 0 -2px; }
+    .button-group.round > * > button, .button-group.round > * .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.round > *:first-child button, .button-group.round > *:first-child .button {
+      border-left: 0; }
+    .button-group.round > *,
+    .button-group.round > * > a,
+    .button-group.round > * > button,
+    .button-group.round > * > .button {
+      border-radius: 0; }
+    .button-group.round > *:first-child, .button-group.round > *:first-child > a, .button-group.round > *:first-child > button, .button-group.round > *:first-child > .button {
+      -webkit-border-bottom-left-radius: 1000px;
+      -webkit-border-top-left-radius: 1000px;
+      border-bottom-left-radius: 1000px;
+      border-top-left-radius: 1000px; }
+    .button-group.round > *:last-child, .button-group.round > *:last-child > a, .button-group.round > *:last-child > button, .button-group.round > *:last-child > .button {
+      -webkit-border-bottom-right-radius: 1000px;
+      -webkit-border-top-right-radius: 1000px;
+      border-bottom-right-radius: 1000px;
+      border-top-right-radius: 1000px; }
+  .button-group.round.stack > * {
+    display: block;
+    margin: 0; }
+    .button-group.round.stack > * > button, .button-group.round.stack > * .button {
+      border-left: 1px solid;
+      border-color: rgba(255, 255, 255, 0.5); }
+    .button-group.round.stack > *:first-child button, .button-group.round.stack > *:first-child .button {
+      border-left: 0; }
+    .button-group.round.stack > * > button, .button-group.round.stack > * .button {
+      border-color: rgba(255, 255, 255, 0.5);
+      border-left-width: 0;
+      border-top: 1px solid;
+      display: block;
+      margin: 0; }
+    .button-group.round.stack > * > button {
+      width: 100%; }
+    .button-group.round.stack > *:first-child button, .button-group.round.stack > *:first-child .button {
+      border-top: 0; }
+    .button-group.round.stack > *,
+    .button-group.round.stack > * > a,
+    .button-group.round.stack > * > button,
+    .button-group.round.stack > * > .button {
+      border-radius: 0; }
+    .button-group.round.stack > *:first-child, .button-group.round.stack > *:first-child > a, .button-group.round.stack > *:first-child > button, .button-group.round.stack > *:first-child > .button {
+      -webkit-top-left-radius: 1rem;
+      -webkit-top-right-radius: 1rem;
+      border-top-left-radius: 1rem;
+      border-top-right-radius: 1rem; }
+    .button-group.round.stack > *:last-child, .button-group.round.stack > *:last-child > a, .button-group.round.stack > *:last-child > button, .button-group.round.stack > *:last-child > .button {
+      -webkit-bottom-left-radius: 1rem;
+      -webkit-bottom-right-radius: 1rem;
+      border-bottom-left-radius: 1rem;
+      border-bottom-right-radius: 1rem; }
+  @media only screen and (min-width: 40.0625em) {
+    .button-group.round.stack-for-small > * {
+      display: inline-block;
+      margin: 0 -2px; }
+      .button-group.round.stack-for-small > * > button, .button-group.round.stack-for-small > * .button {
+        border-left: 1px solid;
+        border-color: rgba(255, 255, 255, 0.5); }
+      .button-group.round.stack-for-small > *:first-child button, .button-group.round.stack-for-small > *:first-child .button {
+        border-left: 0; }
+      .button-group.round.stack-for-small > *,
+      .button-group.round.stack-for-small > * > a,
+      .button-group.round.stack-for-small > * > button,
+      .button-group.round.stack-for-small > * > .button {
+        border-radius: 0; }
+      .button-group.round.stack-for-small > *:first-child, .button-group.round.stack-for-small > *:first-child > a, .button-group.round.stack-for-small > *:first-child > button, .button-group.round.stack-for-small > *:first-child > .button {
+        -webkit-border-bottom-left-radius: 1000px;
+        -webkit-border-top-left-radius: 1000px;
+        border-bottom-left-radius: 1000px;
+        border-top-left-radius: 1000px; }
+      .button-group.round.stack-for-small > *:last-child, .button-group.round.stack-for-small > *:last-child > a, .button-group.round.stack-for-small > *:last-child > button, .button-group.round.stack-for-small > *:last-child > .button {
+        -webkit-border-bottom-right-radius: 1000px;
+        -webkit-border-top-right-radius: 1000px;
+        border-bottom-right-radius: 1000px;
+        border-top-right-radius: 1000px; } }
+  @media only screen and (max-width: 40em) {
+    .button-group.round.stack-for-small > * {
+      display: block;
+      margin: 0; }
+      .button-group.round.stack-for-small > * > button, .button-group.round.stack-for-small > * .button {
+        border-left: 1px solid;
+        border-color: rgba(255, 255, 255, 0.5); }
+      .button-group.round.stack-for-small > *:first-child button, .button-group.round.stack-for-small > *:first-child .button {
+        border-left: 0; }
+      .button-group.round.stack-for-small > * > button, .button-group.round.stack-for-small > * .button {
+        border-color: rgba(255, 255, 255, 0.5);
+        border-left-width: 0;
+        border-top: 1px solid;
+        display: block;
+        margin: 0; }
+      .button-group.round.stack-for-small > * > button {
+        width: 100%; }
+      .button-group.round.stack-for-small > *:first-child button, .button-group.round.stack-for-small > *:first-child .button {
+        border-top: 0; }
+      .button-group.round.stack-for-small > *,
+      .button-group.round.stack-for-small > * > a,
+      .button-group.round.stack-for-small > * > button,
+      .button-group.round.stack-for-small > * > .button {
+        border-radius: 0; }
+      .button-group.round.stack-for-small > *:first-child, .button-group.round.stack-for-small > *:first-child > a, .button-group.round.stack-for-small > *:first-child > button, .button-group.round.stack-for-small > *:first-child > .button {
+        -webkit-top-left-radius: 1rem;
+        -webkit-top-right-radius: 1rem;
+        border-top-left-radius: 1rem;
+        border-top-right-radius: 1rem; }
+      .button-group.round.stack-for-small > *:last-child, .button-group.round.stack-for-small > *:last-child > a, .button-group.round.stack-for-small > *:last-child > button, .button-group.round.stack-for-small > *:last-child > .button {
+        -webkit-bottom-left-radius: 1rem;
+        -webkit-bottom-right-radius: 1rem;
+        border-bottom-left-radius: 1rem;
+        border-bottom-right-radius: 1rem; } }
+
+.button-bar:before, .button-bar:after {
+  content: " ";
+  display: table; }
+.button-bar:after {
+  clear: both; }
+.button-bar .button-group {
+  float: left;
+  margin-right: 0.625rem; }
+  .button-bar .button-group div {
+    overflow: hidden; }
+
+/* Panels */
+.panel {
+  border-style: solid;
+  border-width: 1px;
+  border-color: #d8d8d8;
+  margin-bottom: 1.25rem;
+  padding: 1.25rem;
+  background: #f2f2f2;
+  color: #333333; }
+  .panel > :first-child {
+    margin-top: 0; }
+  .panel > :last-child {
+    margin-bottom: 0; }
+  .panel h1, .panel h2, .panel h3, .panel h4, .panel h5, .panel h6, .panel p, .panel li, .panel dl {
+    color: #333333; }
+  .panel h1, .panel h2, .panel h3, .panel h4, .panel h5, .panel h6 {
+    line-height: 1;
+    margin-bottom: 0.625rem; }
+    .panel h1.subheader, .panel h2.subheader, .panel h3.subheader, .panel h4.subheader, .panel h5.subheader, .panel h6.subheader {
+      line-height: 1.4; }
+  .panel.callout {
+    border-style: solid;
+    border-width: 1px;
+    border-color: #d8d8d8;
+    margin-bottom: 1.25rem;
+    padding: 1.25rem;
+    background: #ecfaff;
+    color: #333333; }
+    .panel.callout > :first-child {
+      margin-top: 0; }
+    .panel.callout > :last-child {
+      margin-bottom: 0; }
+    .panel.callout h1, .panel.callout h2, .panel.callout h3, .panel.callout h4, .panel.callout h5, .panel.callout h6, .panel.callout p, .panel.callout li, .panel.callout dl {
+      color: #333333; }
+    .panel.callout h1, .panel.callout h2, .panel.callout h3, .panel.callout h4, .panel.callout h5, .panel.callout h6 {
+      line-height: 1;
+      margin-bottom: 0.625rem; }
+      .panel.callout h1.subheader, .panel.callout h2.subheader, .panel.callout h3.subheader, .panel.callout h4.subheader, .panel.callout h5.subheader, .panel.callout h6.subheader {
+        line-height: 1.4; }
+    .panel.callout a:not(.button) {
+      color: #008CBA; }
+      .panel.callout a:not(.button):hover, .panel.callout a:not(.button):focus {
+        color: #0078a0; }
+  .panel.radius {
+    border-radius: 3px; }
+
+.dropdown.button, button.dropdown {
+  position: relative;
+  padding-right: 3.5625rem; }
+  .dropdown.button::after, button.dropdown::after {
+    border-color: #FFFFFF transparent transparent transparent;
+    border-style: solid;
+    content: "";
+    display: block;
+    height: 0;
+    position: absolute;
+    top: 50%;
+    width: 0; }
+  .dropdown.button::after, button.dropdown::after {
+    border-width: 0.375rem;
+    right: 1.40625rem;
+    margin-top: -0.15625rem; }
+  .dropdown.button::after, button.dropdown::after {
+    border-color: #FFFFFF transparent transparent transparent; }
+  .dropdown.button.tiny, button.dropdown.tiny {
+    padding-right: 2.625rem; }
+    .dropdown.button.tiny:after, button.dropdown.tiny:after {
+      border-width: 0.375rem;
+      right: 1.125rem;
+      margin-top: -0.125rem; }
+    .dropdown.button.tiny::after, button.dropdown.tiny::after {
+      border-color: #FFFFFF transparent transparent transparent; }
+  .dropdown.button.small, button.dropdown.small {
+    padding-right: 3.0625rem; }
+    .dropdown.button.small::after, button.dropdown.small::after {
+      border-width: 0.4375rem;
+      right: 1.3125rem;
+      margin-top: -0.15625rem; }
+    .dropdown.button.small::after, button.dropdown.small::after {
+      border-color: #FFFFFF transparent transparent transparent; }
+  .dropdown.button.large, button.dropdown.large {
+    padding-right: 3.625rem; }
+    .dropdown.button.large::after, button.dropdown.large::after {
+      border-width: 0.3125rem;
+      right: 1.71875rem;
+      margin-top: -0.15625rem; }
+    .dropdown.button.large::after, button.dropdown.large::after {
+      border-color: #FFFFFF transparent transparent transparent; }
+  .dropdown.button.secondary:after, button.dropdown.secondary:after {
+    border-color: #333333 transparent transparent transparent; }
+
+/* Image Thumbnails */
+.th {
+  border: solid 4px #FFFFFF;
+  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
+  display: inline-block;
+  line-height: 0;
+  max-width: 100%;
+  transition: all 200ms ease-out; }
+  .th:hover, .th:focus {
+    box-shadow: 0 0 6px 1px rgba(0, 140, 186, 0.5); }
+  .th.radius {
+    border-radius: 3px; }
+
+/* Pricing Tables */
+.pricing-table {
+  border: solid 1px #DDDDDD;
+  margin-left: 0;
+  margin-bottom: 1.25rem; }
+  .pricing-table * {
+    list-style: none;
+    line-height: 1; }
+  .pricing-table .title {
+    background-color: #333333;
+    color: #EEEEEE;
+    font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+    font-size: 1rem;
+    font-weight: normal;
+    padding: 0.9375rem 1.25rem;
+    text-align: center; }
+  .pricing-table .price {
+    background-color: #F6F6F6;
+    color: #333333;
+    font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+    font-size: 2rem;
+    font-weight: normal;
+    padding: 0.9375rem 1.25rem;
+    text-align: center; }
+  .pricing-table .description {
+    background-color: #FFFFFF;
+    border-bottom: dotted 1px #DDDDDD;
+    color: #777777;
+    font-size: 0.75rem;
+    font-weight: normal;
+    line-height: 1.4;
+    padding: 0.9375rem;
+    text-align: center; }
+  .pricing-table .bullet-item {
+    background-color: #FFFFFF;
+    border-bottom: dotted 1px #DDDDDD;
+    color: #333333;
+    font-size: 0.875rem;
+    font-weight: normal;
+    padding: 0.9375rem;
+    text-align: center; }
+  .pricing-table .cta-button {
+    background-color: #FFFFFF;
+    padding: 1.25rem 1.25rem 0;
+    text-align: center; }
+
+@-webkit-keyframes rotate {
+  from {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg); }
+  to {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg); } }
+@keyframes rotate {
+  from {
+    -webkit-transform: rotate(0deg);
+    -moz-transform: rotate(0deg);
+    -ms-transform: rotate(0deg);
+    transform: rotate(0deg); }
+  to {
+    -webkit-transform: rotate(360deg);
+    -moz-transform: rotate(360deg);
+    -ms-transform: rotate(360deg);
+    transform: rotate(360deg); } }
+/* Orbit Graceful Loading */
+.slideshow-wrapper {
+  position: relative; }
+  .slideshow-wrapper ul {
+    list-style-type: none;
+    margin: 0; }
+    .slideshow-wrapper ul li,
+    .slideshow-wrapper ul li .orbit-caption {
+      display: none; }
+    .slideshow-wrapper ul li:first-child {
+      display: block; }
+  .slideshow-wrapper .orbit-container {
+    background-color: transparent; }
+    .slideshow-wrapper .orbit-container li {
+      display: block; }
+      .slideshow-wrapper .orbit-container li .orbit-caption {
+        display: block; }
+    .slideshow-wrapper .orbit-container .orbit-bullets li {
+      display: inline-block; }
+  .slideshow-wrapper .preloader {
+    border-radius: 1000px;
+    animation-duration: 1.5s;
+    animation-iteration-count: infinite;
+    animation-name: rotate;
+    animation-timing-function: linear;
+    border-color: #555555 #FFFFFF;
+    border: solid 3px;
+    display: block;
+    height: 40px;
+    left: 50%;
+    margin-left: -20px;
+    margin-top: -20px;
+    position: absolute;
+    top: 50%;
+    width: 40px; }
+
+.orbit-container {
+  background: none;
+  overflow: hidden;
+  position: relative;
+  width: 100%; }
+  .orbit-container .orbit-slides-container {
+    list-style: none;
+    margin: 0;
+    padding: 0;
+    position: relative;
+    -webkit-transform: translateZ(0);
+    -moz-transform: translateZ(0);
+    -ms-transform: translateZ(0);
+    -o-transform: translateZ(0);
+    transform: translateZ(0); }
+    .orbit-container .orbit-slides-container img {
+      display: block;
+      max-width: 100%; }
+    .orbit-container .orbit-slides-container > * {
+      position: absolute;
+      top: 0;
+      width: 100%;
+      margin-left: 100%; }
+      .orbit-container .orbit-slides-container > *:first-child {
+        margin-left: 0; }
+      .orbit-container .orbit-slides-container > * .orbit-caption {
+        bottom: 0;
+        position: absolute;
+        background-color: rgba(51, 51, 51, 0.8);
+        color: #FFFFFF;
+        font-size: 0.875rem;
+        padding: 0.625rem 0.875rem;
+        width: 100%; }
+  .orbit-container .orbit-slide-number {
+    left: 10px;
+    background: transparent;
+    color: #FFFFFF;
+    font-size: 12px;
+    position: absolute;
+    top: 10px;
+    z-index: 10; }
+    .orbit-container .orbit-slide-number span {
+      font-weight: 700;
+      padding: 0.3125rem; }
+  .orbit-container .orbit-timer {
+    position: absolute;
+    top: 12px;
+    right: 10px;
+    height: 6px;
+    width: 100px;
+    z-index: 10; }
+    .orbit-container .orbit-timer .orbit-progress {
+      height: 3px;
+      background-color: rgba(255, 255, 255, 0.3);
+      display: block;
+      width: 0;
+      position: relative;
+      right: 20px;
+      top: 5px; }
+    .orbit-container .orbit-timer > span {
+      border: solid 4px #FFFFFF;
+      border-bottom: none;
+      border-top: none;
+      display: none;
+      height: 14px;
+      position: absolute;
+      top: 0;
+      width: 11px;
+      right: 0; }
+    .orbit-container .orbit-timer.paused > span {
+      top: 0;
+      width: 11px;
+      height: 14px;
+      border: inset 8px;
+      border-left-style: solid;
+      border-color: transparent;
+      border-left-color: #FFFFFF;
+      right: -4px; }
+      .orbit-container .orbit-timer.paused > span.dark {
+        border-left-color: #333333; }
+  .orbit-container:hover .orbit-timer > span {
+    display: block; }
+  .orbit-container .orbit-prev,
+  .orbit-container .orbit-next {
+    background-color: transparent;
+    color: white;
+    height: 60px;
+    line-height: 50px;
+    margin-top: -25px;
+    position: absolute;
+    text-indent: -9999px !important;
+    top: 45%;
+    width: 36px;
+    z-index: 10; }
+    .orbit-container .orbit-prev:hover,
+    .orbit-container .orbit-next:hover {
+      background-color: rgba(0, 0, 0, 0.3); }
+    .orbit-container .orbit-prev > span,
+    .orbit-container .orbit-next > span {
+      border: inset 10px;
+      display: block;
+      height: 0;
+      margin-top: -10px;
+      position: absolute;
+      top: 50%;
+      width: 0; }
+  .orbit-container .orbit-prev {
+    left: 0; }
+    .orbit-container .orbit-prev > span {
+      border-right-style: solid;
+      border-color: transparent;
+      border-right-color: #FFFFFF; }
+    .orbit-container .orbit-prev:hover > span {
+      border-right-color: #FFFFFF; }
+  .orbit-container .orbit-next {
+    right: 0; }
+    .orbit-container .orbit-next > span {
+      border-color: transparent;
+      border-left-style: solid;
+      border-left-color: #FFFFFF;
+      left: 50%;
+      margin-left: -4px; }
+    .orbit-container .orbit-next:hover > span {
+      border-left-color: #FFFFFF; }
+
+.orbit-bullets-container {
+  text-align: center; }
+
+.orbit-bullets {
+  display: block;
+  float: none;
+  margin: 0 auto 30px auto;
+  overflow: hidden;
+  position: relative;
+  text-align: center;
+  top: 10px; }
+  .orbit-bullets li {
+    background: #CCCCCC;
+    cursor: pointer;
+    display: inline-block;
+    float: none;
+    height: 0.5625rem;
+    margin-right: 6px;
+    width: 0.5625rem;
+    border-radius: 1000px; }
+    .orbit-bullets li.active {
+      background: #999999; }
+    .orbit-bullets li:last-child {
+      margin-right: 0; }
+
+.touch .orbit-container .orbit-prev,
+.touch .orbit-container .orbit-next {
+  display: none; }
+.touch .orbit-bullets {
+  display: none; }
+
+@media only screen and (min-width: 40.0625em) {
+  .touch .orbit-container .orbit-prev,
+  .touch .orbit-container .orbit-next {
+    display: inherit; }
+  .touch .orbit-bullets {
+    display: block; } }
+@media only screen and (max-width: 40em) {
+  .orbit-stack-on-small .orbit-slides-container {
+    height: auto !important; }
+  .orbit-stack-on-small .orbit-slides-container > * {
+    margin: 0  !important;
+    opacity: 1 !important;
+    position: relative; }
+  .orbit-stack-on-small .orbit-slide-number {
+    display: none; }
+
+  .orbit-timer {
+    display: none; }
+
+  .orbit-next, .orbit-prev {
+    display: none; }
+
+  .orbit-bullets {
+    display: none; } }
+[data-magellan-expedition], [data-magellan-expedition-clone] {
+  background: #FFFFFF;
+  min-width: 100%;
+  padding: 10px;
+  z-index: 50; }
+  [data-magellan-expedition] .sub-nav, [data-magellan-expedition-clone] .sub-nav {
+    margin-bottom: 0; }
+    [data-magellan-expedition] .sub-nav dd, [data-magellan-expedition-clone] .sub-nav dd {
+      margin-bottom: 0; }
+    [data-magellan-expedition] .sub-nav a, [data-magellan-expedition-clone] .sub-nav a {
+      line-height: 1.8em; }
+
+.icon-bar {
+  display: inline-block;
+  font-size: 0;
+  width: 100%;
+  background: #333333; }
+  .icon-bar > * {
+    display: block;
+    float: left;
+    font-size: 1rem;
+    margin: 0 auto;
+    padding: 1.25rem;
+    text-align: center;
+    width: 25%; }
+    .icon-bar > * i, .icon-bar > * img {
+      display: block;
+      margin: 0 auto; }
+      .icon-bar > * i + label, .icon-bar > * img + label {
+        margin-top: .0625rem; }
+    .icon-bar > * i {
+      font-size: 1.875rem;
+      vertical-align: middle; }
+    .icon-bar > * img {
+      height: 1.875rem;
+      width: 1.875rem; }
+  .icon-bar.label-right > * i, .icon-bar.label-right > * img {
+    display: inline-block;
+    margin: 0 .0625rem 0 0; }
+    .icon-bar.label-right > * i + label, .icon-bar.label-right > * img + label {
+      margin-top: 0; }
+  .icon-bar.label-right > * label {
+    display: inline-block; }
+  .icon-bar.vertical.label-right > * {
+    text-align: left; }
+  .icon-bar.vertical, .icon-bar.small-vertical {
+    height: 100%;
+    width: auto; }
+    .icon-bar.vertical .item, .icon-bar.small-vertical .item {
+      float: none;
+      margin: auto;
+      width: auto; }
+  @media only screen and (min-width: 40.0625em) {
+    .icon-bar.medium-vertical {
+      height: 100%;
+      width: auto; }
+      .icon-bar.medium-vertical .item {
+        float: none;
+        margin: auto;
+        width: auto; } }
+  @media only screen and (min-width: 64.0625em) {
+    .icon-bar.large-vertical {
+      height: 100%;
+      width: auto; }
+      .icon-bar.large-vertical .item {
+        float: none;
+        margin: auto;
+        width: auto; } }
+  .icon-bar > * {
+    font-size: 1rem;
+    padding: 1.25rem; }
+    .icon-bar > * i + label, .icon-bar > * img + label {
+      margin-top: .0625rem;
+      font-size: 1rem; }
+    .icon-bar > * i {
+      font-size: 1.875rem; }
+    .icon-bar > * img {
+      height: 1.875rem;
+      width: 1.875rem; }
+  .icon-bar > * label {
+    color: #FFFFFF; }
+  .icon-bar > * i {
+    color: #FFFFFF; }
+  .icon-bar > a:hover {
+    background: #008CBA; }
+    .icon-bar > a:hover label {
+      color: #FFFFFF; }
+    .icon-bar > a:hover i {
+      color: #FFFFFF; }
+  .icon-bar > a.active {
+    background: #008CBA; }
+    .icon-bar > a.active label {
+      color: #FFFFFF; }
+    .icon-bar > a.active i {
+      color: #FFFFFF; }
+  .icon-bar .item.disabled {
+    cursor: not-allowed;
+    opacity: 0.7;
+    pointer-events: none; }
+    .icon-bar .item.disabled > * {
+      opacity: 0.7;
+      cursor: not-allowed; }
+  .icon-bar.two-up .item {
+    width: 50%; }
+  .icon-bar.two-up.vertical .item, .icon-bar.two-up.small-vertical .item {
+    width: auto; }
+  @media only screen and (min-width: 40.0625em) {
+    .icon-bar.two-up.medium-vertical .item {
+      width: auto; } }
+  @media only screen and (min-width: 64.0625em) {
+    .icon-bar.two-up.large-vertical .item {
+      width: auto; } }
+  .icon-bar.three-up .item {
+    width: 33.3333%; }
+  .icon-bar.three-up.vertical .item, .icon-bar.three-up.small-vertical .item {
+    width: auto; }
+  @media only screen and (min-width: 40.0625em) {
+    .icon-bar.three-up.medium-vertical .item {
+      width: auto; } }
+  @media only screen and (min-width: 64.0625em) {
+    .icon-bar.three-up.large-vertical .item {
+      width: auto; } }
+  .icon-bar.four-up .item {
+    width: 25%; }
+  .icon-bar.four-up.vertical .item, .icon-bar.four-up.small-vertical .item {
+    width: auto; }
+  @media only screen and (min-width: 40.0625em) {
+    .icon-bar.four-up.medium-vertical .item {
+      width: auto; } }
+  @media only screen and (min-width: 64.0625em) {
+    .icon-bar.four-up.large-vertical .item {
+      width: auto; } }
+  .icon-bar.five-up .item {
+    width: 20%; }
+  .icon-bar.five-up.vertical .item, .icon-bar.five-up.small-vertical .item {
+    width: auto; }
+  @media only screen and (min-width: 40.0625em) {
+    .icon-bar.five-up.medium-vertical .item {
+      width: auto; } }
+  @media only screen and (min-width: 64.0625em) {
+    .icon-bar.five-up.large-vertical .item {
+      width: auto; } }
+  .icon-bar.six-up .item {
+    width: 16.66667%; }
+  .icon-bar.six-up.vertical .item, .icon-bar.six-up.small-vertical .item {
+    width: auto; }
+  @media only screen and (min-width: 40.0625em) {
+    .icon-bar.six-up.medium-vertical .item {
+      width: auto; } }
+  @media only screen and (min-width: 64.0625em) {
+    .icon-bar.six-up.large-vertical .item {
+      width: auto; } }
+  .icon-bar.seven-up .item {
+    width: 14.28571%; }
+  .icon-bar.seven-up.vertical .item, .icon-bar.seven-up.small-vertical .item {
+    width: auto; }
+  @media only screen and (min-width: 40.0625em) {
+    .icon-bar.seven-up.medium-vertical .item {
+      width: auto; } }
+  @media only screen and (min-width: 64.0625em) {
+    .icon-bar.seven-up.large-vertical .item {
+      width: auto; } }
+  .icon-bar.eight-up .item {
+    width: 12.5%; }
+  .icon-bar.eight-up.vertical .item, .icon-bar.eight-up.small-vertical .item {
+    width: auto; }
+  @media only screen and (min-width: 40.0625em) {
+    .icon-bar.eight-up.medium-vertical .item {
+      width: auto; } }
+  @media only screen and (min-width: 64.0625em) {
+    .icon-bar.eight-up.large-vertical .item {
+      width: auto; } }
+
+.icon-bar.two-up .item {
+  width: 50%; }
+.icon-bar.two-up.vertical .item, .icon-bar.two-up.small-vertical .item {
+  width: auto; }
+@media only screen and (min-width: 40.0625em) {
+  .icon-bar.two-up.medium-vertical .item {
+    width: auto; } }
+@media only screen and (min-width: 64.0625em) {
+  .icon-bar.two-up.large-vertical .item {
+    width: auto; } }
+.icon-bar.three-up .item {
+  width: 33.3333%; }
+.icon-bar.three-up.vertical .item, .icon-bar.three-up.small-vertical .item {
+  width: auto; }
+@media only screen and (min-width: 40.0625em) {
+  .icon-bar.three-up.medium-vertical .item {
+    width: auto; } }
+@media only screen and (min-width: 64.0625em) {
+  .icon-bar.three-up.large-vertical .item {
+    width: auto; } }
+.icon-bar.four-up .item {
+  width: 25%; }
+.icon-bar.four-up.vertical .item, .icon-bar.four-up.small-vertical .item {
+  width: auto; }
+@media only screen and (min-width: 40.0625em) {
+  .icon-bar.four-up.medium-vertical .item {
+    width: auto; } }
+@media only screen and (min-width: 64.0625em) {
+  .icon-bar.four-up.large-vertical .item {
+    width: auto; } }
+.icon-bar.five-up .item {
+  width: 20%; }
+.icon-bar.five-up.vertical .item, .icon-bar.five-up.small-vertical .item {
+  width: auto; }
+@media only screen and (min-width: 40.0625em) {
+  .icon-bar.five-up.medium-vertical .item {
+    width: auto; } }
+@media only screen and (min-width: 64.0625em) {
+  .icon-bar.five-up.large-vertical .item {
+    width: auto; } }
+.icon-bar.six-up .item {
+  width: 16.66667%; }
+.icon-bar.six-up.vertical .item, .icon-bar.six-up.small-vertical .item {
+  width: auto; }
+@media only screen and (min-width: 40.0625em) {
+  .icon-bar.six-up.medium-vertical .item {
+    width: auto; } }
+@media only screen and (min-width: 64.0625em) {
+  .icon-bar.six-up.large-vertical .item {
+    width: auto; } }
+.icon-bar.seven-up .item {
+  width: 14.28571%; }
+.icon-bar.seven-up.vertical .item, .icon-bar.seven-up.small-vertical .item {
+  width: auto; }
+@media only screen and (min-width: 40.0625em) {
+  .icon-bar.seven-up.medium-vertical .item {
+    width: auto; } }
+@media only screen and (min-width: 64.0625em) {
+  .icon-bar.seven-up.large-vertical .item {
+    width: auto; } }
+.icon-bar.eight-up .item {
+  width: 12.5%; }
+.icon-bar.eight-up.vertical .item, .icon-bar.eight-up.small-vertical .item {
+  width: auto; }
+@media only screen and (min-width: 40.0625em) {
+  .icon-bar.eight-up.medium-vertical .item {
+    width: auto; } }
+@media only screen and (min-width: 64.0625em) {
+  .icon-bar.eight-up.large-vertical .item {
+    width: auto; } }
+
+.tabs {
+  margin-bottom: 0 !important;
+  margin-left: 0; }
+  .tabs:before, .tabs:after {
+    content: " ";
+    display: table; }
+  .tabs:after {
+    clear: both; }
+  .tabs dd,
+  .tabs .tab-title {
+    float: left;
+    list-style: none;
+    margin-bottom: 0 !important;
+    position: relative; }
+    .tabs dd > a,
+    .tabs .tab-title > a {
+      display: block;
+      background-color: #EFEFEF;
+      color: #222222;
+      font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+      font-size: 1rem;
+      padding: 1rem 2rem; }
+      .tabs dd > a:hover,
+      .tabs .tab-title > a:hover {
+        background-color: #e1e1e1; }
+    .tabs dd.active > a,
+    .tabs .tab-title.active > a {
+      background-color: #FFFFFF;
+      color: #222222; }
+  .tabs.radius dd:first-child a,
+  .tabs.radius .tab:first-child a {
+    -webkit-border-bottom-left-radius: 3px;
+    -webkit-border-top-left-radius: 3px;
+    border-bottom-left-radius: 3px;
+    border-top-left-radius: 3px; }
+  .tabs.radius dd:last-child a,
+  .tabs.radius .tab:last-child a {
+    -webkit-border-bottom-right-radius: 3px;
+    -webkit-border-top-right-radius: 3px;
+    border-bottom-right-radius: 3px;
+    border-top-right-radius: 3px; }
+  .tabs.vertical dd,
+  .tabs.vertical .tab-title {
+    position: inherit;
+    float: none;
+    display: block;
+    top: auto; }
+
+.tabs-content {
+  margin-bottom: 1.5rem;
+  width: 100%; }
+  .tabs-content:before, .tabs-content:after {
+    content: " ";
+    display: table; }
+  .tabs-content:after {
+    clear: both; }
+  .tabs-content > .content {
+    display: none;
+    float: left;
+    padding: 0.9375rem 0;
+    width: 100%; }
+    .tabs-content > .content.active {
+      display: block;
+      float: none; }
+    .tabs-content > .content.contained {
+      padding: 0.9375rem; }
+  .tabs-content.vertical {
+    display: block; }
+    .tabs-content.vertical > .content {
+      padding: 0 0.9375rem; }
+
+@media only screen and (min-width: 40.0625em) {
+  .tabs.vertical {
+    float: left;
+    margin: 0;
+    margin-bottom: 1.25rem !important;
+    max-width: 20%;
+    width: 20%; }
+
+  .tabs-content.vertical {
+    float: left;
+    margin-left: -1px;
+    max-width: 80%;
+    padding-left: 1rem;
+    width: 80%; } }
+.no-js .tabs-content > .content {
+  display: block;
+  float: none; }
+
+ul.pagination {
+  display: block;
+  margin-left: -0.3125rem;
+  min-height: 1.5rem; }
+  ul.pagination li {
+    color: #222222;
+    font-size: 0.875rem;
+    height: 1.5rem;
+    margin-left: 0.3125rem; }
+    ul.pagination li a, ul.pagination li button {
+      border-radius: 3px;
+      transition: background-color 300ms ease-out;
+      background: none;
+      color: #999999;
+      display: block;
+      font-size: 1em;
+      font-weight: normal;
+      line-height: inherit;
+      padding: 0.0625rem 0.625rem 0.0625rem; }
+    ul.pagination li:hover a,
+    ul.pagination li a:focus, ul.pagination li:hover button,
+    ul.pagination li button:focus {
+      background: #e6e6e6; }
+    ul.pagination li.unavailable a, ul.pagination li.unavailable button {
+      cursor: default;
+      color: #999999;
+      pointer-events: none; }
+    ul.pagination li.unavailable:hover a, ul.pagination li.unavailable a:focus, ul.pagination li.unavailable:hover button, ul.pagination li.unavailable button:focus {
+      background: transparent; }
+    ul.pagination li.current a, ul.pagination li.current button {
+      background: #008CBA;
+      color: #FFFFFF;
+      cursor: default;
+      font-weight: bold; }
+      ul.pagination li.current a:hover, ul.pagination li.current a:focus, ul.pagination li.current button:hover, ul.pagination li.current button:focus {
+        background: #008CBA; }
+  ul.pagination li {
+    display: block;
+    float: left; }
+
+/* Pagination centred wrapper */
+.pagination-centered {
+  text-align: center; }
+  .pagination-centered ul.pagination li {
+    display: inline-block;
+    float: none; }
+
+.side-nav {
+  display: block;
+  font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+  list-style-position: outside;
+  list-style-type: none;
+  margin: 0;
+  padding: 0.875rem 0; }
+  .side-nav li {
+    font-size: 0.875rem;
+    font-weight: normal;
+    margin: 0 0 0.4375rem 0; }
+    .side-nav li a:not(.button) {
+      color: #008CBA;
+      display: block;
+      margin: 0;
+      padding: 0.4375rem 0.875rem; }
+      .side-nav li a:not(.button):hover, .side-nav li a:not(.button):focus {
+        background: rgba(0, 0, 0, 0.025);
+        color: #1cc7ff; }
+      .side-nav li a:not(.button):active {
+        color: #1cc7ff; }
+    .side-nav li.active > a:first-child:not(.button) {
+      color: #1cc7ff;
+      font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+      font-weight: normal; }
+    .side-nav li.divider {
+      border-top: 1px solid;
+      height: 0;
+      list-style: none;
+      padding: 0;
+      border-top-color: #e6e6e6; }
+    .side-nav li.heading {
+      color: #008CBA;
+      font-size: 0.875rem;
+      font-weight: bold;
+      text-transform: uppercase; }
+
+.accordion {
+  margin-bottom: 0;
+  margin-left: 0; }
+  .accordion:before, .accordion:after {
+    content: " ";
+    display: table; }
+  .accordion:after {
+    clear: both; }
+  .accordion .accordion-navigation, .accordion dd {
+    display: block;
+    margin-bottom: 0 !important; }
+    .accordion .accordion-navigation.active > a, .accordion dd.active > a {
+      background: #e8e8e8;
+      color: #222222; }
+    .accordion .accordion-navigation > a, .accordion dd > a {
+      background: #EFEFEF;
+      color: #222222;
+      display: block;
+      font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+      font-size: 1rem;
+      padding: 1rem; }
+      .accordion .accordion-navigation > a:hover, .accordion dd > a:hover {
+        background: #e3e3e3; }
+    .accordion .accordion-navigation > .content, .accordion dd > .content {
+      display: none;
+      padding: 0.9375rem; }
+      .accordion .accordion-navigation > .content.active, .accordion dd > .content.active {
+        background: #FFFFFF;
+        display: block; }
+
+.text-left {
+  text-align: left !important; }
+
+.text-right {
+  text-align: right !important; }
+
+.text-center {
+  text-align: center !important; }
+
+.text-justify {
+  text-align: justify !important; }
+
+@media only screen and (max-width: 40em) {
+  .small-only-text-left {
+    text-align: left !important; }
+
+  .small-only-text-right {
+    text-align: right !important; }
+
+  .small-only-text-center {
+    text-align: center !important; }
+
+  .small-only-text-justify {
+    text-align: justify !important; } }
+@media only screen {
+  .small-text-left {
+    text-align: left !important; }
+
+  .small-text-right {
+    text-align: right !important; }
+
+  .small-text-center {
+    text-align: center !important; }
+
+  .small-text-justify {
+    text-align: justify !important; } }
+@media only screen and (min-width: 40.0625em) and (max-width: 64em) {
+  .medium-only-text-left {
+    text-align: left !important; }
+
+  .medium-only-text-right {
+    text-align: right !important; }
+
+  .medium-only-text-center {
+    text-align: center !important; }
+
+  .medium-only-text-justify {
+    text-align: justify !important; } }
+@media only screen and (min-width: 40.0625em) {
+  .medium-text-left {
+    text-align: left !important; }
+
+  .medium-text-right {
+    text-align: right !important; }
+
+  .medium-text-center {
+    text-align: center !important; }
+
+  .medium-text-justify {
+    text-align: justify !important; } }
+@media only screen and (min-width: 64.0625em) and (max-width: 90em) {
+  .large-only-text-left {
+    text-align: left !important; }
+
+  .large-only-text-right {
+    text-align: right !important; }
+
+  .large-only-text-center {
+    text-align: center !important; }
+
+  .large-only-text-justify {
+    text-align: justify !important; } }
+@media only screen and (min-width: 64.0625em) {
+  .large-text-left {
+    text-align: left !important; }
+
+  .large-text-right {
+    text-align: right !important; }
+
+  .large-text-center {
+    text-align: center !important; }
+
+  .large-text-justify {
+    text-align: justify !important; } }
+@media only screen and (min-width: 90.0625em) and (max-width: 120em) {
+  .xlarge-only-text-left {
+    text-align: left !important; }
+
+  .xlarge-only-text-right {
+    text-align: right !important; }
+
+  .xlarge-only-text-center {
+    text-align: center !important; }
+
+  .xlarge-only-text-justify {
+    text-align: justify !important; } }
+@media only screen and (min-width: 90.0625em) {
+  .xlarge-text-left {
+    text-align: left !important; }
+
+  .xlarge-text-right {
+    text-align: right !important; }
+
+  .xlarge-text-center {
+    text-align: center !important; }
+
+  .xlarge-text-justify {
+    text-align: justify !important; } }
+@media only screen and (min-width: 120.0625em) and (max-width: 6249999.9375em) {
+  .xxlarge-only-text-left {
+    text-align: left !important; }
+
+  .xxlarge-only-text-right {
+    text-align: right !important; }
+
+  .xxlarge-only-text-center {
+    text-align: center !important; }
+
+  .xxlarge-only-text-justify {
+    text-align: justify !important; } }
+@media only screen and (min-width: 120.0625em) {
+  .xxlarge-text-left {
+    text-align: left !important; }
+
+  .xxlarge-text-right {
+    text-align: right !important; }
+
+  .xxlarge-text-center {
+    text-align: center !important; }
+
+  .xxlarge-text-justify {
+    text-align: justify !important; } }
+/* Typography resets */
+div,
+dl,
+dt,
+dd,
+ul,
+ol,
+li,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+pre,
+form,
+p,
+blockquote,
+th,
+td {
+  margin: 0;
+  padding: 0; }
+
+/* Default Link Styles */
+a {
+  color: #008CBA;
+  line-height: inherit;
+  text-decoration: none; }
+  a:hover, a:focus {
+    color: #0078a0; }
+  a img {
+    border: none; }
+
+/* Default paragraph styles */
+p {
+  font-family: inherit;
+  font-size: 1rem;
+  font-weight: normal;
+  line-height: 1.6;
+  margin-bottom: 1.25rem;
+  text-rendering: optimizeLegibility; }
+  p.lead {
+    font-size: 1.21875rem;
+    line-height: 1.6; }
+  p aside {
+    font-size: 0.875rem;
+    font-style: italic;
+    line-height: 1.35; }
+
+/* Default header styles */
+h1, h2, h3, h4, h5, h6 {
+  color: #222222;
+  font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1.4;
+  margin-bottom: 0.5rem;
+  margin-top: 0.2rem;
+  text-rendering: optimizeLegibility; }
+  h1 small, h2 small, h3 small, h4 small, h5 small, h6 small {
+    color: #6f6f6f;
+    font-size: 60%;
+    line-height: 0; }
+
+h1 {
+  font-size: 2.125rem; }
+
+h2 {
+  font-size: 1.6875rem; }
+
+h3 {
+  font-size: 1.375rem; }
+
+h4 {
+  font-size: 1.125rem; }
+
+h5 {
+  font-size: 1.125rem; }
+
+h6 {
+  font-size: 1rem; }
+
+.subheader {
+  line-height: 1.4;
+  color: #6f6f6f;
+  font-weight: normal;
+  margin-top: 0.2rem;
+  margin-bottom: 0.5rem; }
+
+hr {
+  border: solid #DDDDDD;
+  border-width: 1px 0 0;
+  clear: both;
+  height: 0;
+  margin: 1.25rem 0 1.1875rem; }
+
+/* Helpful Typography Defaults */
+em,
+i {
+  font-style: italic;
+  line-height: inherit; }
+
+strong,
+b {
+  font-weight: bold;
+  line-height: inherit; }
+
+small {
+  font-size: 60%;
+  line-height: inherit; }
+
+code {
+  background-color: #f8f8f8;
+  border-color: #dfdfdf;
+  border-style: solid;
+  border-width: 1px;
+  color: #333333;
+  font-family: Consolas, "Liberation Mono", Courier, monospace;
+  font-weight: normal;
+  padding: 0.125rem 0.3125rem 0.0625rem; }
+
+/* Lists */
+ul,
+ol,
+dl {
+  font-family: inherit;
+  font-size: 1rem;
+  line-height: 1.6;
+  list-style-position: outside;
+  margin-bottom: 1.25rem; }
+
+ul {
+  margin-left: 1.1rem; }
+
+/* Unordered Lists */
+ul li ul,
+ul li ol {
+  margin-left: 1.25rem;
+  margin-bottom: 0; }
+ul.square li ul, ul.circle li ul, ul.disc li ul {
+  list-style: inherit; }
+ul.square {
+  list-style-type: square;
+  margin-left: 1.1rem; }
+ul.circle {
+  list-style-type: circle;
+  margin-left: 1.1rem; }
+ul.disc {
+  list-style-type: disc;
+  margin-left: 1.1rem; }
+
+/* Ordered Lists */
+ol {
+  margin-left: 1.4rem; }
+  ol li ul,
+  ol li ol {
+    margin-left: 1.25rem;
+    margin-bottom: 0; }
+
+.no-bullet {
+  list-style-type: none;
+  margin-left: 0; }
+  .no-bullet li ul,
+  .no-bullet li ol {
+    margin-left: 1.25rem;
+    margin-bottom: 0;
+    list-style: none; }
+
+/* Definition Lists */
+dl dt {
+  margin-bottom: 0.3rem;
+  font-weight: bold; }
+dl dd {
+  margin-bottom: 0.75rem; }
+
+/* Abbreviations */
+abbr,
+acronym {
+  text-transform: uppercase;
+  font-size: 90%;
+  color: #222;
+  cursor: help; }
+
+abbr {
+  text-transform: none; }
+  abbr[title] {
+    border-bottom: 1px dotted #DDDDDD; }
+
+/* Blockquotes */
+blockquote {
+  margin: 0 0 1.25rem;
+  padding: 0.5625rem 1.25rem 0 1.1875rem;
+  border-left: 1px solid #DDDDDD; }
+  blockquote cite {
+    display: block;
+    font-size: 0.8125rem;
+    color: #555555; }
+    blockquote cite:before {
+      content: "\2014 \0020"; }
+    blockquote cite a,
+    blockquote cite a:visited {
+      color: #555555; }
+
+blockquote,
+blockquote p {
+  line-height: 1.6;
+  color: #6f6f6f; }
+
+/* Microformats */
+.vcard {
+  display: inline-block;
+  margin: 0 0 1.25rem 0;
+  border: 1px solid #DDDDDD;
+  padding: 0.625rem 0.75rem; }
+  .vcard li {
+    margin: 0;
+    display: block; }
+  .vcard .fn {
+    font-weight: bold;
+    font-size: 0.9375rem; }
+
+.vevent .summary {
+  font-weight: bold; }
+.vevent abbr {
+  cursor: default;
+  text-decoration: none;
+  font-weight: bold;
+  border: none;
+  padding: 0 0.0625rem; }
+
+@media only screen and (min-width: 40.0625em) {
+  h1, h2, h3, h4, h5, h6 {
+    line-height: 1.4; }
+
+  h1 {
+    font-size: 2.75rem; }
+
+  h2 {
+    font-size: 2.3125rem; }
+
+  h3 {
+    font-size: 1.6875rem; }
+
+  h4 {
+    font-size: 1.4375rem; }
+
+  h5 {
+    font-size: 1.125rem; }
+
+  h6 {
+    font-size: 1rem; } }
+/*
+ * Print styles.
+ *
+ * Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/
+ * Credit to Paul Irish and HTML5 Boilerplate (html5boilerplate.com)
+*/
+@media print {
+  * {
+    background: transparent !important;
+    color: #000000 !important;
+    /* Black prints faster: h5bp.com/s */
+    box-shadow: none !important;
+    text-shadow: none !important; }
+
+  a,
+  a:visited {
+    text-decoration: underline; }
+
+  a[href]:after {
+    content: " (" attr(href) ")"; }
+
+  abbr[title]:after {
+    content: " (" attr(title) ")"; }
+
+  .ir a:after,
+  a[href^="javascript:"]:after,
+  a[href^="#"]:after {
+    content: ""; }
+
+  pre,
+  blockquote {
+    border: 1px solid #999999;
+    page-break-inside: avoid; }
+
+  thead {
+    display: table-header-group;
+    /* h5bp.com/t */ }
+
+  tr,
+  img {
+    page-break-inside: avoid; }
+
+  img {
+    max-width: 100% !important; }
+
+  @page {
+    margin: 0.34in; }
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3; }
+
+  h2,
+  h3 {
+    page-break-after: avoid; } }
+.split.button {
+  position: relative;
+  padding-right: 5.0625rem; }
+  .split.button span {
+    display: block;
+    height: 100%;
+    position: absolute;
+    right: 0;
+    top: 0;
+    border-left: solid 1px; }
+    .split.button span:after {
+      position: absolute;
+      content: "";
+      width: 0;
+      height: 0;
+      display: block;
+      border-style: inset;
+      top: 50%;
+      left: 50%; }
+    .split.button span:active {
+      background-color: rgba(0, 0, 0, 0.1); }
+  .split.button span {
+    border-left-color: rgba(255, 255, 255, 0.5); }
+  .split.button span {
+    width: 3.09375rem; }
+    .split.button span:after {
+      border-top-style: solid;
+      border-width: 0.375rem;
+      margin-left: -0.375rem;
+      top: 48%; }
+  .split.button span:after {
+    border-color: #FFFFFF transparent transparent transparent; }
+  .split.button.secondary span {
+    border-left-color: rgba(255, 255, 255, 0.5); }
+  .split.button.secondary span:after {
+    border-color: #FFFFFF transparent transparent transparent; }
+  .split.button.alert span {
+    border-left-color: rgba(255, 255, 255, 0.5); }
+  .split.button.success span {
+    border-left-color: rgba(255, 255, 255, 0.5); }
+  .split.button.tiny {
+    padding-right: 3.75rem; }
+    .split.button.tiny span {
+      width: 2.25rem; }
+      .split.button.tiny span:after {
+        border-top-style: solid;
+        border-width: 0.375rem;
+        margin-left: -0.375rem;
+        top: 48%; }
+  .split.button.small {
+    padding-right: 4.375rem; }
+    .split.button.small span {
+      width: 2.625rem; }
+      .split.button.small span:after {
+        border-top-style: solid;
+        border-width: 0.4375rem;
+        margin-left: -0.375rem;
+        top: 48%; }
+  .split.button.large {
+    padding-right: 5.5rem; }
+    .split.button.large span {
+      width: 3.4375rem; }
+      .split.button.large span:after {
+        border-top-style: solid;
+        border-width: 0.3125rem;
+        margin-left: -0.375rem;
+        top: 48%; }
+  .split.button.expand {
+    padding-left: 2rem; }
+  .split.button.secondary span:after {
+    border-color: #333333 transparent transparent transparent; }
+  .split.button.radius span {
+    -webkit-border-bottom-right-radius: 3px;
+    -webkit-border-top-right-radius: 3px;
+    border-bottom-right-radius: 3px;
+    border-top-right-radius: 3px; }
+  .split.button.round span {
+    -webkit-border-bottom-right-radius: 1000px;
+    -webkit-border-top-right-radius: 1000px;
+    border-bottom-right-radius: 1000px;
+    border-top-right-radius: 1000px; }
+  .split.button.no-pip span:before {
+    border-style: none; }
+  .split.button.no-pip span:after {
+    border-style: none; }
+  .split.button.no-pip span > i {
+    display: block;
+    left: 50%;
+    margin-left: -0.28889em;
+    margin-top: -0.48889em;
+    position: absolute;
+    top: 50%; }
+
+.reveal-modal-bg {
+  background: #000000;
+  background: rgba(0, 0, 0, 0.45);
+  bottom: 0;
+  display: none;
+  left: 0;
+  position: fixed;
+  right: 0;
+  top: 0;
+  z-index: 1004;
+  left: 0; }
+
+.reveal-modal {
+  border-radius: 3px;
+  display: none;
+  position: absolute;
+  top: 0;
+  visibility: hidden;
+  width: 100%;
+  z-index: 1005;
+  left: 0;
+  background-color: #FFFFFF;
+  padding: 1.875rem;
+  border: solid 1px #666666;
+  box-shadow: 0 0 10px rgba(0, 0, 0, 0.4); }
+  @media only screen and (max-width: 40em) {
+    .reveal-modal {
+      min-height: 100vh; } }
+  .reveal-modal .column, .reveal-modal .columns {
+    min-width: 0; }
+  .reveal-modal > :first-child {
+    margin-top: 0; }
+  .reveal-modal > :last-child {
+    margin-bottom: 0; }
+  @media only screen and (min-width: 40.0625em) {
+    .reveal-modal {
+      left: 0;
+      margin: 0 auto;
+      max-width: 62.5rem;
+      right: 0;
+      width: 80%; } }
+  @media only screen and (min-width: 40.0625em) {
+    .reveal-modal {
+      top: 6.25rem; } }
+  .reveal-modal.radius {
+    box-shadow: none;
+    border-radius: 3px; }
+  .reveal-modal.round {
+    box-shadow: none;
+    border-radius: 1000px; }
+  .reveal-modal.collapse {
+    padding: 0;
+    box-shadow: none; }
+  @media only screen and (min-width: 40.0625em) {
+    .reveal-modal.tiny {
+      left: 0;
+      margin: 0 auto;
+      max-width: 62.5rem;
+      right: 0;
+      width: 30%; } }
+  @media only screen and (min-width: 40.0625em) {
+    .reveal-modal.small {
+      left: 0;
+      margin: 0 auto;
+      max-width: 62.5rem;
+      right: 0;
+      width: 40%; } }
+  @media only screen and (min-width: 40.0625em) {
+    .reveal-modal.medium {
+      left: 0;
+      margin: 0 auto;
+      max-width: 62.5rem;
+      right: 0;
+      width: 60%; } }
+  @media only screen and (min-width: 40.0625em) {
+    .reveal-modal.large {
+      left: 0;
+      margin: 0 auto;
+      max-width: 62.5rem;
+      right: 0;
+      width: 70%; } }
+  @media only screen and (min-width: 40.0625em) {
+    .reveal-modal.xlarge {
+      left: 0;
+      margin: 0 auto;
+      max-width: 62.5rem;
+      right: 0;
+      width: 95%; } }
+  .reveal-modal.full {
+    height: 100vh;
+    height: 100%;
+    left: 0;
+    margin-left: 0 !important;
+    max-width: none !important;
+    min-height: 100vh;
+    top: 0; }
+    @media only screen and (min-width: 40.0625em) {
+      .reveal-modal.full {
+        left: 0;
+        margin: 0 auto;
+        max-width: 62.5rem;
+        right: 0;
+        width: 100%; } }
+  .reveal-modal.toback {
+    z-index: 1003; }
+  .reveal-modal .close-reveal-modal {
+    color: #AAAAAA;
+    cursor: pointer;
+    font-size: 2.5rem;
+    font-weight: bold;
+    line-height: 1;
+    position: absolute;
+    top: 0.625rem;
+    right: 1.375rem; }
+
+/* Tooltips */
+.has-tip {
+  border-bottom: dotted 1px #CCCCCC;
+  color: #333333;
+  cursor: help;
+  font-weight: bold; }
+  .has-tip:hover, .has-tip:focus {
+    border-bottom: dotted 1px #003f54;
+    color: #008CBA; }
+  .has-tip.tip-left, .has-tip.tip-right {
+    float: none !important; }
+
+.tooltip {
+  background: #333333;
+  color: #FFFFFF;
+  display: none;
+  font-size: 0.875rem;
+  font-weight: normal;
+  line-height: 1.3;
+  max-width: 300px;
+  padding: 0.75rem;
+  position: absolute;
+  width: 100%;
+  z-index: 1006;
+  left: 50%; }
+  .tooltip > .nub {
+    border: solid 5px;
+    border-color: transparent transparent #333333 transparent;
+    display: block;
+    height: 0;
+    pointer-events: none;
+    position: absolute;
+    top: -10px;
+    width: 0;
+    left: 5px; }
+    .tooltip > .nub.rtl {
+      left: auto;
+      right: 5px; }
+  .tooltip.radius {
+    border-radius: 3px; }
+  .tooltip.round {
+    border-radius: 1000px; }
+    .tooltip.round > .nub {
+      left: 2rem; }
+  .tooltip.opened {
+    border-bottom: dotted 1px #003f54 !important;
+    color: #008CBA !important; }
+
+.tap-to-close {
+  color: #777777;
+  display: block;
+  font-size: 0.625rem;
+  font-weight: normal; }
+
+@media only screen {
+  .tooltip > .nub {
+    border-color: transparent transparent #333333 transparent;
+    top: -10px; }
+  .tooltip.tip-top > .nub {
+    border-color: #333333 transparent transparent transparent;
+    bottom: -10px;
+    top: auto; }
+  .tooltip.tip-left, .tooltip.tip-right {
+    float: none !important; }
+  .tooltip.tip-left > .nub {
+    border-color: transparent transparent transparent #333333;
+    left: auto;
+    margin-top: -5px;
+    right: -10px;
+    top: 50%; }
+  .tooltip.tip-right > .nub {
+    border-color: transparent #333333 transparent transparent;
+    left: -10px;
+    margin-top: -5px;
+    right: auto;
+    top: 50%; } }
+/* Clearing Styles */
+.clearing-thumbs, [data-clearing] {
+  list-style: none;
+  margin-left: 0;
+  margin-bottom: 0; }
+  .clearing-thumbs:before, .clearing-thumbs:after, [data-clearing]:before, [data-clearing]:after {
+    content: " ";
+    display: table; }
+  .clearing-thumbs:after, [data-clearing]:after {
+    clear: both; }
+  .clearing-thumbs li, [data-clearing] li {
+    float: left;
+    margin-right: 10px; }
+  .clearing-thumbs[class*="block-grid-"] li, [data-clearing][class*="block-grid-"] li {
+    margin-right: 0; }
+
+.clearing-blackout {
+  background: #333333;
+  height: 100%;
+  position: fixed;
+  top: 0;
+  width: 100%;
+  z-index: 998;
+  left: 0; }
+  .clearing-blackout .clearing-close {
+    display: block; }
+
+.clearing-container {
+  height: 100%;
+  margin: 0;
+  overflow: hidden;
+  position: relative;
+  z-index: 998; }
+
+.clearing-touch-label {
+  color: #AAAAAA;
+  font-size: .6em;
+  left: 50%;
+  position: absolute;
+  top: 50%; }
+
+.visible-img {
+  height: 95%;
+  position: relative; }
+  .visible-img img {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    -webkit-transform: translateY(-50%) translateX(-50%);
+    -moz-transform: translateY(-50%) translateX(-50%);
+    -ms-transform: translateY(-50%) translateX(-50%);
+    -o-transform: translateY(-50%) translateX(-50%);
+    transform: translateY(-50%) translateX(-50%);
+    max-height: 100%;
+    max-width: 100%; }
+
+.clearing-caption {
+  background: #333333;
+  bottom: 0;
+  color: #CCCCCC;
+  font-size: 0.875em;
+  line-height: 1.3;
+  margin-bottom: 0;
+  padding: 10px 30px 20px;
+  position: absolute;
+  text-align: center;
+  width: 100%;
+  left: 0; }
+
+.clearing-close {
+  color: #CCCCCC;
+  display: none;
+  font-size: 30px;
+  line-height: 1;
+  padding-left: 20px;
+  padding-top: 10px;
+  z-index: 999; }
+  .clearing-close:hover, .clearing-close:focus {
+    color: #CCCCCC; }
+
+.clearing-assembled .clearing-container {
+  height: 100%; }
+  .clearing-assembled .clearing-container .carousel > ul {
+    display: none; }
+
+.clearing-feature li {
+  display: none; }
+  .clearing-feature li.clearing-featured-img {
+    display: block; }
+
+@media only screen and (min-width: 40.0625em) {
+  .clearing-main-prev,
+  .clearing-main-next {
+    height: 100%;
+    position: absolute;
+    top: 0;
+    width: 40px; }
+    .clearing-main-prev > span,
+    .clearing-main-next > span {
+      border: solid 12px;
+      display: block;
+      height: 0;
+      position: absolute;
+      top: 50%;
+      width: 0; }
+      .clearing-main-prev > span:hover,
+      .clearing-main-next > span:hover {
+        opacity: .8; }
+
+  .clearing-main-prev {
+    left: 0; }
+    .clearing-main-prev > span {
+      left: 5px;
+      border-color: transparent;
+      border-right-color: #CCCCCC; }
+
+  .clearing-main-next {
+    right: 0; }
+    .clearing-main-next > span {
+      border-color: transparent;
+      border-left-color: #CCCCCC; }
+
+  .clearing-main-prev.disabled,
+  .clearing-main-next.disabled {
+    opacity: .3; }
+
+  .clearing-assembled .clearing-container .carousel {
+    background: rgba(51, 51, 51, 0.8);
+    height: 120px;
+    margin-top: 10px;
+    text-align: center; }
+    .clearing-assembled .clearing-container .carousel > ul {
+      display: inline-block;
+      z-index: 999;
+      height: 100%;
+      position: relative;
+      float: none; }
+      .clearing-assembled .clearing-container .carousel > ul li {
+        clear: none;
+        cursor: pointer;
+        display: block;
+        float: left;
+        margin-right: 0;
+        min-height: inherit;
+        opacity: .4;
+        overflow: hidden;
+        padding: 0;
+        position: relative;
+        width: 120px; }
+        .clearing-assembled .clearing-container .carousel > ul li.fix-height img {
+          height: 100%;
+          max-width: none; }
+        .clearing-assembled .clearing-container .carousel > ul li a.th {
+          border: none;
+          box-shadow: none;
+          display: block; }
+        .clearing-assembled .clearing-container .carousel > ul li img {
+          cursor: pointer !important;
+          width: 100% !important; }
+        .clearing-assembled .clearing-container .carousel > ul li.visible {
+          opacity: 1; }
+        .clearing-assembled .clearing-container .carousel > ul li:hover {
+          opacity: .8; }
+  .clearing-assembled .clearing-container .visible-img {
+    background: #333333;
+    height: 85%;
+    overflow: hidden; }
+
+  .clearing-close {
+    padding-left: 0;
+    padding-top: 0;
+    position: absolute;
+    top: 10px;
+    right: 20px; } }
+/* Progress Bar */
+.progress {
+  background-color: #F6F6F6;
+  border: 1px solid white;
+  height: 1.5625rem;
+  margin-bottom: 0.625rem;
+  padding: 0.125rem; }
+  .progress .meter {
+    background: #008CBA;
+    display: block;
+    height: 100%;
+    float: left;
+    width: 0%; }
+    .progress .meter.secondary {
+      background: #e7e7e7;
+      display: block;
+      height: 100%;
+      float: left;
+      width: 0%; }
+    .progress .meter.success {
+      background: #43AC6A;
+      display: block;
+      height: 100%;
+      float: left;
+      width: 0%; }
+    .progress .meter.alert {
+      background: #f04124;
+      display: block;
+      height: 100%;
+      float: left;
+      width: 0%; }
+  .progress.secondary .meter {
+    background: #e7e7e7;
+    display: block;
+    height: 100%;
+    float: left;
+    width: 0%; }
+  .progress.success .meter {
+    background: #43AC6A;
+    display: block;
+    height: 100%;
+    float: left;
+    width: 0%; }
+  .progress.alert .meter {
+    background: #f04124;
+    display: block;
+    height: 100%;
+    float: left;
+    width: 0%; }
+  .progress.radius {
+    border-radius: 3px; }
+    .progress.radius .meter {
+      border-radius: 2px; }
+  .progress.round {
+    border-radius: 1000px; }
+    .progress.round .meter {
+      border-radius: 999px; }
+
+.sub-nav {
+  display: block;
+  margin: -0.25rem 0 1.125rem;
+  overflow: hidden;
+  padding-top: 0.25rem;
+  width: auto; }
+  .sub-nav dt {
+    text-transform: uppercase; }
+  .sub-nav dt,
+  .sub-nav dd,
+  .sub-nav li {
+    color: #999999;
+    float: left;
+    font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+    font-size: 0.875rem;
+    font-weight: normal;
+    margin-left: 1rem;
+    margin-bottom: 0; }
+    .sub-nav dt a,
+    .sub-nav dd a,
+    .sub-nav li a {
+      color: #999999;
+      padding: 0.1875rem 1rem;
+      text-decoration: none; }
+      .sub-nav dt a:hover,
+      .sub-nav dd a:hover,
+      .sub-nav li a:hover {
+        color: #737373; }
+    .sub-nav dt.active a,
+    .sub-nav dd.active a,
+    .sub-nav li.active a {
+      border-radius: 3px;
+      background: #008CBA;
+      color: #FFFFFF;
+      cursor: default;
+      font-weight: normal;
+      padding: 0.1875rem 1rem; }
+      .sub-nav dt.active a:hover,
+      .sub-nav dd.active a:hover,
+      .sub-nav li.active a:hover {
+        background: #0078a0; }
+
+/* Foundation Joyride */
+.joyride-list {
+  display: none; }
+
+/* Default styles for the container */
+.joyride-tip-guide {
+  background: #333333;
+  color: #FFFFFF;
+  display: none;
+  font-family: inherit;
+  font-weight: normal;
+  position: absolute;
+  top: 0;
+  width: 95%;
+  z-index: 103;
+  left: 2.5%; }
+
+.lt-ie9 .joyride-tip-guide {
+  margin-left: -400px;
+  max-width: 800px;
+  left: 50%; }
+
+.joyride-content-wrapper {
+  padding: 1.125rem 1.25rem 1.5rem;
+  width: 100%; }
+  .joyride-content-wrapper .button {
+    margin-bottom: 0 !important; }
+  .joyride-content-wrapper .joyride-prev-tip {
+    margin-right: 10px; }
+
+/* Add a little css triangle pip, older browser just miss out on the fanciness of it */
+.joyride-tip-guide .joyride-nub {
+  border: 10px solid #333333;
+  display: block;
+  height: 0;
+  position: absolute;
+  width: 0;
+  left: 22px; }
+  .joyride-tip-guide .joyride-nub.top {
+    border-color: #333333;
+    border-top-color: transparent !important;
+    border-top-style: solid;
+    border-left-color: transparent !important;
+    border-right-color: transparent !important;
+    top: -20px; }
+  .joyride-tip-guide .joyride-nub.bottom {
+    border-color: #333333 !important;
+    border-bottom-color: transparent !important;
+    border-bottom-style: solid;
+    border-left-color: transparent !important;
+    border-right-color: transparent !important;
+    bottom: -20px; }
+  .joyride-tip-guide .joyride-nub.right {
+    right: -20px; }
+  .joyride-tip-guide .joyride-nub.left {
+    left: -20px; }
+
+/* Typography */
+.joyride-tip-guide h1,
+.joyride-tip-guide h2,
+.joyride-tip-guide h3,
+.joyride-tip-guide h4,
+.joyride-tip-guide h5,
+.joyride-tip-guide h6 {
+  color: #FFFFFF;
+  font-weight: bold;
+  line-height: 1.25;
+  margin: 0; }
+
+.joyride-tip-guide p {
+  font-size: 0.875rem;
+  line-height: 1.3;
+  margin: 0 0 1.125rem 0; }
+
+.joyride-timer-indicator-wrap {
+  border: solid 1px #555555;
+  bottom: 1rem;
+  height: 3px;
+  position: absolute;
+  width: 50px;
+  right: 1.0625rem; }
+
+.joyride-timer-indicator {
+  background: #666666;
+  display: block;
+  height: inherit;
+  width: 0; }
+
+.joyride-close-tip {
+  color: #777777 !important;
+  font-size: 24px;
+  font-weight: normal;
+  line-height: .5 !important;
+  position: absolute;
+  text-decoration: none;
+  top: 10px;
+  right: 12px; }
+  .joyride-close-tip:hover, .joyride-close-tip:focus {
+    color: #EEEEEE !important; }
+
+.joyride-modal-bg {
+  background: rgba(0, 0, 0, 0.5);
+  cursor: pointer;
+  display: none;
+  height: 100%;
+  position: fixed;
+  top: 0;
+  width: 100%;
+  z-index: 100;
+  left: 0; }
+
+.joyride-expose-wrapper {
+  background-color: #FFFFFF;
+  border-radius: 3px;
+  box-shadow: 0 0 15px #FFFFFF;
+  position: absolute;
+  z-index: 102; }
+
+.joyride-expose-cover {
+  background: transparent;
+  border-radius: 3px;
+  left: 0;
+  position: absolute;
+  top: 0;
+  z-index: 9999; }
+
+/* Styles for screens that are at least 768px; */
+@media only screen {
+  .joyride-tip-guide {
+    width: 300px;
+    left: inherit; }
+    .joyride-tip-guide .joyride-nub.bottom {
+      border-color: #333333 !important;
+      border-bottom-color: transparent !important;
+      border-left-color: transparent !important;
+      border-right-color: transparent !important;
+      bottom: -20px; }
+    .joyride-tip-guide .joyride-nub.right {
+      border-color: #333333 !important;
+      border-right-color: transparent !important;
+      border-bottom-color: transparent !important;
+      border-top-color: transparent !important;
+      left: auto;
+      right: -20px;
+      top: 22px; }
+    .joyride-tip-guide .joyride-nub.left {
+      border-color: #333333 !important;
+      border-bottom-color: transparent !important;
+      border-left-color: transparent !important;
+      border-top-color: transparent !important;
+      left: -20px;
+      right: auto;
+      top: 22px; } }
+.label {
+  display: inline-block;
+  font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+  font-weight: normal;
+  line-height: 1;
+  margin-bottom: auto;
+  position: relative;
+  text-align: center;
+  text-decoration: none;
+  white-space: nowrap;
+  padding: 0.25rem 0.5rem 0.25rem;
+  font-size: 0.6875rem;
+  background-color: #008CBA;
+  color: #FFFFFF; }
+  .label.radius {
+    border-radius: 3px; }
+  .label.round {
+    border-radius: 1000px; }
+  .label.alert {
+    background-color: #f04124;
+    color: #FFFFFF; }
+  .label.warning {
+    background-color: #f08a24;
+    color: #FFFFFF; }
+  .label.success {
+    background-color: #43AC6A;
+    color: #FFFFFF; }
+  .label.secondary {
+    background-color: #e7e7e7;
+    color: #333333; }
+  .label.info {
+    background-color: #a0d3e8;
+    color: #333333; }
+
+.off-canvas-wrap {
+  -webkit-backface-visibility: hidden;
+  position: relative;
+  width: 100%;
+  overflow: hidden; }
+  .off-canvas-wrap.move-right, .off-canvas-wrap.move-left, .off-canvas-wrap.move-bottom, .off-canvas-wrap.move-top {
+    min-height: 100%;
+    -webkit-overflow-scrolling: touch; }
+
+.inner-wrap {
+  position: relative;
+  width: 100%;
+  -webkit-transition: -webkit-transform 500ms ease;
+  -moz-transition: -moz-transform 500ms ease;
+  -ms-transition: -ms-transform 500ms ease;
+  -o-transition: -o-transform 500ms ease;
+  transition: transform 500ms ease; }
+  .inner-wrap:before, .inner-wrap:after {
+    content: " ";
+    display: table; }
+  .inner-wrap:after {
+    clear: both; }
+
+.tab-bar {
+  -webkit-backface-visibility: hidden;
+  background: #333333;
+  color: #FFFFFF;
+  height: 2.8125rem;
+  line-height: 2.8125rem;
+  position: relative; }
+  .tab-bar h1, .tab-bar h2, .tab-bar h3, .tab-bar h4, .tab-bar h5, .tab-bar h6 {
+    color: #FFFFFF;
+    font-weight: bold;
+    line-height: 2.8125rem;
+    margin: 0; }
+  .tab-bar h1, .tab-bar h2, .tab-bar h3, .tab-bar h4 {
+    font-size: 1.125rem; }
+
+.left-small {
+  height: 2.8125rem;
+  position: absolute;
+  top: 0;
+  width: 2.8125rem;
+  border-right: solid 1px #1a1a1a;
+  left: 0; }
+
+.right-small {
+  height: 2.8125rem;
+  position: absolute;
+  top: 0;
+  width: 2.8125rem;
+  border-left: solid 1px #1a1a1a;
+  right: 0; }
+
+.tab-bar-section {
+  height: 2.8125rem;
+  padding: 0 0.625rem;
+  position: absolute;
+  text-align: center;
+  top: 0; }
+  .tab-bar-section.left {
+    text-align: left; }
+  .tab-bar-section.right {
+    text-align: right; }
+  .tab-bar-section.left {
+    left: 0;
+    right: 2.8125rem; }
+  .tab-bar-section.right {
+    left: 2.8125rem;
+    right: 0; }
+  .tab-bar-section.middle {
+    left: 2.8125rem;
+    right: 2.8125rem; }
+
+.tab-bar .menu-icon {
+  color: #FFFFFF;
+  display: block;
+  height: 2.8125rem;
+  padding: 0;
+  position: relative;
+  text-indent: 2.1875rem;
+  transform: translate3d(0, 0, 0);
+  width: 2.8125rem; }
+  .tab-bar .menu-icon span::after {
+    content: "";
+    display: block;
+    height: 0;
+    position: absolute;
+    top: 50%;
+    margin-top: -0.5rem;
+    left: 0.90625rem;
+    box-shadow: 0 0 0 1px #FFFFFF, 0 7px 0 1px #FFFFFF, 0 14px 0 1px #FFFFFF;
+    width: 1rem; }
+  .tab-bar .menu-icon span:hover:after {
+    box-shadow: 0 0 0 1px #b3b3b3, 0 7px 0 1px #b3b3b3, 0 14px 0 1px #b3b3b3; }
+
+.left-off-canvas-menu {
+  -webkit-backface-visibility: hidden;
+  background: #333333;
+  bottom: 0;
+  box-sizing: content-box;
+  -webkit-overflow-scrolling: touch;
+  -ms-overflow-style: -ms-autohiding-scrollbar;
+  overflow-x: hidden;
+  overflow-y: auto;
+  position: absolute;
+  transition: transform 500ms ease 0s;
+  width: 15.625rem;
+  z-index: 1001;
+  -webkit-transform: translate3d(-100%, 0, 0);
+  -moz-transform: translate3d(-100%, 0, 0);
+  -ms-transform: translate(-100%, 0);
+  -o-transform: translate3d(-100%, 0, 0);
+  transform: translate3d(-100%, 0, 0);
+  left: 0;
+  top: 0; }
+  .left-off-canvas-menu * {
+    -webkit-backface-visibility: hidden; }
+
+.right-off-canvas-menu {
+  -webkit-backface-visibility: hidden;
+  background: #333333;
+  bottom: 0;
+  box-sizing: content-box;
+  -webkit-overflow-scrolling: touch;
+  -ms-overflow-style: -ms-autohiding-scrollbar;
+  overflow-x: hidden;
+  overflow-y: auto;
+  position: absolute;
+  transition: transform 500ms ease 0s;
+  width: 15.625rem;
+  z-index: 1001;
+  -webkit-transform: translate3d(100%, 0, 0);
+  -moz-transform: translate3d(100%, 0, 0);
+  -ms-transform: translate(100%, 0);
+  -o-transform: translate3d(100%, 0, 0);
+  transform: translate3d(100%, 0, 0);
+  right: 0;
+  top: 0; }
+  .right-off-canvas-menu * {
+    -webkit-backface-visibility: hidden; }
+
+.top-off-canvas-menu {
+  -webkit-backface-visibility: hidden;
+  background: #333333;
+  bottom: 0;
+  box-sizing: content-box;
+  -webkit-overflow-scrolling: touch;
+  -ms-overflow-style: -ms-autohiding-scrollbar;
+  overflow-x: hidden;
+  overflow-y: auto;
+  position: absolute;
+  transition: transform 500ms ease 0s;
+  width: 15.625rem;
+  z-index: 1001;
+  -webkit-transform: translate3d(0, -100%, 0);
+  -moz-transform: translate3d(0, -100%, 0);
+  -ms-transform: translate(0, -100%);
+  -o-transform: translate3d(0, -100%, 0);
+  transform: translate3d(0, -100%, 0);
+  top: 0;
+  width: 100%;
+  height: 18.75rem; }
+  .top-off-canvas-menu * {
+    -webkit-backface-visibility: hidden; }
+
+.bottom-off-canvas-menu {
+  -webkit-backface-visibility: hidden;
+  background: #333333;
+  bottom: 0;
+  box-sizing: content-box;
+  -webkit-overflow-scrolling: touch;
+  -ms-overflow-style: -ms-autohiding-scrollbar;
+  overflow-x: hidden;
+  overflow-y: auto;
+  position: absolute;
+  transition: transform 500ms ease 0s;
+  width: 15.625rem;
+  z-index: 1001;
+  -webkit-transform: translate3d(0, 100%, 0);
+  -moz-transform: translate3d(0, 100%, 0);
+  -ms-transform: translate(0, 100%);
+  -o-transform: translate3d(0, 100%, 0);
+  transform: translate3d(0, 100%, 0);
+  bottom: 0;
+  width: 100%;
+  height: 18.75rem; }
+  .bottom-off-canvas-menu * {
+    -webkit-backface-visibility: hidden; }
+
+ul.off-canvas-list {
+  list-style-type: none;
+  margin: 0;
+  padding: 0; }
+  ul.off-canvas-list li label {
+    background: #444444;
+    border-bottom: none;
+    border-top: 1px solid #5e5e5e;
+    color: #999999;
+    display: block;
+    font-size: 0.75rem;
+    font-weight: bold;
+    margin: 0;
+    padding: 0.3rem 0.9375rem;
+    text-transform: uppercase; }
+  ul.off-canvas-list li a {
+    border-bottom: 1px solid #262626;
+    color: rgba(255, 255, 255, 0.7);
+    display: block;
+    padding: 0.66667rem;
+    transition: background 300ms ease; }
+    ul.off-canvas-list li a:hover {
+      background: #242424; }
+    ul.off-canvas-list li a:active {
+      background: #242424; }
+
+.move-right > .inner-wrap {
+  -webkit-transform: translate3d(15.625rem, 0, 0);
+  -moz-transform: translate3d(15.625rem, 0, 0);
+  -ms-transform: translate(15.625rem, 0);
+  -o-transform: translate3d(15.625rem, 0, 0);
+  transform: translate3d(15.625rem, 0, 0); }
+.move-right .exit-off-canvas {
+  -webkit-backface-visibility: hidden;
+  box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5);
+  cursor: pointer;
+  transition: background 300ms ease;
+  -webkit-tap-highlight-color: transparent;
+  background: rgba(255, 255, 255, 0.2);
+  bottom: 0;
+  display: block;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 1002; }
+  @media only screen and (min-width: 40.0625em) {
+    .move-right .exit-off-canvas:hover {
+      background: rgba(255, 255, 255, 0.05); } }
+
+.move-left > .inner-wrap {
+  -webkit-transform: translate3d(-15.625rem, 0, 0);
+  -moz-transform: translate3d(-15.625rem, 0, 0);
+  -ms-transform: translate(-15.625rem, 0);
+  -o-transform: translate3d(-15.625rem, 0, 0);
+  transform: translate3d(-15.625rem, 0, 0); }
+.move-left .exit-off-canvas {
+  -webkit-backface-visibility: hidden;
+  box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5);
+  cursor: pointer;
+  transition: background 300ms ease;
+  -webkit-tap-highlight-color: transparent;
+  background: rgba(255, 255, 255, 0.2);
+  bottom: 0;
+  display: block;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 1002; }
+  @media only screen and (min-width: 40.0625em) {
+    .move-left .exit-off-canvas:hover {
+      background: rgba(255, 255, 255, 0.05); } }
+
+.move-top > .inner-wrap {
+  -webkit-transform: translate3d(0, -18.75rem, 0);
+  -moz-transform: translate3d(0, -18.75rem, 0);
+  -ms-transform: translate(0, -18.75rem);
+  -o-transform: translate3d(0, -18.75rem, 0);
+  transform: translate3d(0, -18.75rem, 0); }
+.move-top .exit-off-canvas {
+  -webkit-backface-visibility: hidden;
+  box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5);
+  cursor: pointer;
+  transition: background 300ms ease;
+  -webkit-tap-highlight-color: transparent;
+  background: rgba(255, 255, 255, 0.2);
+  bottom: 0;
+  display: block;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 1002; }
+  @media only screen and (min-width: 40.0625em) {
+    .move-top .exit-off-canvas:hover {
+      background: rgba(255, 255, 255, 0.05); } }
+
+.move-bottom > .inner-wrap {
+  -webkit-transform: translate3d(0, 18.75rem, 0);
+  -moz-transform: translate3d(0, 18.75rem, 0);
+  -ms-transform: translate(0, 18.75rem);
+  -o-transform: translate3d(0, 18.75rem, 0);
+  transform: translate3d(0, 18.75rem, 0); }
+.move-bottom .exit-off-canvas {
+  -webkit-backface-visibility: hidden;
+  box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5);
+  cursor: pointer;
+  transition: background 300ms ease;
+  -webkit-tap-highlight-color: transparent;
+  background: rgba(255, 255, 255, 0.2);
+  bottom: 0;
+  display: block;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 1002; }
+  @media only screen and (min-width: 40.0625em) {
+    .move-bottom .exit-off-canvas:hover {
+      background: rgba(255, 255, 255, 0.05); } }
+
+.offcanvas-overlap .left-off-canvas-menu, .offcanvas-overlap .right-off-canvas-menu,
+.offcanvas-overlap .top-off-canvas-menu, .offcanvas-overlap .bottom-off-canvas-menu {
+  -ms-transform: none;
+  -webkit-transform: none;
+  -moz-transform: none;
+  -o-transform: none;
+  transform: none;
+  z-index: 1003; }
+.offcanvas-overlap .exit-off-canvas {
+  -webkit-backface-visibility: hidden;
+  box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5);
+  cursor: pointer;
+  transition: background 300ms ease;
+  -webkit-tap-highlight-color: transparent;
+  background: rgba(255, 255, 255, 0.2);
+  bottom: 0;
+  display: block;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 1002; }
+  @media only screen and (min-width: 40.0625em) {
+    .offcanvas-overlap .exit-off-canvas:hover {
+      background: rgba(255, 255, 255, 0.05); } }
+
+.offcanvas-overlap-left .right-off-canvas-menu {
+  -ms-transform: none;
+  -webkit-transform: none;
+  -moz-transform: none;
+  -o-transform: none;
+  transform: none;
+  z-index: 1003; }
+.offcanvas-overlap-left .exit-off-canvas {
+  -webkit-backface-visibility: hidden;
+  box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5);
+  cursor: pointer;
+  transition: background 300ms ease;
+  -webkit-tap-highlight-color: transparent;
+  background: rgba(255, 255, 255, 0.2);
+  bottom: 0;
+  display: block;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 1002; }
+  @media only screen and (min-width: 40.0625em) {
+    .offcanvas-overlap-left .exit-off-canvas:hover {
+      background: rgba(255, 255, 255, 0.05); } }
+
+.offcanvas-overlap-right .left-off-canvas-menu {
+  -ms-transform: none;
+  -webkit-transform: none;
+  -moz-transform: none;
+  -o-transform: none;
+  transform: none;
+  z-index: 1003; }
+.offcanvas-overlap-right .exit-off-canvas {
+  -webkit-backface-visibility: hidden;
+  box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5);
+  cursor: pointer;
+  transition: background 300ms ease;
+  -webkit-tap-highlight-color: transparent;
+  background: rgba(255, 255, 255, 0.2);
+  bottom: 0;
+  display: block;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 1002; }
+  @media only screen and (min-width: 40.0625em) {
+    .offcanvas-overlap-right .exit-off-canvas:hover {
+      background: rgba(255, 255, 255, 0.05); } }
+
+.offcanvas-overlap-top .bottom-off-canvas-menu {
+  -ms-transform: none;
+  -webkit-transform: none;
+  -moz-transform: none;
+  -o-transform: none;
+  transform: none;
+  z-index: 1003; }
+.offcanvas-overlap-top .exit-off-canvas {
+  -webkit-backface-visibility: hidden;
+  box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5);
+  cursor: pointer;
+  transition: background 300ms ease;
+  -webkit-tap-highlight-color: transparent;
+  background: rgba(255, 255, 255, 0.2);
+  bottom: 0;
+  display: block;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 1002; }
+  @media only screen and (min-width: 40.0625em) {
+    .offcanvas-overlap-top .exit-off-canvas:hover {
+      background: rgba(255, 255, 255, 0.05); } }
+
+.offcanvas-overlap-bottom .top-off-canvas-menu {
+  -ms-transform: none;
+  -webkit-transform: none;
+  -moz-transform: none;
+  -o-transform: none;
+  transform: none;
+  z-index: 1003; }
+.offcanvas-overlap-bottom .exit-off-canvas {
+  -webkit-backface-visibility: hidden;
+  box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5);
+  cursor: pointer;
+  transition: background 300ms ease;
+  -webkit-tap-highlight-color: transparent;
+  background: rgba(255, 255, 255, 0.2);
+  bottom: 0;
+  display: block;
+  left: 0;
+  position: absolute;
+  right: 0;
+  top: 0;
+  z-index: 1002; }
+  @media only screen and (min-width: 40.0625em) {
+    .offcanvas-overlap-bottom .exit-off-canvas:hover {
+      background: rgba(255, 255, 255, 0.05); } }
+
+.no-csstransforms .left-off-canvas-menu {
+  left: -15.625rem; }
+.no-csstransforms .right-off-canvas-menu {
+  right: -15.625rem; }
+.no-csstransforms .top-off-canvas-menu {
+  top: -18.75rem; }
+.no-csstransforms .bottom-off-canvas-menu {
+  bottom: -18.75rem; }
+.no-csstransforms .move-left > .inner-wrap {
+  right: 15.625rem; }
+.no-csstransforms .move-right > .inner-wrap {
+  left: 15.625rem; }
+.no-csstransforms .move-top > .inner-wrap {
+  right: 18.75rem; }
+.no-csstransforms .move-bottom > .inner-wrap {
+  left: 18.75rem; }
+
+.left-submenu {
+  -webkit-backface-visibility: hidden;
+  -webkit-overflow-scrolling: touch;
+  background: #333333;
+  bottom: 0;
+  box-sizing: content-box;
+  margin: 0;
+  overflow-x: hidden;
+  overflow-y: auto;
+  position: absolute;
+  top: 0;
+  width: 15.625rem;
+  height: 18.75rem;
+  z-index: 1002;
+  -webkit-transform: translate3d(-100%, 0, 0);
+  -moz-transform: translate3d(-100%, 0, 0);
+  -ms-transform: translate(-100%, 0);
+  -o-transform: translate3d(-100%, 0, 0);
+  transform: translate3d(-100%, 0, 0);
+  left: 0;
+  -webkit-transition: -webkit-transform 500ms ease;
+  -moz-transition: -moz-transform 500ms ease;
+  -ms-transition: -ms-transform 500ms ease;
+  -o-transition: -o-transform 500ms ease;
+  transition: transform 500ms ease; }
+  .left-submenu * {
+    -webkit-backface-visibility: hidden; }
+  .left-submenu .back > a {
+    background: #444;
+    border-bottom: none;
+    border-top: 1px solid #5e5e5e;
+    color: #999999;
+    font-weight: bold;
+    padding: 0.3rem 0.9375rem;
+    text-transform: uppercase;
+    margin: 0; }
+    .left-submenu .back > a:hover {
+      background: #303030;
+      border-bottom: none;
+      border-top: 1px solid #5e5e5e; }
+    .left-submenu .back > a:before {
+      content: "\AB";
+      margin-right: .5rem;
+      display: inline; }
+  .left-submenu.move-right, .left-submenu.offcanvas-overlap-right, .left-submenu.offcanvas-overlap {
+    -webkit-transform: translate3d(0%, 0, 0);
+    -moz-transform: translate3d(0%, 0, 0);
+    -ms-transform: translate(0%, 0);
+    -o-transform: translate3d(0%, 0, 0);
+    transform: translate3d(0%, 0, 0); }
+
+.right-submenu {
+  -webkit-backface-visibility: hidden;
+  -webkit-overflow-scrolling: touch;
+  background: #333333;
+  bottom: 0;
+  box-sizing: content-box;
+  margin: 0;
+  overflow-x: hidden;
+  overflow-y: auto;
+  position: absolute;
+  top: 0;
+  width: 15.625rem;
+  height: 18.75rem;
+  z-index: 1002;
+  -webkit-transform: translate3d(100%, 0, 0);
+  -moz-transform: translate3d(100%, 0, 0);
+  -ms-transform: translate(100%, 0);
+  -o-transform: translate3d(100%, 0, 0);
+  transform: translate3d(100%, 0, 0);
+  right: 0;
+  -webkit-transition: -webkit-transform 500ms ease;
+  -moz-transition: -moz-transform 500ms ease;
+  -ms-transition: -ms-transform 500ms ease;
+  -o-transition: -o-transform 500ms ease;
+  transition: transform 500ms ease; }
+  .right-submenu * {
+    -webkit-backface-visibility: hidden; }
+  .right-submenu .back > a {
+    background: #444;
+    border-bottom: none;
+    border-top: 1px solid #5e5e5e;
+    color: #999999;
+    font-weight: bold;
+    padding: 0.3rem 0.9375rem;
+    text-transform: uppercase;
+    margin: 0; }
+    .right-submenu .back > a:hover {
+      background: #303030;
+      border-bottom: none;
+      border-top: 1px solid #5e5e5e; }
+    .right-submenu .back > a:after {
+      content: "\BB";
+      margin-left: .5rem;
+      display: inline; }
+  .right-submenu.move-left, .right-submenu.offcanvas-overlap-left, .right-submenu.offcanvas-overlap {
+    -webkit-transform: translate3d(0%, 0, 0);
+    -moz-transform: translate3d(0%, 0, 0);
+    -ms-transform: translate(0%, 0);
+    -o-transform: translate3d(0%, 0, 0);
+    transform: translate3d(0%, 0, 0); }
+
+.top-submenu {
+  -webkit-backface-visibility: hidden;
+  -webkit-overflow-scrolling: touch;
+  background: #333333;
+  bottom: 0;
+  box-sizing: content-box;
+  margin: 0;
+  overflow-x: hidden;
+  overflow-y: auto;
+  position: absolute;
+  top: 0;
+  width: 15.625rem;
+  height: 18.75rem;
+  z-index: 1002;
+  -webkit-transform: translate3d(0, -100%, 0);
+  -moz-transform: translate3d(0, -100%, 0);
+  -ms-transform: translate(0, -100%);
+  -o-transform: translate3d(0, -100%, 0);
+  transform: translate3d(0, -100%, 0);
+  top: 0;
+  width: 100%;
+  -webkit-transition: -webkit-transform 500ms ease;
+  -moz-transition: -moz-transform 500ms ease;
+  -ms-transition: -ms-transform 500ms ease;
+  -o-transition: -o-transform 500ms ease;
+  transition: transform 500ms ease; }
+  .top-submenu * {
+    -webkit-backface-visibility: hidden; }
+  .top-submenu .back > a {
+    background: #444;
+    border-bottom: none;
+    border-top: 1px solid #5e5e5e;
+    color: #999999;
+    font-weight: bold;
+    padding: 0.3rem 0.9375rem;
+    text-transform: uppercase;
+    margin: 0; }
+    .top-submenu .back > a:hover {
+      background: #303030;
+      border-bottom: none;
+      border-top: 1px solid #5e5e5e; }
+  .top-submenu.move-bottom, .top-submenu.offcanvas-overlap-bottom, .top-submenu.offcanvas-overlap {
+    -webkit-transform: translate3d(0, 0%, 0);
+    -moz-transform: translate3d(0, 0%, 0);
+    -ms-transform: translate(0, 0%);
+    -o-transform: translate3d(0, 0%, 0);
+    transform: translate3d(0, 0%, 0); }
+
+.bottom-submenu {
+  -webkit-backface-visibility: hidden;
+  -webkit-overflow-scrolling: touch;
+  background: #333333;
+  bottom: 0;
+  box-sizing: content-box;
+  margin: 0;
+  overflow-x: hidden;
+  overflow-y: auto;
+  position: absolute;
+  top: 0;
+  width: 15.625rem;
+  height: 18.75rem;
+  z-index: 1002;
+  -webkit-transform: translate3d(0, 100%, 0);
+  -moz-transform: translate3d(0, 100%, 0);
+  -ms-transform: translate(0, 100%);
+  -o-transform: translate3d(0, 100%, 0);
+  transform: translate3d(0, 100%, 0);
+  bottom: 0;
+  width: 100%;
+  -webkit-transition: -webkit-transform 500ms ease;
+  -moz-transition: -moz-transform 500ms ease;
+  -ms-transition: -ms-transform 500ms ease;
+  -o-transition: -o-transform 500ms ease;
+  transition: transform 500ms ease; }
+  .bottom-submenu * {
+    -webkit-backface-visibility: hidden; }
+  .bottom-submenu .back > a {
+    background: #444;
+    border-bottom: none;
+    border-top: 1px solid #5e5e5e;
+    color: #999999;
+    font-weight: bold;
+    padding: 0.3rem 0.9375rem;
+    text-transform: uppercase;
+    margin: 0; }
+    .bottom-submenu .back > a:hover {
+      background: #303030;
+      border-bottom: none;
+      border-top: 1px solid #5e5e5e; }
+  .bottom-submenu.move-top, .bottom-submenu.offcanvas-overlap-top, .bottom-submenu.offcanvas-overlap {
+    -webkit-transform: translate3d(0, 0%, 0);
+    -moz-transform: translate3d(0, 0%, 0);
+    -ms-transform: translate(0, 0%);
+    -o-transform: translate3d(0, 0%, 0);
+    transform: translate3d(0, 0%, 0); }
+
+.left-off-canvas-menu ul.off-canvas-list li.has-submenu > a:after {
+  content: "\BB";
+  margin-left: .5rem;
+  display: inline; }
+
+.right-off-canvas-menu ul.off-canvas-list li.has-submenu > a:before {
+  content: "\AB";
+  margin-right: .5rem;
+  display: inline; }
+
+/* Foundation Dropdowns */
+.f-dropdown {
+  display: none;
+  left: -9999px;
+  list-style: none;
+  margin-left: 0;
+  position: absolute;
+  background: #FFFFFF;
+  border: solid 1px #cccccc;
+  font-size: 0.875rem;
+  height: auto;
+  max-height: none;
+  width: 100%;
+  z-index: 89;
+  margin-top: 2px;
+  max-width: 200px; }
+  .f-dropdown.open {
+    display: block; }
+  .f-dropdown > *:first-child {
+    margin-top: 0; }
+  .f-dropdown > *:last-child {
+    margin-bottom: 0; }
+  .f-dropdown:before {
+    border: inset 6px;
+    content: "";
+    display: block;
+    height: 0;
+    width: 0;
+    border-color: transparent transparent #FFFFFF transparent;
+    border-bottom-style: solid;
+    position: absolute;
+    top: -12px;
+    left: 10px;
+    z-index: 89; }
+  .f-dropdown:after {
+    border: inset 7px;
+    content: "";
+    display: block;
+    height: 0;
+    width: 0;
+    border-color: transparent transparent #cccccc transparent;
+    border-bottom-style: solid;
+    position: absolute;
+    top: -14px;
+    left: 9px;
+    z-index: 88; }
+  .f-dropdown.right:before {
+    left: auto;
+    right: 10px; }
+  .f-dropdown.right:after {
+    left: auto;
+    right: 9px; }
+  .f-dropdown.drop-right {
+    display: none;
+    left: -9999px;
+    list-style: none;
+    margin-left: 0;
+    position: absolute;
+    background: #FFFFFF;
+    border: solid 1px #cccccc;
+    font-size: 0.875rem;
+    height: auto;
+    max-height: none;
+    width: 100%;
+    z-index: 89;
+    margin-top: 0;
+    margin-left: 2px;
+    max-width: 200px; }
+    .f-dropdown.drop-right.open {
+      display: block; }
+    .f-dropdown.drop-right > *:first-child {
+      margin-top: 0; }
+    .f-dropdown.drop-right > *:last-child {
+      margin-bottom: 0; }
+    .f-dropdown.drop-right:before {
+      border: inset 6px;
+      content: "";
+      display: block;
+      height: 0;
+      width: 0;
+      border-color: transparent #FFFFFF transparent transparent;
+      border-right-style: solid;
+      position: absolute;
+      top: 10px;
+      left: -12px;
+      z-index: 89; }
+    .f-dropdown.drop-right:after {
+      border: inset 7px;
+      content: "";
+      display: block;
+      height: 0;
+      width: 0;
+      border-color: transparent #cccccc transparent transparent;
+      border-right-style: solid;
+      position: absolute;
+      top: 9px;
+      left: -14px;
+      z-index: 88; }
+  .f-dropdown.drop-left {
+    display: none;
+    left: -9999px;
+    list-style: none;
+    margin-left: 0;
+    position: absolute;
+    background: #FFFFFF;
+    border: solid 1px #cccccc;
+    font-size: 0.875rem;
+    height: auto;
+    max-height: none;
+    width: 100%;
+    z-index: 89;
+    margin-top: 0;
+    margin-left: -2px;
+    max-width: 200px; }
+    .f-dropdown.drop-left.open {
+      display: block; }
+    .f-dropdown.drop-left > *:first-child {
+      margin-top: 0; }
+    .f-dropdown.drop-left > *:last-child {
+      margin-bottom: 0; }
+    .f-dropdown.drop-left:before {
+      border: inset 6px;
+      content: "";
+      display: block;
+      height: 0;
+      width: 0;
+      border-color: transparent transparent transparent #FFFFFF;
+      border-left-style: solid;
+      position: absolute;
+      top: 10px;
+      right: -12px;
+      left: auto;
+      z-index: 89; }
+    .f-dropdown.drop-left:after {
+      border: inset 7px;
+      content: "";
+      display: block;
+      height: 0;
+      width: 0;
+      border-color: transparent transparent transparent #cccccc;
+      border-left-style: solid;
+      position: absolute;
+      top: 9px;
+      right: -14px;
+      left: auto;
+      z-index: 88; }
+  .f-dropdown.drop-top {
+    display: none;
+    left: -9999px;
+    list-style: none;
+    margin-left: 0;
+    position: absolute;
+    background: #FFFFFF;
+    border: solid 1px #cccccc;
+    font-size: 0.875rem;
+    height: auto;
+    max-height: none;
+    width: 100%;
+    z-index: 89;
+    margin-left: 0;
+    margin-top: -2px;
+    max-width: 200px; }
+    .f-dropdown.drop-top.open {
+      display: block; }
+    .f-dropdown.drop-top > *:first-child {
+      margin-top: 0; }
+    .f-dropdown.drop-top > *:last-child {
+      margin-bottom: 0; }
+    .f-dropdown.drop-top:before {
+      border: inset 6px;
+      content: "";
+      display: block;
+      height: 0;
+      width: 0;
+      border-color: #FFFFFF transparent transparent transparent;
+      border-top-style: solid;
+      bottom: -12px;
+      position: absolute;
+      top: auto;
+      left: 10px;
+      right: auto;
+      z-index: 89; }
+    .f-dropdown.drop-top:after {
+      border: inset 7px;
+      content: "";
+      display: block;
+      height: 0;
+      width: 0;
+      border-color: #cccccc transparent transparent transparent;
+      border-top-style: solid;
+      bottom: -14px;
+      position: absolute;
+      top: auto;
+      left: 9px;
+      right: auto;
+      z-index: 88; }
+  .f-dropdown li {
+    cursor: pointer;
+    font-size: 0.875rem;
+    line-height: 1.125rem;
+    margin: 0; }
+    .f-dropdown li:hover, .f-dropdown li:focus {
+      background: #EEEEEE; }
+    .f-dropdown li a {
+      display: block;
+      padding: 0.5rem;
+      color: #555555; }
+  .f-dropdown.content {
+    display: none;
+    left: -9999px;
+    list-style: none;
+    margin-left: 0;
+    position: absolute;
+    background: #FFFFFF;
+    border: solid 1px #cccccc;
+    font-size: 0.875rem;
+    height: auto;
+    max-height: none;
+    padding: 1.25rem;
+    width: 100%;
+    z-index: 89;
+    max-width: 200px; }
+    .f-dropdown.content.open {
+      display: block; }
+    .f-dropdown.content > *:first-child {
+      margin-top: 0; }
+    .f-dropdown.content > *:last-child {
+      margin-bottom: 0; }
+  .f-dropdown.radius {
+    border-radius: 3px; }
+  .f-dropdown.tiny {
+    max-width: 200px; }
+  .f-dropdown.small {
+    max-width: 300px; }
+  .f-dropdown.medium {
+    max-width: 500px; }
+  .f-dropdown.large {
+    max-width: 800px; }
+  .f-dropdown.mega {
+    width: 100% !important;
+    max-width: 100% !important; }
+    .f-dropdown.mega.open {
+      left: 0 !important; }
+
+table {
+  background: #FFFFFF;
+  border: solid 1px #DDDDDD;
+  margin-bottom: 1.25rem;
+  table-layout: auto; }
+  table caption {
+    background: transparent;
+    color: #222222;
+    font-size: 1rem;
+    font-weight: bold; }
+  table thead {
+    background: #F5F5F5; }
+    table thead tr th,
+    table thead tr td {
+      color: #222222;
+      font-size: 0.875rem;
+      font-weight: bold;
+      padding: 0.5rem 0.625rem 0.625rem; }
+  table tfoot {
+    background: #F5F5F5; }
+    table tfoot tr th,
+    table tfoot tr td {
+      color: #222222;
+      font-size: 0.875rem;
+      font-weight: bold;
+      padding: 0.5rem 0.625rem 0.625rem; }
+  table tr th,
+  table tr td {
+    color: #222222;
+    font-size: 0.875rem;
+    padding: 0.5625rem 0.625rem;
+    text-align: left; }
+  table tr.even, table tr.alt, table tr:nth-of-type(even) {
+    background: #F9F9F9; }
+  table thead tr th,
+  table tfoot tr th,
+  table tfoot tr td,
+  table tbody tr th,
+  table tbody tr td,
+  table tr td {
+    display: table-cell;
+    line-height: 1.125rem; }
+
+.range-slider {
+  border: 1px solid #DDDDDD;
+  margin: 1.25rem 0;
+  position: relative;
+  -ms-touch-action: none;
+  touch-action: none;
+  display: block;
+  height: 1rem;
+  width: 100%;
+  background: #FAFAFA; }
+  .range-slider.vertical-range {
+    border: 1px solid #DDDDDD;
+    margin: 1.25rem 0;
+    position: relative;
+    -ms-touch-action: none;
+    touch-action: none;
+    display: inline-block;
+    height: 12.5rem;
+    width: 1rem; }
+    .range-slider.vertical-range .range-slider-handle {
+      bottom: -10.5rem;
+      margin-left: -0.5rem;
+      margin-top: 0;
+      position: absolute; }
+    .range-slider.vertical-range .range-slider-active-segment {
+      border-bottom-left-radius: inherit;
+      border-bottom-right-radius: inherit;
+      border-top-left-radius: initial;
+      bottom: 0;
+      height: auto;
+      width: 0.875rem; }
+  .range-slider.radius {
+    background: #FAFAFA;
+    border-radius: 3px; }
+    .range-slider.radius .range-slider-handle {
+      background: #008CBA;
+      border-radius: 3px; }
+      .range-slider.radius .range-slider-handle:hover {
+        background: #007ba4; }
+  .range-slider.round {
+    background: #FAFAFA;
+    border-radius: 1000px; }
+    .range-slider.round .range-slider-handle {
+      background: #008CBA;
+      border-radius: 1000px; }
+      .range-slider.round .range-slider-handle:hover {
+        background: #007ba4; }
+  .range-slider.disabled, .range-slider[disabled] {
+    background: #FAFAFA;
+    cursor: not-allowed;
+    opacity: 0.7; }
+    .range-slider.disabled .range-slider-handle, .range-slider[disabled] .range-slider-handle {
+      background: #008CBA;
+      cursor: default;
+      opacity: 0.7; }
+      .range-slider.disabled .range-slider-handle:hover, .range-slider[disabled] .range-slider-handle:hover {
+        background: #007ba4; }
+
+.range-slider-active-segment {
+  background: #e5e5e5;
+  border-bottom-left-radius: inherit;
+  border-top-left-radius: inherit;
+  display: inline-block;
+  height: 0.875rem;
+  position: absolute; }
+
+.range-slider-handle {
+  border: 1px solid none;
+  cursor: pointer;
+  display: inline-block;
+  height: 1.375rem;
+  position: absolute;
+  top: -0.3125rem;
+  width: 2rem;
+  z-index: 1;
+  -ms-touch-action: manipulation;
+  touch-action: manipulation;
+  background: #008CBA; }
+  .range-slider-handle:hover {
+    background: #007ba4; }
+
+[class*="block-grid-"] {
+  display: block;
+  padding: 0;
+  margin: 0 -0.625rem; }
+  [class*="block-grid-"]:before, [class*="block-grid-"]:after {
+    content: " ";
+    display: table; }
+  [class*="block-grid-"]:after {
+    clear: both; }
+  [class*="block-grid-"] > li {
+    display: block;
+    float: left;
+    height: auto;
+    padding: 0 0.625rem 1.25rem; }
+
+@media only screen {
+  .small-block-grid-1 > li {
+    list-style: none;
+    width: 100%; }
+    .small-block-grid-1 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-1 > li:nth-of-type(1n+1) {
+      clear: both; }
+
+  .small-block-grid-2 > li {
+    list-style: none;
+    width: 50%; }
+    .small-block-grid-2 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-2 > li:nth-of-type(2n+1) {
+      clear: both; }
+
+  .small-block-grid-3 > li {
+    list-style: none;
+    width: 33.33333%; }
+    .small-block-grid-3 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-3 > li:nth-of-type(3n+1) {
+      clear: both; }
+
+  .small-block-grid-4 > li {
+    list-style: none;
+    width: 25%; }
+    .small-block-grid-4 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-4 > li:nth-of-type(4n+1) {
+      clear: both; }
+
+  .small-block-grid-5 > li {
+    list-style: none;
+    width: 20%; }
+    .small-block-grid-5 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-5 > li:nth-of-type(5n+1) {
+      clear: both; }
+
+  .small-block-grid-6 > li {
+    list-style: none;
+    width: 16.66667%; }
+    .small-block-grid-6 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-6 > li:nth-of-type(6n+1) {
+      clear: both; }
+
+  .small-block-grid-7 > li {
+    list-style: none;
+    width: 14.28571%; }
+    .small-block-grid-7 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-7 > li:nth-of-type(7n+1) {
+      clear: both; }
+
+  .small-block-grid-8 > li {
+    list-style: none;
+    width: 12.5%; }
+    .small-block-grid-8 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-8 > li:nth-of-type(8n+1) {
+      clear: both; }
+
+  .small-block-grid-9 > li {
+    list-style: none;
+    width: 11.11111%; }
+    .small-block-grid-9 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-9 > li:nth-of-type(9n+1) {
+      clear: both; }
+
+  .small-block-grid-10 > li {
+    list-style: none;
+    width: 10%; }
+    .small-block-grid-10 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-10 > li:nth-of-type(10n+1) {
+      clear: both; }
+
+  .small-block-grid-11 > li {
+    list-style: none;
+    width: 9.09091%; }
+    .small-block-grid-11 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-11 > li:nth-of-type(11n+1) {
+      clear: both; }
+
+  .small-block-grid-12 > li {
+    list-style: none;
+    width: 8.33333%; }
+    .small-block-grid-12 > li:nth-of-type(1n) {
+      clear: none; }
+    .small-block-grid-12 > li:nth-of-type(12n+1) {
+      clear: both; } }
+@media only screen and (min-width: 40.0625em) {
+  .medium-block-grid-1 > li {
+    list-style: none;
+    width: 100%; }
+    .medium-block-grid-1 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-1 > li:nth-of-type(1n+1) {
+      clear: both; }
+
+  .medium-block-grid-2 > li {
+    list-style: none;
+    width: 50%; }
+    .medium-block-grid-2 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-2 > li:nth-of-type(2n+1) {
+      clear: both; }
+
+  .medium-block-grid-3 > li {
+    list-style: none;
+    width: 33.33333%; }
+    .medium-block-grid-3 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-3 > li:nth-of-type(3n+1) {
+      clear: both; }
+
+  .medium-block-grid-4 > li {
+    list-style: none;
+    width: 25%; }
+    .medium-block-grid-4 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-4 > li:nth-of-type(4n+1) {
+      clear: both; }
+
+  .medium-block-grid-5 > li {
+    list-style: none;
+    width: 20%; }
+    .medium-block-grid-5 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-5 > li:nth-of-type(5n+1) {
+      clear: both; }
+
+  .medium-block-grid-6 > li {
+    list-style: none;
+    width: 16.66667%; }
+    .medium-block-grid-6 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-6 > li:nth-of-type(6n+1) {
+      clear: both; }
+
+  .medium-block-grid-7 > li {
+    list-style: none;
+    width: 14.28571%; }
+    .medium-block-grid-7 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-7 > li:nth-of-type(7n+1) {
+      clear: both; }
+
+  .medium-block-grid-8 > li {
+    list-style: none;
+    width: 12.5%; }
+    .medium-block-grid-8 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-8 > li:nth-of-type(8n+1) {
+      clear: both; }
+
+  .medium-block-grid-9 > li {
+    list-style: none;
+    width: 11.11111%; }
+    .medium-block-grid-9 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-9 > li:nth-of-type(9n+1) {
+      clear: both; }
+
+  .medium-block-grid-10 > li {
+    list-style: none;
+    width: 10%; }
+    .medium-block-grid-10 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-10 > li:nth-of-type(10n+1) {
+      clear: both; }
+
+  .medium-block-grid-11 > li {
+    list-style: none;
+    width: 9.09091%; }
+    .medium-block-grid-11 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-11 > li:nth-of-type(11n+1) {
+      clear: both; }
+
+  .medium-block-grid-12 > li {
+    list-style: none;
+    width: 8.33333%; }
+    .medium-block-grid-12 > li:nth-of-type(1n) {
+      clear: none; }
+    .medium-block-grid-12 > li:nth-of-type(12n+1) {
+      clear: both; } }
+@media only screen and (min-width: 64.0625em) {
+  .large-block-grid-1 > li {
+    list-style: none;
+    width: 100%; }
+    .large-block-grid-1 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-1 > li:nth-of-type(1n+1) {
+      clear: both; }
+
+  .large-block-grid-2 > li {
+    list-style: none;
+    width: 50%; }
+    .large-block-grid-2 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-2 > li:nth-of-type(2n+1) {
+      clear: both; }
+
+  .large-block-grid-3 > li {
+    list-style: none;
+    width: 33.33333%; }
+    .large-block-grid-3 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-3 > li:nth-of-type(3n+1) {
+      clear: both; }
+
+  .large-block-grid-4 > li {
+    list-style: none;
+    width: 25%; }
+    .large-block-grid-4 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-4 > li:nth-of-type(4n+1) {
+      clear: both; }
+
+  .large-block-grid-5 > li {
+    list-style: none;
+    width: 20%; }
+    .large-block-grid-5 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-5 > li:nth-of-type(5n+1) {
+      clear: both; }
+
+  .large-block-grid-6 > li {
+    list-style: none;
+    width: 16.66667%; }
+    .large-block-grid-6 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-6 > li:nth-of-type(6n+1) {
+      clear: both; }
+
+  .large-block-grid-7 > li {
+    list-style: none;
+    width: 14.28571%; }
+    .large-block-grid-7 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-7 > li:nth-of-type(7n+1) {
+      clear: both; }
+
+  .large-block-grid-8 > li {
+    list-style: none;
+    width: 12.5%; }
+    .large-block-grid-8 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-8 > li:nth-of-type(8n+1) {
+      clear: both; }
+
+  .large-block-grid-9 > li {
+    list-style: none;
+    width: 11.11111%; }
+    .large-block-grid-9 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-9 > li:nth-of-type(9n+1) {
+      clear: both; }
+
+  .large-block-grid-10 > li {
+    list-style: none;
+    width: 10%; }
+    .large-block-grid-10 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-10 > li:nth-of-type(10n+1) {
+      clear: both; }
+
+  .large-block-grid-11 > li {
+    list-style: none;
+    width: 9.09091%; }
+    .large-block-grid-11 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-11 > li:nth-of-type(11n+1) {
+      clear: both; }
+
+  .large-block-grid-12 > li {
+    list-style: none;
+    width: 8.33333%; }
+    .large-block-grid-12 > li:nth-of-type(1n) {
+      clear: none; }
+    .large-block-grid-12 > li:nth-of-type(12n+1) {
+      clear: both; } }
+.flex-video {
+  height: 0;
+  margin-bottom: 1rem;
+  overflow: hidden;
+  padding-bottom: 67.5%;
+  padding-top: 1.5625rem;
+  position: relative; }
+  .flex-video.widescreen {
+    padding-bottom: 56.34%; }
+  .flex-video.vimeo {
+    padding-top: 0; }
+  .flex-video iframe,
+  .flex-video object,
+  .flex-video embed,
+  .flex-video video {
+    height: 100%;
+    position: absolute;
+    top: 0;
+    width: 100%;
+    left: 0; }
+
+.keystroke,
+kbd {
+  background-color: #ededed;
+  border-color: #dddddd;
+  color: #222222;
+  border-style: solid;
+  border-width: 1px;
+  font-family: "Consolas", "Menlo", "Courier", monospace;
+  font-size: inherit;
+  margin: 0;
+  padding: 0.125rem 0.25rem 0;
+  border-radius: 3px; }
+
+.switch {
+  border: none;
+  margin-bottom: 1.5rem;
+  outline: 0;
+  padding: 0;
+  position: relative;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  user-select: none; }
+  .switch label {
+    background: #DDDDDD;
+    color: transparent;
+    cursor: pointer;
+    display: block;
+    margin-bottom: 1rem;
+    position: relative;
+    text-indent: 100%;
+    width: 4rem;
+    height: 2rem;
+    transition: left 0.15s ease-out; }
+  .switch input {
+    left: 10px;
+    opacity: 0;
+    padding: 0;
+    position: absolute;
+    top: 9px; }
+    .switch input + label {
+      margin-left: 0;
+      margin-right: 0; }
+  .switch label:after {
+    background: #FFFFFF;
+    content: "";
+    display: block;
+    height: 1.5rem;
+    left: .25rem;
+    position: absolute;
+    top: .25rem;
+    width: 1.5rem;
+    -webkit-transition: left 0.15s ease-out;
+    -moz-transition: left 0.15s ease-out;
+    -o-transition: translate3d(0, 0, 0);
+    transition: left 0.15s ease-out;
+    -webkit-transform: translate3d(0, 0, 0);
+    -moz-transform: translate3d(0, 0, 0);
+    -ms-transform: translate3d(0, 0, 0);
+    -o-transform: translate3d(0, 0, 0);
+    transform: translate3d(0, 0, 0); }
+  .switch input:checked + label {
+    background: #008CBA; }
+  .switch input:checked + label:after {
+    left: 2.25rem; }
+  .switch label {
+    height: 2rem;
+    width: 4rem; }
+  .switch label:after {
+    height: 1.5rem;
+    width: 1.5rem; }
+  .switch input:checked + label:after {
+    left: 2.25rem; }
+  .switch label {
+    color: transparent;
+    background: #DDDDDD; }
+  .switch label:after {
+    background: #FFFFFF; }
+  .switch input:checked + label {
+    background: #008CBA; }
+  .switch.large label {
+    height: 2.5rem;
+    width: 5rem; }
+  .switch.large label:after {
+    height: 2rem;
+    width: 2rem; }
+  .switch.large input:checked + label:after {
+    left: 2.75rem; }
+  .switch.small label {
+    height: 1.75rem;
+    width: 3.5rem; }
+  .switch.small label:after {
+    height: 1.25rem;
+    width: 1.25rem; }
+  .switch.small input:checked + label:after {
+    left: 2rem; }
+  .switch.tiny label {
+    height: 1.5rem;
+    width: 3rem; }
+  .switch.tiny label:after {
+    height: 1rem;
+    width: 1rem; }
+  .switch.tiny input:checked + label:after {
+    left: 1.75rem; }
+  .switch.radius label {
+    border-radius: 4px; }
+  .switch.radius label:after {
+    border-radius: 3px; }
+  .switch.round {
+    border-radius: 1000px; }
+    .switch.round label {
+      border-radius: 2rem; }
+    .switch.round label:after {
+      border-radius: 2rem; }
+
+/* small displays */
+@media only screen {
+  .show-for-small-only, .show-for-small-up, .show-for-small, .show-for-small-down, .hide-for-medium-only, .hide-for-medium-up, .hide-for-medium, .show-for-medium-down, .hide-for-large-only, .hide-for-large-up, .hide-for-large, .show-for-large-down, .hide-for-xlarge-only, .hide-for-xlarge-up, .hide-for-xlarge, .show-for-xlarge-down, .hide-for-xxlarge-only, .hide-for-xxlarge-up, .hide-for-xxlarge, .show-for-xxlarge-down {
+    display: inherit !important; }
+
+  .hide-for-small-only, .hide-for-small-up, .hide-for-small, .hide-for-small-down, .show-for-medium-only, .show-for-medium-up, .show-for-medium, .hide-for-medium-down, .show-for-large-only, .show-for-large-up, .show-for-large, .hide-for-large-down, .show-for-xlarge-only, .show-for-xlarge-up, .show-for-xlarge, .hide-for-xlarge-down, .show-for-xxlarge-only, .show-for-xxlarge-up, .show-for-xxlarge, .hide-for-xxlarge-down {
+    display: none !important; }
+
+  .visible-for-small-only, .visible-for-small-up, .visible-for-small, .visible-for-small-down, .hidden-for-medium-only, .hidden-for-medium-up, .hidden-for-medium, .visible-for-medium-down, .hidden-for-large-only, .hidden-for-large-up, .hidden-for-large, .visible-for-large-down, .hidden-for-xlarge-only, .hidden-for-xlarge-up, .hidden-for-xlarge, .visible-for-xlarge-down, .hidden-for-xxlarge-only, .hidden-for-xxlarge-up, .hidden-for-xxlarge, .visible-for-xxlarge-down {
+    position: static !important;
+    height: auto;
+    width: auto;
+    overflow: visible;
+    clip: auto; }
+
+  .hidden-for-small-only, .hidden-for-small-up, .hidden-for-small, .hidden-for-small-down, .visible-for-medium-only, .visible-for-medium-up, .visible-for-medium, .hidden-for-medium-down, .visible-for-large-only, .visible-for-large-up, .visible-for-large, .hidden-for-large-down, .visible-for-xlarge-only, .visible-for-xlarge-up, .visible-for-xlarge, .hidden-for-xlarge-down, .visible-for-xxlarge-only, .visible-for-xxlarge-up, .visible-for-xxlarge, .hidden-for-xxlarge-down {
+    clip: rect(1px, 1px, 1px, 1px);
+    height: 1px;
+    overflow: hidden;
+    position: absolute !important;
+    width: 1px; }
+
+  table.show-for-small-only, table.show-for-small-up, table.show-for-small, table.show-for-small-down, table.hide-for-medium-only, table.hide-for-medium-up, table.hide-for-medium, table.show-for-medium-down, table.hide-for-large-only, table.hide-for-large-up, table.hide-for-large, table.show-for-large-down, table.hide-for-xlarge-only, table.hide-for-xlarge-up, table.hide-for-xlarge, table.show-for-xlarge-down, table.hide-for-xxlarge-only, table.hide-for-xxlarge-up, table.hide-for-xxlarge, table.show-for-xxlarge-down {
+    display: table !important; }
+
+  thead.show-for-small-only, thead.show-for-small-up, thead.show-for-small, thead.show-for-small-down, thead.hide-for-medium-only, thead.hide-for-medium-up, thead.hide-for-medium, thead.show-for-medium-down, thead.hide-for-large-only, thead.hide-for-large-up, thead.hide-for-large, thead.show-for-large-down, thead.hide-for-xlarge-only, thead.hide-for-xlarge-up, thead.hide-for-xlarge, thead.show-for-xlarge-down, thead.hide-for-xxlarge-only, thead.hide-for-xxlarge-up, thead.hide-for-xxlarge, thead.show-for-xxlarge-down {
+    display: table-header-group !important; }
+
+  tbody.show-for-small-only, tbody.show-for-small-up, tbody.show-for-small, tbody.show-for-small-down, tbody.hide-for-medium-only, tbody.hide-for-medium-up, tbody.hide-for-medium, tbody.show-for-medium-down, tbody.hide-for-large-only, tbody.hide-for-large-up, tbody.hide-for-large, tbody.show-for-large-down, tbody.hide-for-xlarge-only, tbody.hide-for-xlarge-up, tbody.hide-for-xlarge, tbody.show-for-xlarge-down, tbody.hide-for-xxlarge-only, tbody.hide-for-xxlarge-up, tbody.hide-for-xxlarge, tbody.show-for-xxlarge-down {
+    display: table-row-group !important; }
+
+  tr.show-for-small-only, tr.show-for-small-up, tr.show-for-small, tr.show-for-small-down, tr.hide-for-medium-only, tr.hide-for-medium-up, tr.hide-for-medium, tr.show-for-medium-down, tr.hide-for-large-only, tr.hide-for-large-up, tr.hide-for-large, tr.show-for-large-down, tr.hide-for-xlarge-only, tr.hide-for-xlarge-up, tr.hide-for-xlarge, tr.show-for-xlarge-down, tr.hide-for-xxlarge-only, tr.hide-for-xxlarge-up, tr.hide-for-xxlarge, tr.show-for-xxlarge-down {
+    display: table-row; }
+
+  th.show-for-small-only, td.show-for-small-only, th.show-for-small-up, td.show-for-small-up, th.show-for-small, td.show-for-small, th.show-for-small-down, td.show-for-small-down, th.hide-for-medium-only, td.hide-for-medium-only, th.hide-for-medium-up, td.hide-for-medium-up, th.hide-for-medium, td.hide-for-medium, th.show-for-medium-down, td.show-for-medium-down, th.hide-for-large-only, td.hide-for-large-only, th.hide-for-large-up, td.hide-for-large-up, th.hide-for-large, td.hide-for-large, th.show-for-large-down, td.show-for-large-down, th.hide-for-xlarge-only, td.hide-for-xlarge-only, th.hide-for-xlarge-up, td.hide-for-xlarge-up, th.hide-for-xlarge, td.hide-for-xlarge, th.show-for-xlarge-down, td.show-for-xlarge-down, th.hide-for-xxlarge-only, td.hide-for-xxlarge-only, th.hide-for-xxlarge-up, td.hide-for-xxlarge-up, th.hide-for-xxlarge, td.hide-for-xxlarge, th.show-for-xxlarge-down, td.show-for-xxlarge-down {
+    display: table-cell !important; } }
+/* medium displays */
+@media only screen and (min-width: 40.0625em) {
+  .hide-for-small-only, .show-for-small-up, .hide-for-small, .hide-for-small-down, .show-for-medium-only, .show-for-medium-up, .show-for-medium, .show-for-medium-down, .hide-for-large-only, .hide-for-large-up, .hide-for-large, .show-for-large-down, .hide-for-xlarge-only, .hide-for-xlarge-up, .hide-for-xlarge, .show-for-xlarge-down, .hide-for-xxlarge-only, .hide-for-xxlarge-up, .hide-for-xxlarge, .show-for-xxlarge-down {
+    display: inherit !important; }
+
+  .show-for-small-only, .hide-for-small-up, .show-for-small, .show-for-small-down, .hide-for-medium-only, .hide-for-medium-up, .hide-for-medium, .hide-for-medium-down, .show-for-large-only, .show-for-large-up, .show-for-large, .hide-for-large-down, .show-for-xlarge-only, .show-for-xlarge-up, .show-for-xlarge, .hide-for-xlarge-down, .show-for-xxlarge-only, .show-for-xxlarge-up, .show-for-xxlarge, .hide-for-xxlarge-down {
+    display: none !important; }
+
+  .hidden-for-small-only, .visible-for-small-up, .hidden-for-small, .hidden-for-small-down, .visible-for-medium-only, .visible-for-medium-up, .visible-for-medium, .visible-for-medium-down, .hidden-for-large-only, .hidden-for-large-up, .hidden-for-large, .visible-for-large-down, .hidden-for-xlarge-only, .hidden-for-xlarge-up, .hidden-for-xlarge, .visible-for-xlarge-down, .hidden-for-xxlarge-only, .hidden-for-xxlarge-up, .hidden-for-xxlarge, .visible-for-xxlarge-down {
+    position: static !important;
+    height: auto;
+    width: auto;
+    overflow: visible;
+    clip: auto; }
+
+  .visible-for-small-only, .hidden-for-small-up, .visible-for-small, .visible-for-small-down, .hidden-for-medium-only, .hidden-for-medium-up, .hidden-for-medium, .hidden-for-medium-down, .visible-for-large-only, .visible-for-large-up, .visible-for-large, .hidden-for-large-down, .visible-for-xlarge-only, .visible-for-xlarge-up, .visible-for-xlarge, .hidden-for-xlarge-down, .visible-for-xxlarge-only, .visible-for-xxlarge-up, .visible-for-xxlarge, .hidden-for-xxlarge-down {
+    clip: rect(1px, 1px, 1px, 1px);
+    height: 1px;
+    overflow: hidden;
+    position: absolute !important;
+    width: 1px; }
+
+  table.hide-for-small-only, table.show-for-small-up, table.hide-for-small, table.hide-for-small-down, table.show-for-medium-only, table.show-for-medium-up, table.show-for-medium, table.show-for-medium-down, table.hide-for-large-only, table.hide-for-large-up, table.hide-for-large, table.show-for-large-down, table.hide-for-xlarge-only, table.hide-for-xlarge-up, table.hide-for-xlarge, table.show-for-xlarge-down, table.hide-for-xxlarge-only, table.hide-for-xxlarge-up, table.hide-for-xxlarge, table.show-for-xxlarge-down {
+    display: table !important; }
+
+  thead.hide-for-small-only, thead.show-for-small-up, thead.hide-for-small, thead.hide-for-small-down, thead.show-for-medium-only, thead.show-for-medium-up, thead.show-for-medium, thead.show-for-medium-down, thead.hide-for-large-only, thead.hide-for-large-up, thead.hide-for-large, thead.show-for-large-down, thead.hide-for-xlarge-only, thead.hide-for-xlarge-up, thead.hide-for-xlarge, thead.show-for-xlarge-down, thead.hide-for-xxlarge-only, thead.hide-for-xxlarge-up, thead.hide-for-xxlarge, thead.show-for-xxlarge-down {
+    display: table-header-group !important; }
+
+  tbody.hide-for-small-only, tbody.show-for-small-up, tbody.hide-for-small, tbody.hide-for-small-down, tbody.show-for-medium-only, tbody.show-for-medium-up, tbody.show-for-medium, tbody.show-for-medium-down, tbody.hide-for-large-only, tbody.hide-for-large-up, tbody.hide-for-large, tbody.show-for-large-down, tbody.hide-for-xlarge-only, tbody.hide-for-xlarge-up, tbody.hide-for-xlarge, tbody.show-for-xlarge-down, tbody.hide-for-xxlarge-only, tbody.hide-for-xxlarge-up, tbody.hide-for-xxlarge, tbody.show-for-xxlarge-down {
+    display: table-row-group !important; }
+
+  tr.hide-for-small-only, tr.show-for-small-up, tr.hide-for-small, tr.hide-for-small-down, tr.show-for-medium-only, tr.show-for-medium-up, tr.show-for-medium, tr.show-for-medium-down, tr.hide-for-large-only, tr.hide-for-large-up, tr.hide-for-large, tr.show-for-large-down, tr.hide-for-xlarge-only, tr.hide-for-xlarge-up, tr.hide-for-xlarge, tr.show-for-xlarge-down, tr.hide-for-xxlarge-only, tr.hide-for-xxlarge-up, tr.hide-for-xxlarge, tr.show-for-xxlarge-down {
+    display: table-row; }
+
+  th.hide-for-small-only, td.hide-for-small-only, th.show-for-small-up, td.show-for-small-up, th.hide-for-small, td.hide-for-small, th.hide-for-small-down, td.hide-for-small-down, th.show-for-medium-only, td.show-for-medium-only, th.show-for-medium-up, td.show-for-medium-up, th.show-for-medium, td.show-for-medium, th.show-for-medium-down, td.show-for-medium-down, th.hide-for-large-only, td.hide-for-large-only, th.hide-for-large-up, td.hide-for-large-up, th.hide-for-large, td.hide-for-large, th.show-for-large-down, td.show-for-large-down, th.hide-for-xlarge-only, td.hide-for-xlarge-only, th.hide-for-xlarge-up, td.hide-for-xlarge-up, th.hide-for-xlarge, td.hide-for-xlarge, th.show-for-xlarge-down, td.show-for-xlarge-down, th.hide-for-xxlarge-only, td.hide-for-xxlarge-only, th.hide-for-xxlarge-up, td.hide-for-xxlarge-up, th.hide-for-xxlarge, td.hide-for-xxlarge, th.show-for-xxlarge-down, td.show-for-xxlarge-down {
+    display: table-cell !important; } }
+/* large displays */
+@media only screen and (min-width: 64.0625em) {
+  .hide-for-small-only, .show-for-small-up, .hide-for-small, .hide-for-small-down, .hide-for-medium-only, .show-for-medium-up, .hide-for-medium, .hide-for-medium-down, .show-for-large-only, .show-for-large-up, .show-for-large, .show-for-large-down, .hide-for-xlarge-only, .hide-for-xlarge-up, .hide-for-xlarge, .show-for-xlarge-down, .hide-for-xxlarge-only, .hide-for-xxlarge-up, .hide-for-xxlarge, .show-for-xxlarge-down {
+    display: inherit !important; }
+
+  .show-for-small-only, .hide-for-small-up, .show-for-small, .show-for-small-down, .show-for-medium-only, .hide-for-medium-up, .show-for-medium, .show-for-medium-down, .hide-for-large-only, .hide-for-large-up, .hide-for-large, .hide-for-large-down, .show-for-xlarge-only, .show-for-xlarge-up, .show-for-xlarge, .hide-for-xlarge-down, .show-for-xxlarge-only, .show-for-xxlarge-up, .show-for-xxlarge, .hide-for-xxlarge-down {
+    display: none !important; }
+
+  .hidden-for-small-only, .visible-for-small-up, .hidden-for-small, .hidden-for-small-down, .hidden-for-medium-only, .visible-for-medium-up, .hidden-for-medium, .hidden-for-medium-down, .visible-for-large-only, .visible-for-large-up, .visible-for-large, .visible-for-large-down, .hidden-for-xlarge-only, .hidden-for-xlarge-up, .hidden-for-xlarge, .visible-for-xlarge-down, .hidden-for-xxlarge-only, .hidden-for-xxlarge-up, .hidden-for-xxlarge, .visible-for-xxlarge-down {
+    position: static !important;
+    height: auto;
+    width: auto;
+    overflow: visible;
+    clip: auto; }
+
+  .visible-for-small-only, .hidden-for-small-up, .visible-for-small, .visible-for-small-down, .visible-for-medium-only, .hidden-for-medium-up, .visible-for-medium, .visible-for-medium-down, .hidden-for-large-only, .hidden-for-large-up, .hidden-for-large, .hidden-for-large-down, .visible-for-xlarge-only, .visible-for-xlarge-up, .visible-for-xlarge, .hidden-for-xlarge-down, .visible-for-xxlarge-only, .visible-for-xxlarge-up, .visible-for-xxlarge, .hidden-for-xxlarge-down {
+    clip: rect(1px, 1px, 1px, 1px);
+    height: 1px;
+    overflow: hidden;
+    position: absolute !important;
+    width: 1px; }
+
+  table.hide-for-small-only, table.show-for-small-up, table.hide-for-small, table.hide-for-small-down, table.hide-for-medium-only, table.show-for-medium-up, table.hide-for-medium, table.hide-for-medium-down, table.show-for-large-only, table.show-for-large-up, table.show-for-large, table.show-for-large-down, table.hide-for-xlarge-only, table.hide-for-xlarge-up, table.hide-for-xlarge, table.show-for-xlarge-down, table.hide-for-xxlarge-only, table.hide-for-xxlarge-up, table.hide-for-xxlarge, table.show-for-xxlarge-down {
+    display: table !important; }
+
+  thead.hide-for-small-only, thead.show-for-small-up, thead.hide-for-small, thead.hide-for-small-down, thead.hide-for-medium-only, thead.show-for-medium-up, thead.hide-for-medium, thead.hide-for-medium-down, thead.show-for-large-only, thead.show-for-large-up, thead.show-for-large, thead.show-for-large-down, thead.hide-for-xlarge-only, thead.hide-for-xlarge-up, thead.hide-for-xlarge, thead.show-for-xlarge-down, thead.hide-for-xxlarge-only, thead.hide-for-xxlarge-up, thead.hide-for-xxlarge, thead.show-for-xxlarge-down {
+    display: table-header-group !important; }
+
+  tbody.hide-for-small-only, tbody.show-for-small-up, tbody.hide-for-small, tbody.hide-for-small-down, tbody.hide-for-medium-only, tbody.show-for-medium-up, tbody.hide-for-medium, tbody.hide-for-medium-down, tbody.show-for-large-only, tbody.show-for-large-up, tbody.show-for-large, tbody.show-for-large-down, tbody.hide-for-xlarge-only, tbody.hide-for-xlarge-up, tbody.hide-for-xlarge, tbody.show-for-xlarge-down, tbody.hide-for-xxlarge-only, tbody.hide-for-xxlarge-up, tbody.hide-for-xxlarge, tbody.show-for-xxlarge-down {
+    display: table-row-group !important; }
+
+  tr.hide-for-small-only, tr.show-for-small-up, tr.hide-for-small, tr.hide-for-small-down, tr.hide-for-medium-only, tr.show-for-medium-up, tr.hide-for-medium, tr.hide-for-medium-down, tr.show-for-large-only, tr.show-for-large-up, tr.show-for-large, tr.show-for-large-down, tr.hide-for-xlarge-only, tr.hide-for-xlarge-up, tr.hide-for-xlarge, tr.show-for-xlarge-down, tr.hide-for-xxlarge-only, tr.hide-for-xxlarge-up, tr.hide-for-xxlarge, tr.show-for-xxlarge-down {
+    display: table-row; }
+
+  th.hide-for-small-only, td.hide-for-small-only, th.show-for-small-up, td.show-for-small-up, th.hide-for-small, td.hide-for-small, th.hide-for-small-down, td.hide-for-small-down, th.hide-for-medium-only, td.hide-for-medium-only, th.show-for-medium-up, td.show-for-medium-up, th.hide-for-medium, td.hide-for-medium, th.hide-for-medium-down, td.hide-for-medium-down, th.show-for-large-only, td.show-for-large-only, th.show-for-large-up, td.show-for-large-up, th.show-for-large, td.show-for-large, th.show-for-large-down, td.show-for-large-down, th.hide-for-xlarge-only, td.hide-for-xlarge-only, th.hide-for-xlarge-up, td.hide-for-xlarge-up, th.hide-for-xlarge, td.hide-for-xlarge, th.show-for-xlarge-down, td.show-for-xlarge-down, th.hide-for-xxlarge-only, td.hide-for-xxlarge-only, th.hide-for-xxlarge-up, td.hide-for-xxlarge-up, th.hide-for-xxlarge, td.hide-for-xxlarge, th.show-for-xxlarge-down, td.show-for-xxlarge-down {
+    display: table-cell !important; } }
+/* xlarge displays */
+@media only screen and (min-width: 90.0625em) {
+  .hide-for-small-only, .show-for-small-up, .hide-for-small, .hide-for-small-down, .hide-for-medium-only, .show-for-medium-up, .hide-for-medium, .hide-for-medium-down, .hide-for-large-only, .show-for-large-up, .hide-for-large, .hide-for-large-down, .show-for-xlarge-only, .show-for-xlarge-up, .show-for-xlarge, .show-for-xlarge-down, .hide-for-xxlarge-only, .hide-for-xxlarge-up, .hide-for-xxlarge, .show-for-xxlarge-down {
+    display: inherit !important; }
+
+  .show-for-small-only, .hide-for-small-up, .show-for-small, .show-for-small-down, .show-for-medium-only, .hide-for-medium-up, .show-for-medium, .show-for-medium-down, .show-for-large-only, .hide-for-large-up, .show-for-large, .show-for-large-down, .hide-for-xlarge-only, .hide-for-xlarge-up, .hide-for-xlarge, .hide-for-xlarge-down, .show-for-xxlarge-only, .show-for-xxlarge-up, .show-for-xxlarge, .hide-for-xxlarge-down {
+    display: none !important; }
+
+  .hidden-for-small-only, .visible-for-small-up, .hidden-for-small, .hidden-for-small-down, .hidden-for-medium-only, .visible-for-medium-up, .hidden-for-medium, .hidden-for-medium-down, .hidden-for-large-only, .visible-for-large-up, .hidden-for-large, .hidden-for-large-down, .visible-for-xlarge-only, .visible-for-xlarge-up, .visible-for-xlarge, .visible-for-xlarge-down, .hidden-for-xxlarge-only, .hidden-for-xxlarge-up, .hidden-for-xxlarge, .visible-for-xxlarge-down {
+    position: static !important;
+    height: auto;
+    width: auto;
+    overflow: visible;
+    clip: auto; }
+
+  .visible-for-small-only, .hidden-for-small-up, .visible-for-small, .visible-for-small-down, .visible-for-medium-only, .hidden-for-medium-up, .visible-for-medium, .visible-for-medium-down, .visible-for-large-only, .hidden-for-large-up, .visible-for-large, .visible-for-large-down, .hidden-for-xlarge-only, .hidden-for-xlarge-up, .hidden-for-xlarge, .hidden-for-xlarge-down, .visible-for-xxlarge-only, .visible-for-xxlarge-up, .visible-for-xxlarge, .hidden-for-xxlarge-down {
+    clip: rect(1px, 1px, 1px, 1px);
+    height: 1px;
+    overflow: hidden;
+    position: absolute !important;
+    width: 1px; }
+
+  table.hide-for-small-only, table.show-for-small-up, table.hide-for-small, table.hide-for-small-down, table.hide-for-medium-only, table.show-for-medium-up, table.hide-for-medium, table.hide-for-medium-down, table.hide-for-large-only, table.show-for-large-up, table.hide-for-large, table.hide-for-large-down, table.show-for-xlarge-only, table.show-for-xlarge-up, table.show-for-xlarge, table.show-for-xlarge-down, table.hide-for-xxlarge-only, table.hide-for-xxlarge-up, table.hide-for-xxlarge, table.show-for-xxlarge-down {
+    display: table !important; }
+
+  thead.hide-for-small-only, thead.show-for-small-up, thead.hide-for-small, thead.hide-for-small-down, thead.hide-for-medium-only, thead.show-for-medium-up, thead.hide-for-medium, thead.hide-for-medium-down, thead.hide-for-large-only, thead.show-for-large-up, thead.hide-for-large, thead.hide-for-large-down, thead.show-for-xlarge-only, thead.show-for-xlarge-up, thead.show-for-xlarge, thead.show-for-xlarge-down, thead.hide-for-xxlarge-only, thead.hide-for-xxlarge-up, thead.hide-for-xxlarge, thead.show-for-xxlarge-down {
+    display: table-header-group !important; }
+
+  tbody.hide-for-small-only, tbody.show-for-small-up, tbody.hide-for-small, tbody.hide-for-small-down, tbody.hide-for-medium-only, tbody.show-for-medium-up, tbody.hide-for-medium, tbody.hide-for-medium-down, tbody.hide-for-large-only, tbody.show-for-large-up, tbody.hide-for-large, tbody.hide-for-large-down, tbody.show-for-xlarge-only, tbody.show-for-xlarge-up, tbody.show-for-xlarge, tbody.show-for-xlarge-down, tbody.hide-for-xxlarge-only, tbody.hide-for-xxlarge-up, tbody.hide-for-xxlarge, tbody.show-for-xxlarge-down {
+    display: table-row-group !important; }
+
+  tr.hide-for-small-only, tr.show-for-small-up, tr.hide-for-small, tr.hide-for-small-down, tr.hide-for-medium-only, tr.show-for-medium-up, tr.hide-for-medium, tr.hide-for-medium-down, tr.hide-for-large-only, tr.show-for-large-up, tr.hide-for-large, tr.hide-for-large-down, tr.show-for-xlarge-only, tr.show-for-xlarge-up, tr.show-for-xlarge, tr.show-for-xlarge-down, tr.hide-for-xxlarge-only, tr.hide-for-xxlarge-up, tr.hide-for-xxlarge, tr.show-for-xxlarge-down {
+    display: table-row; }
+
+  th.hide-for-small-only, td.hide-for-small-only, th.show-for-small-up, td.show-for-small-up, th.hide-for-small, td.hide-for-small, th.hide-for-small-down, td.hide-for-small-down, th.hide-for-medium-only, td.hide-for-medium-only, th.show-for-medium-up, td.show-for-medium-up, th.hide-for-medium, td.hide-for-medium, th.hide-for-medium-down, td.hide-for-medium-down, th.hide-for-large-only, td.hide-for-large-only, th.show-for-large-up, td.show-for-large-up, th.hide-for-large, td.hide-for-large, th.hide-for-large-down, td.hide-for-large-down, th.show-for-xlarge-only, td.show-for-xlarge-only, th.show-for-xlarge-up, td.show-for-xlarge-up, th.show-for-xlarge, td.show-for-xlarge, th.show-for-xlarge-down, td.show-for-xlarge-down, th.hide-for-xxlarge-only, td.hide-for-xxlarge-only, th.hide-for-xxlarge-up, td.hide-for-xxlarge-up, th.hide-for-xxlarge, td.hide-for-xxlarge, th.show-for-xxlarge-down, td.show-for-xxlarge-down {
+    display: table-cell !important; } }
+/* xxlarge displays */
+@media only screen and (min-width: 120.0625em) {
+  .hide-for-small-only, .show-for-small-up, .hide-for-small, .hide-for-small-down, .hide-for-medium-only, .show-for-medium-up, .hide-for-medium, .hide-for-medium-down, .hide-for-large-only, .show-for-large-up, .hide-for-large, .hide-for-large-down, .hide-for-xlarge-only, .show-for-xlarge-up, .hide-for-xlarge, .hide-for-xlarge-down, .show-for-xxlarge-only, .show-for-xxlarge-up, .show-for-xxlarge, .show-for-xxlarge-down {
+    display: inherit !important; }
+
+  .show-for-small-only, .hide-for-small-up, .show-for-small, .show-for-small-down, .show-for-medium-only, .hide-for-medium-up, .show-for-medium, .show-for-medium-down, .show-for-large-only, .hide-for-large-up, .show-for-large, .show-for-large-down, .show-for-xlarge-only, .hide-for-xlarge-up, .show-for-xlarge, .show-for-xlarge-down, .hide-for-xxlarge-only, .hide-for-xxlarge-up, .hide-for-xxlarge, .hide-for-xxlarge-down {
+    display: none !important; }
+
+  .hidden-for-small-only, .visible-for-small-up, .hidden-for-small, .hidden-for-small-down, .hidden-for-medium-only, .visible-for-medium-up, .hidden-for-medium, .hidden-for-medium-down, .hidden-for-large-only, .visible-for-large-up, .hidden-for-large, .hidden-for-large-down, .hidden-for-xlarge-only, .visible-for-xlarge-up, .hidden-for-xlarge, .hidden-for-xlarge-down, .visible-for-xxlarge-only, .visible-for-xxlarge-up, .visible-for-xxlarge, .visible-for-xxlarge-down {
+    position: static !important;
+    height: auto;
+    width: auto;
+    overflow: visible;
+    clip: auto; }
+
+  .visible-for-small-only, .hidden-for-small-up, .visible-for-small, .visible-for-small-down, .visible-for-medium-only, .hidden-for-medium-up, .visible-for-medium, .visible-for-medium-down, .visible-for-large-only, .hidden-for-large-up, .visible-for-large, .visible-for-large-down, .visible-for-xlarge-only, .hidden-for-xlarge-up, .visible-for-xlarge, .visible-for-xlarge-down, .hidden-for-xxlarge-only, .hidden-for-xxlarge-up, .hidden-for-xxlarge, .hidden-for-xxlarge-down {
+    clip: rect(1px, 1px, 1px, 1px);
+    height: 1px;
+    overflow: hidden;
+    position: absolute !important;
+    width: 1px; }
+
+  table.hide-for-small-only, table.show-for-small-up, table.hide-for-small, table.hide-for-small-down, table.hide-for-medium-only, table.show-for-medium-up, table.hide-for-medium, table.hide-for-medium-down, table.hide-for-large-only, table.show-for-large-up, table.hide-for-large, table.hide-for-large-down, table.hide-for-xlarge-only, table.show-for-xlarge-up, table.hide-for-xlarge, table.hide-for-xlarge-down, table.show-for-xxlarge-only, table.show-for-xxlarge-up, table.show-for-xxlarge, table.show-for-xxlarge-down {
+    display: table !important; }
+
+  thead.hide-for-small-only, thead.show-for-small-up, thead.hide-for-small, thead.hide-for-small-down, thead.hide-for-medium-only, thead.show-for-medium-up, thead.hide-for-medium, thead.hide-for-medium-down, thead.hide-for-large-only, thead.show-for-large-up, thead.hide-for-large, thead.hide-for-large-down, thead.hide-for-xlarge-only, thead.show-for-xlarge-up, thead.hide-for-xlarge, thead.hide-for-xlarge-down, thead.show-for-xxlarge-only, thead.show-for-xxlarge-up, thead.show-for-xxlarge, thead.show-for-xxlarge-down {
+    display: table-header-group !important; }
+
+  tbody.hide-for-small-only, tbody.show-for-small-up, tbody.hide-for-small, tbody.hide-for-small-down, tbody.hide-for-medium-only, tbody.show-for-medium-up, tbody.hide-for-medium, tbody.hide-for-medium-down, tbody.hide-for-large-only, tbody.show-for-large-up, tbody.hide-for-large, tbody.hide-for-large-down, tbody.hide-for-xlarge-only, tbody.show-for-xlarge-up, tbody.hide-for-xlarge, tbody.hide-for-xlarge-down, tbody.show-for-xxlarge-only, tbody.show-for-xxlarge-up, tbody.show-for-xxlarge, tbody.show-for-xxlarge-down {
+    display: table-row-group !important; }
+
+  tr.hide-for-small-only, tr.show-for-small-up, tr.hide-for-small, tr.hide-for-small-down, tr.hide-for-medium-only, tr.show-for-medium-up, tr.hide-for-medium, tr.hide-for-medium-down, tr.hide-for-large-only, tr.show-for-large-up, tr.hide-for-large, tr.hide-for-large-down, tr.hide-for-xlarge-only, tr.show-for-xlarge-up, tr.hide-for-xlarge, tr.hide-for-xlarge-down, tr.show-for-xxlarge-only, tr.show-for-xxlarge-up, tr.show-for-xxlarge, tr.show-for-xxlarge-down {
+    display: table-row; }
+
+  th.hide-for-small-only, td.hide-for-small-only, th.show-for-small-up, td.show-for-small-up, th.hide-for-small, td.hide-for-small, th.hide-for-small-down, td.hide-for-small-down, th.hide-for-medium-only, td.hide-for-medium-only, th.show-for-medium-up, td.show-for-medium-up, th.hide-for-medium, td.hide-for-medium, th.hide-for-medium-down, td.hide-for-medium-down, th.hide-for-large-only, td.hide-for-large-only, th.show-for-large-up, td.show-for-large-up, th.hide-for-large, td.hide-for-large, th.hide-for-large-down, td.hide-for-large-down, th.hide-for-xlarge-only, td.hide-for-xlarge-only, th.show-for-xlarge-up, td.show-for-xlarge-up, th.hide-for-xlarge, td.hide-for-xlarge, th.hide-for-xlarge-down, td.hide-for-xlarge-down, th.show-for-xxlarge-only, td.show-for-xxlarge-only, th.show-for-xxlarge-up, td.show-for-xxlarge-up, th.show-for-xxlarge, td.show-for-xxlarge, th.show-for-xxlarge-down, td.show-for-xxlarge-down {
+    display: table-cell !important; } }
+/* Orientation targeting */
+.show-for-landscape,
+.hide-for-portrait {
+  display: inherit !important; }
+
+.hide-for-landscape,
+.show-for-portrait {
+  display: none !important; }
+
+/* Specific visibility for tables */
+table.hide-for-landscape, table.show-for-portrait {
+  display: table !important; }
+
+thead.hide-for-landscape, thead.show-for-portrait {
+  display: table-header-group !important; }
+
+tbody.hide-for-landscape, tbody.show-for-portrait {
+  display: table-row-group !important; }
+
+tr.hide-for-landscape, tr.show-for-portrait {
+  display: table-row !important; }
+
+td.hide-for-landscape, td.show-for-portrait,
+th.hide-for-landscape,
+th.show-for-portrait {
+  display: table-cell !important; }
+
+@media only screen and (orientation: landscape) {
+  .show-for-landscape,
+  .hide-for-portrait {
+    display: inherit !important; }
+
+  .hide-for-landscape,
+  .show-for-portrait {
+    display: none !important; }
+
+  /* Specific visibility for tables */
+  table.show-for-landscape, table.hide-for-portrait {
+    display: table !important; }
+
+  thead.show-for-landscape, thead.hide-for-portrait {
+    display: table-header-group !important; }
+
+  tbody.show-for-landscape, tbody.hide-for-portrait {
+    display: table-row-group !important; }
+
+  tr.show-for-landscape, tr.hide-for-portrait {
+    display: table-row !important; }
+
+  td.show-for-landscape, td.hide-for-portrait,
+  th.show-for-landscape,
+  th.hide-for-portrait {
+    display: table-cell !important; } }
+@media only screen and (orientation: portrait) {
+  .show-for-portrait,
+  .hide-for-landscape {
+    display: inherit !important; }
+
+  .hide-for-portrait,
+  .show-for-landscape {
+    display: none !important; }
+
+  /* Specific visibility for tables */
+  table.show-for-portrait, table.hide-for-landscape {
+    display: table !important; }
+
+  thead.show-for-portrait, thead.hide-for-landscape {
+    display: table-header-group !important; }
+
+  tbody.show-for-portrait, tbody.hide-for-landscape {
+    display: table-row-group !important; }
+
+  tr.show-for-portrait, tr.hide-for-landscape {
+    display: table-row !important; }
+
+  td.show-for-portrait, td.hide-for-landscape,
+  th.show-for-portrait,
+  th.hide-for-landscape {
+    display: table-cell !important; } }
+/* Touch-enabled device targeting */
+.show-for-touch {
+  display: none !important; }
+
+.hide-for-touch {
+  display: inherit !important; }
+
+.touch .show-for-touch {
+  display: inherit !important; }
+
+.touch .hide-for-touch {
+  display: none !important; }
+
+/* Specific visibility for tables */
+table.hide-for-touch {
+  display: table !important; }
+
+.touch table.show-for-touch {
+  display: table !important; }
+
+thead.hide-for-touch {
+  display: table-header-group !important; }
+
+.touch thead.show-for-touch {
+  display: table-header-group !important; }
+
+tbody.hide-for-touch {
+  display: table-row-group !important; }
+
+.touch tbody.show-for-touch {
+  display: table-row-group !important; }
+
+tr.hide-for-touch {
+  display: table-row !important; }
+
+.touch tr.show-for-touch {
+  display: table-row !important; }
+
+td.hide-for-touch {
+  display: table-cell !important; }
+
+.touch td.show-for-touch {
+  display: table-cell !important; }
+
+th.hide-for-touch {
+  display: table-cell !important; }
+
+.touch th.show-for-touch {
+  display: table-cell !important; }
+
+/* Screen reader-specific classes */
+.show-for-sr {
+  clip: rect(1px, 1px, 1px, 1px);
+  height: 1px;
+  overflow: hidden;
+  position: absolute !important;
+  width: 1px; }
+
+.show-on-focus {
+  clip: rect(1px, 1px, 1px, 1px);
+  height: 1px;
+  overflow: hidden;
+  position: absolute !important;
+  width: 1px; }
+  .show-on-focus:focus, .show-on-focus:active {
+    position: static !important;
+    height: auto;
+    width: auto;
+    overflow: visible;
+    clip: auto; }
+
+/* Print visibility */
+.print-only,
+.show-for-print {
+  display: none !important; }
+
+@media print {
+  .print-only,
+  .show-for-print {
+    display: block !important; }
+
+  .hide-on-print,
+  .hide-for-print {
+    display: none !important; }
+
+  table.show-for-print {
+    display: table !important; }
+
+  thead.show-for-print {
+    display: table-header-group !important; }
+
+  tbody.show-for-print {
+    display: table-row-group !important; }
+
+  tr.show-for-print {
+    display: table-row !important; }
+
+  td.show-for-print {
+    display: table-cell !important; }
+
+  th.show-for-print {
+    display: table-cell !important; } }
diff --git a/record-and-playback/presentation_export/playback/presentation_export/css/normalize.css b/record-and-playback/presentation_export/playback/presentation_export/css/normalize.css
new file mode 100644
index 0000000000000000000000000000000000000000..5e5e3c898106bb66986f7224bf51eea2dc3c82a3
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/css/normalize.css
@@ -0,0 +1,424 @@
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS and IE text size adjust after device orientation change,
+ *    without disabling user zoom.
+ */
+
+html {
+  font-family: sans-serif; /* 1 */
+  -ms-text-size-adjust: 100%; /* 2 */
+  -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+  margin: 0;
+}
+
+/* HTML5 display definitions
+   ========================================================================== */
+
+/**
+ * Correct `block` display not defined for any HTML5 element in IE 8/9.
+ * Correct `block` display not defined for `details` or `summary` in IE 10/11
+ * and Firefox.
+ * Correct `block` display not defined for `main` in IE 11.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+  display: block;
+}
+
+/**
+ * 1. Correct `inline-block` display not defined in IE 8/9.
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ */
+
+audio,
+canvas,
+progress,
+video {
+  display: inline-block; /* 1 */
+  vertical-align: baseline; /* 2 */
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9/10.
+ * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
+ */
+
+[hidden],
+template {
+  display: none;
+}
+
+/* Links
+   ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+  background-color: transparent;
+}
+
+/**
+ * Improve readability of focused elements when they are also in an
+ * active/hover state.
+ */
+
+a:active,
+a:hover {
+  outline: 0;
+}
+
+/* Text-level semantics
+   ========================================================================== */
+
+/**
+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
+ */
+
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+ */
+
+b,
+strong {
+  font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari and Chrome.
+ */
+
+dfn {
+  font-style: italic;
+}
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari, and Chrome.
+ */
+
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+  background: #ff0;
+  color: #000;
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+  font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+
+sup {
+  top: -0.5em;
+}
+
+sub {
+  bottom: -0.25em;
+}
+
+/* Embedded content
+   ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9/10.
+ */
+
+img {
+  border: 0;
+}
+
+/**
+ * Correct overflow not hidden in IE 9/10/11.
+ */
+
+svg:not(:root) {
+  overflow: hidden;
+}
+
+/* Grouping content
+   ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari.
+ */
+
+figure {
+  margin: 1em 40px;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+  box-sizing: content-box;
+  height: 0;
+}
+
+/**
+ * Contain overflow in all browsers.
+ */
+
+pre {
+  overflow: auto;
+}
+
+/**
+ * Address odd `em`-unit font size rendering in all browsers.
+ */
+
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em;
+}
+
+/* Forms
+   ========================================================================== */
+
+/**
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
+ * styling of `select`, unless a `border` property is set.
+ */
+
+/**
+ * 1. Correct color not being inherited.
+ *    Known issue: affects color of disabled elements.
+ * 2. Correct font properties not being inherited.
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+  color: inherit; /* 1 */
+  font: inherit; /* 2 */
+  margin: 0; /* 3 */
+}
+
+/**
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
+ */
+
+button {
+  overflow: visible;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
+ * Correct `select` style inheritance in Firefox.
+ */
+
+button,
+select {
+  text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ *    and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ *    `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button; /* 2 */
+  cursor: pointer; /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  border: 0;
+  padding: 0;
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+input {
+  line-height: normal;
+}
+
+/**
+ * It's recommended that you don't attempt to style these elements.
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
+ *
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+  box-sizing: border-box; /* 1 */
+  padding: 0; /* 2 */
+}
+
+/**
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
+ * `font-size` values of the `input`, it causes the cursor style of the
+ * decrement button to change from `default` to `text`.
+ */
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
+ */
+
+input[type="search"] {
+  -webkit-appearance: textfield; /* 1 */
+  box-sizing: content-box; /* 2 */
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
+ * Safari (but not Chrome) clips the cancel button when the search input has
+ * padding (and `textfield` appearance).
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+  border: 1px solid #c0c0c0;
+  margin: 0 2px;
+  padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9/10/11.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+  border: 0; /* 1 */
+  padding: 0; /* 2 */
+}
+
+/**
+ * Remove default vertical scrollbar in IE 8/9/10/11.
+ */
+
+textarea {
+  overflow: auto;
+}
+
+/**
+ * Don't inherit the `font-weight` (applied by a rule above).
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ */
+
+optgroup {
+  font-weight: bold;
+}
+
+/* Tables
+   ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+td,
+th {
+  padding: 0;
+}
diff --git a/record-and-playback/presentation_export/playback/presentation_export/lib/foundation.min.js b/record-and-playback/presentation_export/playback/presentation_export/lib/foundation.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..894eb5ea46bf8dc481f8b6ffdfb1d1887a8fb861
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/lib/foundation.min.js
@@ -0,0 +1,20 @@
+/*
+ * Foundation Responsive Library
+ * http://foundation.zurb.com
+ * Copyright 2015, ZURB
+ * Free to use under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+*/
+!function(t,e,i,s){"use strict";function n(t){return("string"==typeof t||t instanceof String)&&(t=t.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g,"")),t}function a(t){this.selector=t,this.query=""}var o=function(e){var i=t("head");i.prepend(t.map(e,function(t){return 0===i.has("."+t).length?'<meta class="'+t+'" />':void 0}))};o(["foundation-mq-small","foundation-mq-small-only","foundation-mq-medium","foundation-mq-medium-only","foundation-mq-large","foundation-mq-large-only","foundation-mq-xlarge","foundation-mq-xlarge-only","foundation-mq-xxlarge","foundation-data-attribute-namespace"]),t(function(){"undefined"!=typeof FastClick&&"undefined"!=typeof i.body&&FastClick.attach(i.body)});var r=function(e,s){if("string"==typeof e){if(s){var n;if(s.jquery){if(n=s[0],!n)return s}else n=s;return t(n.querySelectorAll(e))}return t(i.querySelectorAll(e))}return t(e,s)},l=function(t){var e=[];return t||e.push("data"),this.namespace.length>0&&e.push(this.namespace),e.push(this.name),e.join("-")},d=function(t){for(var e=t.split("-"),i=e.length,s=[];i--;)0!==i?s.push(e[i]):this.namespace.length>0?s.push(this.namespace,e[i]):s.push(e[i]);return s.reverse().join("-")},c=function(e,i){var s=this,n=function(){var n=r(this),a=!n.data(s.attr_name(!0)+"-init");n.data(s.attr_name(!0)+"-init",t.extend({},s.settings,i||e,s.data_options(n))),a&&s.events(this)};return r(this.scope).is("["+this.attr_name()+"]")?n.call(this.scope):r("["+this.attr_name()+"]",this.scope).each(n),"string"==typeof e?this[e].call(this,i):void 0},h=function(t,e){function i(){e(t[0])}function s(){if(this.one("load",i),/MSIE (\d+\.\d+);/.test(navigator.userAgent)){var t=this.attr("src"),e=t.match(/\?/)?"&":"?";e+="random="+(new Date).getTime(),this.attr("src",t+e)}}return t.attr("src")?void(t[0].complete||4===t[0].readyState?i():s.call(t)):void i()};/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */
+e.matchMedia||(e.matchMedia=function(){var t=e.styleMedia||e.media;if(!t){var s=i.createElement("style"),n=i.getElementsByTagName("script")[0],a=null;s.type="text/css",s.id="matchmediajs-test",n.parentNode.insertBefore(s,n),a="getComputedStyle"in e&&e.getComputedStyle(s,null)||s.currentStyle,t={matchMedium:function(t){var e="@media "+t+"{ #matchmediajs-test { width: 1px; } }";return s.styleSheet?s.styleSheet.cssText=e:s.textContent=e,"1px"===a.width}}}return function(e){return{matches:t.matchMedium(e||"all"),media:e||"all"}}}()),/*
+   * jquery.requestAnimationFrame
+   * https://github.com/gnarf37/jquery-requestAnimationFrame
+   * Requires jQuery 1.8+
+   *
+   * Copyright (c) 2012 Corey Frang
+   * Licensed under the MIT license.
+   */
+function(t){function i(){s&&(o(i),l&&t.fx.tick())}for(var s,n=0,a=["webkit","moz"],o=e.requestAnimationFrame,r=e.cancelAnimationFrame,l="undefined"!=typeof t.fx;n<a.length&&!o;n++)o=e[a[n]+"RequestAnimationFrame"],r=r||e[a[n]+"CancelAnimationFrame"]||e[a[n]+"CancelRequestAnimationFrame"];o?(e.requestAnimationFrame=o,e.cancelAnimationFrame=r,l&&(t.fx.timer=function(e){e()&&t.timers.push(e)&&!s&&(s=!0,i())},t.fx.stop=function(){s=!1})):(e.requestAnimationFrame=function(t){var i=(new Date).getTime(),s=Math.max(0,16-(i-n)),a=e.setTimeout(function(){t(i+s)},s);return n=i+s,a},e.cancelAnimationFrame=function(t){clearTimeout(t)})}(t),a.prototype.toString=function(){return this.query||(this.query=r(this.selector).css("font-family").replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g,""))},e.Foundation={name:"Foundation",version:"5.5.3",media_queries:{small:new a(".foundation-mq-small"),"small-only":new a(".foundation-mq-small-only"),medium:new a(".foundation-mq-medium"),"medium-only":new a(".foundation-mq-medium-only"),large:new a(".foundation-mq-large"),"large-only":new a(".foundation-mq-large-only"),xlarge:new a(".foundation-mq-xlarge"),"xlarge-only":new a(".foundation-mq-xlarge-only"),xxlarge:new a(".foundation-mq-xxlarge")},stylesheet:t("<style></style>").appendTo("head")[0].sheet,global:{namespace:s},init:function(t,i,s,n,a){var o=[t,s,n,a],l=[];if(this.rtl=/rtl/i.test(r("html").attr("dir")),this.scope=t||this.scope,this.set_namespace(),i&&"string"==typeof i&&!/reflow/i.test(i))this.libs.hasOwnProperty(i)&&l.push(this.init_lib(i,o));else for(var d in this.libs)l.push(this.init_lib(d,i));return r(e).load(function(){r(e).trigger("resize.fndtn.clearing").trigger("resize.fndtn.dropdown").trigger("resize.fndtn.equalizer").trigger("resize.fndtn.interchange").trigger("resize.fndtn.joyride").trigger("resize.fndtn.magellan").trigger("resize.fndtn.topbar").trigger("resize.fndtn.slider")}),t},init_lib:function(e,i){return this.libs.hasOwnProperty(e)?(this.patch(this.libs[e]),i&&i.hasOwnProperty(e)?("undefined"!=typeof this.libs[e].settings?t.extend(!0,this.libs[e].settings,i[e]):"undefined"!=typeof this.libs[e].defaults&&t.extend(!0,this.libs[e].defaults,i[e]),this.libs[e].init.apply(this.libs[e],[this.scope,i[e]])):(i=i instanceof Array?i:new Array(i),this.libs[e].init.apply(this.libs[e],i))):function(){}},patch:function(t){t.scope=this.scope,t.namespace=this.global.namespace,t.rtl=this.rtl,t.data_options=this.utils.data_options,t.attr_name=l,t.add_namespace=d,t.bindings=c,t.S=this.utils.S},inherit:function(t,e){for(var i=e.split(" "),s=i.length;s--;)this.utils.hasOwnProperty(i[s])&&(t[i[s]]=this.utils[i[s]])},set_namespace:function(){var e=this.global.namespace===s?t(".foundation-data-attribute-namespace").css("font-family"):this.global.namespace;this.global.namespace=e===s||/false/i.test(e)?"":e},libs:{},utils:{S:r,throttle:function(t,e){var i=null;return function(){var s=this,n=arguments;null==i&&(i=setTimeout(function(){t.apply(s,n),i=null},e))}},debounce:function(t,e,i){var s,n;return function(){var a=this,o=arguments,r=function(){s=null,i||(n=t.apply(a,o))},l=i&&!s;return clearTimeout(s),s=setTimeout(r,e),l&&(n=t.apply(a,o)),n}},data_options:function(e,i){function s(t){return!isNaN(t-0)&&null!==t&&""!==t&&t!==!1&&t!==!0}function n(e){return"string"==typeof e?t.trim(e):e}i=i||"options";var a,o,r,l={},d=function(t){var e=Foundation.global.namespace;return t.data(e.length>0?e+"-"+i:i)},c=d(e);if("object"==typeof c)return c;for(r=(c||":").split(";"),a=r.length;a--;)o=r[a].split(":"),o=[o[0],o.slice(1).join(":")],/true/i.test(o[1])&&(o[1]=!0),/false/i.test(o[1])&&(o[1]=!1),s(o[1])&&(o[1]=-1===o[1].indexOf(".")?parseInt(o[1],10):parseFloat(o[1])),2===o.length&&o[0].length>0&&(l[n(o[0])]=n(o[1]));return l},register_media:function(e,i){Foundation.media_queries[e]===s&&(t("head").append('<meta class="'+i+'"/>'),Foundation.media_queries[e]=n(t("."+i).css("font-family")))},add_custom_rule:function(t,e){if(e===s&&Foundation.stylesheet)Foundation.stylesheet.insertRule(t,Foundation.stylesheet.cssRules.length);else{var i=Foundation.media_queries[e];i!==s&&Foundation.stylesheet.insertRule("@media "+Foundation.media_queries[e]+"{ "+t+" }",Foundation.stylesheet.cssRules.length)}},image_loaded:function(t,e){function i(t){for(var e=t.length,i=e-1;i>=0;i--)if(t.attr("height")===s)return!1;return!0}var n=this,a=t.length;(0===a||i(t))&&e(t),t.each(function(){h(n.S(this),function(){a-=1,0===a&&e(t)})})},random_str:function(){return this.fidx||(this.fidx=0),this.prefix=this.prefix||[this.name||"F",(+new Date).toString(36)].join("-"),this.prefix+(this.fidx++).toString(36)},match:function(t){return e.matchMedia(t).matches},is_small_up:function(){return this.match(Foundation.media_queries.small)},is_medium_up:function(){return this.match(Foundation.media_queries.medium)},is_large_up:function(){return this.match(Foundation.media_queries.large)},is_xlarge_up:function(){return this.match(Foundation.media_queries.xlarge)},is_xxlarge_up:function(){return this.match(Foundation.media_queries.xxlarge)},is_small_only:function(){return!(this.is_medium_up()||this.is_large_up()||this.is_xlarge_up()||this.is_xxlarge_up())},is_medium_only:function(){return this.is_medium_up()&&!this.is_large_up()&&!this.is_xlarge_up()&&!this.is_xxlarge_up()},is_large_only:function(){return this.is_medium_up()&&this.is_large_up()&&!this.is_xlarge_up()&&!this.is_xxlarge_up()},is_xlarge_only:function(){return this.is_medium_up()&&this.is_large_up()&&this.is_xlarge_up()&&!this.is_xxlarge_up()},is_xxlarge_only:function(){return this.is_medium_up()&&this.is_large_up()&&this.is_xlarge_up()&&this.is_xxlarge_up()}}},t.fn.foundation=function(){var t=Array.prototype.slice.call(arguments,0);return this.each(function(){return Foundation.init.apply(Foundation,[this].concat(t)),this})}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs.slider={name:"slider",version:"5.5.3",settings:{start:0,end:100,step:1,precision:2,initial:null,display_selector:"",vertical:!1,trigger_input_change:!1,on_change:function(){}},cache:{},init:function(t,e,i){Foundation.inherit(this,"throttle"),this.bindings(e,i),this.reflow()},events:function(){var i=this;t(this.scope).off(".slider").on("mousedown.fndtn.slider touchstart.fndtn.slider pointerdown.fndtn.slider","["+i.attr_name()+"]:not(.disabled, [disabled]) .range-slider-handle",function(e){i.cache.active||(e.preventDefault(),i.set_active_slider(t(e.target)))}).on("mousemove.fndtn.slider touchmove.fndtn.slider pointermove.fndtn.slider",function(s){if(i.cache.active)if(s.preventDefault(),t.data(i.cache.active[0],"settings").vertical){var n=0;s.pageY||(n=e.scrollY),i.calculate_position(i.cache.active,i.get_cursor_position(s,"y")+n)}else i.calculate_position(i.cache.active,i.get_cursor_position(s,"x"))}).on("mouseup.fndtn.slider touchend.fndtn.slider pointerup.fndtn.slider",function(s){if(!i.cache.active){var n="slider"===t(s.target).attr("role")?t(s.target):t(s.target).closest(".range-slider").find("[role='slider']");if(n.length&&!n.parent().hasClass("disabled")&&!n.parent().attr("disabled"))if(i.set_active_slider(n),t.data(i.cache.active[0],"settings").vertical){var a=0;s.pageY||(a=e.scrollY),i.calculate_position(i.cache.active,i.get_cursor_position(s,"y")+a)}else i.calculate_position(i.cache.active,i.get_cursor_position(s,"x"))}i.remove_active_slider()}).on("change.fndtn.slider",function(){i.settings.on_change()}),i.S(e).on("resize.fndtn.slider",i.throttle(function(){i.reflow()},300)),this.S("["+this.attr_name()+"]").each(function(){var e=t(this),s=e.children(".range-slider-handle")[0],n=i.initialize_settings(s);""!=n.display_selector&&t(n.display_selector).each(function(){t(this).attr("value")&&t(this).off("change").on("change",function(){e.foundation("slider","set_value",t(this).val())})})})},get_cursor_position:function(t,e){var i,s="page"+e.toUpperCase(),n="client"+e.toUpperCase();return"undefined"!=typeof t[s]?i=t[s]:"undefined"!=typeof t.originalEvent[n]?i=t.originalEvent[n]:t.originalEvent.touches&&t.originalEvent.touches[0]&&"undefined"!=typeof t.originalEvent.touches[0][n]?i=t.originalEvent.touches[0][n]:t.currentPoint&&"undefined"!=typeof t.currentPoint[e]&&(i=t.currentPoint[e]),i},set_active_slider:function(t){this.cache.active=t},remove_active_slider:function(){this.cache.active=null},calculate_position:function(e,i){var s=this,n=t.data(e[0],"settings"),a=(t.data(e[0],"handle_l"),t.data(e[0],"handle_o"),t.data(e[0],"bar_l")),o=t.data(e[0],"bar_o");requestAnimationFrame(function(){var t;t=Foundation.rtl&&!n.vertical?s.limit_to((o+a-i)/a,0,1):s.limit_to((i-o)/a,0,1),t=n.vertical?1-t:t;var r=s.normalized_value(t,n.start,n.end,n.step,n.precision);s.set_ui(e,r)})},set_ui:function(e,i){var s=t.data(e[0],"settings"),n=t.data(e[0],"handle_l"),a=t.data(e[0],"bar_l"),o=this.normalized_percentage(i,s.start,s.end),r=o*(a-n)-1,l=100*o,d=e.parent(),c=e.parent().children("input[type=hidden]");Foundation.rtl&&!s.vertical&&(r=-r),r=s.vertical?-r+a-n+1:r,this.set_translate(e,r,s.vertical),s.vertical?e.siblings(".range-slider-active-segment").css("height",l+"%"):e.siblings(".range-slider-active-segment").css("width",l+"%"),d.attr(this.attr_name(),i).trigger("change.fndtn.slider"),c.val(i),s.trigger_input_change&&c.trigger("change.fndtn.slider"),e[0].hasAttribute("aria-valuemin")||e.attr({"aria-valuemin":s.start,"aria-valuemax":s.end}),e.attr("aria-valuenow",i),""!=s.display_selector&&t(s.display_selector).each(function(){this.hasAttribute("value")?t(this).val(i):t(this).text(i)})},normalized_percentage:function(t,e,i){return Math.min(1,(t-e)/(i-e))},normalized_value:function(t,e,i,s,n){var a=i-e,o=t*a,r=(o-o%s)/s,l=o%s,d=l>=.5*s?s:0;return(r*s+d+e).toFixed(n)},set_translate:function(e,i,s){s?t(e).css("-webkit-transform","translateY("+i+"px)").css("-moz-transform","translateY("+i+"px)").css("-ms-transform","translateY("+i+"px)").css("-o-transform","translateY("+i+"px)").css("transform","translateY("+i+"px)"):t(e).css("-webkit-transform","translateX("+i+"px)").css("-moz-transform","translateX("+i+"px)").css("-ms-transform","translateX("+i+"px)").css("-o-transform","translateX("+i+"px)").css("transform","translateX("+i+"px)")},limit_to:function(t,e,i){return Math.min(Math.max(t,e),i)},initialize_settings:function(e){var i,s=t.extend({},this.settings,this.data_options(t(e).parent()));return null===s.precision&&(i=(""+s.step).match(/\.([\d]*)/),s.precision=i&&i[1]?i[1].length:0),s.vertical?(t.data(e,"bar_o",t(e).parent().offset().top),t.data(e,"bar_l",t(e).parent().outerHeight()),t.data(e,"handle_o",t(e).offset().top),t.data(e,"handle_l",t(e).outerHeight())):(t.data(e,"bar_o",t(e).parent().offset().left),t.data(e,"bar_l",t(e).parent().outerWidth()),t.data(e,"handle_o",t(e).offset().left),t.data(e,"handle_l",t(e).outerWidth())),t.data(e,"bar",t(e).parent()),t.data(e,"settings",s)},set_initial_position:function(e){var i=t.data(e.children(".range-slider-handle")[0],"settings"),s="number"!=typeof i.initial||isNaN(i.initial)?Math.floor(.5*(i.end-i.start)/i.step)*i.step+i.start:i.initial,n=e.children(".range-slider-handle");this.set_ui(n,s)},set_value:function(e){var i=this;t("["+i.attr_name()+"]",this.scope).each(function(){t(this).attr(i.attr_name(),e)}),t(this.scope).attr(i.attr_name())&&t(this.scope).attr(i.attr_name(),e),i.reflow()},reflow:function(){var e=this;e.S("["+this.attr_name()+"]").each(function(){var i=t(this).children(".range-slider-handle")[0],s=t(this).attr(e.attr_name());e.initialize_settings(i),s?e.set_ui(t(i),parseFloat(s)):e.set_initial_position(t(this))})}}}(jQuery,window,window.document),function(t,e,i,s){"use strict";Foundation.libs.joyride={name:"joyride",version:"5.5.3",defaults:{expose:!1,modal:!0,keyboard:!0,tip_location:"bottom",nub_position:"auto",scroll_speed:1500,scroll_animation:"linear",timer:0,start_timer_on_click:!0,start_offset:0,next_button:!0,prev_button:!0,tip_animation:"fade",pause_after:[],exposed:[],tip_animation_fade_speed:300,cookie_monster:!1,cookie_name:"joyride",cookie_domain:!1,cookie_expires:365,tip_container:"body",abort_on_close:!0,tip_location_patterns:{top:["bottom"],bottom:[],left:["right","top","bottom"],right:["left","top","bottom"]},post_ride_callback:function(){},post_step_callback:function(){},pre_step_callback:function(){},pre_ride_callback:function(){},post_expose_callback:function(){},template:{link:'<a href="#close" class="joyride-close-tip">&times;</a>',timer:'<div class="joyride-timer-indicator-wrap"><span class="joyride-timer-indicator"></span></div>',tip:'<div class="joyride-tip-guide"><span class="joyride-nub"></span></div>',wrapper:'<div class="joyride-content-wrapper"></div>',button:'<a href="#" class="small button joyride-next-tip"></a>',prev_button:'<a href="#" class="small button joyride-prev-tip"></a>',modal:'<div class="joyride-modal-bg"></div>',expose:'<div class="joyride-expose-wrapper"></div>',expose_cover:'<div class="joyride-expose-cover"></div>'},expose_add_class:""},init:function(e,i,s){Foundation.inherit(this,"throttle random_str"),this.settings=this.settings||t.extend({},this.defaults,s||i),this.bindings(i,s)},go_next:function(){this.settings.$li.next().length<1?this.end():this.settings.timer>0?(clearTimeout(this.settings.automate),this.hide(),this.show(),this.startTimer()):(this.hide(),this.show())},go_prev:function(){this.settings.$li.prev().length<1||(this.settings.timer>0?(clearTimeout(this.settings.automate),this.hide(),this.show(null,!0),this.startTimer()):(this.hide(),this.show(null,!0)))},events:function(){var i=this;t(this.scope).off(".joyride").on("click.fndtn.joyride",".joyride-next-tip, .joyride-modal-bg",function(t){t.preventDefault(),this.go_next()}.bind(this)).on("click.fndtn.joyride",".joyride-prev-tip",function(t){t.preventDefault(),this.go_prev()}.bind(this)).on("click.fndtn.joyride",".joyride-close-tip",function(t){t.preventDefault(),this.end(this.settings.abort_on_close)}.bind(this)).on("keyup.fndtn.joyride",function(t){if(this.settings.keyboard&&this.settings.riding)switch(t.which){case 39:t.preventDefault(),this.go_next();break;case 37:t.preventDefault(),this.go_prev();break;case 27:t.preventDefault(),this.end(this.settings.abort_on_close)}}.bind(this)),t(e).off(".joyride").on("resize.fndtn.joyride",i.throttle(function(){if(t("["+i.attr_name()+"]").length>0&&i.settings.$next_tip&&i.settings.riding){if(i.settings.exposed.length>0){var e=t(i.settings.exposed);e.each(function(){var e=t(this);i.un_expose(e),i.expose(e)})}i.is_phone()?i.pos_phone():i.pos_default(!1)}},100))},start:function(){var e=this,i=t("["+this.attr_name()+"]",this.scope),s=["timer","scrollSpeed","startOffset","tipAnimationFadeSpeed","cookieExpires"],n=s.length;!i.length>0||(this.settings.init||this.events(),this.settings=i.data(this.attr_name(!0)+"-init"),this.settings.$content_el=i,this.settings.$body=t(this.settings.tip_container),this.settings.body_offset=t(this.settings.tip_container).position(),this.settings.$tip_content=this.settings.$content_el.find("> li"),this.settings.paused=!1,this.settings.attempts=0,this.settings.riding=!0,"function"!=typeof t.cookie&&(this.settings.cookie_monster=!1),(!this.settings.cookie_monster||this.settings.cookie_monster&&!t.cookie(this.settings.cookie_name))&&(this.settings.$tip_content.each(function(i){var a=t(this);this.settings=t.extend({},e.defaults,e.data_options(a));for(var o=n;o--;)e.settings[s[o]]=parseInt(e.settings[s[o]],10);e.create({$li:a,index:i})}),!this.settings.start_timer_on_click&&this.settings.timer>0?(this.show("init"),this.startTimer()):this.show("init")))},resume:function(){this.set_li(),this.show()},tip_template:function(e){var i,s;return e.tip_class=e.tip_class||"",i=t(this.settings.template.tip).addClass(e.tip_class),s=t.trim(t(e.li).html())+this.prev_button_text(e.prev_button_text,e.index)+this.button_text(e.button_text)+this.settings.template.link+this.timer_instance(e.index),i.append(t(this.settings.template.wrapper)),i.first().attr(this.add_namespace("data-index"),e.index),t(".joyride-content-wrapper",i).append(s),i[0]},timer_instance:function(e){var i;return i=0===e&&this.settings.start_timer_on_click&&this.settings.timer>0||0===this.settings.timer?"":t(this.settings.template.timer)[0].outerHTML},button_text:function(e){return this.settings.tip_settings.next_button?(e=t.trim(e)||"Next",e=t(this.settings.template.button).append(e)[0].outerHTML):e="",e},prev_button_text:function(e,i){return this.settings.tip_settings.prev_button?(e=t.trim(e)||"Previous",e=0==i?t(this.settings.template.prev_button).append(e).addClass("disabled")[0].outerHTML:t(this.settings.template.prev_button).append(e)[0].outerHTML):e="",e},create:function(e){this.settings.tip_settings=t.extend({},this.settings,this.data_options(e.$li));var i=e.$li.attr(this.add_namespace("data-button"))||e.$li.attr(this.add_namespace("data-text")),s=e.$li.attr(this.add_namespace("data-button-prev"))||e.$li.attr(this.add_namespace("data-prev-text")),n=e.$li.attr("class"),a=t(this.tip_template({tip_class:n,index:e.index,button_text:i,prev_button_text:s,li:e.$li}));t(this.settings.tip_container).append(a)},show:function(e,i){var n=null;if(this.settings.$li===s||-1===t.inArray(this.settings.$li.index(),this.settings.pause_after))if(this.settings.paused?this.settings.paused=!1:this.set_li(e,i),this.settings.attempts=0,this.settings.$li.length&&this.settings.$target.length>0){if(e&&(this.settings.pre_ride_callback(this.settings.$li.index(),this.settings.$next_tip),this.settings.modal&&this.show_modal()),this.settings.pre_step_callback(this.settings.$li.index(),this.settings.$next_tip),this.settings.modal&&this.settings.expose&&this.expose(),this.settings.tip_settings=t.extend({},this.settings,this.data_options(this.settings.$li)),this.settings.timer=parseInt(this.settings.timer,10),this.settings.tip_settings.tip_location_pattern=this.settings.tip_location_patterns[this.settings.tip_settings.tip_location],!/body/i.test(this.settings.$target.selector)&&!this.settings.expose){var a=t(".joyride-modal-bg");/pop/i.test(this.settings.tipAnimation)?a.hide():a.fadeOut(this.settings.tipAnimationFadeSpeed),this.scroll_to()}this.is_phone()?this.pos_phone(!0):this.pos_default(!0),n=this.settings.$next_tip.find(".joyride-timer-indicator"),/pop/i.test(this.settings.tip_animation)?(n.width(0),this.settings.timer>0?(this.settings.$next_tip.show(),setTimeout(function(){n.animate({width:n.parent().width()},this.settings.timer,"linear")}.bind(this),this.settings.tip_animation_fade_speed)):this.settings.$next_tip.show()):/fade/i.test(this.settings.tip_animation)&&(n.width(0),this.settings.timer>0?(this.settings.$next_tip.fadeIn(this.settings.tip_animation_fade_speed).show(),setTimeout(function(){n.animate({width:n.parent().width()},this.settings.timer,"linear")}.bind(this),this.settings.tip_animation_fade_speed)):this.settings.$next_tip.fadeIn(this.settings.tip_animation_fade_speed)),this.settings.$current_tip=this.settings.$next_tip}else this.settings.$li&&this.settings.$target.length<1?this.show(e,i):this.end();else this.settings.paused=!0},is_phone:function(){return matchMedia(Foundation.media_queries.small).matches&&!matchMedia(Foundation.media_queries.medium).matches},hide:function(){this.settings.modal&&this.settings.expose&&this.un_expose(),this.settings.modal||t(".joyride-modal-bg").hide(),this.settings.$current_tip.css("visibility","hidden"),setTimeout(t.proxy(function(){this.hide(),this.css("visibility","visible")},this.settings.$current_tip),0),this.settings.post_step_callback(this.settings.$li.index(),this.settings.$current_tip)},set_li:function(t,e){t?(this.settings.$li=this.settings.$tip_content.eq(this.settings.start_offset),this.set_next_tip(),this.settings.$current_tip=this.settings.$next_tip):(this.settings.$li=e?this.settings.$li.prev():this.settings.$li.next(),this.set_next_tip()),this.set_target()},set_next_tip:function(){this.settings.$next_tip=t(".joyride-tip-guide").eq(this.settings.$li.index()),this.settings.$next_tip.data("closed","")},set_target:function(){var e=this.settings.$li.attr(this.add_namespace("data-class")),s=this.settings.$li.attr(this.add_namespace("data-id")),n=function(){return s?t(i.getElementById(s)):e?t("."+e).first():t("body")};this.settings.$target=n()},scroll_to:function(){var i,s;i=t(e).height()/2,s=Math.ceil(this.settings.$target.offset().top-i+this.settings.$next_tip.outerHeight()),0!=s&&t("html, body").stop().animate({scrollTop:s},this.settings.scroll_speed,"swing")},paused:function(){return-1===t.inArray(this.settings.$li.index()+1,this.settings.pause_after)},restart:function(){this.hide(),this.settings.$li=s,this.show("init")},pos_default:function(t){var e=this.settings.$next_tip.find(".joyride-nub"),i=Math.ceil(e.outerWidth()/2),s=Math.ceil(e.outerHeight()/2),n=t||!1;if(n&&(this.settings.$next_tip.css("visibility","hidden"),this.settings.$next_tip.show()),/body/i.test(this.settings.$target.selector))this.settings.$li.length&&this.pos_modal(e);else{var a=this.settings.tip_settings.tipAdjustmentY?parseInt(this.settings.tip_settings.tipAdjustmentY):0,o=this.settings.tip_settings.tipAdjustmentX?parseInt(this.settings.tip_settings.tipAdjustmentX):0;this.bottom()?(this.settings.$next_tip.css(this.rtl?{top:this.settings.$target.offset().top+s+this.settings.$target.outerHeight()+a,left:this.settings.$target.offset().left+this.settings.$target.outerWidth()-this.settings.$next_tip.outerWidth()+o}:{top:this.settings.$target.offset().top+s+this.settings.$target.outerHeight()+a,left:this.settings.$target.offset().left+o}),this.nub_position(e,this.settings.tip_settings.nub_position,"top")):this.top()?(this.settings.$next_tip.css(this.rtl?{top:this.settings.$target.offset().top-this.settings.$next_tip.outerHeight()-s+a,left:this.settings.$target.offset().left+this.settings.$target.outerWidth()-this.settings.$next_tip.outerWidth()}:{top:this.settings.$target.offset().top-this.settings.$next_tip.outerHeight()-s+a,left:this.settings.$target.offset().left+o}),this.nub_position(e,this.settings.tip_settings.nub_position,"bottom")):this.right()?(this.settings.$next_tip.css({top:this.settings.$target.offset().top+a,left:this.settings.$target.outerWidth()+this.settings.$target.offset().left+i+o}),this.nub_position(e,this.settings.tip_settings.nub_position,"left")):this.left()&&(this.settings.$next_tip.css({top:this.settings.$target.offset().top+a,left:this.settings.$target.offset().left-this.settings.$next_tip.outerWidth()-i+o}),this.nub_position(e,this.settings.tip_settings.nub_position,"right")),!this.visible(this.corners(this.settings.$next_tip))&&this.settings.attempts<this.settings.tip_settings.tip_location_pattern.length&&(e.removeClass("bottom").removeClass("top").removeClass("right").removeClass("left"),this.settings.tip_settings.tip_location=this.settings.tip_settings.tip_location_pattern[this.settings.attempts],this.settings.attempts++,this.pos_default())}n&&(this.settings.$next_tip.hide(),this.settings.$next_tip.css("visibility","visible"))},pos_phone:function(e){var i=this.settings.$next_tip.outerHeight(),s=(this.settings.$next_tip.offset(),this.settings.$target.outerHeight()),n=t(".joyride-nub",this.settings.$next_tip),a=Math.ceil(n.outerHeight()/2),o=e||!1;n.removeClass("bottom").removeClass("top").removeClass("right").removeClass("left"),o&&(this.settings.$next_tip.css("visibility","hidden"),this.settings.$next_tip.show()),/body/i.test(this.settings.$target.selector)?this.settings.$li.length&&this.pos_modal(n):this.top()?(this.settings.$next_tip.offset({top:this.settings.$target.offset().top-i-a}),n.addClass("bottom")):(this.settings.$next_tip.offset({top:this.settings.$target.offset().top+s+a}),n.addClass("top")),o&&(this.settings.$next_tip.hide(),this.settings.$next_tip.css("visibility","visible"))},pos_modal:function(t){this.center(),t.hide(),this.show_modal()},show_modal:function(){if(!this.settings.$next_tip.data("closed")){var e=t(".joyride-modal-bg");if(e.length<1){var e=t(this.settings.template.modal);e.appendTo("body")}/pop/i.test(this.settings.tip_animation)?e.show():e.fadeIn(this.settings.tip_animation_fade_speed)}},expose:function(){var i,s,n,a,o,r="expose-"+this.random_str(6);if(arguments.length>0&&arguments[0]instanceof t)n=arguments[0];else{if(!this.settings.$target||/body/i.test(this.settings.$target.selector))return!1;n=this.settings.$target}return n.length<1?(e.console&&console.error("element not valid",n),!1):(i=t(this.settings.template.expose),this.settings.$body.append(i),i.css({top:n.offset().top,left:n.offset().left,width:n.outerWidth(!0),height:n.outerHeight(!0)}),s=t(this.settings.template.expose_cover),a={zIndex:n.css("z-index"),position:n.css("position")},o=null==n.attr("class")?"":n.attr("class"),n.css("z-index",parseInt(i.css("z-index"))+1),"static"==a.position&&n.css("position","relative"),n.data("expose-css",a),n.data("orig-class",o),n.attr("class",o+" "+this.settings.expose_add_class),s.css({top:n.offset().top,left:n.offset().left,width:n.outerWidth(!0),height:n.outerHeight(!0)}),this.settings.modal&&this.show_modal(),this.settings.$body.append(s),i.addClass(r),s.addClass(r),n.data("expose",r),this.settings.post_expose_callback(this.settings.$li.index(),this.settings.$next_tip,n),void this.add_exposed(n))},un_expose:function(){var i,s,n,a,o,r=!1;if(arguments.length>0&&arguments[0]instanceof t)s=arguments[0];else{if(!this.settings.$target||/body/i.test(this.settings.$target.selector))return!1;s=this.settings.$target}return s.length<1?(e.console&&console.error("element not valid",s),!1):(i=s.data("expose"),n=t("."+i),arguments.length>1&&(r=arguments[1]),r===!0?t(".joyride-expose-wrapper,.joyride-expose-cover").remove():n.remove(),a=s.data("expose-css"),"auto"==a.zIndex?s.css("z-index",""):s.css("z-index",a.zIndex),a.position!=s.css("position")&&("static"==a.position?s.css("position",""):s.css("position",a.position)),o=s.data("orig-class"),s.attr("class",o),s.removeData("orig-classes"),s.removeData("expose"),s.removeData("expose-z-index"),void this.remove_exposed(s))},add_exposed:function(e){this.settings.exposed=this.settings.exposed||[],e instanceof t||"object"==typeof e?this.settings.exposed.push(e[0]):"string"==typeof e&&this.settings.exposed.push(e)},remove_exposed:function(e){var i,s;for(e instanceof t?i=e[0]:"string"==typeof e&&(i=e),this.settings.exposed=this.settings.exposed||[],s=this.settings.exposed.length;s--;)if(this.settings.exposed[s]==i)return void this.settings.exposed.splice(s,1)},center:function(){var i=t(e);return this.settings.$next_tip.css({top:(i.height()-this.settings.$next_tip.outerHeight())/2+i.scrollTop(),left:(i.width()-this.settings.$next_tip.outerWidth())/2+i.scrollLeft()}),!0},bottom:function(){return/bottom/i.test(this.settings.tip_settings.tip_location)},top:function(){return/top/i.test(this.settings.tip_settings.tip_location)},right:function(){return/right/i.test(this.settings.tip_settings.tip_location)},left:function(){return/left/i.test(this.settings.tip_settings.tip_location)},corners:function(i){if(0===i.length)return[!1,!1,!1,!1];var s=t(e),n=s.height()/2,a=Math.ceil(this.settings.$target.offset().top-n+this.settings.$next_tip.outerHeight()),o=s.width()+s.scrollLeft(),r=s.height()+a,l=s.height()+s.scrollTop(),d=s.scrollTop();return d>a&&(d=0>a?0:a),r>l&&(l=r),[i.offset().top<d,o<i.offset().left+i.outerWidth(),l<i.offset().top+i.outerHeight(),s.scrollLeft()>i.offset().left]},visible:function(t){for(var e=t.length;e--;)if(t[e])return!1;return!0},nub_position:function(t,e,i){t.addClass("auto"===e?i:e)},startTimer:function(){this.settings.$li.length?this.settings.automate=setTimeout(function(){this.hide(),this.show(),this.startTimer()}.bind(this),this.settings.timer):clearTimeout(this.settings.automate)},end:function(e){this.settings.cookie_monster&&t.cookie(this.settings.cookie_name,"ridden",{expires:this.settings.cookie_expires,domain:this.settings.cookie_domain}),this.settings.timer>0&&clearTimeout(this.settings.automate),this.settings.modal&&this.settings.expose&&this.un_expose(),t(this.scope).off("keyup.joyride"),this.settings.$next_tip.data("closed",!0),this.settings.riding=!1,t(".joyride-modal-bg").hide(),this.settings.$current_tip.hide(),("undefined"==typeof e||e===!1)&&(this.settings.post_step_callback(this.settings.$li.index(),this.settings.$current_tip),this.settings.post_ride_callback(this.settings.$li.index(),this.settings.$current_tip)),t(".joyride-tip-guide").remove()},off:function(){t(this.scope).off(".joyride"),t(e).off(".joyride"),t(".joyride-close-tip, .joyride-next-tip, .joyride-modal-bg").off(".joyride"),t(".joyride-tip-guide, .joyride-modal-bg").remove(),clearTimeout(this.settings.automate)},reflow:function(){}}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs.equalizer={name:"equalizer",version:"5.5.3",settings:{use_tallest:!0,before_height_change:t.noop,after_height_change:t.noop,equalize_on_stack:!1,act_on_hidden_el:!1},init:function(t,e,i){Foundation.inherit(this,"image_loaded"),this.bindings(e,i),this.reflow()},events:function(){this.S(e).off(".equalizer").on("resize.fndtn.equalizer",function(){this.reflow()}.bind(this))},equalize:function(e){var i,s,n=!1,a=e.data("equalizer"),o=e.data(this.attr_name(!0)+"-init")||this.settings;if(i=e.find(o.act_on_hidden_el?a?"["+this.attr_name()+'-watch="'+a+'"]':"["+this.attr_name()+"-watch]":a?"["+this.attr_name()+'-watch="'+a+'"]:visible':"["+this.attr_name()+"-watch]:visible"),0!==i.length&&(o.before_height_change(),e.trigger("before-height-change.fndth.equalizer"),i.height("inherit"),o.equalize_on_stack!==!1||(s=i.first().offset().top,i.each(function(){return t(this).offset().top!==s?(n=!0,!1):void 0}),!n))){var r=i.map(function(){return t(this).outerHeight(!1)}).get();if(o.use_tallest){var l=Math.max.apply(null,r);i.css("height",l)}else{var d=Math.min.apply(null,r);i.css("height",d)}o.after_height_change(),e.trigger("after-height-change.fndtn.equalizer")}},reflow:function(){var e=this;this.S("["+this.attr_name()+"]",this.scope).each(function(){var i=t(this),s=i.data("equalizer-mq"),n=!0;s&&(s="is_"+s.replace(/-/g,"_"),Foundation.utils.hasOwnProperty(s)&&(n=!1)),e.image_loaded(e.S("img",this),function(){if(n||Foundation.utils[s]())e.equalize(i);else{var t=i.find("["+e.attr_name()+"-watch]:visible");t.css("height","auto")}})})}}}(jQuery,window,window.document),function(t,e,i){"use strict";Foundation.libs.dropdown={name:"dropdown",version:"5.5.3",settings:{active_class:"open",disabled_class:"disabled",mega_class:"mega",align:"bottom",is_hover:!1,hover_timeout:150,opened:function(){},closed:function(){}},init:function(e,i,s){Foundation.inherit(this,"throttle"),t.extend(!0,this.settings,i,s),this.bindings(i,s)},events:function(){var s=this,n=s.S;n(this.scope).off(".dropdown").on("click.fndtn.dropdown","["+this.attr_name()+"]",function(e){var i=n(this).data(s.attr_name(!0)+"-init")||s.settings;(!i.is_hover||Modernizr.touch)&&(e.preventDefault(),n(this).parent("[data-reveal-id]").length&&e.stopPropagation(),s.toggle(t(this)))}).on("mouseenter.fndtn.dropdown","["+this.attr_name()+"], ["+this.attr_name()+"-content]",function(t){var e,i,a=n(this);clearTimeout(s.timeout),a.data(s.data_attr())?(e=n("#"+a.data(s.data_attr())),i=a):(e=a,i=n("["+s.attr_name()+'="'+e.attr("id")+'"]'));var o=i.data(s.attr_name(!0)+"-init")||s.settings;n(t.currentTarget).data(s.data_attr())&&o.is_hover&&s.closeall.call(s),o.is_hover&&s.open.apply(s,[e,i])}).on("mouseleave.fndtn.dropdown","["+this.attr_name()+"], ["+this.attr_name()+"-content]",function(){var t,e=n(this);if(e.data(s.data_attr()))t=e.data(s.data_attr(!0)+"-init")||s.settings;else var i=n("["+s.attr_name()+'="'+n(this).attr("id")+'"]'),t=i.data(s.attr_name(!0)+"-init")||s.settings;s.timeout=setTimeout(function(){e.data(s.data_attr())?t.is_hover&&s.close.call(s,n("#"+e.data(s.data_attr()))):t.is_hover&&s.close.call(s,e)}.bind(this),t.hover_timeout)}).on("click.fndtn.dropdown",function(e){var a=n(e.target).closest("["+s.attr_name()+"-content]"),o=a.find("a");return o.length>0&&"false"!==a.attr("aria-autoclose")&&s.close.call(s,n("["+s.attr_name()+"-content]")),e.target!==i&&!t.contains(i.documentElement,e.target)||n(e.target).closest("["+s.attr_name()+"]").length>0?void 0:!n(e.target).data("revealId")&&a.length>0&&(n(e.target).is("["+s.attr_name()+"-content]")||t.contains(a.first()[0],e.target))?void e.stopPropagation():void s.close.call(s,n("["+s.attr_name()+"-content]"))}).on("opened.fndtn.dropdown","["+s.attr_name()+"-content]",function(){s.settings.opened.call(this)}).on("closed.fndtn.dropdown","["+s.attr_name()+"-content]",function(){s.settings.closed.call(this)}),n(e).off(".dropdown").on("resize.fndtn.dropdown",s.throttle(function(){s.resize.call(s)},50)),this.resize()},close:function(e){var i=this;e.each(function(s){var n=t("["+i.attr_name()+"="+e[s].id+"]")||t("aria-controls="+e[s].id+"]");
+n.attr("aria-expanded","false"),i.S(this).hasClass(i.settings.active_class)&&(i.S(this).css(Foundation.rtl?"right":"left","-99999px").attr("aria-hidden","true").removeClass(i.settings.active_class).prev("["+i.attr_name()+"]").removeClass(i.settings.active_class).removeData("target"),i.S(this).trigger("closed.fndtn.dropdown",[e]))}),e.removeClass("f-open-"+this.attr_name(!0))},closeall:function(){var e=this;t.each(e.S(".f-open-"+this.attr_name(!0)),function(){e.close.call(e,e.S(this))})},open:function(t,e){this.css(t.addClass(this.settings.active_class),e),t.prev("["+this.attr_name()+"]").addClass(this.settings.active_class),t.data("target",e.get(0)).trigger("opened.fndtn.dropdown",[t,e]),t.attr("aria-hidden","false"),e.attr("aria-expanded","true"),t.focus(),t.addClass("f-open-"+this.attr_name(!0))},data_attr:function(){return this.namespace.length>0?this.namespace+"-"+this.name:this.name},toggle:function(t){if(!t.hasClass(this.settings.disabled_class)){var e=this.S("#"+t.data(this.data_attr()));0!==e.length&&(this.close.call(this,this.S("["+this.attr_name()+"-content]").not(e)),e.hasClass(this.settings.active_class)?(this.close.call(this,e),e.data("target")!==t.get(0)&&this.open.call(this,e,t)):this.open.call(this,e,t))}},resize:function(){var e=this.S("["+this.attr_name()+"-content].open"),i=t(e.data("target"));e.length&&i.length&&this.css(e,i)},css:function(t,e){var i=Math.max((e.width()-t.width())/2,8),s=e.data(this.attr_name(!0)+"-init")||this.settings,n=t.parent().css("overflow-y")||t.parent().css("overflow");if(this.clear_idx(),this.small()){var a=this.dirs.bottom.call(t,e,s);t.attr("style","").removeClass("drop-left drop-right drop-top").css({position:"absolute",width:"95%","max-width":"none",top:a.top}),t.css(Foundation.rtl?"right":"left",i)}else if("visible"!==n){var o=e[0].offsetTop+e[0].offsetHeight;t.attr("style","").css({position:"absolute",top:o}),t.css(Foundation.rtl?"right":"left",i)}else this.style(t,e,s);return t},style:function(e,i,s){var n=t.extend({position:"absolute"},this.dirs[s.align].call(e,i,s));e.attr("style","").css(n)},dirs:{_base:function(t,s){var n=this.offsetParent(),a=n.offset(),o=t.offset();o.top-=a.top,o.left-=a.left,o.missRight=!1,o.missTop=!1,o.missLeft=!1,o.leftRightFlag=!1;var r,l=e.innerWidth;r=i.getElementsByClassName("row")[0]?i.getElementsByClassName("row")[0].clientWidth:l;var d=(l-r)/2,c=r;if(!this.hasClass("mega")&&!s.ignore_repositioning){var h=this.outerWidth(),u=t.offset().left;t.offset().top<=this.outerHeight()&&(o.missTop=!0,c=l-d,o.leftRightFlag=!0),u+h>u+d&&u-d>h&&(o.missRight=!0,o.missLeft=!1),0>=u-h&&(o.missLeft=!0,o.missRight=!1)}return o},top:function(t,e){var i=Foundation.libs.dropdown,s=i.dirs._base.call(this,t,e);return this.addClass("drop-top"),1==s.missTop&&(s.top=s.top+t.outerHeight()+this.outerHeight(),this.removeClass("drop-top")),1==s.missRight&&(s.left=s.left-this.outerWidth()+t.outerWidth()),(t.outerWidth()<this.outerWidth()||i.small()||this.hasClass(e.mega_menu))&&i.adjust_pip(this,t,e,s),Foundation.rtl?{left:s.left-this.outerWidth()+t.outerWidth(),top:s.top-this.outerHeight()}:{left:s.left,top:s.top-this.outerHeight()}},bottom:function(t,e){var i=Foundation.libs.dropdown,s=i.dirs._base.call(this,t,e);return 1==s.missRight&&(s.left=s.left-this.outerWidth()+t.outerWidth()),(t.outerWidth()<this.outerWidth()||i.small()||this.hasClass(e.mega_menu))&&i.adjust_pip(this,t,e,s),i.rtl?{left:s.left-this.outerWidth()+t.outerWidth(),top:s.top+t.outerHeight()}:{left:s.left,top:s.top+t.outerHeight()}},left:function(t,e){var i=Foundation.libs.dropdown.dirs._base.call(this,t,e);return this.addClass("drop-left"),1==i.missLeft&&(i.left=i.left+this.outerWidth(),i.top=i.top+t.outerHeight(),this.removeClass("drop-left")),{left:i.left-this.outerWidth(),top:i.top}},right:function(t,e){var i=Foundation.libs.dropdown.dirs._base.call(this,t,e);this.addClass("drop-right"),1==i.missRight?(i.left=i.left-this.outerWidth(),i.top=i.top+t.outerHeight(),this.removeClass("drop-right")):i.triggeredRight=!0;var s=Foundation.libs.dropdown;return(t.outerWidth()<this.outerWidth()||s.small()||this.hasClass(e.mega_menu))&&s.adjust_pip(this,t,e,i),{left:i.left+t.outerWidth(),top:i.top}}},adjust_pip:function(t,e,i,s){var n=Foundation.stylesheet,a=8;t.hasClass(i.mega_class)?a=s.left+e.outerWidth()/2-8:this.small()&&(a+=s.left-8),this.rule_idx=n.cssRules.length;var o=".f-dropdown.open:before",r=".f-dropdown.open:after",l="left: "+a+"px;",d="left: "+(a-1)+"px;";1==s.missRight&&(a=t.outerWidth()-23,o=".f-dropdown.open:before",r=".f-dropdown.open:after",l="left: "+a+"px;",d="left: "+(a-1)+"px;"),1==s.triggeredRight&&(o=".f-dropdown.open:before",r=".f-dropdown.open:after",l="left:-12px;",d="left:-14px;"),n.insertRule?(n.insertRule([o,"{",l,"}"].join(" "),this.rule_idx),n.insertRule([r,"{",d,"}"].join(" "),this.rule_idx+1)):(n.addRule(o,l,this.rule_idx),n.addRule(r,d,this.rule_idx+1))},clear_idx:function(){var t=Foundation.stylesheet;"undefined"!=typeof this.rule_idx&&(t.deleteRule(this.rule_idx),t.deleteRule(this.rule_idx),delete this.rule_idx)},small:function(){return matchMedia(Foundation.media_queries.small).matches&&!matchMedia(Foundation.media_queries.medium).matches},off:function(){this.S(this.scope).off(".fndtn.dropdown"),this.S("html, body").off(".fndtn.dropdown"),this.S(e).off(".fndtn.dropdown"),this.S("[data-dropdown-content]").off(".fndtn.dropdown")},reflow:function(){}}}(jQuery,window,window.document),function(t,e,i,s){"use strict";Foundation.libs.clearing={name:"clearing",version:"5.5.3",settings:{templates:{viewing:'<a href="#" class="clearing-close">&times;</a><div class="visible-img" style="display: none"><div class="clearing-touch-label"></div><img src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" alt="" /><p class="clearing-caption"></p><a href="#" class="clearing-main-prev"><span></span></a><a href="#" class="clearing-main-next"><span></span></a></div><img class="clearing-preload-next" style="display: none" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" alt="" /><img class="clearing-preload-prev" style="display: none" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" alt="" />'},close_selectors:".clearing-close, div.clearing-blackout",open_selectors:"",skip_selector:"",touch_label:"",init:!1,locked:!1},init:function(t,e,i){var s=this;Foundation.inherit(this,"throttle image_loaded"),this.bindings(e,i),s.S(this.scope).is("["+this.attr_name()+"]")?this.assemble(s.S("li",this.scope)):s.S("["+this.attr_name()+"]",this.scope).each(function(){s.assemble(s.S("li",this))})},events:function(s){var n=this,a=n.S,o=t(".scroll-container");o.length>0&&(this.scope=o),a(this.scope).off(".clearing").on("click.fndtn.clearing","ul["+this.attr_name()+"] li "+this.settings.open_selectors,function(t,e,i){var e=e||a(this),i=i||e,s=e.next("li"),o=e.closest("["+n.attr_name()+"]").data(n.attr_name(!0)+"-init"),r=a(t.target);t.preventDefault(),o||(n.init(),o=e.closest("["+n.attr_name()+"]").data(n.attr_name(!0)+"-init")),i.hasClass("visible")&&e[0]===i[0]&&s.length>0&&n.is_open(e)&&(i=s,r=a("img",i)),n.open(r,e,i),n.update_paddles(i)}).on("click.fndtn.clearing",".clearing-main-next",function(t){n.nav(t,"next")}).on("click.fndtn.clearing",".clearing-main-prev",function(t){n.nav(t,"prev")}).on("click.fndtn.clearing",this.settings.close_selectors,function(t){Foundation.libs.clearing.close(t,this)}),t(i).on("keydown.fndtn.clearing",function(t){n.keydown(t)}),a(e).off(".clearing").on("resize.fndtn.clearing",function(){n.resize()}),this.swipe_events(s)},swipe_events:function(){var t=this,e=t.S;e(this.scope).on("touchstart.fndtn.clearing",".visible-img",function(t){t.touches||(t=t.originalEvent);var i={start_page_x:t.touches[0].pageX,start_page_y:t.touches[0].pageY,start_time:(new Date).getTime(),delta_x:0,is_scrolling:s};e(this).data("swipe-transition",i),t.stopPropagation()}).on("touchmove.fndtn.clearing",".visible-img",function(i){if(i.touches||(i=i.originalEvent),!(i.touches.length>1||i.scale&&1!==i.scale)){var s=e(this).data("swipe-transition");if("undefined"==typeof s&&(s={}),s.delta_x=i.touches[0].pageX-s.start_page_x,Foundation.rtl&&(s.delta_x=-s.delta_x),"undefined"==typeof s.is_scrolling&&(s.is_scrolling=!!(s.is_scrolling||Math.abs(s.delta_x)<Math.abs(i.touches[0].pageY-s.start_page_y))),!s.is_scrolling&&!s.active){i.preventDefault();var n=s.delta_x<0?"next":"prev";s.active=!0,t.nav(i,n)}}}).on("touchend.fndtn.clearing",".visible-img",function(t){e(this).data("swipe-transition",{}),t.stopPropagation()})},assemble:function(e){var i=e.parent();if(!i.parent().hasClass("carousel")){i.after('<div id="foundationClearingHolder"></div>');var s=i.detach(),n="";if(null!=s[0]){n=s[0].outerHTML;var a=this.S("#foundationClearingHolder"),o=i.data(this.attr_name(!0)+"-init"),r={grid:'<div class="carousel">'+n+"</div>",viewing:o.templates.viewing},l='<div class="clearing-assembled"><div>'+r.viewing+r.grid+"</div></div>",d=this.settings.touch_label;Modernizr.touch&&(l=t(l).find(".clearing-touch-label").html(d).end()),a.after(l).remove()}}},open:function(e,s,n){function a(){setTimeout(function(){this.image_loaded(u,function(){1!==u.outerWidth()||p?o.call(this,u):a.call(this)}.bind(this))}.bind(this),100)}function o(e){var i=t(e);i.css("visibility","visible"),i.trigger("imageVisible"),l.css("overflow","hidden"),d.addClass("clearing-blackout"),c.addClass("clearing-container"),h.show(),this.fix_height(n).caption(r.S(".clearing-caption",h),r.S("img",n)).center_and_label(e,f).shift(s,n,function(){n.closest("li").siblings().removeClass("visible"),n.closest("li").addClass("visible")}),h.trigger("opened.fndtn.clearing")}var r=this,l=t(i.body),d=n.closest(".clearing-assembled"),c=r.S("div",d).first(),h=r.S(".visible-img",c),u=r.S("img",h).not(e),f=r.S(".clearing-touch-label",c),p=!1,g={};t("body").on("touchmove",function(t){t.preventDefault()}),u.error(function(){p=!0}),this.locked()||(h.trigger("open.fndtn.clearing"),g=this.load(e),g.interchange?u.attr("data-interchange",g.interchange).foundation("interchange","reflow"):u.attr("src",g.src).attr("data-interchange",""),u.css("visibility","hidden"),a.call(this))},close:function(e,s){e.preventDefault();var n,a,o=function(t){return/blackout/.test(t.selector)?t:t.closest(".clearing-blackout")}(t(s)),r=t(i.body);return s===e.target&&o&&(r.css("overflow",""),n=t("div",o).first(),a=t(".visible-img",n),a.trigger("close.fndtn.clearing"),this.settings.prev_index=0,t("ul["+this.attr_name()+"]",o).attr("style","").closest(".clearing-blackout").removeClass("clearing-blackout"),n.removeClass("clearing-container"),a.hide(),a.trigger("closed.fndtn.clearing")),t("body").off("touchmove"),!1},is_open:function(t){return t.parent().prop("style").length>0},keydown:function(e){var i=t(".clearing-blackout ul["+this.attr_name()+"]"),s=this.rtl?37:39,n=this.rtl?39:37,a=27;e.which===s&&this.go(i,"next"),e.which===n&&this.go(i,"prev"),e.which===a&&this.S("a.clearing-close").trigger("click.fndtn.clearing")},nav:function(e,i){var s=t("ul["+this.attr_name()+"]",".clearing-blackout");e.preventDefault(),this.go(s,i)},resize:function(){var e=t("img",".clearing-blackout .visible-img"),i=t(".clearing-touch-label",".clearing-blackout");e.length&&(this.center_and_label(e,i),e.trigger("resized.fndtn.clearing"))},fix_height:function(t){var e=t.parent().children(),i=this;return e.each(function(){var t=i.S(this),e=t.find("img");t.height()>e.outerHeight()&&t.addClass("fix-height")}).closest("ul").width(100*e.length+"%"),this},update_paddles:function(t){t=t.closest("li");var e=t.closest(".carousel").siblings(".visible-img");t.next().length>0?this.S(".clearing-main-next",e).removeClass("disabled"):this.S(".clearing-main-next",e).addClass("disabled"),t.prev().length>0?this.S(".clearing-main-prev",e).removeClass("disabled"):this.S(".clearing-main-prev",e).addClass("disabled")},center_and_label:function(t,e){return e.css(!this.rtl&&e.length>0?{marginLeft:-(e.outerWidth()/2),marginTop:-(t.outerHeight()/2)-e.outerHeight()-10}:{marginRight:-(e.outerWidth()/2),marginTop:-(t.outerHeight()/2)-e.outerHeight()-10,left:"auto",right:"50%"}),this},load:function(t){var e,i,s;return"A"===t[0].nodeName?(e=t.attr("href"),i=t.data("clearing-interchange")):(s=t.closest("a"),e=s.attr("href"),i=s.data("clearing-interchange")),this.preload(t),{src:e?e:t.attr("src"),interchange:e?i:t.data("clearing-interchange")}},preload:function(t){this.img(t.closest("li").next(),"next").img(t.closest("li").prev(),"prev")},img:function(e,i){if(e.length){var s,n,a,o=t(".clearing-preload-"+i),r=this.S("a",e);r.length?(s=r.attr("href"),n=r.data("clearing-interchange")):(a=this.S("img",e),s=a.attr("src"),n=a.data("clearing-interchange")),n?o.attr("data-interchange",n):(o.attr("src",s),o.attr("data-interchange",""))}return this},caption:function(t,e){var i=e.attr("data-caption");if(i){var s=t.get(0);s.innerHTML=i,t.show()}else t.text("").hide();return this},go:function(t,e){var i=this.S(".visible",t),s=i[e]();this.settings.skip_selector&&0!=s.find(this.settings.skip_selector).length&&(s=s[e]()),s.length&&this.S("img",s).trigger("click.fndtn.clearing",[i,s]).trigger("change.fndtn.clearing")},shift:function(t,e,i){var s,n=e.parent(),a=this.settings.prev_index||e.index(),o=this.direction(n,t,e),r=this.rtl?"right":"left",l=parseInt(n.css("left"),10),d=e.outerWidth(),c={};e.index()===a||/skip/.test(o)?/skip/.test(o)&&(s=e.index()-this.settings.up_count,this.lock(),s>0?(c[r]=-(s*d),n.animate(c,300,this.unlock())):(c[r]=0,n.animate(c,300,this.unlock()))):/left/.test(o)?(this.lock(),c[r]=l+d,n.animate(c,300,this.unlock())):/right/.test(o)&&(this.lock(),c[r]=l-d,n.animate(c,300,this.unlock())),i()},direction:function(t,e,i){var s,n=this.S("li",t),a=n.outerWidth()+n.outerWidth()/4,o=Math.floor(this.S(".clearing-container").outerWidth()/a)-1,r=n.index(i);return this.settings.up_count=o,s=this.adjacent(this.settings.prev_index,r)?r>o&&r>this.settings.prev_index?"right":r>o-1&&r<=this.settings.prev_index?"left":!1:"skip",this.settings.prev_index=r,s},adjacent:function(t,e){for(var i=e+1;i>=e-1;i--)if(i===t)return!0;return!1},lock:function(){this.settings.locked=!0},unlock:function(){this.settings.locked=!1},locked:function(){return this.settings.locked},off:function(){this.S(this.scope).off(".fndtn.clearing"),this.S(e).off(".fndtn.clearing")},reflow:function(){this.init()}}}(jQuery,window,window.document),function(t,e,i,s){"use strict";var n=function(){},a=function(n,a){if(n.hasClass(a.slides_container_class))return this;var d,c,h,u,f,p,g=this,_=n,m=0,v=!1;g.slides=function(){return _.children(a.slide_selector)},g.slides().first().addClass(a.active_slide_class),g.update_slide_number=function(e){a.slide_number&&(c.find("span:first").text(parseInt(e)+1),c.find("span:last").text(g.slides().length)),a.bullets&&(h.children().removeClass(a.bullets_active_class),t(h.children().get(e)).addClass(a.bullets_active_class))},g.update_active_link=function(e){var i=t('[data-orbit-link="'+g.slides().eq(e).attr("data-orbit-slide")+'"]');i.siblings().removeClass(a.bullets_active_class),i.addClass(a.bullets_active_class)},g.build_markup=function(){_.wrap('<div class="'+a.container_class+'"></div>'),d=_.parent(),_.addClass(a.slides_container_class),a.stack_on_small&&d.addClass(a.stack_on_small_class),a.navigation_arrows&&(d.append(t('<a href="#"><span></span></a>').addClass(a.prev_class)),d.append(t('<a href="#"><span></span></a>').addClass(a.next_class))),a.timer&&(u=t("<div>").addClass(a.timer_container_class),u.append("<span>"),u.append(t("<div>").addClass(a.timer_progress_class)),u.addClass(a.timer_paused_class),d.append(u)),a.slide_number&&(c=t("<div>").addClass(a.slide_number_class),c.append("<span></span> "+a.slide_number_text+" <span></span>"),d.append(c)),a.bullets&&(h=t("<ol>").addClass(a.bullets_container_class),d.append(h),h.wrap('<div class="orbit-bullets-container"></div>'),g.slides().each(function(e){var i=t("<li>").attr("data-orbit-slide",e).on("click",g.link_bullet);h.append(i)}))},g._goto=function(e,i){if(e===m)return!1;"object"==typeof p&&p.restart();var s=g.slides(),n="next";if(v=!0,m>e&&(n="prev"),e>=s.length){if(!a.circular)return!1;e=0}else if(0>e){if(!a.circular)return!1;e=s.length-1}var o=t(s.get(m)),r=t(s.get(e));o.css("zIndex",2),o.removeClass(a.active_slide_class),r.css("zIndex",4).addClass(a.active_slide_class),_.trigger("before-slide-change.fndtn.orbit"),a.before_slide_change(),g.update_active_link(e);var l=function(){var t=function(){m=e,v=!1,i===!0&&(p=g.create_timer(),p.start()),g.update_slide_number(m),_.trigger("after-slide-change.fndtn.orbit",[{slide_number:m,total_slides:s.length}]),a.after_slide_change(m,s.length)};_.outerHeight()!=r.outerHeight()&&a.variable_height?_.animate({height:r.outerHeight()},250,"linear",t):t()};if(1===s.length)return l(),!1;var d=function(){"next"===n&&f.next(o,r,l),"prev"===n&&f.prev(o,r,l)};r.outerHeight()>_.outerHeight()&&a.variable_height?_.animate({height:r.outerHeight()},250,"linear",d):d()},g.next=function(t){t.stopImmediatePropagation(),t.preventDefault(),g._goto(m+1)},g.prev=function(t){t.stopImmediatePropagation(),t.preventDefault(),g._goto(m-1)},g.link_custom=function(e){e.preventDefault();var i=t(this).attr("data-orbit-link");if("string"==typeof i&&""!=(i=t.trim(i))){var s=d.find("[data-orbit-slide="+i+"]");-1!=s.index()&&g._goto(s.index())}},g.link_bullet=function(){var e=t(this).attr("data-orbit-slide");if("string"==typeof e&&""!=(e=t.trim(e)))if(isNaN(parseInt(e))){var i=d.find("[data-orbit-slide="+e+"]");-1!=i.index()&&g._goto(i.index()+1)}else g._goto(parseInt(e))},g.timer_callback=function(){g._goto(m+1,!0)},g.compute_dimensions=function(){var e=t(g.slides().get(m)),i=e.outerHeight();a.variable_height||g.slides().each(function(){t(this).outerHeight()>i&&(i=t(this).outerHeight())}),_.height(i)},g.create_timer=function(){var t=new o(d.find("."+a.timer_container_class),a,g.timer_callback);return t},g.stop_timer=function(){"object"==typeof p&&p.stop()},g.toggle_timer=function(){var t=d.find("."+a.timer_container_class);t.hasClass(a.timer_paused_class)?("undefined"==typeof p&&(p=g.create_timer()),p.start()):"object"==typeof p&&p.stop()},g.init=function(){g.build_markup(),a.timer&&(p=g.create_timer(),Foundation.utils.image_loaded(this.slides().children("img"),p.start)),f=new l(a,_),"slide"===a.animation&&(f=new r(a,_)),d.on("click","."+a.next_class,g.next),d.on("click","."+a.prev_class,g.prev),a.next_on_click&&d.on("click","."+a.slides_container_class+" [data-orbit-slide]",g.link_bullet),d.on("click",g.toggle_timer),a.swipe&&d.on("touchstart.fndtn.orbit",function(t){t.touches||(t=t.originalEvent);var e={start_page_x:t.touches[0].pageX,start_page_y:t.touches[0].pageY,start_time:(new Date).getTime(),delta_x:0,is_scrolling:s};d.data("swipe-transition",e),t.stopPropagation()}).on("touchmove.fndtn.orbit",function(t){if(t.touches||(t=t.originalEvent),!(t.touches.length>1||t.scale&&1!==t.scale)){var e=d.data("swipe-transition");if("undefined"==typeof e&&(e={}),e.delta_x=t.touches[0].pageX-e.start_page_x,"undefined"==typeof e.is_scrolling&&(e.is_scrolling=!!(e.is_scrolling||Math.abs(e.delta_x)<Math.abs(t.touches[0].pageY-e.start_page_y))),!e.is_scrolling&&!e.active){t.preventDefault();var i=e.delta_x<0?m+1:m-1;e.active=!0,g._goto(i)}}}).on("touchend.fndtn.orbit",function(t){d.data("swipe-transition",{}),t.stopPropagation()}),d.on("mouseenter.fndtn.orbit",function(){a.timer&&a.pause_on_hover&&g.stop_timer()}).on("mouseleave.fndtn.orbit",function(){a.timer&&a.resume_on_mouseout&&p.start()}),t(i).on("click","[data-orbit-link]",g.link_custom),t(e).on("load resize",g.compute_dimensions),Foundation.utils.image_loaded(this.slides().children("img"),g.compute_dimensions),Foundation.utils.image_loaded(this.slides().children("img"),function(){d.prev("."+a.preloader_class).css("display","none"),g.update_slide_number(0),g.update_active_link(0),_.trigger("ready.fndtn.orbit")})},g.init()},o=function(t,e,i){var s,n,a=this,o=e.timer_speed,r=t.find("."+e.timer_progress_class),l=-1;this.update_progress=function(t){var e=r.clone();e.attr("style",""),e.css("width",t+"%"),r.replaceWith(e),r=e},this.restart=function(){clearTimeout(n),t.addClass(e.timer_paused_class),l=-1,a.update_progress(0)},this.start=function(){return t.hasClass(e.timer_paused_class)?(l=-1===l?o:l,t.removeClass(e.timer_paused_class),s=(new Date).getTime(),r.animate({width:"100%"},l,"linear"),n=setTimeout(function(){a.restart(),i()},l),void t.trigger("timer-started.fndtn.orbit")):!0},this.stop=function(){if(t.hasClass(e.timer_paused_class))return!0;clearTimeout(n),t.addClass(e.timer_paused_class);var i=(new Date).getTime();l-=i-s;var r=100-l/o*100;a.update_progress(r),t.trigger("timer-stopped.fndtn.orbit")}},r=function(e){var i=e.animation_speed,s=1===t("html[dir=rtl]").length,n=s?"marginRight":"marginLeft",a={};a[n]="0%",this.next=function(t,e,s){t.animate({marginLeft:"-100%"},i),e.animate(a,i,function(){t.css(n,"100%"),s()})},this.prev=function(t,e,s){t.animate({marginLeft:"100%"},i),e.css(n,"-100%"),e.animate(a,i,function(){t.css(n,"100%"),s()})}},l=function(e){{var i=e.animation_speed;1===t("html[dir=rtl]").length}this.next=function(t,e,s){e.css({margin:"0%",opacity:"0.01"}),e.animate({opacity:"1"},i,"linear",function(){t.css("margin","100%"),s()})},this.prev=function(t,e,s){e.css({margin:"0%",opacity:"0.01"}),e.animate({opacity:"1"},i,"linear",function(){t.css("margin","100%"),s()})}};Foundation.libs=Foundation.libs||{},Foundation.libs.orbit={name:"orbit",version:"5.5.3",settings:{animation:"slide",timer_speed:1e4,pause_on_hover:!0,resume_on_mouseout:!1,next_on_click:!0,animation_speed:500,stack_on_small:!1,navigation_arrows:!0,slide_number:!0,slide_number_text:"of",container_class:"orbit-container",stack_on_small_class:"orbit-stack-on-small",next_class:"orbit-next",prev_class:"orbit-prev",timer_container_class:"orbit-timer",timer_paused_class:"paused",timer_progress_class:"orbit-progress",slides_container_class:"orbit-slides-container",preloader_class:"preloader",slide_selector:"*",bullets_container_class:"orbit-bullets",bullets_active_class:"active",slide_number_class:"orbit-slide-number",caption_class:"orbit-caption",active_slide_class:"active",orbit_transition_class:"orbit-transitioning",bullets:!0,circular:!0,timer:!0,variable_height:!1,swipe:!0,before_slide_change:n,after_slide_change:n},init:function(t,e,i){this.bindings(e,i)},events:function(t){var e=new a(this.S(t),this.S(t).data("orbit-init"));this.S(t).data(this.name+"-instance",e)},reflow:function(){var t=this;if(t.S(t.scope).is("[data-orbit]")){var e=t.S(t.scope),i=e.data(t.name+"-instance");i.compute_dimensions()}else t.S("[data-orbit]",t.scope).each(function(e,i){var s=t.S(i),n=(t.data_options(s),s.data(t.name+"-instance"));n.compute_dimensions()})}}}(jQuery,window,window.document),function(t){"use strict";Foundation.libs.offcanvas={name:"offcanvas",version:"5.5.3",settings:{open_method:"move",close_on_click:!1},init:function(t,e,i){this.bindings(e,i)},events:function(){var e=this,i=e.S,s="",n="",a="",o="",r="";"move"===this.settings.open_method?(s="move-",n="right",a="left",o="top",r="bottom"):"overlap_single"===this.settings.open_method?(s="offcanvas-overlap-",n="right",a="left",o="top",r="bottom"):"overlap"===this.settings.open_method&&(s="offcanvas-overlap"),i(this.scope).off(".offcanvas").on("click.fndtn.offcanvas",".left-off-canvas-toggle",function(a){e.click_toggle_class(a,s+n),"overlap"!==e.settings.open_method&&i(".left-submenu").removeClass(s+n),t(".left-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".left-off-canvas-menu a",function(a){var o=e.get_settings(a),r=i(this).parent();!o.close_on_click||r.hasClass("has-submenu")||r.hasClass("back")?i(this).parent().hasClass("has-submenu")?(a.preventDefault(),i(this).siblings(".left-submenu").toggleClass(s+n)):r.hasClass("back")&&(a.preventDefault(),r.parent().removeClass(s+n)):(e.hide.call(e,s+n,e.get_wrapper(a)),r.parent().removeClass(s+n)),t(".left-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".right-off-canvas-toggle",function(n){e.click_toggle_class(n,s+a),"overlap"!==e.settings.open_method&&i(".right-submenu").removeClass(s+a),t(".right-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".right-off-canvas-menu a",function(n){var o=e.get_settings(n),r=i(this).parent();!o.close_on_click||r.hasClass("has-submenu")||r.hasClass("back")?i(this).parent().hasClass("has-submenu")?(n.preventDefault(),i(this).siblings(".right-submenu").toggleClass(s+a)):r.hasClass("back")&&(n.preventDefault(),r.parent().removeClass(s+a)):(e.hide.call(e,s+a,e.get_wrapper(n)),r.parent().removeClass(s+a)),t(".right-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".top-off-canvas-toggle",function(n){e.click_toggle_class(n,s+r),"overlap"!==e.settings.open_method&&i(".top-submenu").removeClass(s+r),t(".top-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".top-off-canvas-menu a",function(n){var a=e.get_settings(n),o=i(this).parent();!a.close_on_click||o.hasClass("has-submenu")||o.hasClass("back")?i(this).parent().hasClass("has-submenu")?(n.preventDefault(),i(this).siblings(".top-submenu").toggleClass(s+r)):o.hasClass("back")&&(n.preventDefault(),o.parent().removeClass(s+r)):(e.hide.call(e,s+r,e.get_wrapper(n)),o.parent().removeClass(s+r)),t(".top-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".bottom-off-canvas-toggle",function(n){e.click_toggle_class(n,s+o),"overlap"!==e.settings.open_method&&i(".bottom-submenu").removeClass(s+o),t(".bottom-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".bottom-off-canvas-menu a",function(n){var a=e.get_settings(n),r=i(this).parent();!a.close_on_click||r.hasClass("has-submenu")||r.hasClass("back")?i(this).parent().hasClass("has-submenu")?(n.preventDefault(),i(this).siblings(".bottom-submenu").toggleClass(s+o)):r.hasClass("back")&&(n.preventDefault(),r.parent().removeClass(s+o)):(e.hide.call(e,s+o,e.get_wrapper(n)),r.parent().removeClass(s+o)),t(".bottom-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".exit-off-canvas",function(o){e.click_remove_class(o,s+a),i(".right-submenu").removeClass(s+a),n&&(e.click_remove_class(o,s+n),i(".left-submenu").removeClass(s+a)),t(".right-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".exit-off-canvas",function(i){e.click_remove_class(i,s+a),t(".left-off-canvas-toggle").attr("aria-expanded","false"),n&&(e.click_remove_class(i,s+n),t(".right-off-canvas-toggle").attr("aria-expanded","false"))}).on("click.fndtn.offcanvas",".exit-off-canvas",function(n){e.click_remove_class(n,s+o),i(".bottom-submenu").removeClass(s+o),r&&(e.click_remove_class(n,s+r),i(".top-submenu").removeClass(s+o)),t(".bottom-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".exit-off-canvas",function(i){e.click_remove_class(i,s+o),t(".top-off-canvas-toggle").attr("aria-expanded","false"),r&&(e.click_remove_class(i,s+r),t(".bottom-off-canvas-toggle").attr("aria-expanded","false"))})},toggle:function(t,e){e=e||this.get_wrapper(),e.is("."+t)?this.hide(t,e):this.show(t,e)},show:function(t,e){e=e||this.get_wrapper(),e.trigger("open.fndtn.offcanvas"),e.addClass(t)},hide:function(t,e){e=e||this.get_wrapper(),e.trigger("close.fndtn.offcanvas"),e.removeClass(t)},click_toggle_class:function(t,e){t.preventDefault();var i=this.get_wrapper(t);this.toggle(e,i)},click_remove_class:function(t,e){t.preventDefault();var i=this.get_wrapper(t);this.hide(e,i)},get_settings:function(t){var e=this.S(t.target).closest("["+this.attr_name()+"]");return e.data(this.attr_name(!0)+"-init")||this.settings},get_wrapper:function(t){var e=this.S(t?t.target:this.scope).closest(".off-canvas-wrap");return 0===e.length&&(e=this.S(".off-canvas-wrap")),e},reflow:function(){}}}(jQuery,window,window.document),function(t){"use strict";Foundation.libs.alert={name:"alert",version:"5.5.3",settings:{callback:function(){}},init:function(t,e,i){this.bindings(e,i)},events:function(){var e=this,i=this.S;t(this.scope).off(".alert").on("click.fndtn.alert","["+this.attr_name()+"] .close",function(t){var s=i(this).closest("["+e.attr_name()+"]"),n=s.data(e.attr_name(!0)+"-init")||e.settings;t.preventDefault(),Modernizr.csstransitions?(s.addClass("alert-close"),s.on("transitionend webkitTransitionEnd oTransitionEnd",function(){i(this).trigger("close.fndtn.alert").remove(),n.callback()})):s.fadeOut(300,function(){i(this).trigger("close.fndtn.alert").remove(),n.callback()})})},reflow:function(){}}}(jQuery,window,window.document),function(t,e,i,s){"use strict";function n(t){var e=/fade/i.test(t),i=/pop/i.test(t);return{animate:e||i,pop:i,fade:e}}var a=[];Foundation.libs.reveal={name:"reveal",version:"5.5.3",locked:!1,settings:{animation:"fadeAndPop",animation_speed:250,close_on_background_click:!0,close_on_esc:!0,dismiss_modal_class:"close-reveal-modal",multiple_opened:!1,bg_class:"reveal-modal-bg",root_element:"body",open:function(){},opened:function(){},close:function(){},closed:function(){},on_ajax_error:t.noop,bg:t(".reveal-modal-bg"),css:{open:{opacity:0,visibility:"visible",display:"block"},close:{opacity:1,visibility:"hidden",display:"none"}}},init:function(e,i,s){t.extend(!0,this.settings,i,s),this.bindings(i,s)},events:function(){var t=this,e=t.S;return e(this.scope).off(".reveal").on("click.fndtn.reveal","["+this.add_namespace("data-reveal-id")+"]:not([disabled])",function(i){if(i.preventDefault(),!t.locked){var s=e(this),n=s.data(t.data_attr("reveal-ajax")),a=s.data(t.data_attr("reveal-replace-content"));if(t.locked=!0,"undefined"==typeof n)t.open.call(t,s);else{var o=n===!0?s.attr("href"):n;t.open.call(t,s,{url:o},{replaceContentSel:a})}}}),e(i).on("click.fndtn.reveal",this.close_targets(),function(i){if(i.preventDefault(),!t.locked){var s=e("["+t.attr_name()+"].open").data(t.attr_name(!0)+"-init")||t.settings,n=e(i.target)[0]===e("."+s.bg_class)[0];if(n){if(!s.close_on_background_click)return;i.stopPropagation()}t.locked=!0,t.close.call(t,n?e("["+t.attr_name()+"].open:not(.toback)"):e(this).closest("["+t.attr_name()+"]"))}}),e("["+t.attr_name()+"]",this.scope).length>0?e(this.scope).on("open.fndtn.reveal",this.settings.open).on("opened.fndtn.reveal",this.settings.opened).on("opened.fndtn.reveal",this.open_video).on("close.fndtn.reveal",this.settings.close).on("closed.fndtn.reveal",this.settings.closed).on("closed.fndtn.reveal",this.close_video):e(this.scope).on("open.fndtn.reveal","["+t.attr_name()+"]",this.settings.open).on("opened.fndtn.reveal","["+t.attr_name()+"]",this.settings.opened).on("opened.fndtn.reveal","["+t.attr_name()+"]",this.open_video).on("close.fndtn.reveal","["+t.attr_name()+"]",this.settings.close).on("closed.fndtn.reveal","["+t.attr_name()+"]",this.settings.closed).on("closed.fndtn.reveal","["+t.attr_name()+"]",this.close_video),!0},key_up_on:function(){var t=this;return t.S("body").off("keyup.fndtn.reveal").on("keyup.fndtn.reveal",function(e){var i=t.S("["+t.attr_name()+"].open"),s=i.data(t.attr_name(!0)+"-init")||t.settings;s&&27===e.which&&s.close_on_esc&&!t.locked&&t.close.call(t,i)}),!0},key_up_off:function(){return this.S("body").off("keyup.fndtn.reveal"),!0},open:function(i,n){var o,r=this;i?"undefined"!=typeof i.selector?o=r.S("#"+i.data(r.data_attr("reveal-id"))).first():(o=r.S(this.scope),n=i):o=r.S(this.scope);var l=o.data(r.attr_name(!0)+"-init");if(l=l||this.settings,o.hasClass("open")&&i!==s&&i.attr("data-reveal-id")==o.attr("id"))return r.close(o);if(!o.hasClass("open")){var d=r.S("["+r.attr_name()+"].open");"undefined"==typeof o.data("css-top")&&o.data("css-top",parseInt(o.css("top"),10)).data("offset",this.cache_offset(o)),o.attr("tabindex","0").attr("aria-hidden","false"),this.key_up_on(o),o.on("open.fndtn.reveal",function(t){"fndtn.reveal"!==t.namespace}),o.on("open.fndtn.reveal").trigger("open.fndtn.reveal"),d.length<1&&this.toggle_bg(o,!0),"string"==typeof n&&(n={url:n});var c=function(){d.length>0&&(l.multiple_opened?r.to_back(d):r.hide(d,l.css.close)),l.multiple_opened&&a.push(o),r.show(o,l.css.open)};if("undefined"!=typeof n&&n.url){var h="undefined"!=typeof n.success?n.success:null;t.extend(n,{success:function(e,i,s){if(t.isFunction(h)){var n=h(e,i,s);"string"==typeof n&&(e=n)}"undefined"!=typeof options&&"undefined"!=typeof options.replaceContentSel?o.find(options.replaceContentSel).html(e):o.html(e),r.S(o).foundation("section","reflow"),r.S(o).children().foundation(),c()}}),l.on_ajax_error!==t.noop&&t.extend(n,{error:l.on_ajax_error}),t.ajax(n)}else c()}r.S(e).trigger("resize")},close:function(e){var e=e&&e.length?e:this.S(this.scope),i=this.S("["+this.attr_name()+"].open"),s=e.data(this.attr_name(!0)+"-init")||this.settings,n=this;
+if(i.length>0)if(e.removeAttr("tabindex","0").attr("aria-hidden","true"),this.locked=!0,this.key_up_off(e),e.trigger("close.fndtn.reveal"),(s.multiple_opened&&1===i.length||!s.multiple_opened||e.length>1)&&(n.toggle_bg(e,!1),n.to_front(e)),s.multiple_opened){var o=e.is(":not(.toback)");n.hide(e,s.css.close,s),o?a.pop():a=t.grep(a,function(t){var i=t[0]===e[0];return i&&n.to_front(e),!i}),a.length>0&&n.to_front(a[a.length-1])}else n.hide(i,s.css.close,s)},close_targets:function(){var t="."+this.settings.dismiss_modal_class;return this.settings.close_on_background_click?t+", ."+this.settings.bg_class:t},toggle_bg:function(e,i){0===this.S("."+this.settings.bg_class).length&&(this.settings.bg=t("<div />",{"class":this.settings.bg_class}).appendTo("body").hide());var n=this.settings.bg.filter(":visible").length>0;i!=n&&((i==s?n:!i)?this.hide(this.settings.bg):this.show(this.settings.bg))},show:function(i,s){if(s){var a=i.data(this.attr_name(!0)+"-init")||this.settings,o=a.root_element,r=this;if(0===i.parent(o).length){var l=i.wrap('<div style="display: none;" />').parent();i.on("closed.fndtn.reveal.wrapped",function(){i.detach().appendTo(l),i.unwrap().unbind("closed.fndtn.reveal.wrapped")}),i.detach().appendTo(o)}var d=n(a.animation);if(d.animate||(this.locked=!1),d.pop){s.top=t(e).scrollTop()-i.data("offset")+"px";var c={top:t(e).scrollTop()+i.data("css-top")+"px",opacity:1};return setTimeout(function(){return i.css(s).animate(c,a.animation_speed,"linear",function(){r.locked=!1,i.trigger("opened.fndtn.reveal")}).addClass("open")},a.animation_speed/2)}if(s.top=t(e).scrollTop()+i.data("css-top")+"px",d.fade){var c={opacity:1};return setTimeout(function(){return i.css(s).animate(c,a.animation_speed,"linear",function(){r.locked=!1,i.trigger("opened.fndtn.reveal")}).addClass("open")},a.animation_speed/2)}return i.css(s).show().css({opacity:1}).addClass("open").trigger("opened.fndtn.reveal")}var a=this.settings;return n(a.animation).fade?i.fadeIn(a.animation_speed/2):(this.locked=!1,i.show())},to_back:function(t){t.addClass("toback")},to_front:function(t){t.removeClass("toback")},hide:function(i,s){if(s){var a=i.data(this.attr_name(!0)+"-init"),o=this;a=a||this.settings;var r=n(a.animation);if(r.animate||(this.locked=!1),r.pop){var l={top:-t(e).scrollTop()-i.data("offset")+"px",opacity:0};return setTimeout(function(){return i.animate(l,a.animation_speed,"linear",function(){o.locked=!1,i.css(s).trigger("closed.fndtn.reveal")}).removeClass("open")},a.animation_speed/2)}if(r.fade){var l={opacity:0};return setTimeout(function(){return i.animate(l,a.animation_speed,"linear",function(){o.locked=!1,i.css(s).trigger("closed.fndtn.reveal")}).removeClass("open")},a.animation_speed/2)}return i.hide().css(s).removeClass("open").trigger("closed.fndtn.reveal")}var a=this.settings;return n(a.animation).fade?i.fadeOut(a.animation_speed/2):i.hide()},close_video:function(e){var i=t(".flex-video",e.target),s=t("iframe",i);s.length>0&&(s.attr("data-src",s[0].src),s.attr("src",s.attr("src")),i.hide())},open_video:function(e){var i=t(".flex-video",e.target),n=i.find("iframe");if(n.length>0){var a=n.attr("data-src");if("string"==typeof a)n[0].src=n.attr("data-src");else{var o=n[0].src;n[0].src=s,n[0].src=o}i.show()}},data_attr:function(t){return this.namespace.length>0?this.namespace+"-"+t:t},cache_offset:function(t){var e=t.show().height()+parseInt(t.css("top"),10)+t.scrollY;return t.hide(),e},off:function(){t(this.scope).off(".fndtn.reveal")},reflow:function(){}}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs.interchange={name:"interchange",version:"5.5.3",cache:{},images_loaded:!1,nodes_loaded:!1,settings:{load_attr:"interchange",named_queries:{"default":"only screen",small:Foundation.media_queries.small,"small-only":Foundation.media_queries["small-only"],medium:Foundation.media_queries.medium,"medium-only":Foundation.media_queries["medium-only"],large:Foundation.media_queries.large,"large-only":Foundation.media_queries["large-only"],xlarge:Foundation.media_queries.xlarge,"xlarge-only":Foundation.media_queries["xlarge-only"],xxlarge:Foundation.media_queries.xxlarge,landscape:"only screen and (orientation: landscape)",portrait:"only screen and (orientation: portrait)",retina:"only screen and (-webkit-min-device-pixel-ratio: 2),only screen and (min--moz-device-pixel-ratio: 2),only screen and (-o-min-device-pixel-ratio: 2/1),only screen and (min-device-pixel-ratio: 2),only screen and (min-resolution: 192dpi),only screen and (min-resolution: 2dppx)"},directives:{replace:function(e,i,s){if(null!==e&&/IMG/.test(e[0].nodeName)){var n=t.each(e,function(){this.src=i});if(new RegExp(i,"i").test(n))return;return e.attr("src",i),s(e[0].src)}var a=e.data(this.data_attr+"-last-path"),o=this;if(a!=i)return/\.(gif|jpg|jpeg|tiff|png)([?#].*)?/i.test(i)?(t(e).css("background-image","url("+i+")"),e.data("interchange-last-path",i),s(i)):t.get(i,function(t){e.html(t),e.data(o.data_attr+"-last-path",i),s()})}}},init:function(e,i,s){Foundation.inherit(this,"throttle random_str"),this.data_attr=this.set_data_attr(),t.extend(!0,this.settings,i,s),this.bindings(i,s),this.reflow()},get_media_hash:function(){var t="";for(var e in this.settings.named_queries)t+=matchMedia(this.settings.named_queries[e]).matches.toString();return t},events:function(){var i,s=this;return t(e).off(".interchange").on("resize.fndtn.interchange",s.throttle(function(){var t=s.get_media_hash();t!==i&&s.resize(),i=t},50)),this},resize:function(){var e=this.cache;if(!this.images_loaded||!this.nodes_loaded)return void setTimeout(t.proxy(this.resize,this),50);for(var i in e)if(e.hasOwnProperty(i)){var s=this.results(i,e[i]);s&&this.settings.directives[s.scenario[1]].call(this,s.el,s.scenario[0],function(t){if(arguments[0]instanceof Array)var e=arguments[0];else var e=Array.prototype.slice.call(arguments,0);return function(){t.el.trigger(t.scenario[1],e)}}(s))}},results:function(t,e){var i=e.length;if(i>0)for(var s=this.S("["+this.add_namespace("data-uuid")+'="'+t+'"]');i--;){var n,a=e[i][2];if(n=matchMedia(this.settings.named_queries.hasOwnProperty(a)?this.settings.named_queries[a]:a),n.matches)return{el:s,scenario:e[i]}}return!1},load:function(t,e){return("undefined"==typeof this["cached_"+t]||e)&&this["update_"+t](),this["cached_"+t]},update_images:function(){var t=this.S("img["+this.data_attr+"]"),e=t.length,i=e,s=0,n=this.data_attr;for(this.cache={},this.cached_images=[],this.images_loaded=0===e;i--;){if(s++,t[i]){var a=t[i].getAttribute(n)||"";a.length>0&&this.cached_images.push(t[i])}s===e&&(this.images_loaded=!0,this.enhance("images"))}return this},update_nodes:function(){var t=this.S("["+this.data_attr+"]").not("img"),e=t.length,i=e,s=0,n=this.data_attr;for(this.cached_nodes=[],this.nodes_loaded=0===e;i--;){s++;var a=t[i].getAttribute(n)||"";a.length>0&&this.cached_nodes.push(t[i]),s===e&&(this.nodes_loaded=!0,this.enhance("nodes"))}return this},enhance:function(i){for(var s=this["cached_"+i].length;s--;)this.object(t(this["cached_"+i][s]));return t(e).trigger("resize.fndtn.interchange")},convert_directive:function(t){var e=this.trim(t);return e.length>0?e:"replace"},parse_scenario:function(t){var e=t[0].match(/(.+),\s*(\w+)\s*$/),i=t[1].match(/(.*)\)/);if(e)var s=e[1],n=e[2];else var a=t[0].split(/,\s*$/),s=a[0],n="";return[this.trim(s),this.convert_directive(n),this.trim(i[1])]},object:function(t){var e=this.parse_data_attr(t),i=[],s=e.length;if(s>0)for(;s--;){var n=e[s].split(/,\s?\(/);if(n.length>1){var a=this.parse_scenario(n);i.push(a)}}return this.store(t,i)},store:function(t,e){var i=this.random_str(),s=t.data(this.add_namespace("uuid",!0));return this.cache[s]?this.cache[s]:(t.attr(this.add_namespace("data-uuid"),i),this.cache[i]=e)},trim:function(e){return"string"==typeof e?t.trim(e):e},set_data_attr:function(t){return t?this.namespace.length>0?this.namespace+"-"+this.settings.load_attr:this.settings.load_attr:this.namespace.length>0?"data-"+this.namespace+"-"+this.settings.load_attr:"data-"+this.settings.load_attr},parse_data_attr:function(t){for(var e=t.attr(this.attr_name()).split(/\[(.*?)\]/),i=e.length,s=[];i--;)e[i].replace(/[\W\d]+/,"").length>4&&s.push(e[i]);return s},reflow:function(){this.load("images",!0),this.load("nodes",!0)}}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs["magellan-expedition"]={name:"magellan-expedition",version:"5.5.3",settings:{active_class:"active",threshold:0,destination_threshold:20,throttle_delay:30,fixed_top:0,offset_by_height:!0,duration:700,easing:"swing"},init:function(t,e,i){Foundation.inherit(this,"throttle"),this.bindings(e,i)},events:function(){var e=this,i=e.S,s=e.settings;e.set_expedition_position(),i(e.scope).off(".magellan").on("click.fndtn.magellan","["+e.add_namespace("data-magellan-arrival")+"] a[href*=#]",function(i){var s=this.hostname===location.hostname||!this.hostname,n=e.filterPathname(location.pathname)===e.filterPathname(this.pathname),a=this.hash.replace(/(:|\.|\/)/g,"\\$1"),o=this;if(s&&n&&a){i.preventDefault();var r=t(this).closest("["+e.attr_name()+"]"),l=r.data("magellan-expedition-init"),d=this.hash.split("#").join(""),c=t('a[name="'+d+'"]');0===c.length&&(c=t("#"+d));var h=c.offset().top-l.destination_threshold+1;l.offset_by_height&&(h-=r.outerHeight()),t("html, body").stop().animate({scrollTop:h},l.duration,l.easing,function(){history.pushState?history.pushState(null,null,o.pathname+o.search+"#"+d):location.hash=o.pathname+o.search+"#"+d})}}).on("scroll.fndtn.magellan",e.throttle(this.check_for_arrivals.bind(this),s.throttle_delay))},check_for_arrivals:function(){var t=this;t.update_arrivals(),t.update_expedition_positions()},set_expedition_position:function(){var e=this;t("["+this.attr_name()+"=fixed]",e.scope).each(function(){var i,s,n=t(this),a=n.data("magellan-expedition-init"),o=n.attr("styles");n.attr("style",""),i=n.offset().top+a.threshold,s=parseInt(n.data("magellan-fixed-top")),isNaN(s)||(e.settings.fixed_top=s),n.data(e.data_attr("magellan-top-offset"),i),n.attr("style",o)})},update_expedition_positions:function(){var i=this,s=t(e).scrollTop();t("["+this.attr_name()+"=fixed]",i.scope).each(function(){var e=t(this),n=e.data("magellan-expedition-init"),a=e.attr("style"),o=e.data("magellan-top-offset");if(s+i.settings.fixed_top>=o){var r=e.prev("["+i.add_namespace("data-magellan-expedition-clone")+"]");0===r.length&&(r=e.clone(),r.removeAttr(i.attr_name()),r.attr(i.add_namespace("data-magellan-expedition-clone"),""),e.before(r)),e.css({position:"fixed",top:n.fixed_top}).addClass("fixed")}else e.prev("["+i.add_namespace("data-magellan-expedition-clone")+"]").remove(),e.attr("style",a).css("position","").css("top","").removeClass("fixed")})},update_arrivals:function(){var i=this,s=t(e).scrollTop();t("["+this.attr_name()+"]",i.scope).each(function(){var e=t(this),n=e.data(i.attr_name(!0)+"-init"),a=i.offsets(e,s),o=e.find("["+i.add_namespace("data-magellan-arrival")+"]"),r=!1;a.each(function(t,s){if(s.viewport_offset>=s.top_offset){var a=e.find("["+i.add_namespace("data-magellan-arrival")+"]");return a.not(s.arrival).removeClass(n.active_class),s.arrival.addClass(n.active_class),r=!0,!0}}),r||o.removeClass(n.active_class)})},offsets:function(e,i){var s=this,n=e.data(s.attr_name(!0)+"-init"),a=i;return e.find("["+s.add_namespace("data-magellan-arrival")+"]").map(function(){var i=t(this).data(s.data_attr("magellan-arrival")),o=t("["+s.add_namespace("data-magellan-destination")+"="+i+"]");if(o.length>0){var r=o.offset().top-n.destination_threshold;return n.offset_by_height&&(r-=e.outerHeight()),r=Math.floor(r),{destination:o,arrival:t(this),top_offset:r,viewport_offset:a}}}).sort(function(t,e){return t.top_offset<e.top_offset?-1:t.top_offset>e.top_offset?1:0})},data_attr:function(t){return this.namespace.length>0?this.namespace+"-"+t:t},off:function(){this.S(this.scope).off(".magellan"),this.S(e).off(".magellan")},filterPathname:function(t){return t=t||"",t.replace(/^\//,"").replace(/(?:index|default).[a-zA-Z]{3,4}$/,"").replace(/\/$/,"")},reflow:function(){var e=this;t("["+e.add_namespace("data-magellan-expedition-clone")+"]",e.scope).remove()}}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs.accordion={name:"accordion",version:"5.5.3",settings:{content_class:"content",active_class:"active",multi_expand:!1,toggleable:!0,callback:function(){}},init:function(t,e,i){this.bindings(e,i)},events:function(e){var i=this,s=this.S;i.create(this.S(e)),s(this.scope).off(".fndtn.accordion").on("click.fndtn.accordion","["+this.attr_name()+"] > dd > a, ["+this.attr_name()+"] > li > a",function(e){var n=s(this).closest("["+i.attr_name()+"]"),a=i.attr_name()+"="+n.attr(i.attr_name()),o=n.data(i.attr_name(!0)+"-init")||i.settings,r=s("#"+this.href.split("#")[1]),l=t("> dd, > li",n),d=l.children("."+o.content_class),c=d.filter("."+o.active_class);return e.preventDefault(),n.attr(i.attr_name())&&(d=d.add("["+a+"] dd > ."+o.content_class+", ["+a+"] li > ."+o.content_class),l=l.add("["+a+"] dd, ["+a+"] li")),o.toggleable&&r.is(c)?(r.parent("dd, li").toggleClass(o.active_class,!1),r.toggleClass(o.active_class,!1),s(this).attr("aria-expanded",function(t,e){return"true"===e?"false":"true"}),o.callback(r),r.triggerHandler("toggled",[n]),void n.triggerHandler("toggled",[r])):(o.multi_expand||(d.removeClass(o.active_class),l.removeClass(o.active_class),l.children("a").attr("aria-expanded","false")),r.addClass(o.active_class).parent().addClass(o.active_class),o.callback(r),r.triggerHandler("toggled",[n]),n.triggerHandler("toggled",[r]),void s(this).attr("aria-expanded","true"))})},create:function(e){var i=this,s=e,n=t("> .accordion-navigation",s),a=s.data(i.attr_name(!0)+"-init")||i.settings;n.children("a").attr("aria-expanded","false"),n.has("."+a.content_class+"."+a.active_class).addClass(a.active_class).children("a").attr("aria-expanded","true"),a.multi_expand&&e.attr("aria-multiselectable","true")},toggle:function(t){var t="undefined"!=typeof t?t:{},i="undefined"!=typeof t.selector?t.selector:"",s="undefined"!=typeof t.toggle_state?t.toggle_state:"",n="undefined"!=typeof t.$accordion?t.$accordion:this.S(this.scope).closest("["+this.attr_name()+"]"),a=n.find("> dd"+i+", > li"+i);if(a.length<1)return e.console&&console.error("Selection not found.",i),!1;var o=this.S,r=this.settings.active_class;a.each(function(){var t=o(this),e=t.hasClass(r);(e&&"close"===s||!e&&"open"===s||""===s)&&t.find("> a").trigger("click.fndtn.accordion")})},open:function(t){var t="undefined"!=typeof t?t:{};t.toggle_state="open",this.toggle(t)},close:function(t){var t="undefined"!=typeof t?t:{};t.toggle_state="close",this.toggle(t)},off:function(){},reflow:function(){}}}(jQuery,window,window.document),function(t,e,i){"use strict";Foundation.libs.topbar={name:"topbar",version:"5.5.3",settings:{index:0,start_offset:0,sticky_class:"sticky",custom_back_text:!0,back_text:"Back",mobile_show_parent_link:!0,is_hover:!0,scrolltop:!0,sticky_on:"all",dropdown_autoclose:!0},init:function(e,i,s){Foundation.inherit(this,"add_custom_rule register_media throttle");var n=this;n.register_media("topbar","foundation-mq-topbar"),this.bindings(i,s),n.S("["+this.attr_name()+"]",this.scope).each(function(){{var e=t(this),i=e.data(n.attr_name(!0)+"-init");n.S("section, .top-bar-section",this)}e.data("index",0);var s=e.parent();s.hasClass("fixed")||n.is_sticky(e,s,i)?(n.settings.sticky_class=i.sticky_class,n.settings.sticky_topbar=e,e.data("height",s.outerHeight()),e.data("stickyoffset",s.offset().top)):e.data("height",e.outerHeight()),i.assembled||n.assemble(e),i.is_hover?n.S(".has-dropdown",e).addClass("not-click"):n.S(".has-dropdown",e).removeClass("not-click"),n.add_custom_rule(".f-topbar-fixed { padding-top: "+e.data("height")+"px }"),s.hasClass("fixed")&&n.S("body").addClass("f-topbar-fixed")})},is_sticky:function(t,e,i){var s=e.hasClass(i.sticky_class),n=matchMedia(Foundation.media_queries.small).matches,a=matchMedia(Foundation.media_queries.medium).matches,o=matchMedia(Foundation.media_queries.large).matches;return s&&"all"===i.sticky_on?!0:s&&this.small()&&-1!==i.sticky_on.indexOf("small")&&n&&!a&&!o?!0:s&&this.medium()&&-1!==i.sticky_on.indexOf("medium")&&n&&a&&!o?!0:s&&this.large()&&-1!==i.sticky_on.indexOf("large")&&n&&a&&o?!0:!1},toggle:function(i){var s,n=this;s=i?n.S(i).closest("["+this.attr_name()+"]"):n.S("["+this.attr_name()+"]");var a=s.data(this.attr_name(!0)+"-init"),o=n.S("section, .top-bar-section",s);n.breakpoint()&&(n.rtl?(o.css({right:"0%"}),t(">.name",o).css({right:"100%"})):(o.css({left:"0%"}),t(">.name",o).css({left:"100%"})),n.S("li.moved",o).removeClass("moved"),s.data("index",0),s.toggleClass("expanded").css("height","")),a.scrolltop?s.hasClass("expanded")?s.parent().hasClass("fixed")&&(a.scrolltop?(s.parent().removeClass("fixed"),s.addClass("fixed"),n.S("body").removeClass("f-topbar-fixed"),e.scrollTo(0,0)):s.parent().removeClass("expanded")):s.hasClass("fixed")&&(s.parent().addClass("fixed"),s.removeClass("fixed"),n.S("body").addClass("f-topbar-fixed")):(n.is_sticky(s,s.parent(),a)&&s.parent().addClass("fixed"),s.parent().hasClass("fixed")&&(s.hasClass("expanded")?(s.addClass("fixed"),s.parent().addClass("expanded"),n.S("body").addClass("f-topbar-fixed")):(s.removeClass("fixed"),s.parent().removeClass("expanded"),n.update_sticky_positioning())))},timer:null,events:function(){var i=this,s=this.S;s(this.scope).off(".topbar").on("click.fndtn.topbar","["+this.attr_name()+"] .toggle-topbar",function(t){t.preventDefault(),i.toggle(this)}).on("click.fndtn.topbar contextmenu.fndtn.topbar",'.top-bar .top-bar-section li a[href^="#"],['+this.attr_name()+'] .top-bar-section li a[href^="#"]',function(){var e=t(this).closest("li"),s=e.closest("["+i.attr_name()+"]"),n=s.data(i.attr_name(!0)+"-init");if(n.dropdown_autoclose&&n.is_hover){var a=t(this).closest(".hover");a.removeClass("hover")}!i.breakpoint()||e.hasClass("back")||e.hasClass("has-dropdown")||i.toggle()}).on("click.fndtn.topbar","["+this.attr_name()+"] li.has-dropdown",function(e){var n=s(this),a=s(e.target),o=n.closest("["+i.attr_name()+"]"),r=o.data(i.attr_name(!0)+"-init");return a.data("revealId")?void i.toggle():void(i.breakpoint()||(!r.is_hover||Modernizr.touch)&&(e.stopImmediatePropagation(),n.hasClass("hover")?(n.removeClass("hover").find("li").removeClass("hover"),n.parents("li.hover").removeClass("hover")):(n.addClass("hover"),t(n).siblings().removeClass("hover"),"A"===a[0].nodeName&&a.parent().hasClass("has-dropdown")&&e.preventDefault())))}).on("click.fndtn.topbar","["+this.attr_name()+"] .has-dropdown>a",function(t){if(i.breakpoint()){t.preventDefault();var e=s(this),n=e.closest("["+i.attr_name()+"]"),a=n.find("section, .top-bar-section"),o=(e.next(".dropdown").outerHeight(),e.closest("li"));n.data("index",n.data("index")+1),o.addClass("moved"),i.rtl?(a.css({right:-(100*n.data("index"))+"%"}),a.find(">.name").css({right:100*n.data("index")+"%"})):(a.css({left:-(100*n.data("index"))+"%"}),a.find(">.name").css({left:100*n.data("index")+"%"})),n.css("height",e.siblings("ul").outerHeight(!0)+n.data("height"))}}),s(e).off(".topbar").on("resize.fndtn.topbar",i.throttle(function(){i.resize.call(i)},50)).trigger("resize.fndtn.topbar").load(function(){s(this).trigger("resize.fndtn.topbar")}),s("body").off(".topbar").on("click.fndtn.topbar",function(t){var e=s(t.target).closest("li").closest("li.hover");e.length>0||s("["+i.attr_name()+"] li.hover").removeClass("hover")}),s(this.scope).on("click.fndtn.topbar","["+this.attr_name()+"] .has-dropdown .back",function(t){t.preventDefault();var e=s(this),n=e.closest("["+i.attr_name()+"]"),a=n.find("section, .top-bar-section"),o=(n.data(i.attr_name(!0)+"-init"),e.closest("li.moved")),r=o.parent();n.data("index",n.data("index")-1),i.rtl?(a.css({right:-(100*n.data("index"))+"%"}),a.find(">.name").css({right:100*n.data("index")+"%"})):(a.css({left:-(100*n.data("index"))+"%"}),a.find(">.name").css({left:100*n.data("index")+"%"})),0===n.data("index")?n.css("height",""):n.css("height",r.outerHeight(!0)+n.data("height")),setTimeout(function(){o.removeClass("moved")},300)}),s(this.scope).find(".dropdown a").focus(function(){t(this).parents(".has-dropdown").addClass("hover")}).blur(function(){t(this).parents(".has-dropdown").removeClass("hover")})},resize:function(){var t=this;t.S("["+this.attr_name()+"]").each(function(){var e,s=t.S(this),n=s.data(t.attr_name(!0)+"-init"),a=s.parent("."+t.settings.sticky_class);if(!t.breakpoint()){var o=s.hasClass("expanded");s.css("height","").removeClass("expanded").find("li").removeClass("hover"),o&&t.toggle(s)}t.is_sticky(s,a,n)&&(a.hasClass("fixed")?(a.removeClass("fixed"),e=a.offset().top,t.S(i.body).hasClass("f-topbar-fixed")&&(e-=s.data("height")),s.data("stickyoffset",e),a.addClass("fixed")):(e=a.offset().top,s.data("stickyoffset",e)))})},breakpoint:function(){return!matchMedia(Foundation.media_queries.topbar).matches},small:function(){return matchMedia(Foundation.media_queries.small).matches},medium:function(){return matchMedia(Foundation.media_queries.medium).matches},large:function(){return matchMedia(Foundation.media_queries.large).matches},assemble:function(e){var i=this,s=e.data(this.attr_name(!0)+"-init"),n=i.S("section, .top-bar-section",e);n.detach(),i.S(".has-dropdown>a",n).each(function(){var e,n=i.S(this),a=n.siblings(".dropdown"),o=n.attr("href");a.find(".title.back").length||(e=t(1==s.mobile_show_parent_link&&o?'<li class="title back js-generated"><h5><a href="javascript:void(0)"></a></h5></li><li class="parent-link hide-for-medium-up"><a class="parent-link js-generated" href="'+o+'">'+n.html()+"</a></li>":'<li class="title back js-generated"><h5><a href="javascript:void(0)"></a></h5>'),t("h5>a",e).html(1==s.custom_back_text?s.back_text:"&laquo; "+n.html()),a.prepend(e))}),n.appendTo(e),this.sticky(),this.assembled(e)},assembled:function(e){e.data(this.attr_name(!0),t.extend({},e.data(this.attr_name(!0)),{assembled:!0}))},height:function(e){var i=0,s=this;return t("> li",e).each(function(){i+=s.S(this).outerHeight(!0)}),i},sticky:function(){var t=this;this.S(e).on("scroll",function(){t.update_sticky_positioning()})},update_sticky_positioning:function(){var t="."+this.settings.sticky_class,i=this.S(e),s=this;if(s.settings.sticky_topbar&&s.is_sticky(this.settings.sticky_topbar,this.settings.sticky_topbar.parent(),this.settings)){var n=this.settings.sticky_topbar.data("stickyoffset")+this.settings.start_offset;s.S(t).hasClass("expanded")||(i.scrollTop()>n?s.S(t).hasClass("fixed")||(s.S(t).addClass("fixed"),s.S("body").addClass("f-topbar-fixed")):i.scrollTop()<=n&&s.S(t).hasClass("fixed")&&(s.S(t).removeClass("fixed"),s.S("body").removeClass("f-topbar-fixed")))}},off:function(){this.S(this.scope).off(".fndtn.topbar"),this.S(e).off(".fndtn.topbar")},reflow:function(){}}}(jQuery,window,window.document),function(t,e,i,s){"use strict";Foundation.libs.tab={name:"tab",version:"5.5.3",settings:{active_class:"active",callback:function(){},deep_linking:!1,scroll_to_content:!0,is_hover:!1},default_tab_hashes:[],init:function(t,e,i){var s=this,n=this.S;n("["+this.attr_name()+"] > .active > a",this.scope).each(function(){s.default_tab_hashes.push(this.hash)}),this.bindings(e,i),this.handle_location_hash_change()},events:function(){var t=this,i=this.S,s=function(e,s){var n=i(s).closest("["+t.attr_name()+"]").data(t.attr_name(!0)+"-init");if(!n.is_hover||Modernizr.touch){var a=e.keyCode||e.which;9!==a&&(e.preventDefault(),e.stopPropagation()),t.toggle_active_tab(i(s).parent())}};i(this.scope).off(".tab").on("keydown.fndtn.tab","["+this.attr_name()+"] > * > a",function(t){var e=t.keyCode||t.which;if(13===e||32===e){var i=this;s(t,i)}}).on("click.fndtn.tab","["+this.attr_name()+"] > * > a",function(t){var e=this;s(t,e)}).on("mouseenter.fndtn.tab","["+this.attr_name()+"] > * > a",function(){var e=i(this).closest("["+t.attr_name()+"]").data(t.attr_name(!0)+"-init");e.is_hover&&t.toggle_active_tab(i(this).parent())}),i(e).on("hashchange.fndtn.tab",function(e){e.preventDefault(),t.handle_location_hash_change()})},handle_location_hash_change:function(){var e=this,i=this.S;i("["+this.attr_name()+"]",this.scope).each(function(){var n=i(this).data(e.attr_name(!0)+"-init");if(n.deep_linking){var a;if(a=n.scroll_to_content?e.scope.location.hash:e.scope.location.hash.replace("fndtn-",""),""!=a){var o=i(a);if(o.hasClass("content")&&o.parent().hasClass("tabs-content"))e.toggle_active_tab(t("["+e.attr_name()+"] > * > a[href="+a+"]").parent());else{var r=o.closest(".content").attr("id");r!=s&&e.toggle_active_tab(t("["+e.attr_name()+"] > * > a[href=#"+r+"]").parent(),a)}}else for(var l=0;l<e.default_tab_hashes.length;l++)e.toggle_active_tab(t("["+e.attr_name()+"] > * > a[href="+e.default_tab_hashes[l]+"]").parent())}})},toggle_active_tab:function(n,a){var o=this,r=o.S,l=n.closest("["+this.attr_name()+"]"),d=n.find("a"),c=n.children("a").first(),h="#"+c.attr("href").split("#")[1],u=r(h),f=n.siblings(),p=l.data(this.attr_name(!0)+"-init"),g=function(e){var s,n=t(this),a=t(this).parents("li").prev().children('[role="tab"]'),o=t(this).parents("li").next().children('[role="tab"]');switch(e.keyCode){case 37:s=a;break;case 39:s=o;break;default:s=!1}s.length&&(n.attr({tabindex:"-1","aria-selected":null}),s.attr({tabindex:"0","aria-selected":!0}).focus()),t('[role="tabpanel"]').attr("aria-hidden","true"),t("#"+t(i.activeElement).attr("href").substring(1)).attr("aria-hidden",null)},_=function(t){var i=p.scroll_to_content?o.default_tab_hashes[0]:"fndtn-"+o.default_tab_hashes[0].replace("#","");(t!==i||e.location.hash)&&(e.location.hash=t)};c.data("tab-content")&&(h="#"+c.data("tab-content").split("#")[1],u=r(h)),p.deep_linking&&(p.scroll_to_content?(_(a||h),a==s||a==h?n.parent()[0].scrollIntoView():r(h)[0].scrollIntoView()):_(a!=s?"fndtn-"+a.replace("#",""):"fndtn-"+h.replace("#",""))),n.addClass(p.active_class).triggerHandler("opened"),d.attr({"aria-selected":"true",tabindex:0}),f.removeClass(p.active_class),f.find("a").attr({"aria-selected":"false"}),u.siblings().removeClass(p.active_class).attr({"aria-hidden":"true"}),u.addClass(p.active_class).attr("aria-hidden","false").removeAttr("tabindex"),p.callback(n),u.triggerHandler("toggled",[u]),l.triggerHandler("toggled",[n]),d.off("keydown").on("keydown",g)},data_attr:function(t){return this.namespace.length>0?this.namespace+"-"+t:t},off:function(){},reflow:function(){}}}(jQuery,window,window.document),function(t,e,i){"use strict";Foundation.libs.abide={name:"abide",version:"5.5.3",settings:{live_validate:!0,validate_on_blur:!0,focus_on_invalid:!0,error_labels:!0,error_class:"error",timeout:1e3,patterns:{alpha:/^[a-zA-Z]+$/,alpha_numeric:/^[a-zA-Z0-9]+$/,integer:/^[-+]?\d+$/,number:/^[-+]?\d*(?:[\.\,]\d+)?$/,card:/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/,cvv:/^([0-9]){3,4}$/,email:/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/,url:/^(https?|ftp|file|ssh):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+~%\/\.\w]+)?\??([-\+=&;%@\.\w]+)?#?([\w]+)?)?/,domain:/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,8}$/,datetime:/^([0-2][0-9]{3})\-([0-1][0-9])\-([0-3][0-9])T([0-5][0-9])\:([0-5][0-9])\:([0-5][0-9])(Z|([\-\+]([0-1][0-9])\:00))$/,date:/(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))$/,time:/^(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}$/,dateISO:/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,month_day_year:/^(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.]\d{4}$/,day_month_year:/^(0[1-9]|[12][0-9]|3[01])[- \/.](0[1-9]|1[012])[- \/.]\d{4}$/,color:/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/},validators:{equalTo:function(t){var e=i.getElementById(t.getAttribute(this.add_namespace("data-equalto"))).value,s=t.value,n=e===s;return n}}},timer:null,init:function(t,e,i){this.bindings(e,i)},events:function(e){function i(t,e){clearTimeout(s.timer),s.timer=setTimeout(function(){s.validate([t],e)}.bind(t),a.timeout)}var s=this,n=s.S(e).attr("novalidate","novalidate"),a=n.data(this.attr_name(!0)+"-init")||{};this.invalid_attr=this.add_namespace("data-invalid"),n.off(".abide").on("submit.fndtn.abide",function(t){var e=/ajax/i.test(s.S(this).attr(s.attr_name()));return s.validate(s.S(this).find("input, textarea, select").not(":hidden, [data-abide-ignore]").get(),t,e)}).on("validate.fndtn.abide",function(t){"manual"===a.validate_on&&s.validate([t.target],t)}).on("reset",function(e){return s.reset(t(this),e)}).find("input, textarea, select").not(":hidden, [data-abide-ignore]").off(".abide").on("blur.fndtn.abide change.fndtn.abide",function(t){var e=this.getAttribute("id"),s=n.find('[data-equalto="'+e+'"]');a.validate_on_blur&&a.validate_on_blur===!0&&i(this,t),"undefined"!=typeof s.get(0)&&s.val().length&&i(s.get(0),t),"change"===a.validate_on&&i(this,t)}).on("keydown.fndtn.abide",function(t){var e=this.getAttribute("id"),s=n.find('[data-equalto="'+e+'"]');a.live_validate&&a.live_validate===!0&&9!=t.which&&i(this,t),"undefined"!=typeof s.get(0)&&s.val().length&&i(s.get(0),t),"tab"===a.validate_on&&9===t.which?i(this,t):"change"===a.validate_on&&i(this,t)}).on("focus",function(e){navigator.userAgent.match(/iPad|iPhone|Android|BlackBerry|Windows Phone|webOS/i)&&t("html, body").animate({scrollTop:t(e.target).offset().top},100)})},reset:function(e){var i=this;e.removeAttr(i.invalid_attr),t("["+i.invalid_attr+"]",e).removeAttr(i.invalid_attr),t("."+i.settings.error_class,e).not("small").removeClass(i.settings.error_class),t(":input",e).not(":button, :submit, :reset, :hidden, [data-abide-ignore]").val("").removeAttr(i.invalid_attr)},validate:function(t,e,i){for(var s=this.parse_patterns(t),n=s.length,a=this.S(t[0]).closest("form"),o=/submit/.test(e.type),r=0;n>r;r++)if(!s[r]&&(o||i))return this.settings.focus_on_invalid&&t[r].focus(),a.trigger("invalid.fndtn.abide"),this.S(t[r]).closest("form").attr(this.invalid_attr,""),!1;return(o||i)&&a.trigger("valid.fndtn.abide"),a.removeAttr(this.invalid_attr),i?!1:!0},parse_patterns:function(t){for(var e=t.length,i=[];e--;)i.push(this.pattern(t[e]));return this.check_validation_and_apply_styles(i)},pattern:function(t){var e=t.getAttribute("type"),i="string"==typeof t.getAttribute("required"),s=t.getAttribute("pattern")||"";return this.settings.patterns.hasOwnProperty(s)&&s.length>0?[t,this.settings.patterns[s],i]:s.length>0?[t,new RegExp(s),i]:this.settings.patterns.hasOwnProperty(e)?[t,this.settings.patterns[e],i]:(s=/.*/,[t,s,i])},check_validation_and_apply_styles:function(e){var i=e.length,s=[];if(0==i)return s;var n=this.S(e[0][0]).closest("[data-"+this.attr_name(!0)+"]");for(n.data(this.attr_name(!0)+"-init")||{};i--;){var a,o,r=e[i][0],l=e[i][2],d=r.value.trim(),c=this.S(r).parent(),h=r.getAttribute(this.add_namespace("data-abide-validator")),u="radio"===r.type,f="checkbox"===r.type,p=this.S('label[for="'+r.getAttribute("id")+'"]'),g=l?r.value.length>0:!0,_=[];if(r.getAttribute(this.add_namespace("data-equalto"))&&(h="equalTo"),a=c.is("label")?c.parent():c,u&&l)_.push(this.valid_radio(r,l));else if(f&&l)_.push(this.valid_checkbox(r,l));else if(h){for(var m=h.split(" "),v=!0,b=!0,x=0;x<m.length;x++)o=this.settings.validators[m[x]].apply(this,[r,l,a]),_.push(o),b=o&&v,v=o;b?(this.S(r).removeAttr(this.invalid_attr),a.removeClass("error"),p.length>0&&this.settings.error_labels&&p.removeClass(this.settings.error_class).removeAttr("role"),t(r).triggerHandler("valid")):(this.S(r).attr(this.invalid_attr,""),a.addClass("error"),p.length>0&&this.settings.error_labels&&p.addClass(this.settings.error_class).attr("role","alert"),t(r).triggerHandler("invalid"))}else if(_.push(e[i][1].test(d)&&g||!l&&r.value.length<1||t(r).attr("disabled")?!0:!1),_=[_.every(function(t){return t})],_[0])this.S(r).removeAttr(this.invalid_attr),r.setAttribute("aria-invalid","false"),r.removeAttribute("aria-describedby"),a.removeClass(this.settings.error_class),p.length>0&&this.settings.error_labels&&p.removeClass(this.settings.error_class).removeAttr("role"),t(r).triggerHandler("valid");else{this.S(r).attr(this.invalid_attr,""),r.setAttribute("aria-invalid","true");var y=a.find("small."+this.settings.error_class,"span."+this.settings.error_class),w=y.length>0?y[0].id:"";w.length>0&&r.setAttribute("aria-describedby",w),a.addClass(this.settings.error_class),p.length>0&&this.settings.error_labels&&p.addClass(this.settings.error_class).attr("role","alert"),t(r).triggerHandler("invalid")}s=s.concat(_)}return s},valid_checkbox:function(e,i){var e=this.S(e),s=e.is(":checked")||!i||e.get(0).getAttribute("disabled");return s?(e.removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class),t(e).triggerHandler("valid")):(e.attr(this.invalid_attr,"").parent().addClass(this.settings.error_class),t(e).triggerHandler("invalid")),s
+},valid_radio:function(e){for(var i=e.getAttribute("name"),s=this.S(e).closest("[data-"+this.attr_name(!0)+"]").find("[name='"+i+"']"),n=s.length,a=!1,o=!1,r=0;n>r;r++)s[r].getAttribute("disabled")?(o=!0,a=!0):s[r].checked?a=!0:o&&(a=!1);for(var r=0;n>r;r++)a?(this.S(s[r]).removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class),t(s[r]).triggerHandler("valid")):(this.S(s[r]).attr(this.invalid_attr,"").parent().addClass(this.settings.error_class),t(s[r]).triggerHandler("invalid"));return a},valid_equal:function(t,e,s){var n=i.getElementById(t.getAttribute(this.add_namespace("data-equalto"))).value,a=t.value,o=n===a;return o?(this.S(t).removeAttr(this.invalid_attr),s.removeClass(this.settings.error_class),label.length>0&&settings.error_labels&&label.removeClass(this.settings.error_class)):(this.S(t).attr(this.invalid_attr,""),s.addClass(this.settings.error_class),label.length>0&&settings.error_labels&&label.addClass(this.settings.error_class)),o},valid_oneof:function(t,e,i,s){var t=this.S(t),n=this.S("["+this.add_namespace("data-oneof")+"]"),a=n.filter(":checked").length>0;if(a?t.removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class):t.attr(this.invalid_attr,"").parent().addClass(this.settings.error_class),!s){var o=this;n.each(function(){o.valid_oneof.call(o,this,null,null,!0)})}return a},reflow:function(){var t=this,e=t.S("["+this.attr_name()+"]").attr("novalidate","novalidate");t.S(e).each(function(e,i){t.events(i)})}}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs.tooltip={name:"tooltip",version:"5.5.3",settings:{additional_inheritable_classes:[],tooltip_class:".tooltip",append_to:"body",touch_close_text:"Tap To Close",disable_for_touch:!1,hover_delay:200,fade_in_duration:150,fade_out_duration:150,show_on:"all",tip_template:function(t,e){return'<span data-selector="'+t+'" id="'+t+'" class="'+Foundation.libs.tooltip.settings.tooltip_class.substring(1)+'" role="tooltip">'+e+'<span class="nub"></span></span>'}},cache:{},init:function(t,e,i){Foundation.inherit(this,"random_str"),this.bindings(e,i)},should_show:function(e){var i=t.extend({},this.settings,this.data_options(e));return"all"===i.show_on?!0:this.small()&&"small"===i.show_on?!0:this.medium()&&"medium"===i.show_on?!0:this.large()&&"large"===i.show_on?!0:!1},medium:function(){return matchMedia(Foundation.media_queries.medium).matches},large:function(){return matchMedia(Foundation.media_queries.large).matches},events:function(e){function i(t,e,i){t.timer||(i?(t.timer=null,n.showTip(e)):t.timer=setTimeout(function(){t.timer=null,n.showTip(e)}.bind(t),n.settings.hover_delay))}function s(t,e){t.timer&&(clearTimeout(t.timer),t.timer=null),n.hide(e)}var n=this,a=n.S;n.create(this.S(e)),t(this.scope).off(".tooltip").on("mouseenter.fndtn.tooltip mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip","["+this.attr_name()+"]",function(e){var o=a(this),r=t.extend({},n.settings,n.data_options(o)),l=!1;if(Modernizr.touch&&/touchstart|MSPointerDown/i.test(e.type)&&a(e.target).is("a"))return!1;if(/mouse/i.test(e.type)&&n.ie_touch(e))return!1;if(o.hasClass("open"))Modernizr.touch&&/touchstart|MSPointerDown/i.test(e.type)&&e.preventDefault(),n.hide(o);else{if(r.disable_for_touch&&Modernizr.touch&&/touchstart|MSPointerDown/i.test(e.type))return;if(!r.disable_for_touch&&Modernizr.touch&&/touchstart|MSPointerDown/i.test(e.type)&&(e.preventDefault(),a(r.tooltip_class+".open").hide(),l=!0,t(".open["+n.attr_name()+"]").length>0)){var d=a(t(".open["+n.attr_name()+"]")[0]);n.hide(d)}/enter|over/i.test(e.type)?i(this,o):"mouseout"===e.type||"mouseleave"===e.type?s(this,o):i(this,o,!0)}}).on("mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip","["+this.attr_name()+"].open",function(e){return/mouse/i.test(e.type)&&n.ie_touch(e)?!1:void(("touch"!=t(this).data("tooltip-open-event-type")||"mouseleave"!=e.type)&&("mouse"==t(this).data("tooltip-open-event-type")&&/MSPointerDown|touchstart/i.test(e.type)?n.convert_to_touch(t(this)):s(this,t(this))))}).on("DOMNodeRemoved DOMAttrModified","["+this.attr_name()+"]:not(a)",function(){s(this,a(this))})},ie_touch:function(){return!1},showTip:function(t){var e=this.getTip(t);return this.should_show(t,e)?this.show(t):void 0},getTip:function(e){var i=this.selector(e),s=t.extend({},this.settings,this.data_options(e)),n=null;return i&&(n=this.S('span[data-selector="'+i+'"]'+s.tooltip_class)),"object"==typeof n?n:!1},selector:function(t){var e=t.attr(this.attr_name())||t.attr("data-selector");return"string"!=typeof e&&(e=this.random_str(6),t.attr("data-selector",e).attr("aria-describedby",e)),e},create:function(i){var s=this,n=t.extend({},this.settings,this.data_options(i)),a=this.settings.tip_template;"string"==typeof n.tip_template&&e.hasOwnProperty(n.tip_template)&&(a=e[n.tip_template]);var o=t(a(this.selector(i),t("<div></div>").html(i.attr("title")).html())),r=this.inheritable_classes(i);o.addClass(r).appendTo(n.append_to),Modernizr.touch&&(o.append('<span class="tap-to-close">'+n.touch_close_text+"</span>"),o.on("touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip",function(){s.hide(i)})),i.removeAttr("title").attr("title","")},reposition:function(e,i,s){var n,a,o,r,l;i.css("visibility","hidden").show(),n=e.data("width"),a=i.children(".nub"),o=a.outerHeight(),r=a.outerWidth(),i.css(this.small()?{width:"100%"}:{width:n?n:"auto"}),l=function(t,e,i,s,n){return t.css({top:e?e:"auto",bottom:s?s:"auto",left:n?n:"auto",right:i?i:"auto"}).end()};var d=e.offset().top,c=e.offset().left,h=e.outerHeight();if(l(i,d+h+10,"auto","auto",c),this.small())l(i,d+h+10,"auto","auto",12.5,t(this.scope).width()),i.addClass("tip-override"),l(a,-o,"auto","auto",c);else{Foundation.rtl&&(a.addClass("rtl"),c=c+e.outerWidth()-i.outerWidth()),l(i,d+h+10,"auto","auto",c),a.attr("style")&&a.removeAttr("style"),i.removeClass("tip-override");var u=i.outerHeight();s&&s.indexOf("tip-top")>-1?(Foundation.rtl&&a.addClass("rtl"),l(i,d-u,"auto","auto",c).removeClass("tip-override")):s&&s.indexOf("tip-left")>-1?(l(i,d+h/2-u/2,"auto","auto",c-i.outerWidth()-o).removeClass("tip-override"),a.removeClass("rtl")):s&&s.indexOf("tip-right")>-1&&(l(i,d+h/2-u/2,"auto","auto",c+e.outerWidth()+o).removeClass("tip-override"),a.removeClass("rtl"))}i.css("visibility","visible").hide()},small:function(){return matchMedia(Foundation.media_queries.small).matches&&!matchMedia(Foundation.media_queries.medium).matches},inheritable_classes:function(e){var i=t.extend({},this.settings,this.data_options(e)),s=["tip-top","tip-left","tip-bottom","tip-right","radius","round"].concat(i.additional_inheritable_classes),n=e.attr("class"),a=n?t.map(n.split(" "),function(e){return-1!==t.inArray(e,s)?e:void 0}).join(" "):"";return t.trim(a)},convert_to_touch:function(e){var i=this,s=i.getTip(e),n=t.extend({},i.settings,i.data_options(e));0===s.find(".tap-to-close").length&&(s.append('<span class="tap-to-close">'+n.touch_close_text+"</span>"),s.on("click.fndtn.tooltip.tapclose touchstart.fndtn.tooltip.tapclose MSPointerDown.fndtn.tooltip.tapclose",function(){i.hide(e)})),e.data("tooltip-open-event-type","touch")},show:function(t){var e=this.getTip(t);"touch"==t.data("tooltip-open-event-type")&&this.convert_to_touch(t),this.reposition(t,e,t.attr("class")),t.addClass("open"),e.fadeIn(this.settings.fade_in_duration)},hide:function(t){var e=this.getTip(t);e.fadeOut(this.settings.fade_out_duration,function(){e.find(".tap-to-close").remove(),e.off("click.fndtn.tooltip.tapclose MSPointerDown.fndtn.tapclose"),t.removeClass("open")})},off:function(){var e=this;this.S(this.scope).off(".fndtn.tooltip"),this.S(this.settings.tooltip_class).each(function(i){t("["+e.attr_name()+"]").eq(i).attr("title",t(this).text())}).remove()},reflow:function(){}}}(jQuery,window,window.document);
diff --git a/record-and-playback/presentation_export/playback/presentation_export/lib/jquery-ui-1.8.23.custom.min.js b/record-and-playback/presentation_export/playback/presentation_export/lib/jquery-ui-1.8.23.custom.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..2812f523c0ae8c4dd12c4ce56287f43f860789dc
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/lib/jquery-ui-1.8.23.custom.min.js
@@ -0,0 +1,21 @@
+/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.core.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.23",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("<a>").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;return b[d]>0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.widget.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++)try{a(e).triggerHandler("remove")}catch(f){}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){return c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){try{a(this).triggerHandler("remove")}catch(b){}}),d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1],f=e+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][f]=function(c){return!!a.data(c,b)},a[e]=a[e]||{},a[e][b]=function(a,b){arguments.length&&this._createWidget(a,b)};var g=new c;g.options=a.extend(!0,{},g.options),a[e][b].prototype=a.extend(!0,g,{namespace:e,widgetName:b,widgetEventPrefix:a[e][b].prototype.widgetEventPrefix||b,widgetBaseClass:f},d),a.widget.bridge(b,a[e][b])},a.widget.bridge=function(c,d){a.fn[c]=function(e){var f=typeof e=="string",g=Array.prototype.slice.call(arguments,1),h=this;return e=!f&&g.length?a.extend.apply(null,[!0,e].concat(g)):e,f&&e.charAt(0)==="_"?h:(f?this.each(function(){var d=a.data(this,c),f=d&&a.isFunction(d[e])?d[e].apply(d,g):d;if(f!==d&&f!==b)return h=f,!1}):this.each(function(){var b=a.data(this,c);b?b.option(e||{})._init():a.data(this,c,new d(e,this))}),h)}},a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)},a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:!1},_createWidget:function(b,c){a.data(c,this.widgetName,this),this.element=a(c),this.options=a.extend(!0,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()}),this._create(),this._trigger("create"),this._init()},_getCreateOptions:function(){return a.metadata&&a.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName),this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled "+"ui-state-disabled")},widget:function(){return this.element},option:function(c,d){var e=c;if(arguments.length===0)return a.extend({},this.options);if(typeof c=="string"){if(d===b)return this.options[c];e={},e[c]=d}return this._setOptions(e),this},_setOptions:function(b){var c=this;return a.each(b,function(a,b){c._setOption(a,b)}),this},_setOption:function(a,b){return this.options[a]=b,a==="disabled"&&this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled"+" "+"ui-state-disabled").attr("aria-disabled",b),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_trigger:function(b,c,d){var e,f,g=this.options[b];d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent;if(f)for(e in f)e in c||(c[e]=f[e]);return this.element.trigger(c,d),!(a.isFunction(g)&&g.call(this.element[0],c,d)===!1||c.isDefaultPrevented())}}})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.mouse.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent"))return a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation(),!1}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(b){if(c)return;this._mouseStarted&&this._mouseUp(b),this._mouseDownEvent=b;var d=this,e=b.which==1,f=typeof this.options.cancel=="string"&&b.target.nodeName?a(b.target).closest(this.options.cancel).length:!1;if(!e||f||!this._mouseCapture(b))return!0;this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){d.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=this._mouseStart(b)!==!1;if(!this._mouseStarted)return b.preventDefault(),!0}return!0===a.data(b.target,this.widgetName+".preventClickEvent")&&a.removeData(b.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(a){return d._mouseMove(a)},this._mouseUpDelegate=function(a){return d._mouseUp(a)},a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),b.preventDefault(),c=!0,!0},_mouseMove:function(b){return!a.browser.msie||document.documentMode>=9||!!b.button?this._mouseStarted?(this._mouseDrag(b),b.preventDefault()):(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b)),!this._mouseStarted):this._mouseUp(b)},_mouseUp:function(b){return a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b)),!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.position.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;return i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),n.left+=k[0],n.top+=k[1],this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),a.curCSS||(a.curCSS=a.css),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()})(jQuery);;/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.slider.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;i<g;i+=1)h.push(f);this.handles=e.add(a(h.join("")).appendTo(b.element)),this.handle=this.handles.eq(0),this.handles.add(this.range).filter("a").click(function(a){a.preventDefault()}).hover(function(){d.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){d.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")}),this.handles.each(function(b){a(this).data("index.ui-slider-handle",b)}),this.handles.keydown(function(d){var e=a(this).data("index.ui-slider-handle"),f,g,h,i;if(b.options.disabled)return;switch(d.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:d.preventDefault();if(!b._keySliding){b._keySliding=!0,a(this).addClass("ui-state-active"),f=b._start(d,e);if(f===!1)return}}i=b.options.step,b.options.values&&b.options.values.length?g=h=b.values(e):g=h=b.value();switch(d.keyCode){case a.ui.keyCode.HOME:h=b._valueMin();break;case a.ui.keyCode.END:h=b._valueMax();break;case a.ui.keyCode.PAGE_UP:h=b._trimAlignValue(g+(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.PAGE_DOWN:h=b._trimAlignValue(g-(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g===b._valueMax())return;h=b._trimAlignValue(g+i);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g===b._valueMin())return;h=b._trimAlignValue(g-i)}b._slide(d,e,h)}).keyup(function(c){var d=a(this).data("index.ui-slider-handle");b._keySliding&&(b._keySliding=!1,b._stop(c,d),b._change(c,d),a(this).removeClass("ui-state-active"))}),this._refreshValue(),this._animateOff=!1},destroy:function(){return this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options,d,e,f,g,h,i,j,k,l;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),d={x:b.pageX,y:b.pageY},e=this._normValueFromMouse(d),f=this._valueMax()-this._valueMin()+1,h=this,this.handles.each(function(b){var c=Math.abs(e-h.values(b));f>c&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c<d)&&(c=d),c!==this.values(b)&&(e=this.values(),e[b]=c,f=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e}),d=this.values(b?0:1),f!==!1&&this.values(b,c,!0))):c!==this.value()&&(f=this._trigger("slide",a,{handle:this.handles[b],value:c}),f!==!1&&this.value(c))},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=this._trimAlignValue(a),this._refreshValue(),this._change(null,0);return}return this._value()},values:function(b,c){var d,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f<d.length;f+=1)d[f]=this._trimAlignValue(e[f]),this._change(null,f);this._refreshValue()},_setOption:function(b,c){var d,e=0;a.isArray(this.options.values)&&(e=this.options.values.length),a.Widget.prototype._setOption.apply(this,arguments);switch(b){case"disabled":c?(this.handles.filter(".ui-state-focus").blur(),this.handles.removeClass("ui-state-hover"),this.handles.propAttr("disabled",!0),this.element.addClass("ui-disabled")):(this.handles.propAttr("disabled",!1),this.element.removeClass("ui-disabled"));break;case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":this._animateOff=!0,this._refreshValue();for(d=0;d<e;d+=1)this._change(null,d);this._animateOff=!1}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a),a},_values:function(a){var b,c,d;if(arguments.length)return b=this.options.values[a],b=this._trimAlignValue(b),b;c=this.options.values.slice();for(d=0;d<c.length;d+=1)c[d]=this._trimAlignValue(c[d]);return c},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.23"})})(jQuery);;
\ No newline at end of file
diff --git a/record-and-playback/presentation_export/playback/presentation_export/lib/jquery-ui.min.js b/record-and-playback/presentation_export/playback/presentation_export/lib/jquery-ui.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..62acf7c16cd63d33d60900e62c5edfb754ac25c6
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/lib/jquery-ui.min.js
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.8.23 - 2012-08-15
+* https://github.com/jquery/jquery-ui
+* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.effects.core.js, jquery.effects.blind.js, jquery.effects.bounce.js, jquery.effects.clip.js, jquery.effects.drop.js, jquery.effects.explode.js, jquery.effects.fade.js, jquery.effects.fold.js, jquery.effects.highlight.js, jquery.effects.pulsate.js, jquery.effects.scale.js, jquery.effects.shake.js, jquery.effects.slide.js, jquery.effects.transfer.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.tabs.js
+* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */
+(function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.23",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("<a>").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;return b[d]>0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}})})(jQuery),function(a,b){if(a.cleanData){var c=a.cleanData;a.cleanData=function(b){for(var d=0,e;(e=b[d])!=null;d++)try{a(e).triggerHandler("remove")}catch(f){}c(b)}}else{var d=a.fn.remove;a.fn.remove=function(b,c){return this.each(function(){return c||(!b||a.filter(b,[this]).length)&&a("*",this).add([this]).each(function(){try{a(this).triggerHandler("remove")}catch(b){}}),d.call(a(this),b,c)})}}a.widget=function(b,c,d){var e=b.split(".")[0],f;b=b.split(".")[1],f=e+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][f]=function(c){return!!a.data(c,b)},a[e]=a[e]||{},a[e][b]=function(a,b){arguments.length&&this._createWidget(a,b)};var g=new c;g.options=a.extend(!0,{},g.options),a[e][b].prototype=a.extend(!0,g,{namespace:e,widgetName:b,widgetEventPrefix:a[e][b].prototype.widgetEventPrefix||b,widgetBaseClass:f},d),a.widget.bridge(b,a[e][b])},a.widget.bridge=function(c,d){a.fn[c]=function(e){var f=typeof e=="string",g=Array.prototype.slice.call(arguments,1),h=this;return e=!f&&g.length?a.extend.apply(null,[!0,e].concat(g)):e,f&&e.charAt(0)==="_"?h:(f?this.each(function(){var d=a.data(this,c),f=d&&a.isFunction(d[e])?d[e].apply(d,g):d;if(f!==d&&f!==b)return h=f,!1}):this.each(function(){var b=a.data(this,c);b?b.option(e||{})._init():a.data(this,c,new d(e,this))}),h)}},a.Widget=function(a,b){arguments.length&&this._createWidget(a,b)},a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:!1},_createWidget:function(b,c){a.data(c,this.widgetName,this),this.element=a(c),this.options=a.extend(!0,{},this.options,this._getCreateOptions(),b);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()}),this._create(),this._trigger("create"),this._init()},_getCreateOptions:function(){return a.metadata&&a.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName),this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled "+"ui-state-disabled")},widget:function(){return this.element},option:function(c,d){var e=c;if(arguments.length===0)return a.extend({},this.options);if(typeof c=="string"){if(d===b)return this.options[c];e={},e[c]=d}return this._setOptions(e),this},_setOptions:function(b){var c=this;return a.each(b,function(a,b){c._setOption(a,b)}),this},_setOption:function(a,b){return this.options[a]=b,a==="disabled"&&this.widget()[b?"addClass":"removeClass"](this.widgetBaseClass+"-disabled"+" "+"ui-state-disabled").attr("aria-disabled",b),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_trigger:function(b,c,d){var e,f,g=this.options[b];d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent;if(f)for(e in f)e in c||(c[e]=f[e]);return this.element.trigger(c,d),!(a.isFunction(g)&&g.call(this.element[0],c,d)===!1||c.isDefaultPrevented())}}}(jQuery),function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent"))return a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation(),!1}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(b){if(c)return;this._mouseStarted&&this._mouseUp(b),this._mouseDownEvent=b;var d=this,e=b.which==1,f=typeof this.options.cancel=="string"&&b.target.nodeName?a(b.target).closest(this.options.cancel).length:!1;if(!e||f||!this._mouseCapture(b))return!0;this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){d.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=this._mouseStart(b)!==!1;if(!this._mouseStarted)return b.preventDefault(),!0}return!0===a.data(b.target,this.widgetName+".preventClickEvent")&&a.removeData(b.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(a){return d._mouseMove(a)},this._mouseUpDelegate=function(a){return d._mouseUp(a)},a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),b.preventDefault(),c=!0,!0},_mouseMove:function(b){return!a.browser.msie||document.documentMode>=9||!!b.button?this._mouseStarted?(this._mouseDrag(b),b.preventDefault()):(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b)),!this._mouseStarted):this._mouseUp(b)},_mouseUp:function(b){return a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b)),!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})}(jQuery),function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!this.element.data("draggable"))return;return this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options;return this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(b),this.handle?(c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(b){var c=this.options;return this.helper=this._createHelper(b),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment(),this._trigger("start",b)===!1?(this._clear(),!1):(this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b),!0)},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1)return this._mouseUp({}),!1;this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);var d=this.element[0],e=!1;while(d&&(d=d.parentNode))d==document&&(e=!0);if(!e&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var f=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){f._trigger("stop",b)!==!1&&f._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){return this.options.iframeFix===!0&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b),a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?!0:!1;return a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)}),c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute"),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h=[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.left<h[0]&&(f=h[0]+this.offset.click.left),b.pageY-this.offset.click.top<h[1]&&(g=h[1]+this.offset.click.top),b.pageX-this.offset.click.left>h[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.top<h[1]||j-this.offset.click.top>h[3]?j-this.offset.click.top<h[1]?j+c.grid[1]:j-c.grid[1]:j:j;var k=c.grid[0]?this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0]:this.originalPageX;f=h?k-this.offset.click.left<h[0]||k-this.offset.click.left>h[2]?k-this.offset.click.left<h[0]?k+c.grid[0]:k-c.grid[0]:k:k}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(b,c,d){return d=d||this._uiHash(),a.ui.plugin.call(this,b,[c,d]),b=="drag"&&(this.positionAbs=this._convertPositionTo("absolute")),a.Widget.prototype._trigger.call(this,b,c,d)},plugins:{},_uiHash:function(a){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),a.extend(a.ui.draggable,{version:"1.8.23"}),a.ui.plugin.add("draggable","connectToSortable",{start:function(b,c){var d=a(this).data("draggable"),e=d.options,f=a.extend({},c,{item:d.element});d.sortables=[],a(e.connectToSortable).each(function(){var c=a.data(this,"sortable");c&&!c.options.disabled&&(d.sortables.push({instance:c,shouldRevert:c.options.revert}),c.refreshPositions(),c._trigger("activate",b,f))})},stop:function(b,c){var d=a(this).data("draggable"),e=a.extend({},c,{item:d.element});a.each(d.sortables,function(){this.instance.isOver?(this.instance.isOver=0,d.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=!0),this.instance._mouseStop(b),this.instance.options.helper=this.instance.options._helper,d.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",b,e))})},drag:function(b,c){var d=a(this).data("draggable"),e=this,f=function(b){var c=this.offset.click.top,d=this.offset.click.left,e=this.positionAbs.top,f=this.positionAbs.left,g=b.height,h=b.width,i=b.top,j=b.left;return a.ui.isOver(e+c,f+d,i,j,g,h)};a.each(d.sortables,function(f){this.instance.positionAbs=d.positionAbs,this.instance.helperProportions=d.helperProportions,this.instance.offset.click=d.offset.click,this.instance._intersectsWith(this.instance.containerCache)?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=a(e).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return c.helper[0]},b.target=this.instance.currentItem[0],this.instance._mouseCapture(b,!0),this.instance._mouseStart(b,!0,!0),this.instance.offset.click.top=d.offset.click.top,this.instance.offset.click.left=d.offset.click.left,this.instance.offset.parent.left-=d.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=d.offset.parent.top-this.instance.offset.parent.top,d._trigger("toSortable",b),d.dropped=this.instance.element,d.currentItem=d.element,this.instance.fromOutside=d),this.instance.currentItem&&this.instance._mouseDrag(b)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",b,this.instance._uiHash(this.instance)),this.instance._mouseStop(b,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),d._trigger("fromSortable",b),d.dropped=!1)})}}),a.ui.plugin.add("draggable","cursor",{start:function(b,c){var d=a("body"),e=a(this).data("draggable").options;d.css("cursor")&&(e._cursor=d.css("cursor")),d.css("cursor",e.cursor)},stop:function(b,c){var d=a(this).data("draggable").options;d._cursor&&a("body").css("cursor",d._cursor)}}),a.ui.plugin.add("draggable","opacity",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("opacity")&&(e._opacity=d.css("opacity")),d.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;d._opacity&&a(c.helper).css("opacity",d._opacity)}}),a.ui.plugin.add("draggable","scroll",{start:function(b,c){var d=a(this).data("draggable");d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"&&(d.overflowOffset=d.scrollParent.offset())},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=!1;if(d.scrollParent[0]!=document&&d.scrollParent[0].tagName!="HTML"){if(!e.axis||e.axis!="x")d.overflowOffset.top+d.scrollParent[0].offsetHeight-b.pageY<e.scrollSensitivity?d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop+e.scrollSpeed:b.pageY-d.overflowOffset.top<e.scrollSensitivity&&(d.scrollParent[0].scrollTop=f=d.scrollParent[0].scrollTop-e.scrollSpeed);if(!e.axis||e.axis!="y")d.overflowOffset.left+d.scrollParent[0].offsetWidth-b.pageX<e.scrollSensitivity?d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft+e.scrollSpeed:b.pageX-d.overflowOffset.left<e.scrollSensitivity&&(d.scrollParent[0].scrollLeft=f=d.scrollParent[0].scrollLeft-e.scrollSpeed)}else{if(!e.axis||e.axis!="x")b.pageY-a(document).scrollTop()<e.scrollSensitivity?f=a(document).scrollTop(a(document).scrollTop()-e.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<e.scrollSensitivity&&(f=a(document).scrollTop(a(document).scrollTop()+e.scrollSpeed));if(!e.axis||e.axis!="y")b.pageX-a(document).scrollLeft()<e.scrollSensitivity?f=a(document).scrollLeft(a(document).scrollLeft()-e.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<e.scrollSensitivity&&(f=a(document).scrollLeft(a(document).scrollLeft()+e.scrollSpeed))}f!==!1&&a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(d,b)}}),a.ui.plugin.add("draggable","snap",{start:function(b,c){var d=a(this).data("draggable"),e=d.options;d.snapElements=[],a(e.snap.constructor!=String?e.snap.items||":data(draggable)":e.snap).each(function(){var b=a(this),c=b.offset();this!=d.element[0]&&d.snapElements.push({item:this,width:b.outerWidth(),height:b.outerHeight(),top:c.top,left:c.left})})},drag:function(b,c){var d=a(this).data("draggable"),e=d.options,f=e.snapTolerance,g=c.offset.left,h=g+d.helperProportions.width,i=c.offset.top,j=i+d.helperProportions.height;for(var k=d.snapElements.length-1;k>=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f<g&&g<m+f&&n-f<i&&i<o+f||l-f<g&&g<m+f&&n-f<j&&j<o+f||l-f<h&&h<m+f&&n-f<i&&i<o+f||l-f<h&&h<m+f&&n-f<j&&j<o+f)){d.snapElements[k].snapping&&d.options.snap.release&&d.options.snap.release.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=!1;continue}if(e.snapMode!="inner"){var p=Math.abs(n-j)<=f,q=Math.abs(o-i)<=f,r=Math.abs(l-h)<=f,s=Math.abs(m-g)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n-d.helperProportions.height,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l-d.helperProportions.width}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m}).left-d.margins.left)}var t=p||q||r||s;if(e.snapMode!="outer"){var p=Math.abs(n-i)<=f,q=Math.abs(o-j)<=f,r=Math.abs(l-g)<=f,s=Math.abs(m-h)<=f;p&&(c.position.top=d._convertPositionTo("relative",{top:n,left:0}).top-d.margins.top),q&&(c.position.top=d._convertPositionTo("relative",{top:o-d.helperProportions.height,left:0}).top-d.margins.top),r&&(c.position.left=d._convertPositionTo("relative",{top:0,left:l}).left-d.margins.left),s&&(c.position.left=d._convertPositionTo("relative",{top:0,left:m-d.helperProportions.width}).left-d.margins.left)}!d.snapElements[k].snapping&&(p||q||r||s||t)&&d.options.snap.snap&&d.options.snap.snap.call(d.element,b,a.extend(d._uiHash(),{snapItem:d.snapElements[k].item})),d.snapElements[k].snapping=p||q||r||s||t}}}),a.ui.plugin.add("draggable","stack",{start:function(b,c){var d=a(this).data("draggable").options,e=a.makeArray(a(d.stack)).sort(function(b,c){return(parseInt(a(b).css("zIndex"),10)||0)-(parseInt(a(c).css("zIndex"),10)||0)});if(!e.length)return;var f=parseInt(e[0].style.zIndex)||0;a(e).each(function(a){this.style.zIndex=f+a}),this[0].style.zIndex=f+e.length}}),a.ui.plugin.add("draggable","zIndex",{start:function(b,c){var d=a(c.helper),e=a(this).data("draggable").options;d.css("zIndex")&&(e._zIndex=d.css("zIndex")),d.css("zIndex",e.zIndex)},stop:function(b,c){var d=a(this).data("draggable").options;d._zIndex&&a(c.helper).css("zIndex",d._zIndex)}})}(jQuery),function(a,b){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var b=this.options,c=b.accept;this.isover=0,this.isout=1,this.accept=a.isFunction(c)?c:function(a){return a.is(c)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},a.ui.ddmanager.droppables[b.scope]=a.ui.ddmanager.droppables[b.scope]||[],a.ui.ddmanager.droppables[b.scope].push(this),b.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c<b.length;c++)b[c]==this&&b.splice(c,1);return this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable"),this},_setOption:function(b,c){b=="accept"&&(this.accept=a.isFunction(c)?c:function(a){return a.is(c)}),a.Widget.prototype._setOption.apply(this,arguments)},_activate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),c&&this._trigger("activate",b,this.ui(c))},_deactivate:function(b){var c=a.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),c&&this._trigger("deactivate",b,this.ui(c))},_over:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",b,this.ui(c)))},_out:function(b){var c=a.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return;this.accept.call(this.element[0],c.currentItem||c.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",b,this.ui(c)))},_drop:function(b,c){var d=c||a.ui.ddmanager.current;if(!d||(d.currentItem||d.element)[0]==this.element[0])return!1;var e=!1;return this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var b=a.data(this,"droppable");if(b.options.greedy&&!b.options.disabled&&b.options.scope==d.options.scope&&b.accept.call(b.element[0],d.currentItem||d.element)&&a.ui.intersect(d,a.extend(b,{offset:b.element.offset()}),b.options.tolerance))return e=!0,!1}),e?!1:this.accept.call(this.element[0],d.currentItem||d.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",b,this.ui(d)),this.element):!1},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}}),a.extend(a.ui.droppable,{version:"1.8.23"}),a.ui.intersect=function(b,c,d){if(!c.offset)return!1;var e=(b.positionAbs||b.position.absolute).left,f=e+b.helperProportions.width,g=(b.positionAbs||b.position.absolute).top,h=g+b.helperProportions.height,i=c.offset.left,j=i+c.proportions.width,k=c.offset.top,l=k+c.proportions.height;switch(d){case"fit":return i<=e&&f<=j&&k<=g&&h<=l;case"intersect":return i<e+b.helperProportions.width/2&&f-b.helperProportions.width/2<j&&k<g+b.helperProportions.height/2&&h-b.helperProportions.height/2<l;case"pointer":var m=(b.positionAbs||b.position.absolute).left+(b.clickOffset||b.offset.click).left,n=(b.positionAbs||b.position.absolute).top+(b.clickOffset||b.offset.click).top,o=a.ui.isOver(n,m,k,i,c.proportions.height,c.proportions.width);return o;case"touch":return(g>=k&&g<=l||h>=k&&h<=l||g<k&&h>l)&&(e>=i&&e<=j||f>=i&&f<=j||e<i&&f>j);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();g:for(var h=0;h<d.length;h++){if(d[h].options.disabled||b&&!d[h].accept.call(d[h].element[0],b.currentItem||b.element))continue;for(var i=0;i<f.length;i++)if(f[i]==d[h].element[0]){d[h].proportions.height=0;continue g}d[h].visible=d[h].element.css("display")!="none";if(!d[h].visible)continue;e=="mousedown"&&d[h]._activate.call(d[h],c),d[h].offset=d[h].element.offset(),d[h].proportions={width:d[h].element[0].offsetWidth,height:d[h].element[0].offsetHeight}}},drop:function(b,c){var d=!1;return a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(!this.options)return;!this.options.disabled&&this.visible&&a.ui.intersect(b,this,this.options.tolerance)&&(d=this._drop.call(this,c)||d),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],b.currentItem||b.element)&&(this.isout=1,this.isover=0,this._deactivate.call(this,c))}),d},dragStart:function(b,c){b.element.parents(":not(body,html)").bind("scroll.droppable",function(){b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)})},drag:function(b,c){b.options.refreshPositions&&a.ui.ddmanager.prepareOffsets(b,c),a.each(a.ui.ddmanager.droppables[b.options.scope]||[],function(){if(this.options.disabled||this.greedyChild||!this.visible)return;var d=a.ui.intersect(b,this,this.options.tolerance),e=!d&&this.isover==1?"isout":d&&this.isover==0?"isover":null;if(!e)return;var f;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");g.length&&(f=a.data(g[0],"droppable"),f.greedyChild=e=="isover"?1:0)}f&&e=="isover"&&(f.isover=0,f.isout=1,f._out.call(f,c)),this[e]=1,this[e=="isout"?"isover":"isout"]=0,this[e=="isover"?"_over":"_out"].call(this,c),f&&e=="isout"&&(f.isout=0,f.isover=1,f._over.call(f,c))})},dragStop:function(b,c){b.element.parents(":not(body,html)").unbind("scroll.droppable"),b.options.refreshPositions||a.ui.ddmanager.prepareOffsets(b,c)}}}(jQuery),function(a,b){a.widget("ui.resizable",a.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var b=this,c=this.options;this.element.addClass("ui-resizable"),a.extend(this,{_aspectRatio:!!c.aspectRatio,aspectRatio:c.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:c.helper||c.ghost||c.animate?c.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(a('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e<d.length;e++){var f=a.trim(d[e]),g="ui-resizable-"+f,h=a('<div class="ui-resizable-handle '+g+'"></div>');h.css({zIndex:c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){if(c.disabled)return;a(this).removeClass("ui-resizable-autohide"),b._handles.show()},function(){if(c.disabled)return;b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}return this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement),this},_mouseCapture:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalMousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");return a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b),!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);return l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",b,this.ui()),!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}return a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.minHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),e<h.maxWidth&&(h.maxWidth=e),g<h.maxHeight&&(h.maxHeight=g);this._vBoundaries=h},_updateCache:function(a){var b=this.options;this.offset=this.helper.offset(),d(a.left)&&(this.position.left=a.left),d(a.top)&&(this.position.top=a.top),d(a.height)&&(this.size.height=a.height),d(a.width)&&(this.size.width=a.width)},_updateRatio:function(a,b){var c=this.options,e=this.position,f=this.size,g=this.axis;return d(a.height)?a.width=a.height*this.aspectRatio:d(a.width)&&(a.height=a.width/this.aspectRatio),g=="sw"&&(a.left=e.left+(f.width-a.width),a.top=null),g=="nw"&&(a.top=e.top+(f.height-a.height),a.left=e.left+(f.width-a.width)),a},_respectSize:function(a,b){var c=this.helper,e=this._vBoundaries,f=this._aspectRatio||b.shiftKey,g=this.axis,h=d(a.width)&&e.maxWidth&&e.maxWidth<a.width,i=d(a.height)&&e.maxHeight&&e.maxHeight<a.height,j=d(a.width)&&e.minWidth&&e.minWidth>a.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;return p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null),a},_proportionallyResize:function(){var b=this.options;if(!this._proportionallyResizeElements.length)return;var c=this.helper||this.element;for(var d=0;d<this._proportionallyResizeElements.length;d++){var e=this._proportionallyResizeElements[d];if(!this.borderDif){var f=[e.css("borderTopWidth"),e.css("borderRightWidth"),e.css("borderBottomWidth"),e.css("borderLeftWidth")],g=[e.css("paddingTop"),e.css("paddingRight"),e.css("paddingBottom"),e.css("paddingLeft")];this.borderDif=a.map(f,function(a,b){var c=parseInt(a,10)||0,d=parseInt(g[b],10)||0;return c+d})}if(!a.browser.msie||!a(c).is(":hidden")&&!a(c).parents(":hidden").length)e.css({height:c.height()-this.borderDif[0]-this.borderDif[2]||0,width:c.width()-this.borderDif[1]-this.borderDif[3]||0});else continue}},_renderProxy:function(){var b=this.element,c=this.options;this.elementOffset=b.offset();if(this._helper){this.helper=this.helper||a('<div style="overflow:hidden;"></div>');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSize.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.23"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10)})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,d){a(b).each(function(){var b=a(this),e=a(this).data("resizable-alsoresize"),f={},g=d&&d.length?d:b.parents(c.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(g,function(a,b){var c=(e[b]||0)+(h[b]||0);c&&c>=0&&(f[b]=c||null)}),b.css(f)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),10),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!i)return;e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/d.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*d.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d.sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}}(jQuery),function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("<div class='ui-selectable-helper'></div>")},destroy:function(){return this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy(),this},_mouseStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(this.options.disabled)return;var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");return d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unselecting:d.element}),!1}})},_mouseDrag:function(b){var c=this;this.dragged=!0;if(this.options.disabled)return;var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}return this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!i||i.element==c.element[0])return;var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.right<e||i.top>h||i.bottom<f):d.tolerance=="fit"&&(j=i.left>e&&i.right<g&&i.top>f&&i.bottom<h),j?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,c._trigger("selecting",b,{selecting:i.element}))):(i.selecting&&((b.metaKey||b.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),c._trigger("unselecting",b,{unselecting:i.element}))),i.selected&&!b.metaKey&&!b.ctrlKey&&!i.startselected&&(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,c._trigger("unselecting",b,{unselecting:i.element})))}),!1},_mouseStop:function(b){var c=this;this.dragged=!1;var d=this.options;return a(".ui-unselecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-unselecting"),d.unselecting=!1,d.startselected=!1,c._trigger("unselected",b,{unselected:d.element})}),a(".ui-selecting",this.element[0]).each(function(){var d=a.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected"),d.selecting=!1,d.selected=!0,d.startselected=!0,c._trigger("selected",b,{selected:d.element})}),this._trigger("stop",b),this.helper.remove(),!1}}),a.extend(a.ui.selectable,{version:"1.8.23"})}(jQuery),function(a,b){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},destroy:function(){a.Widget.prototype.destroy.call(this),this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--)this.items[b].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f)return e=a(this),!1});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}return this.currentItem=e,this._removeCurrentsFromItems(),!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY<c.scrollSensitivity?this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop+c.scrollSpeed:b.pageY-this.overflowOffset.top<c.scrollSensitivity&&(this.scrollParent[0].scrollTop=d=this.scrollParent[0].scrollTop-c.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-b.pageX<c.scrollSensitivity?this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft+c.scrollSpeed:b.pageX-this.overflowOffset.left<c.scrollSensitivity&&(this.scrollParent[0].scrollLeft=d=this.scrollParent[0].scrollLeft-c.scrollSpeed)):(b.pageY-a(document).scrollTop()<c.scrollSensitivity?d=a(document).scrollTop(a(document).scrollTop()-c.scrollSpeed):a(window).height()-(b.pageY-a(document).scrollTop())<c.scrollSensitivity&&(d=a(document).scrollTop(a(document).scrollTop()+c.scrollSpeed)),b.pageX-a(document).scrollLeft()<c.scrollSensitivity?d=a(document).scrollLeft(a(document).scrollLeft()-c.scrollSpeed):a(window).width()-(b.pageX-a(document).scrollLeft())<c.scrollSensitivity&&(d=a(document).scrollLeft(a(document).scrollLeft()+c.scrollSpeed))),d!==!1&&a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(var e=this.items.length-1;e>=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(b,c){if(!b)return;a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+j<i&&b+k>f&&b+k<g;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?l:f<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<g&&h<d+this.helperProportions.height/2&&e-this.helperProportions.height/2<i},_intersectsWithPointer:function(b){var c=this.options.axis==="x"||a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top,b.height),d=this.options.axis==="y"||a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left,b.width),e=c&&d,f=this._getDragVerticalDirection(),g=this._getDragHorizontalDirection();return e?this.floating?g&&g=="right"||f=="down"?2:1:f&&(f=="down"?2:1):!1},_intersectsWithSides:function(b){var c=a.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,b.top+b.height/2,b.height),d=a.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,b.left+b.width/2,b.width),e=this._getDragVerticalDirection(),f=this._getDragHorizontalDirection();return this.floating&&f?f=="right"&&d||f=="left"&&!d:e&&(e=="down"&&c||e=="up"&&!c)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options.items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(b){this.items=[],this.containers=[this];var c=this.items,d=this,e=[[a.isFunction(this.options.items)?this.options.items.call(this.element[0],b,{item:this.currentItem}):a(this.options.items,this.element),this]],f=this._connectWith();if(f&&this.ready)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i<m;i++){var n=a(l[i]);n.data(this.widgetName+"-item",k),c.push({item:n,instance:k,width:0,height:0,left:0,top:0})}}},refreshPositions:function(b){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());for(var c=this.items.length-1;c>=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.containers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return e||(b.style.visibility="hidden"),b},update:function(a,b){if(e&&!d.forcePlaceholderSize)return;b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!c)return;if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui.contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.containers[d].floating?this.items[i].item.offset().left:this.items[i].item.offset().top;Math.abs(j-h)<f&&(f=Math.abs(j-h),g=this.items[i],this.direction=j-h>0?"down":"up")}if(!g&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[d],g?this._rearrange(b,g,null,!0):this._rearrange(b,null,this.containers[d].element,!0),this._trigger("change",b,this._uiHash()),this.containers[d]._trigger("change",b,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1}},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b,this.currentItem])):c.helper=="clone"?this.currentItem.clone():this.currentItem;return d.parents("body").length||a(c.appendTo!="parent"?c.appendTo:this.currentItem[0].parentNode)[0].appendChild(d[0]),d[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(d[0].style.width==""||c.forceHelperSize)&&d.width(this.currentItem.width()),(d[0].style.height==""||c.forceHelperSize)&&d.height(this.currentItem.height()),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)){var c=a(b.containment)[0],d=a(b.containment).offset(),e=a(c).css("overflow")!="hidden";this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var f=b.pageX,g=b.pageY;if(this.originalPosition){this.containment&&(b.pageX-this.offset.click.left<this.containment[0]&&(f=this.containment[0]+this.offset.click.left),b.pageY-this.offset.click.top<this.containment[1]&&(g=this.containment[1]+this.offset.click.top),b.pageX-this.offset.click.left>this.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click.top<this.containment[1]||h-this.offset.click.top>this.containment[3]?h-this.offset.click.top<this.containment[1]?h+c.grid[1]:h-c.grid[1]:h:h;var i=this.originalPageX+Math.round((f-this.originalPageX)/c.grid[0])*c.grid[0];f=this.containment?i-this.offset.click.left<this.containment[0]||i-this.offset.click.left>this.containment[2]?i-this.offset.click.left<this.containment[0]?i+c.grid[0]:i-c.grid[0]:i:i}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:d.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(a.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:d.scrollLeft())}},_rearrange:function(a,b,c,d){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var e=this,f=this.counter;window.setTimeout(function(){f==e.counter&&e.refreshPositions(!d)},0)},_clear:function(b,c){this.reverting=!1;var d=[],e=this;!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var f in this._storedCSS)if(this._storedCSS[f]=="auto"||this._storedCSS[f]=="static")this._storedCSS[f]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!c&&d.push(function(a){this._trigger("receive",a,this._uiHash(this.fromOutside))}),(this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!c&&d.push(function(a){this._trigger("update",a,this._uiHash())});if(!a.ui.contains(this.element[0],this.currentItem[0])){c||d.push(function(a){this._trigger("remove",a,this._uiHash())});for(var f=this.containers.length-1;f>=0;f--)a.ui.contains(this.containers[f].element[0],this.currentItem[0])&&!c&&(d.push(function(a){return function(b){a._trigger("receive",b,this._uiHash(this))}}.call(this,this.containers[f])),d.push(function(a){return function(b){a._trigger("update",b,this._uiHash(this))}}.call(this,this.containers[f])))}for(var f=this.containers.length-1;f>=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop",b,this._uiHash());for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!1}c||this._trigger("beforeStop",b,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!=this.currentItem[0]&&this.helper.remove(),this.helper=null;if(!c){for(var f=0;f<d.length;f++)d[f].call(this,b);this._trigger("stop",b,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){a.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(b){var c=b||this;return{helper:c.helper,placeholder:c.placeholder||a([]),position:c.position,originalPosition:c.originalPosition,offset:c.positionAbs,item:c.currentItem,sender:b?b.element:null}}}),a.extend(a.ui.sortable,{version:"1.8.23"})}(jQuery),jQuery.effects||function(a,b){function c(b){var c;return b&&b.constructor==Array&&b.length==3?b:(c=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))?[parseInt(c[1],10),parseInt(c[2],10),parseInt(c[3],10)]:(c=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))?[parseFloat(c[1])*2.55,parseFloat(c[2])*2.55,parseFloat(c[3])*2.55]:(c=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))?[parseInt(c[1],16),parseInt(c[2],16),parseInt(c[3],16)]:(c=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))?[parseInt(c[1]+c[1],16),parseInt(c[2]+c[2],16),parseInt(c[3]+c[3],16)]:(c=/rgba\(0, 0, 0, 0\)/.exec(b))?e.transparent:e[a.trim(b).toLowerCase()]}function d(b,d){var e;do{e=(a.curCSS||a.css)(b,d);if(e!=""&&e!="transparent"||a.nodeName(b,"body"))break;d="backgroundColor"}while(b=b.parentNode);return c(e)}function h(){var a=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,b={},c,d;if(a&&a.length&&a[0]&&a[a[0]]){var e=a.length;while(e--)c=a[e],typeof a[c]=="string"&&(d=c.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()}),b[d]=a[c])}else for(c in a)typeof a[c]=="string"&&(b[c]=a[c]);return b}function i(b){var c,d;for(c in b)d=b[c],(d==null||a.isFunction(d)||c in g||/scrollbar/.test(c)||!/color/i.test(c)&&isNaN(parseFloat(d)))&&delete b[c];return b}function j(a,b){var c={_:0},d;for(d in b)a[d]!=b[d]&&(c[d]=b[d]);return c}function k(b,c,d,e){typeof b=="object"&&(e=c,d=null,c=b,b=c.effect),a.isFunction(c)&&(e=c,d=null,c={});if(typeof c=="number"||a.fx.speeds[c])e=d,d=c,c={};return a.isFunction(d)&&(e=d,d=null),c=c||{},d=d||c.duration,d=a.fx.off?0:typeof d=="number"?d:d in a.fx.speeds?a.fx.speeds[d]:a.fx.speeds._default,e=e||c.complete,[b,c,d,e]}function l(b){return!b||typeof b=="number"||a.fx.speeds[b]?!0:typeof b=="string"&&!a.effects[b]?!0:!1}a.effects={},a.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","borderColor","color","outlineColor"],function(b,e){a.fx.step[e]=function(a){a.colorInit||(a.start=d(a.elem,e),a.end=c(a.end),a.colorInit=!0),a.elem.style[e]="rgb("+Math.max(Math.min(parseInt(a.pos*(a.end[0]-a.start[0])+a.start[0],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[1]-a.start[1])+a.start[1],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[2]-a.start[2])+a.start[2],10),255),0)+")"}});var e={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},f=["add","remove","toggle"],g={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};a.effects.animateClass=function(b,c,d,e){return a.isFunction(d)&&(e=d,d=null),this.queue(function(){var g=a(this),k=g.attr("style")||" ",l=i(h.call(this)),m,n=g.attr("class")||"";a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),m=i(h.call(this)),g.attr("class",n),g.animate(j(l,m),{queue:!1,duration:c,easing:d,complete:function(){a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),typeof g.attr("style")=="object"?(g.attr("style").cssText="",g.attr("style").cssText=k):g.attr("style",k),e&&e.apply(this,arguments),a.dequeue(this)}})})},a.fn.extend({_addClass:a.fn.addClass,addClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{add:b},c,d,e]):this._addClass(b)},_removeClass:a.fn.removeClass,removeClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{remove:b},c,d,e]):this._removeClass(b)},_toggleClass:a.fn.toggleClass,toggleClass:function(c,d,e,f,g){return typeof d=="boolean"||d===b?e?a.effects.animateClass.apply(this,[d?{add:c}:{remove:c},e,f,g]):this._toggleClass(c,d):a.effects.animateClass.apply(this,[{toggle:c},d,e,f])},switchClass:function(b,c,d,e,f){return a.effects.animateClass.apply(this,[{add:c,remove:b},d,e,f])}}),a.extend(a.effects,{version:"1.8.23",save:function(a,b){for(var c=0;c<b.length;c++)b[c]!==null&&a.data("ec.storage."+b[c],a[0].style[b[c]])},restore:function(a,b){for(var c=0;c<b.length;c++)b[c]!==null&&a.css(b[c],a.data("ec.storage."+b[c]))},setMode:function(a,b){return b=="toggle"&&(b=a.is(":hidden")?"show":"hide"),b},getBaseline:function(a,b){var c,d;switch(a[0]){case"top":c=0;break;case"middle":c=.5;break;case"bottom":c=1;break;default:c=a[0]/b.height}switch(a[1]){case"left":d=0;break;case"center":d=.5;break;case"right":d=1;break;default:d=a[1]/b.width}return{x:d,y:c}},createWrapper:function(b){if(b.parent().is(".ui-effects-wrapper"))return b.parent();var c={width:b.outerWidth(!0),height:b.outerHeight(!0),"float":b.css("float")},d=a("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e=document.activeElement;try{e.id}catch(f){e=document.body}return b.wrap(d),(b[0]===e||a.contains(b[0],e))&&a(e).focus(),d=b.parent(),b.css("position")=="static"?(d.css({position:"relative"}),b.css({position:"relative"})):(a.extend(c,{position:b.css("position"),zIndex:b.css("z-index")}),a.each(["top","left","bottom","right"],function(a,d){c[d]=b.css(d),isNaN(parseInt(c[d],10))&&(c[d]="auto")}),b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),d.css(c).show()},removeWrapper:function(b){var c,d=document.activeElement;return b.parent().is(".ui-effects-wrapper")?(c=b.parent().replaceWith(b),(b[0]===d||a.contains(b[0],d))&&a(d).focus(),c):b},setTransition:function(b,c,d,e){return e=e||{},a.each(c,function(a,c){var f=b.cssUnit(c);f[0]>0&&(e[c]=f[0]*d+f[1])}),e}}),a.fn.extend({effect:function(b,c,d,e){var f=k.apply(this,arguments),g={options:f[1],duration:f[2],callback:f[3]},h=g.options.mode,i=a.effects[b];return a.fx.off||!i?h?this[h](g.duration,g.callback):this.each(function(){g.callback&&g.callback.call(this)}):i.call(this,g)},_show:a.fn.show,show:function(a){if(l(a))return this._show.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="show",this.effect.apply(this,b)},_hide:a.fn.hide,hide:function(a){if(l(a))return this._hide.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="hide",this.effect.apply(this,b)},__toggle:a.fn.toggle,toggle:function(b){if(l(b)||typeof b=="boolean"||a.isFunction(b))return this.__toggle.apply(this,arguments);var c=k.apply(this,arguments);return c[1].mode="toggle",this.effect.apply(this,c)},cssUnit:function(b){var c=this.css(b),d=[];return a.each(["em","px","%","pt"],function(a,b){c.indexOf(b)>0&&(d=[parseFloat(c),b])}),d}});var m={};a.each(["Quad","Cubic","Quart","Quint","Expo"],function(a,b){m[b]=function(b){return Math.pow(b,a+2)}}),a.extend(m,{Sine:function(a){return 1-Math.cos(a*Math.PI/2)},Circ:function(a){return 1-Math.sqrt(1-a*a)},Elastic:function(a){return a===0||a===1?a:-Math.pow(2,8*(a-1))*Math.sin(((a-1)*80-7.5)*Math.PI/15)},Back:function(a){return a*a*(3*a-2)},Bounce:function(a){var b,c=4;while(a<((b=Math.pow(2,--c))-1)/11);return 1/Math.pow(4,3-c)-7.5625*Math.pow((b*3-2)/22-a,2)}}),a.each(m,function(b,c){a.easing["easeIn"+b]=c,a.easing["easeOut"+b]=function(a){return 1-c(1-a)},a.easing["easeInOut"+b]=function(a){return a<.5?c(a*2)/2:c(a*-2+2)/-2+1}})}(jQuery),function(a,b){a.effects.blind=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=f=="vertical"?"height":"width",i=f=="vertical"?g.height():g.width();e=="show"&&g.css(h,0);var j={};j[h]=e=="show"?i:0,g.animate(j,b.duration,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}}(jQuery),function(a,b){a.effects.bounce=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"up",g=b.options.distance||20,h=b.options.times||5,i=b.duration||250;/show|hide/.test(e)&&d.push("opacity"),a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",g=b.options.distance||(j=="top"?c.outerHeight(!0)/3:c.outerWidth(!0)/3);e=="show"&&c.css("opacity",0).css(j,k=="pos"?-g:g),e=="hide"&&(g=g/(h*2)),e!="hide"&&h--;if(e=="show"){var l={opacity:1};l[j]=(k=="pos"?"+=":"-=")+g,c.animate(l,i/2,b.options.easing),g=g/2,h--}for(var m=0;m<h;m++){var n={},p={};n[j]=(k=="pos"?"-=":"+=")+g,p[j]=(k=="pos"?"+=":"-=")+g,c.animate(n,i/2,b.options.easing).animate(p,i/2,b.options.easing),g=e=="hide"?g*2:g/2}if(e=="hide"){var l={opacity:0};l[j]=(k=="pos"?"-=":"+=")+g,c.animate(l,i/2,b.options.easing,function(){c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)})}else{var n={},p={};n[j]=(k=="pos"?"-=":"+=")+g,p[j]=(k=="pos"?"+=":"-=")+g,c.animate(n,i/2,b.options.easing).animate(p,i/2,b.options.easing,function(){a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)})}c.queue("fx",function(){c.dequeue()}),c.dequeue()})}}(jQuery),function(a,b){a.effects.clip=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","height","width"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=c[0].tagName=="IMG"?g:c,i={size:f=="vertical"?"height":"width",position:f=="vertical"?"top":"left"},j=f=="vertical"?h.height():h.width();e=="show"&&(h.css(i.size,0),h.css(i.position,j/2));var k={};k[i.size]=e=="show"?j:0,k[i.position]=e=="show"?0:j/2,h.animate(k,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()}})})}}(jQuery),function(a,b){a.effects.drop=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","opacity"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0)/2:c.outerWidth(!0)/2);e=="show"&&c.css("opacity",0).css(g,h=="pos"?-i:i);var j={opacity:e=="show"?1:0};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}}(jQuery),function(a,b){a.effects.explode=function(b){return this.queue(function(){var c=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3,d=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;b.options.mode=b.options.mode=="toggle"?a(this).is(":visible")?"hide":"show":b.options.mode;var e=a(this).show().css("visibility","hidden"),f=e.offset();f.top-=parseInt(e.css("marginTop"),10)||0,f.left-=parseInt(e.css("marginLeft"),10)||0;var g=e.outerWidth(!0),h=e.outerHeight(!0);for(var i=0;i<c;i++)for(var j=0;j<d;j++)e.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-j*(g/d),top:-i*(h/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/d,height:h/c,left:f.left+j*(g/d)+(b.options.mode=="show"?(j-Math.floor(d/2))*(g/d):0),top:f.top+i*(h/c)+(b.options.mode=="show"?(i-Math.floor(c/2))*(h/c):0),opacity:b.options.mode=="show"?0:1}).animate({left:f.left+j*(g/d)+(b.options.mode=="show"?0:(j-Math.floor(d/2))*(g/d)),top:f.top+i*(h/c)+(b.options.mode=="show"?0:(i-Math.floor(c/2))*(h/c)),opacity:b.options.mode=="show"?1:0},b.duration||500);setTimeout(function(){b.options.mode=="show"?e.css({visibility:"visible"}):e.css({visibility:"visible"}).hide(),b.callback&&b.callback.apply(e[0]),e.dequeue(),a("div.ui-effects-explode").remove()},b.duration||500)})}}(jQuery),function(a,b){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}}(jQuery),function(a,b){a.effects.fold=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.size||15,g=!!b.options.horizFirst,h=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(c,d),c.show();var i=a.effects.createWrapper(c).css({overflow:"hidden"}),j=e=="show"!=g,k=j?["width","height"]:["height","width"],l=j?[i.width(),i.height()]:[i.height(),i.width()],m=/([0-9]+)%/.exec(f);m&&(f=parseInt(m[1],10)/100*l[e=="hide"?0:1]),e=="show"&&i.css(g?{height:0,width:f}:{height:f,width:0});var n={},p={};n[k[0]]=e=="show"?l[0]:f,p[k[1]]=e=="show"?l[1]:0,i.animate(n,h,b.options.easing).animate(p,h,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}}(jQuery),function(a,b){a.effects.highlight=function(b){return this.queue(function(){var c=a(this),d=["backgroundImage","backgroundColor","opacity"],e=a.effects.setMode(c,b.options.mode||"show"),f={backgroundColor:c.css("backgroundColor")};e=="hide"&&(f.opacity=0),a.effects.save(c,d),c.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(f,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),e=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}}(jQuery),function(a,b){a.effects.pulsate=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"show"),e=(b.options.times||5)*2-1,f=b.duration?b.duration/2:a.fx.speeds._default/2,g=c.is(":visible"),h=0;g||(c.css("opacity",0).show(),h=1),(d=="hide"&&g||d=="show"&&!g)&&e--;for(var i=0;i<e;i++)c.animate({opacity:h},f,b.options.easing),h=(h+1)%2;c.animate({opacity:h},f,b.options.easing,function(){h==0&&c.hide(),b.callback&&b.callback.apply(this,arguments)}),c.queue("fx",function(){c.dequeue()}).dequeue()})}}(jQuery),function(a,b){a.effects.puff=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide"),e=parseInt(b.options.percent,10)||150,f=e/100,g={height:c.height(),width:c.width()};a.extend(b.options,{fade:!0,mode:d,percent:d=="hide"?e:100,from:d=="hide"?g:{height:g.height*f,width:g.width*f}}),c.effect("scale",b.options,b.duration,b.callback),c.dequeue()})},a.effects.scale=function(b){return this.queue(function(){var c=a(this),d=a.extend(!0,{},b.options),e=a.effects.setMode(c,b.options.mode||"effect"),f=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:e=="hide"?0:100),g=b.options.direction||"both",h=b.options.origin;e!="effect"&&(d.origin=h||["middle","center"],d.restore=!0);var i={height:c.height(),width:c.width()};c.from=b.options.from||(e=="show"?{height:0,width:0}:i);var j={y:g!="horizontal"?f/100:1,x:g!="vertical"?f/100:1};c.to={height:i.height*j.y,width:i.width*j.x},b.options.fade&&(e=="show"&&(c.from.opacity=0,c.to.opacity=1),e=="hide"&&(c.from.opacity=1,c.to.opacity=0)),d.from=c.from,d.to=c.to,d.mode=e,c.effect("size",d,b.duration,b.callback),c.dequeue()})},a.effects.size=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","width","height","overflow","opacity"],e=["position","top","bottom","left","right","overflow","opacity"],f=["width","height","overflow"],g=["fontSize"],h=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],i=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],j=a.effects.setMode(c,b.options.mode||"effect"),k=b.options.restore||!1,l=b.options.scale||"both",m=b.options.origin,n={height:c.height(),width:c.width()};c.from=b.options.from||n,c.to=b.options.to||n;if(m){var p=a.effects.getBaseline(m,n);c.from.top=(n.height-c.from.height)*p.y,c.from.left=(n.width-c.from.width)*p.x,c.to.top=(n.height-c.to.height)*p.y,c.to.left=(n.width-c.to.width)*p.x}var q={from:{y:c.from.height/n.height,x:c.from.width/n.width},to:{y:c.to.height/n.height,x:c.to.width/n.width}};if(l=="box"||l=="both")q.from.y!=q.to.y&&(d=d.concat(h),c.from=a.effects.setTransition(c,h,q.from.y,c.from),c.to=a.effects.setTransition(c,h,q.to.y,c.to)),q.from.x!=q.to.x&&(d=d.concat(i),c.from=a.effects.setTransition(c,i,q.from.x,c.from),c.to=a.effects.setTransition(c,i,q.to.x,c.to));(l=="content"||l=="both")&&q.from.y!=q.to.y&&(d=d.concat(g),c.from=a.effects.setTransition(c,g,q.from.y,c.from),c.to=a.effects.setTransition(c,g,q.to.y,c.to)),a.effects.save(c,k?d:e),c.show(),a.effects.createWrapper(c),c.css("overflow","hidden").css(c.from);if(l=="content"||l=="both")h=h.concat(["marginTop","marginBottom"]).concat(g),i=i.concat(["marginLeft","marginRight"]),f=d.concat(h).concat(i),c.find("*[width]").each(function(){var c=a(this);k&&a.effects.save(c,f);var d={height:c.height(),width:c.width()};c.from={height:d.height*q.from.y,width:d.width*q.from.x},c.to={height:d.height*q.to.y,width:d.width*q.to.x},q.from.y!=q.to.y&&(c.from=a.effects.setTransition(c,h,q.from.y,c.from),c.to=a.effects.setTransition(c,h,q.to.y,c.to)),q.from.x!=q.to.x&&(c.from=a.effects.setTransition(c,i,q.from.x,c.from),c.to=a.effects.setTransition(c,i,q.to.x,c.to)),c.css(c.from),c.animate(c.to,b.duration,b.options.easing,function(){k&&a.effects.restore(c,f)})});c.animate(c.to,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){c.to.opacity===0&&c.css("opacity",c.from.opacity),j=="hide"&&c.hide(),a.effects.restore(c,k?d:e),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}}(jQuery),function(a,b){a.effects.shake=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"left",g=b.options.distance||20,h=b.options.times||3,i=b.duration||b.options.duration||140;a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",l={},m={},n={};l[j]=(k=="pos"?"-=":"+=")+g,m[j]=(k=="pos"?"+=":"-=")+g*2,n[j]=(k=="pos"?"-=":"+=")+g*2,c.animate(l,i,b.options.easing);for(var p=1;p<h;p++)c.animate(m,i,b.options.easing).animate(n,i,b.options.easing);c.animate(m,i,b.options.easing).animate(l,i/2,b.options.easing,function(){a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments)}),c.queue("fx",function(){c.dequeue()}),c.dequeue()})}}(jQuery),function(a,b){a.effects.slide=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"show"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c).css({overflow:"hidden"});var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0):c.outerWidth(!0));e=="show"&&c.css(g,h=="pos"?isNaN(i)?"-"+i:-i:i);var j={};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}}(jQuery),function(a,b){a.effects.transfer=function(b){return this.queue(function(){var c=a(this),d=a(b.options.to),e=d.offset(),f={top:e.top,left:e.left,height:d.innerHeight(),width:d.innerWidth()},g=c.offset(),h=a('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(b.options.className).css({top:g.top,left:g.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(f,b.duration,b.options.easing,function(){h.remove(),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}}(jQuery),function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("<span></span>").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex"),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");return(b.autoHeight||b.fillHeight)&&c.css("height",""),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(this.options.disabled||b.altKey||b.ctrlKey)return;var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._clickHandler({target:b.target},b.target),b.preventDefault()}return f?(a(b.target).attr("tabIndex",-1),a(f).attr("tabIndex",0),f.focus(),!1):!0},resize:function(){var b=this.options,c;if(b.fillSpace){if(a.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height(),a.browser.msie&&this.element.parent().css("overflow",d),this.headers.each(function(){c-=a(this).outerHeight(!0)}),this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")}else b.autoHeight&&(c=0,this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c));return this},activate:function(a){this.options.active=a;var b=this._findActive(a)[0];return this._clickHandler({target:b},b),this},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===!1?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,c){var d=this.options;if(d.disabled)return;if(!b.target){if(!d.collapsible)return;this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),this.active.next().addClass("ui-accordion-content-active");var e=this.active.next(),f={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:e},g=this.active=a([]);this._toggle(g,e,f);return}var h=a(b.currentTarget||c),i=h[0]===this.active[0];d.active=d.collapsible&&i?!1:this.headers.index(h);if(this.running||!d.collapsible&&i)return;var j=this.active,g=h.next(),e=this.active.next(),f={options:d,newHeader:i&&d.collapsible?a([]):h,oldHeader:this.active,newContent:i&&d.collapsible?a([]):g,oldContent:e},k=this.headers.index(this.active[0])>this.headers.index(h[0]);this.active=i?a([]):h,this._toggle(g,e,f,i,k),j.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),i||(h.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected),h.next().addClass("ui-accordion-content-active"));return},_toggle:function(b,c,d,e,f){var g=this,h=g.options;g.toShow=b,g.toHide=c,g.data=d;var i=function(){if(!g)return;return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data),g.running=c.size()===0?b.size():c.size();if(h.animated){var j={};h.collapsible&&e?j={toShow:a([]),toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace}:j={toShow:b,toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace},h.proxied||(h.proxied=h.animated),h.proxiedDuration||(h.proxiedDuration=h.duration),h.animated=a.isFunction(h.proxied)?h.proxied(j):h.proxied,h.duration=a.isFunction(h.proxiedDuration)?h.proxiedDuration(j):h.proxiedDuration;var k=a.ui.accordion.animations,l=h.duration,m=h.animated;m&&!k[m]&&!a.easing[m]&&(m="slide"),k[m]||(k[m]=function(a){this.slide(a,{easing:m,duration:l||700})}),k[m](j)}else h.collapsible&&e?b.toggle():(c.hide(),b.show()),i(!0);c.prev().attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).blur(),b.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(this.running)return;this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""}),this.toHide.removeClass("ui-accordion-content-active"),this.toHide.length&&(this.toHide.parent()[0].className=this.toHide.parent()[0].className),this._trigger("change",null,this.data)}}),a.extend(a.ui.accordion,{version:"1.8.23",animations:{slide:function(b,c){b=a.extend({easing:"swing",duration:300},b,c);if(!b.toHide.size()){b.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},b);return}if(!b.toShow.size()){b.toHide.animate({height:"hide",paddingTop:"hide",paddingBottom:"hide"},b);return}var d=b.toShow.css("overflow"),e=0,f={},g={},h=["height","paddingTop","paddingBottom"],i,j=b.toShow;i=j[0].style.width,j.width(j.parent().width()-parseFloat(j.css("paddingLeft"))-parseFloat(j.css("paddingRight"))-(parseFloat(j.css("borderLeftWidth"))||0)-(parseFloat(j.css("borderRightWidth"))||0)),a.each(h,function(c,d){g[d]="hide";var e=(""+a.css(b.toShow[0],d)).match(/^([\d+-.]+)(.*)$/);f[d]={value:e[1],unit:e[2]||"px"}}),b.toShow.css({height:0,overflow:"hidden"}).show(),b.toHide.filter(":hidden").each(b.complete).end().filter(":visible").animate(g,{step:function(a,c){c.prop=="height"&&(e=c.end-c.start===0?0:(c.now-c.start)/(c.end-c.start)),b.toShow[0].style[c.prop]=e*f[c.prop].value+f[c.prop].unit},duration:b.duration,easing:b.easing,complete:function(){b.autoHeight||b.toShow.css("height",""),b.toShow.css({width:i,overflow:d}),b.complete()}})},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1e3:200})}}})}(jQuery),function(a,b){var c=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var b=this,c=this.element[0].ownerDocument,d;this.isMultiLine=this.element.is("textarea"),this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(b.options.disabled||b.element.propAttr("readOnly"))return;d=!1;var e=a.ui.keyCode;switch(c.keyCode){case e.PAGE_UP:b._move("previousPage",c);break;case e.PAGE_DOWN:b._move("nextPage",c);break;case e.UP:b._keyEvent("previous",c);break;case e.DOWN:b._keyEvent("next",c);break;case e.ENTER:case e.NUMPAD_ENTER:b.menu.active&&(d=!0,c.preventDefault());case e.TAB:if(!b.menu.active)return;b.menu.select(c);break;case e.ESCAPE:b.element.val(b.term),b.close(c);break;default:clearTimeout(b.searching),b.searching=setTimeout(function(){b.term!=b.element.val()&&(b.selectedItem=null,b.search(null,c))},b.options.delay)}}).bind("keypress.autocomplete",function(a){d&&(d=!1,a.preventDefault())}).bind("focus.autocomplete",function(){if(b.options.disabled)return;b.selectedItem=null,b.previous=b.element.val()}).bind("blur.autocomplete",function(a){if(b.options.disabled)return;clearTimeout(b.searching),b.closing=setTimeout(function(){b.close(a),b._change(a)},150)}),this._initSource(),this.menu=a("<ul></ul>").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",c)[0]).mousedown(function(c){var d=b.menu.element[0];a(c.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(c){c.target!==b.element[0]&&c.target!==d&&!a.ui.contains(d,c.target)&&b.close()})},1),setTimeout(function(){clearTimeout(b.closing)},13)}).menu({focus:function(a,c){var d=c.item.data("item.autocomplete");!1!==b._trigger("focus",a,{item:d})&&/^key/.test(a.originalEvent.type)&&b.element.val(d.value)},selected:function(a,d){var e=d.item.data("item.autocomplete"),f=b.previous;b.element[0]!==c.activeElement&&(b.element.focus(),b.previous=f,setTimeout(function(){b.previous=f,b.selectedItem=e},1)),!1!==b._trigger("select",a,{item:e})&&b.element.val(e.value),b.term=b.element.val(),b.close(a),b.selectedItem=e},blur:function(a,c){b.menu.element.is(":visible")&&b.element.val()!==b.term&&b.element.val(b.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"),a.fn.bgiframe&&this.menu.element.bgiframe(),b.beforeunloadHandler=function(){b.element.removeAttr("autocomplete")},a(window).bind("beforeunload",b.beforeunloadHandler)},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"),this.menu.element.remove(),a(window).unbind("beforeunload",this.beforeunloadHandler),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b==="source"&&this._initSource(),b==="appendTo"&&this.menu.element.appendTo(a(c||"body",this.element[0].ownerDocument)[0]),b==="disabled"&&c&&this.xhr&&this.xhr.abort()},_initSource:function(){var b=this,c,d;a.isArray(this.options.source)?(c=this.options.source,this.source=function(b,d){d(a.ui.autocomplete.filter(c,b.term))}):typeof this.options.source=="string"?(d=this.options.source,this.source=function(c,e){b.xhr&&b.xhr.abort(),b.xhr=a.ajax({url:d,data:c,dataType:"json",success:function(a,b){e(a)},error:function(){e([])}})}):this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val(),this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)===!1)return;return this._search(a)},_search:function(a){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.source({term:a},this._response())},_response:function(){var a=this,b=++c;return function(d){b===c&&a.__response(d),a.pending--,a.pending||a.element.removeClass("ui-autocomplete-loading")}},__response:function(a){!this.options.disabled&&a&&a.length?(a=this._normalize(a),this._suggest(a),this._trigger("open")):this.close()},close:function(a){clearTimeout(this.closing),this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.deactivate(),this._trigger("close",a))},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(b){return b.length&&b[0].label&&b[0].value?b:a.map(b,function(b){return typeof b=="string"?{label:b,value:b}:a.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(b){var c=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(c,b),this.menu.deactivate(),this.menu.refresh(),c.show(),this._resizeMenu(),c.position(a.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next(new a.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(b,c){var d=this;a.each(c,function(a,c){d._renderItem(b,c)})},_renderItem:function(b,c){return a("<li></li>").data("item.autocomplete",c).append(a("<a></a>").text(c.label)).appendTo(b)},_move:function(a,b){if(!this.menu.element.is(":visible")){this.search(null,b);return}if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term),this.menu.deactivate();return}this.menu[a](b)},widget:function(){return this.menu.element},_keyEvent:function(a,b){if(!this.isMultiLine||this.menu.element.is(":visible"))this._move(a,b),b.preventDefault()}}),a.extend(a.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(b,c){var d=new RegExp(a.ui.autocomplete.escapeRegex(c),"i");return a.grep(b,function(a){return d.test(a.label||a.value||a)})}})}(jQuery),function(a){a.widget("ui.menu",{_create:function(){var b=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){if(!a(c.target).closest(".ui-menu-item a").length)return;c.preventDefault(),b.select(c)}),this.refresh()},refresh:function(){var b=this,c=this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem");c.children("a").addClass("ui-corner-all").attr("tabindex",-1).mouseenter(function(c){b.activate(c,a(this).parent())}).mouseleave(function(){b.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.scrollTop(),e=this.element.height();c<0?this.element.scrollTop(d+c):c>=e&&this.element.scrollTop(d+c-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end(),this._trigger("focus",a,{item:b})},deactivate:function(){if(!this.active)return;this.active.children("a").removeClass("ui-state-hover").removeAttr("id"),this._trigger("blur"),this.active=null},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(!this.active){this.activate(c,this.element.children(b));return}var d=this.active[a+"All"](".ui-menu-item").eq(0);d.length?this.activate(c,d):this.activate(c,this.element.children(b))},nextPage:function(b){if(this.hasScroll()){if(!this.active||this.last()){this.activate(b,this.element.children(".ui-menu-item:first"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c-d+a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:last")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(b){if(this.hasScroll()){if(!this.active||this.first()){this.activate(b,this.element.children(".ui-menu-item:last"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c+d-a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:first")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[a.fn.prop?"prop":"attr"]("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})}(jQuery),function(a,b){var c,d,e,f,g="ui-button ui-widget ui-state-default ui-corner-all",h="ui-state-hover ui-state-active ",i="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",j=function(){var b=a(this).find(":ui-button");setTimeout(function(){b.button("refresh")},1)},k=function(b){var c=b.name,d=b.form,e=a([]);return c&&(d?e=a(d).find("[name='"+c+"']"):e=a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form})),e};a.widget("ui.button",{options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",j),typeof this.options.disabled!="boolean"?this.options.disabled=!!this.element.propAttr("disabled"):this.element.propAttr("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var b=this,h=this.options,i=this.type==="checkbox"||this.type==="radio",l="ui-state-hover"+(i?"":" ui-state-active"),m="ui-state-focus";h.label===null&&(h.label=this.buttonElement.html()),this.buttonElement.addClass(g).attr("role","button").bind("mouseenter.button",function(){if(h.disabled)return;a(this).addClass("ui-state-hover"),this===c&&a(this).addClass("ui-state-active")}).bind("mouseleave.button",function(){if(h.disabled)return;a(this).removeClass(l)}).bind("click.button",function(a){h.disabled&&(a.preventDefault(),a.stopImmediatePropagation())}),this.element.bind("focus.button",function(){b.buttonElement.addClass(m)}).bind("blur.button",function(){b.buttonElement.removeClass(m)}),i&&(this.element.bind("change.button",function(){if(f)return;b.refresh()}),this.buttonElement.bind("mousedown.button",function(a){if(h.disabled)return;f=!1,d=a.pageX,e=a.pageY}).bind("mouseup.button",function(a){if(h.disabled)return;if(d!==a.pageX||e!==a.pageY)f=!0})),this.type==="checkbox"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).toggleClass("ui-state-active"),b.buttonElement.attr("aria-pressed",b.element[0].checked)}):this.type==="radio"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).addClass("ui-state-active"),b.buttonElement.attr("aria-pressed","true");var c=b.element[0];k(c).not(c).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown.button",function(){if(h.disabled)return!1;a(this).addClass("ui-state-active"),c=this,a(document).one("mouseup",function(){c=null})}).bind("mouseup.button",function(){if(h.disabled)return!1;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(b){if(h.disabled)return!1;(b.keyCode==a.ui.keyCode.SPACE||b.keyCode==a.ui.keyCode.ENTER)&&a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(b){b.keyCode===a.ui.keyCode.SPACE&&a(this).click()})),this._setOption("disabled",h.disabled),this._resetButton()},_determineButtonType:function(){this.element.is(":checkbox")?this.type="checkbox":this.element.is(":radio")?this.type="radio":this.element.is("input")?this.type="input":this.type="button";if(this.type==="checkbox"||this.type==="radio"){var a=this.element.parents().filter(":last"),b="label[for='"+this.element.attr("id")+"']";this.buttonElement=a.find(b),this.buttonElement.length||(a=a.length?a.siblings():this.element.siblings(),this.buttonElement=a.filter(b),this.buttonElement.length||(this.buttonElement=a.find(b))),this.element.addClass("ui-helper-hidden-accessible");var c=this.element.is(":checked");c&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.attr("aria-pressed",c)}else this.buttonElement=this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(g+" "+h+" "+i).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title"),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled"){c?this.element.propAttr("disabled",!0):this.element.propAttr("disabled",!1);return}this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b),this.type==="radio"?k(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):this.type==="checkbox"&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if(this.type==="input"){this.options.label&&this.element.val(this.options.label);return}var b=this.buttonElement.removeClass(i),c=a("<span></span>",this.element[0].ownerDocument).addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary,f=[];d.primary||d.secondary?(this.options.text&&f.push("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary")),d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>"),d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>"),this.options.text||(f.push(e?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||b.attr("title",c))):f.push("ui-button-text-only"),b.addClass(f.join(" "))}}),a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c),a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(b?"ui-corner-left":"ui-corner-right").end().end()},destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"),a.Widget.prototype.destroy.call(this)}})}(jQuery),function($,undefined){function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);if(!c.length)return;c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);if($.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])||!d.length)return;d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover")})}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}$.extend($.ui,{datepicker:{version:"1.8.23"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){return extendRemove(this._defaults,a||{}),this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);if(c.hasClass(this.markerClassName))return;this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a)},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$('<span class="'+this._appendClass+'">'+c+"</span>"),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('<button type="button"></button>').addClass(this._triggerClass).html(g==""?f:$("<img/>").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){return $.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]),!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;d<a.length;d++)a[d].length>b&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);if(c.hasClass(this.markerClassName))return;c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block")},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$('<input type="text" id="'+g+'" style="position: absolute; top: -100px; width: 0px;"/>'),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}return this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f),this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return!0;return!1},_getInst:function(a){try{return $.data(a,PROP_NAME)}catch(b){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(a,b,c){var d=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?$.extend({},$.datepicker._defaults):d?b=="all"?$.extend({},d.settings):this._get(d,b):null;var e=b||{};typeof b=="string"&&(e={},e[b]=c);if(d){this._curInst==d&&this._hideDatepicker();var f=this._getDateDatepicker(a,!0),g=this._getMinMaxDate(d,"min"),h=this._getMinMaxDate(d,"max");extendRemove(d.settings,e),g!==null&&e.dateFormat!==undefined&&e.minDate===undefined&&(d.settings.minDate=this._formatDate(d,g)),h!==null&&e.dateFormat!==undefined&&e.maxDate===undefined&&(d.settings.maxDate=this._formatDate(d,h)),this._attachments($(a),d),this._autoSize(d),this._setDate(d,f),this._updateAlternate(d),this._updateDatepicker(d)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){var b=this._getInst(a);b&&this._updateDatepicker(b)},_setDateDatepicker:function(a,b){var c=this._getInst(a);c&&(this._setDate(c,b),this._updateDatepicker(c),this._updateAlternate(c))},_getDateDatepicker:function(a,b){var c=this._getInst(a);return c&&!c.inline&&this._setDateFromField(c,b),c?this._getDate(c):null},_doKeyDown:function(a){var b=$.datepicker._getInst(a.target),c=!0,d=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=!0;if($.datepicker._datepickerShowing)switch(a.keyCode){case 9:$.datepicker._hideDatepicker(),c=!1;break;case 13:var e=$("td."+$.datepicker._dayOverClass+":not(."+$.datepicker._currentClass+")",b.dpDiv);e[0]&&$.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,e[0]);var f=$.datepicker._get(b,"onSelect");if(f){var g=$.datepicker._formatDate(b);f.apply(b.input?b.input[0]:null,[g,b])}else $.datepicker._hideDatepicker();return!1;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 34:$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 35:(a.ctrlKey||a.metaKey)&&$.datepicker._clearDate(a.target),c=a.ctrlKey||a.metaKey;break;case 36:(a.ctrlKey||a.metaKey)&&$.datepicker._gotoToday(a.target),c=a.ctrlKey||a.metaKey;break;case 37:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?1:-1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 38:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,-7,"D"),c=a.ctrlKey||a.metaKey;break;case 39:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?-1:1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 40:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,7,"D"),c=a.ctrlKey||a.metaKey;break;default:c=!1}else a.keyCode==36&&a.ctrlKey?$.datepicker._showDatepicker(this):c=!1;c&&(a.preventDefault(),a.stopPropagation())},_doKeyPress:function(a){var b=$.datepicker._getInst(a.target);if($.datepicker._get(b,"constrainInput")){var c=$.datepicker._possibleChars($.datepicker._get(b,"dateFormat")),d=String.fromCharCode(a.charCode==undefined?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||d<" "||!c||c.indexOf(d)>-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(d){$.datepicker.log(d)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if($.datepicker._isDisabledDatepicker(a)||$.datepicker._lastInput==a)return;var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){return e|=$(this).css("position")=="fixed",!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a)),this._attachHandlers(a);var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+(c?0:$(document).scrollLeft()),i=document.documentElement.clientHeight+(c?0:$(document).scrollTop());return b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0),b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!b||a&&b!=$.data(a,PROP_NAME))return;if(this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=function(){$.datepicker._tidyDialog(b)};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,e):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,e),c||e(),this._datepickerShowing=!1;var f=this._get(b,"onClose");f&&f.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!$.datepicker._curInst)return;var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);if(this._isDisabledDatepicker(d[0]))return;this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e)},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if($(d).hasClass(this._unselectableClass)||this._isDisabledDatepicker(e[0]))return;var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();return b.setMonth(0),b.setDate(1),Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1<a.length&&a.charAt(s+1)==b;return c&&s++,c},o=function(a){var c=n(a),d=a=="@"?14:a=="!"?20:a=="y"&&c?4:a=="o"?3:2,e=new RegExp("^\\d{1,"+d+"}"),f=b.substring(r).match(e);if(!f)throw"Missing number at position "+r;return r+=f[0].length,parseInt(f[0],10)},p=function(a,c,d){var e=$.map(n(a)?d:c,function(a,b){return[[b,a]]}).sort(function(a,b){return-(a[1].length-b[1].length)}),f=-1;$.each(e,function(a,c){var d=c[1];if(b.substr(r,d.length).toLowerCase()==d.toLowerCase())return f=c[0],r+=d.length,!1});if(f!=-1)return f+1;throw"Unknown name at position "+r},q=function(){if(b.charAt(r)!=a.charAt(s))throw"Unexpected literal at position "+r;r++},r=0;for(var s=0;s<a.length;s++)if(m)a.charAt(s)=="'"&&!n("'")?m=!1:q();else switch(a.charAt(s)){case"d":k=o("d");break;case"D":p("D",e,f);break;case"o":l=o("o");break;case"m":j=o("m");break;case"M":j=p("M",g,h);break;case"y":i=o("y");break;case"@":var t=new Date(o("@"));i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"!":var t=new Date((o("!")-this._ticksTo1970)/1e4);i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"'":n("'")?q():m=!0;break;default:q()}if(r<b.length)throw"Extra/unparsed characters found in date: "+b.substring(r);i==-1?i=(new Date).getFullYear():i<100&&(i+=(new Date).getFullYear()-(new Date).getFullYear()%100+(i<=d?0:-100));if(l>-1){j=1,k=l;do{var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}while(!0)}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+1<a.length&&a.charAt(m+1)==b;return c&&m++,c},i=function(a,b,c){var d=""+b;if(h(a))while(d.length<c)d="0"+d;return d},j=function(a,b,c,d){return h(a)?d[b]:c[b]},k="",l=!1;if(b)for(var m=0;m<a.length;m++)if(l)a.charAt(m)=="'"&&!h("'")?l=!1:k+=a.charAt(m);else switch(a.charAt(m)){case"d":k+=i("d",b.getDate(),2);break;case"D":k+=j("D",b.getDay(),d,e);break;case"o":k+=i("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864e5),3);break;case"m":k+=i("m",b.getMonth()+1,2);break;case"M":k+=j("M",b.getMonth(),f,g);break;case"y":k+=h("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case"@":k+=b.getTime();break;case"!":k+=b.getTime()*1e4+this._ticksTo1970;break;case"'":h("'")?k+="'":l=!0;break;default:k+=a.charAt(m)}return k},_possibleChars:function(a){var b="",c=!1,d=function(b){var c=e+1<a.length&&a.charAt(e+1)==b;return c&&e++,c};for(var e=0;e<a.length;e++)if(c)a.charAt(e)=="'"&&!d("'")?c=!1:b+=a.charAt(e);else switch(a.charAt(e)){case"d":case"m":case"y":case"@":b+="0123456789";break;case"D":case"M":return null;case"'":d("'")?b+="'":c=!0;break;default:b+=a.charAt(e)}return b},_get:function(a,b){return a.settings[b]!==undefined?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()==a.lastVal)return;var c=this._get(a,"dateFormat"),d=a.lastVal=a.input?a.input.val():null,e,f;e=f=this._getDefaultDate(a);var g=this._getFormatConfig(a);try{e=this.parseDate(c,d,g)||f}catch(h){this.log(h),d=b?"":d}a.selectedDay=e.getDate(),a.drawMonth=a.selectedMonth=e.getMonth(),a.drawYear=a.selectedYear=e.getFullYear(),a.currentDay=d?e.getDate():0,a.currentMonth=d?e.getMonth():0,a.currentYear=d?e.getFullYear():0,this._adjustInstDate(a)},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var d=function(a){var b=new Date;return b.setDate(b.getDate()+a),b},e=function(b){try{return $.datepicker.parseDate($.datepicker._get(a,"dateFormat"),b,$.datepicker._getFormatConfig(a))}catch(c){}var d=(b.toLowerCase().match(/^c/)?$.datepicker._getDate(a):null)||new Date,e=d.getFullYear(),f=d.getMonth(),g=d.getDate(),h=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,i=h.exec(b);while(i){switch(i[2]||"d"){case"d":case"D":g+=parseInt(i[1],10);break;case"w":case"W":g+=parseInt(i[1],10)*7;break;case"m":case"M":f+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f));break;case"y":case"Y":e+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f))}i=h.exec(b)}return new Date(e,f,g)},f=b==null||b===""?c:typeof b=="string"?e(b):typeof b=="number"?isNaN(b)?c:d(b):new Date(b.getTime());return f=f&&f.toString()=="Invalid Date"?c:f,f&&(f.setHours(0),f.setMinutes(0),f.setSeconds(0),f.setMilliseconds(0)),this._daylightSavingAdjust(f)},_daylightSavingAdjust:function(a){return a?(a.setHours(a.getHours()>12?a.getHours()+2:0),a):null},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_attachHandlers:function(a){var b=this._get(a,"stepMonths"),c="#"+a.id.replace(/\\\\/g,"\\");a.dpDiv.find("[data-handler]").map(function(){var a={prev:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,-b,"M")},next:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,+b,"M")},hide:function(){window["DP_jQuery_"+dpuuid].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+dpuuid].datepicker._gotoToday(c)},selectDay:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectDay(c,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"Y"),!1}};$(this).bind(this.getAttribute("data-event"),a[this.getAttribute("data-handler")])})},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&p<l?l:p;while(this._daylightSavingAdjust(new Date(o,n,1))>p)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?'<a class="ui-datepicker-prev ui-corner-all" data-handler="prev" data-event="click" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>":e?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?'<a class="ui-datepicker-next ui-corner-all" data-handler="next" data-event="click" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":e?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" data-handler="hide" data-event="click">'+this._get(a,"closeText")+"</button>",x=d?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?w:"")+(this._isInRange(a,v)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" data-handler="today" data-event="click">'+u+"</button>":"")+(c?"":w)+"</div>":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L<g[0];L++){var M="";this.maxRows=4;for(var N=0;N<g[1];N++){var O=this._daylightSavingAdjust(new Date(o,n,a.selectedDay)),P=" ui-corner-all",Q="";if(j){Q+='<div class="ui-datepicker-group';if(g[1]>1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+P+'">'+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'</div><table class="ui-datepicker-calendar"><thead>'+"<tr>";var R=z?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="<th"+((S+y+6)%7>=5?' class="ui-datepicker-week-end"':"")+">"+'<span title="'+A[T]+'">'+C[T]+"</span></th>"}Q+=R+"</tr></thead><tbody>";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z<X;Z++){Q+="<tr>";var _=z?'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(Y)+"</td>":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Y<l||m&&Y>m;_+='<td class="'+((S+y+6)%7>=5?" ui-datepicker-week-end":"")+(bb?" ui-datepicker-other-month":"")+(Y.getTime()==O.getTime()&&n==a.selectedMonth&&a._keyEvent||J.getTime()==Y.getTime()&&J.getTime()==O.getTime()?" "+this._dayOverClass:"")+(bc?" "+this._unselectableClass+" ui-state-disabled":"")+(bb&&!G?"":" "+ba[1]+(Y.getTime()==k.getTime()?" "+this._currentClass:"")+(Y.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!bb||G)&&ba[2]?' title="'+ba[2]+'"':"")+(bc?"":' data-handler="selectDay" data-event="click" data-month="'+Y.getMonth()+'" data-year="'+Y.getFullYear()+'"')+">"+(bb&&!G?"&#xa0;":bc?'<span class="ui-state-default">'+Y.getDate()+"</span>":'<a class="ui-state-default'+(Y.getTime()==b.getTime()?" ui-state-highlight":"")+(Y.getTime()==k.getTime()?" ui-state-active":"")+(bb?" ui-priority-secondary":"")+'" href="#">'+Y.getDate()+"</a>")+"</td>",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+"</tr>"}n++,n>11&&(n=0,o++),Q+="</tbody></table>"+(j?"</div>"+(g[0]>0&&N==g[1]-1?'<div class="ui-datepicker-row-break"></div>':""):""),M+=Q}K+=M}return K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':""),a._keyEvent=!1,K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='<div class="ui-datepicker-title">',m="";if(f||!i)m+='<span class="ui-datepicker-month">'+g[b]+"</span>";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='<select class="ui-datepicker-month" data-handler="selectMonth" data-event="change">';for(var p=0;p<12;p++)(!n||p>=d.getMonth())&&(!o||p<=e.getMonth())&&(m+='<option value="'+p+'"'+(p==b?' selected="selected"':"")+">"+h[p]+"</option>");m+="</select>"}k||(l+=m+(f||!i||!j?"&#xa0;":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+='<span class="ui-datepicker-year">'+c+"</span>";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='<select class="ui-datepicker-year" data-handler="selectYear" data-event="change">';for(;t<=u;t++)a.yearshtml+='<option value="'+t+'"'+(t==c?' selected="selected"':"")+">"+t+"</option>";a.yearshtml+="</select>",l+=a.yearshtml,a.yearshtml=null}}return l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?"&#xa0;":"")+m),l+="</div>",l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&b<c?c:b;return e=d&&e>d?d:e,e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));return b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth())),this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");return b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10),{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);return typeof a!="string"||a!="isDisabled"&&a!="getDate"&&a!="widget"?a=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b)):this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)}):$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.23",window["DP_jQuery_"+dpuuid]=$}(jQuery),function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||"&#160;",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("<div></div>")).appendTo(document.body).hide().addClass(c+d.dialogClass).css({zIndex:d.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){j.addClass("ui-state-hover")},function(){j.removeClass("ui-state-hover")}).focus(function(){j.addClass("ui-state-focus")}).blur(function(){j.removeClass("ui-state-focus")}).click(function(a){return b.close(a),!1}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("<span></span>")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("<span></span>").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);a.isFunction(d.beforeclose)&&!a.isFunction(d.beforeClose)&&(d.beforeClose=d.beforeclose),i.find("*").add(i).disableSelection(),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;return a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle),a},widget:function(){return this.uiDialog},close:function(b){var c=this,d,e;if(!1===c._trigger("beforeClose",b))return;return c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c._isOpen=!1,c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d),c},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;return e.modal&&!b||!e.stack&&!e.modal?d._trigger("focus",c):(e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c),d)},open:function(){if(this._isOpen)return;var b=this,c=b.options,d=b.uiDialog;return b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b._size(),b._position(c.position),d.show(c.show),b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode!==a.ui.keyCode.TAB)return;var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey)return d.focus(1),!1;if(b.target===d[0]&&b.shiftKey)return e.focus(1),!1}),a(b.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(),b._isOpen=!0,b._trigger("open"),b},_createButtons:function(b){var c=this,d=!1,e=a("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),f=a("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)}),d&&(a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a('<button type="button"></button>').click(function(){d.click.apply(c.element[0],arguments)}).appendTo(f);a.each(d,function(a,b){if(a==="click")return;a in e?e[a](b):e.attr(a,b)}),a.fn.button&&e.button()}),e.appendTo(c.uiDialog))},_makeDraggable:function(){function f(a){return{position:a.position,offset:a.offset}}var b=this,c=b.options,d=a(document),e;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(d,g){e=c.height==="auto"?"auto":a(this).height(),a(this).height(a(this).height()).addClass("ui-dialog-dragging"),b._trigger("dragStart",d,f(g))},drag:function(a,c){b._trigger("drag",a,f(c))},stop:function(g,h){c.position=[h.position.left-d.scrollLeft(),h.position.top-d.scrollTop()],a(this).removeClass("ui-dialog-dragging").height(e),b._trigger("dragStop",g,f(h)),a.ui.dialog.overlay.resize()}})},_makeResizable:function(c){function h(a){return{originalPosition:a.originalPosition,originalSize:a.originalSize,position:a.position,size:a.size}}c=c===b?this.options.resizable:c;var d=this,e=d.options,f=d.uiDialog.css("position"),g=typeof c=="string"?c:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:g,start:function(b,c){a(this).addClass("ui-dialog-resizing"),d._trigger("resizeStart",b,h(c))},resize:function(a,b){d._trigger("resize",a,h(b))},stop:function(b,c){a(this).removeClass("ui-dialog-resizing"),e.height=a(this).height(),e.width=a(this).width(),d._trigger("resizeStop",b,h(c)),a.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(b){var c=[],d=[0,0],e;if(b){if(typeof b=="string"||typeof b=="object"&&"0"in b)c=b.split?b.split(" "):[b[0],b[1]],c.length===1&&(c[1]=c[0]),a.each(["left","top"],function(a,b){+c[a]===c[a]&&(d[a]=c[a],c[a]=b)}),b={my:c.join(" "),at:c.join(" "),offset:d.join(" ")};b=a.extend({},a.ui.dialog.prototype.options.position,b)}else b=a.ui.dialog.prototype.options.position;e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},b)),e||this.uiDialog.hide()},_setOptions:function(b){var c=this,f={},g=!1;a.each(b,function(a,b){c._setOption(a,b),a in d&&(g=!0),a in e&&(f[a]=b)}),g&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",f)},_setOption:function(b,d){var e=this,f=e.uiDialog;switch(b){case"beforeclose":b="beforeClose";break;case"buttons":e._createButtons(d);break;case"closeText":e.uiDialogTitlebarCloseText.text(""+d);break;case"dialogClass":f.removeClass(e.options.dialogClass).addClass(c+d);break;case"disabled":d?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case"draggable":var g=f.is(":data(draggable)");g&&!d&&f.draggable("destroy"),!g&&d&&e._makeDraggable();break;case"position":e._position(d);break;case"resizable":var h=f.is(":data(resizable)");h&&!d&&f.resizable("destroy"),h&&typeof d=="string"&&f.resizable("option","handles",d),!h&&d!==!1&&e._makeResizable(d);break;case"title":a(".ui-dialog-title",e.uiDialogTitlebar).html(""+(d||"&#160;"))}a.Widget.prototype._setOption.apply(e,arguments)},_size:function(){var b=this.options,c,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),b.minWidth>b.width&&(b.width=b.minWidth),c=this.uiDialog.css({height:"auto",width:b.width}).height(),d=Math.max(0,b.minHeight-c);if(b.height==="auto")if(a.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();var f=this.element.css("height","auto").height();e||this.uiDialog.hide(),this.element.height(Math.max(f,d))}else this.element.height(Math.max(b.height-c,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),a.extend(a.ui.dialog,{version:"1.8.23",uuid:0,maxZ:0,getTitleId:function(a){var b=a.attr("id");return b||(this.uuid+=1,b=this.uuid),"ui-dialog-title-"+b},overlay:function(b){this.$el=a.ui.dialog.overlay.create(b)}}),a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(b){this.instances.length===0&&(setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()<a.ui.dialog.overlay.maxZ)return!1})},1),a(document).bind("keydown.dialog-overlay",function(c){b.options.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}),a(window).bind("resize.dialog-overlay",a.ui.dialog.overlay.resize));var c=(this.oldInstances.pop()||a("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});return a.fn.bgiframe&&c.bgiframe(),this.instances.push(c),c},destroy:function(b){var c=a.inArray(b,this.instances);c!=-1&&this.oldInstances.push(this.instances.splice(c,1)[0]),this.instances.length===0&&a([document,window]).unbind(".dialog-overlay"),b.remove();var d=0;a.each(this.instances,function(){d=Math.max(d,this.css("z-index"))}),this.maxZ=d},height:function(){var b,c;return a.browser.msie&&a.browser.version<7?(b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),b<c?a(window).height()+"px":b+"px"):a(document).height()+"px"},width:function(){var b,c;return a.browser.msie?(b=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth),c=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth),b<c?a(window).width()+"px":b+"px"):a(document).width()+"px"},resize:function(){var b=a([]);a.each(a.ui.dialog.overlay.instances,function(){b=b.add(this)}),b.css({width:0,height:0}).css({width:a.ui.dialog.overlay.width(),height:a.ui.dialog.overlay.height()})}}),a.extend(a.ui.dialog.overlay.prototype,{destroy:function(){a.ui.dialog.overlay.destroy(this.$el)}})}(jQuery),function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;return i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),n.left+=k[0],n.top+=k[1],this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),a.curCSS||(a.curCSS=a.css),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()}(jQuery),function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){return a===b?this._value():(this._setOption("value",a),this)},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;return typeof a!="number"&&(a=0),Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.23"})}(jQuery),function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;i<g;i+=1)h.push(f);this.handles=e.add(a(h.join("")).appendTo(b.element)),this.handle=this.handles.eq(0),this.handles.add(this.range).filter("a").click(function(a){a.preventDefault()}).hover(function(){d.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){d.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")}),this.handles.each(function(b){a(this).data("index.ui-slider-handle",b)}),this.handles.keydown(function(d){var e=a(this).data("index.ui-slider-handle"),f,g,h,i;if(b.options.disabled)return;switch(d.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:d.preventDefault();if(!b._keySliding){b._keySliding=!0,a(this).addClass("ui-state-active"),f=b._start(d,e);if(f===!1)return}}i=b.options.step,b.options.values&&b.options.values.length?g=h=b.values(e):g=h=b.value();switch(d.keyCode){case a.ui.keyCode.HOME:h=b._valueMin();break;case a.ui.keyCode.END:h=b._valueMax();break;case a.ui.keyCode.PAGE_UP:h=b._trimAlignValue(g+(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.PAGE_DOWN:h=b._trimAlignValue(g-(b._valueMax()-b._valueMin())/c);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g===b._valueMax())return;h=b._trimAlignValue(g+i);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g===b._valueMin())return;h=b._trimAlignValue(g-i)}b._slide(d,e,h)}).keyup(function(c){var d=a(this).data("index.ui-slider-handle");b._keySliding&&(b._keySliding=!1,b._stop(c,d),b._change(c,d),a(this).removeClass("ui-state-active"))}),this._refreshValue(),this._animateOff=!1},destroy:function(){return this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options,d,e,f,g,h,i,j,k,l;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),d={x:b.pageX,y:b.pageY},e=this._normValueFromMouse(d),f=this._valueMax()-this._valueMin()+1,h=this,this.handles.each(function(b){var c=Math.abs(e-h.values(b));f>c&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c<d)&&(c=d),c!==this.values(b)&&(e=this.values(),e[b]=c,f=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e}),d=this.values(b?0:1),f!==!1&&this.values(b,c,!0))):c!==this.value()&&(f=this._trigger("slide",a,{handle:this.handles[b],value:c}),f!==!1&&this.value(c))},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=this._trimAlignValue(a),this._refreshValue(),this._change(null,0);return}return this._value()},values:function(b,c){var d,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f<d.length;f+=1)d[f]=this._trimAlignValue(e[f]),this._change(null,f);this._refreshValue()},_setOption:function(b,c){var d,e=0;a.isArray(this.options.values)&&(e=this.options.values.length),a.Widget.prototype._setOption.apply(this,arguments);switch(b){case"disabled":c?(this.handles.filter(".ui-state-focus").blur(),this.handles.removeClass("ui-state-hover"),this.handles.propAttr("disabled",!0),this.element.addClass("ui-disabled")):(this.handles.propAttr("disabled",!1),this.element.removeClass("ui-disabled"));break;case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":this._animateOff=!0,this._refreshValue();for(d=0;d<e;d+=1)this._change(null,d);this._animateOff=!1}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a),a},_values:function(a){var b,c,d;if(arguments.length)return b=this.options.values[a],b=this._trimAlignValue(b),b;c=this.options.values.slice();for(d=0;d<c.length;d+=1)c[d]=this._trimAlignValue(c[d]);return c},_trimAlignValue:function(a){if(a<=this._valueMin())return this._valueMin();if(a>=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.23"})}(jQuery),function(a,b){function e(){return++c}function f(){return++d}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading&#8230;</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash)return e.selected=a,!1}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1)return this.blur(),!1;e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected"))return e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur(),!1;if(!f.length)return e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur(),!1}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){return typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},destroy:function(){var b=this.options;return this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie),this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);return j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e])),this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();return d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1<this.anchors.length?1:-1)),c.disabled=a.map(a.grep(c.disabled,function(a,c){return a!=b}),function(a,c){return a>=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0])),this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)==-1)return;return this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b])),this},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;return a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a]))),this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;return this.anchors.eq(a).trigger(this.options.event+".tabs"),this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}return this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs"),this},abort:function(){return this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup(),this},url:function(a,b){return this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b),this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.23"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a<c.anchors.length?a:0)},a),b&&b.stopPropagation()}),f=c._unrotate||(c._unrotate=b?function(a){e()}:function(a){a.clientX&&c.rotate(null)});return a?(this.element.bind("tabsshow",e),this.anchors.bind(d.event+".tabs",f),e()):(clearTimeout(c.rotation),this.element.unbind("tabsshow",e),this.anchors.unbind(d.event+".tabs",f),delete this._rotate,delete this._unrotate),this}})}(jQuery);
diff --git a/record-and-playback/presentation_export/playback/presentation_export/lib/jquery.min.js b/record-and-playback/presentation_export/playback/presentation_export/lib/jquery.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..673769cbb77c0a6f7d45b9624841365edf8f4b6e
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/lib/jquery.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v1.8.2 jquery.com | jquery.org/license */
+(function(a,b){function G(a){var b=F[a]={};return p.each(a.split(s),function(a,c){b[c]=!0}),b}function J(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(I,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:+d+""===d?+d:H.test(d)?p.parseJSON(d):d}catch(f){}p.data(a,c,d)}else d=b}return d}function K(a){var b;for(b in a){if(b==="data"&&p.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function ba(){return!1}function bb(){return!0}function bh(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function bi(a,b){do a=a[b];while(a&&a.nodeType!==1);return a}function bj(a,b,c){b=b||0;if(p.isFunction(b))return p.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return p.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=p.grep(a,function(a){return a.nodeType===1});if(be.test(b))return p.filter(b,d,!c);b=p.filter(b,d)}return p.grep(a,function(a,d){return p.inArray(a,b)>=0===c})}function bk(a){var b=bl.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function bC(a,b){return a.getElementsByTagName(b)[0]||a.appendChild(a.ownerDocument.createElement(b))}function bD(a,b){if(b.nodeType!==1||!p.hasData(a))return;var c,d,e,f=p._data(a),g=p._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;d<e;d++)p.event.add(b,c,h[c][d])}g.data&&(g.data=p.extend({},g.data))}function bE(a,b){var c;if(b.nodeType!==1)return;b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?(b.parentNode&&(b.outerHTML=a.outerHTML),p.support.html5Clone&&a.innerHTML&&!p.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):c==="input"&&bv.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text),b.removeAttribute(p.expando)}function bF(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bG(a){bv.test(a.type)&&(a.defaultChecked=a.checked)}function bY(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=bW.length;while(e--){b=bW[e]+c;if(b in a)return b}return d}function bZ(a,b){return a=b||a,p.css(a,"display")==="none"||!p.contains(a.ownerDocument,a)}function b$(a,b){var c,d,e=[],f=0,g=a.length;for(;f<g;f++){c=a[f];if(!c.style)continue;e[f]=p._data(c,"olddisplay"),b?(!e[f]&&c.style.display==="none"&&(c.style.display=""),c.style.display===""&&bZ(c)&&(e[f]=p._data(c,"olddisplay",cc(c.nodeName)))):(d=bH(c,"display"),!e[f]&&d!=="none"&&p._data(c,"olddisplay",d))}for(f=0;f<g;f++){c=a[f];if(!c.style)continue;if(!b||c.style.display==="none"||c.style.display==="")c.style.display=b?e[f]||"":"none"}return a}function b_(a,b,c){var d=bP.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function ca(a,b,c,d){var e=c===(d?"border":"content")?4:b==="width"?1:0,f=0;for(;e<4;e+=2)c==="margin"&&(f+=p.css(a,c+bV[e],!0)),d?(c==="content"&&(f-=parseFloat(bH(a,"padding"+bV[e]))||0),c!=="margin"&&(f-=parseFloat(bH(a,"border"+bV[e]+"Width"))||0)):(f+=parseFloat(bH(a,"padding"+bV[e]))||0,c!=="padding"&&(f+=parseFloat(bH(a,"border"+bV[e]+"Width"))||0));return f}function cb(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=!0,f=p.support.boxSizing&&p.css(a,"boxSizing")==="border-box";if(d<=0||d==null){d=bH(a,b);if(d<0||d==null)d=a.style[b];if(bQ.test(d))return d;e=f&&(p.support.boxSizingReliable||d===a.style[b]),d=parseFloat(d)||0}return d+ca(a,b,c||(f?"border":"content"),e)+"px"}function cc(a){if(bS[a])return bS[a];var b=p("<"+a+">").appendTo(e.body),c=b.css("display");b.remove();if(c==="none"||c===""){bI=e.body.appendChild(bI||p.extend(e.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!bJ||!bI.createElement)bJ=(bI.contentWindow||bI.contentDocument).document,bJ.write("<!doctype html><html><body>"),bJ.close();b=bJ.body.appendChild(bJ.createElement(a)),c=bH(b,"display"),e.body.removeChild(bI)}return bS[a]=c,c}function ci(a,b,c,d){var e;if(p.isArray(b))p.each(b,function(b,e){c||ce.test(a)?d(a,e):ci(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&p.type(b)==="object")for(e in b)ci(a+"["+e+"]",b[e],c,d);else d(a,b)}function cz(a){return function(b,c){typeof b!="string"&&(c=b,b="*");var d,e,f,g=b.toLowerCase().split(s),h=0,i=g.length;if(p.isFunction(c))for(;h<i;h++)d=g[h],f=/^\+/.test(d),f&&(d=d.substr(1)||"*"),e=a[d]=a[d]||[],e[f?"unshift":"push"](c)}}function cA(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h,i=a[f],j=0,k=i?i.length:0,l=a===cv;for(;j<k&&(l||!h);j++)h=i[j](c,d,e),typeof h=="string"&&(!l||g[h]?h=b:(c.dataTypes.unshift(h),h=cA(a,c,d,e,h,g)));return(l||!h)&&!g["*"]&&(h=cA(a,c,d,e,"*",g)),h}function cB(a,c){var d,e,f=p.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((f[d]?a:e||(e={}))[d]=c[d]);e&&p.extend(!0,a,e)}function cC(a,c,d){var e,f,g,h,i=a.contents,j=a.dataTypes,k=a.responseFields;for(f in k)f in d&&(c[k[f]]=d[f]);while(j[0]==="*")j.shift(),e===b&&(e=a.mimeType||c.getResponseHeader("content-type"));if(e)for(f in i)if(i[f]&&i[f].test(e)){j.unshift(f);break}if(j[0]in d)g=j[0];else{for(f in d){if(!j[0]||a.converters[f+" "+j[0]]){g=f;break}h||(h=f)}g=g||h}if(g)return g!==j[0]&&j.unshift(g),d[g]}function cD(a,b){var c,d,e,f,g=a.dataTypes.slice(),h=g[0],i={},j=0;a.dataFilter&&(b=a.dataFilter(b,a.dataType));if(g[1])for(c in a.converters)i[c.toLowerCase()]=a.converters[c];for(;e=g[++j];)if(e!=="*"){if(h!=="*"&&h!==e){c=i[h+" "+e]||i["* "+e];if(!c)for(d in i){f=d.split(" ");if(f[1]===e){c=i[h+" "+f[0]]||i["* "+f[0]];if(c){c===!0?c=i[d]:i[d]!==!0&&(e=f[0],g.splice(j--,0,e));break}}}if(c!==!0)if(c&&a["throws"])b=c(b);else try{b=c(b)}catch(k){return{state:"parsererror",error:c?k:"No conversion from "+h+" to "+e}}}h=e}return{state:"success",data:b}}function cL(){try{return new a.XMLHttpRequest}catch(b){}}function cM(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function cU(){return setTimeout(function(){cN=b},0),cN=p.now()}function cV(a,b){p.each(b,function(b,c){var d=(cT[b]||[]).concat(cT["*"]),e=0,f=d.length;for(;e<f;e++)if(d[e].call(a,b,c))return})}function cW(a,b,c){var d,e=0,f=0,g=cS.length,h=p.Deferred().always(function(){delete i.elem}),i=function(){var b=cN||cU(),c=Math.max(0,j.startTime+j.duration-b),d=1-(c/j.duration||0),e=0,f=j.tweens.length;for(;e<f;e++)j.tweens[e].run(d);return h.notifyWith(a,[j,d,c]),d<1&&f?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:p.extend({},b),opts:p.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:cN||cU(),duration:c.duration,tweens:[],createTween:function(b,c,d){var e=p.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(e),e},stop:function(b){var c=0,d=b?j.tweens.length:0;for(;c<d;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;cX(k,j.opts.specialEasing);for(;e<g;e++){d=cS[e].call(j,a,k,j.opts);if(d)return d}return cV(j,k),p.isFunction(j.opts.start)&&j.opts.start.call(a,j),p.fx.timer(p.extend(i,{anim:j,queue:j.opts.queue,elem:a})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}function cX(a,b){var c,d,e,f,g;for(c in a){d=p.camelCase(c),e=b[d],f=a[c],p.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=p.cssHooks[d];if(g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}}function cY(a,b,c){var d,e,f,g,h,i,j,k,l=this,m=a.style,n={},o=[],q=a.nodeType&&bZ(a);c.queue||(j=p._queueHooks(a,"fx"),j.unqueued==null&&(j.unqueued=0,k=j.empty.fire,j.empty.fire=function(){j.unqueued||k()}),j.unqueued++,l.always(function(){l.always(function(){j.unqueued--,p.queue(a,"fx").length||j.empty.fire()})})),a.nodeType===1&&("height"in b||"width"in b)&&(c.overflow=[m.overflow,m.overflowX,m.overflowY],p.css(a,"display")==="inline"&&p.css(a,"float")==="none"&&(!p.support.inlineBlockNeedsLayout||cc(a.nodeName)==="inline"?m.display="inline-block":m.zoom=1)),c.overflow&&(m.overflow="hidden",p.support.shrinkWrapBlocks||l.done(function(){m.overflow=c.overflow[0],m.overflowX=c.overflow[1],m.overflowY=c.overflow[2]}));for(d in b){f=b[d];if(cP.exec(f)){delete b[d];if(f===(q?"hide":"show"))continue;o.push(d)}}g=o.length;if(g){h=p._data(a,"fxshow")||p._data(a,"fxshow",{}),q?p(a).show():l.done(function(){p(a).hide()}),l.done(function(){var b;p.removeData(a,"fxshow",!0);for(b in n)p.style(a,b,n[b])});for(d=0;d<g;d++)e=o[d],i=l.createTween(e,q?h[e]:0),n[e]=h[e]||p.style(a,e),e in h||(h[e]=i.start,q&&(i.end=i.start,i.start=e==="width"||e==="height"?1:0))}}function cZ(a,b,c,d,e){return new cZ.prototype.init(a,b,c,d,e)}function c$(a,b){var c,d={height:a},e=0;b=b?1:0;for(;e<4;e+=2-b)c=bV[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function da(a){return p.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}var c,d,e=a.document,f=a.location,g=a.navigator,h=a.jQuery,i=a.$,j=Array.prototype.push,k=Array.prototype.slice,l=Array.prototype.indexOf,m=Object.prototype.toString,n=Object.prototype.hasOwnProperty,o=String.prototype.trim,p=function(a,b){return new p.fn.init(a,b,c)},q=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,r=/\S/,s=/\s+/,t=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,u=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,y=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,z=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,A=/^-ms-/,B=/-([\da-z])/gi,C=function(a,b){return(b+"").toUpperCase()},D=function(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",D,!1),p.ready()):e.readyState==="complete"&&(e.detachEvent("onreadystatechange",D),p.ready())},E={};p.fn=p.prototype={constructor:p,init:function(a,c,d){var f,g,h,i;if(!a)return this;if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if(typeof a=="string"){a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3?f=[null,a,null]:f=u.exec(a);if(f&&(f[1]||!c)){if(f[1])return c=c instanceof p?c[0]:c,i=c&&c.nodeType?c.ownerDocument||c:e,a=p.parseHTML(f[1],i,!0),v.test(f[1])&&p.isPlainObject(c)&&this.attr.call(a,c,!0),p.merge(this,a);g=e.getElementById(f[2]);if(g&&g.parentNode){if(g.id!==f[2])return d.find(a);this.length=1,this[0]=g}return this.context=e,this.selector=a,this}return!c||c.jquery?(c||d).find(a):this.constructor(c).find(a)}return p.isFunction(a)?d.ready(a):(a.selector!==b&&(this.selector=a.selector,this.context=a.context),p.makeArray(a,this))},selector:"",jquery:"1.8.2",length:0,size:function(){return this.length},toArray:function(){return k.call(this)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=p.merge(this.constructor(),a);return d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d},each:function(a,b){return p.each(this,a,b)},ready:function(a){return p.ready.promise().done(a),this},eq:function(a){return a=+a,a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(k.apply(this,arguments),"slice",k.call(arguments).join(","))},map:function(a){return this.pushStack(p.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:j,sort:[].sort,splice:[].splice},p.fn.init.prototype=p.fn,p.extend=p.fn.extend=function(){var a,c,d,e,f,g,h=arguments[0]||{},i=1,j=arguments.length,k=!1;typeof h=="boolean"&&(k=h,h=arguments[1]||{},i=2),typeof h!="object"&&!p.isFunction(h)&&(h={}),j===i&&(h=this,--i);for(;i<j;i++)if((a=arguments[i])!=null)for(c in a){d=h[c],e=a[c];if(h===e)continue;k&&e&&(p.isPlainObject(e)||(f=p.isArray(e)))?(f?(f=!1,g=d&&p.isArray(d)?d:[]):g=d&&p.isPlainObject(d)?d:{},h[c]=p.extend(k,g,e)):e!==b&&(h[c]=e)}return h},p.extend({noConflict:function(b){return a.$===p&&(a.$=i),b&&a.jQuery===p&&(a.jQuery=h),p},isReady:!1,readyWait:1,holdReady:function(a){a?p.readyWait++:p.ready(!0)},ready:function(a){if(a===!0?--p.readyWait:p.isReady)return;if(!e.body)return setTimeout(p.ready,1);p.isReady=!0;if(a!==!0&&--p.readyWait>0)return;d.resolveWith(e,[p]),p.fn.trigger&&p(e).trigger("ready").off("ready")},isFunction:function(a){return p.type(a)==="function"},isArray:Array.isArray||function(a){return p.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):E[m.call(a)]||"object"},isPlainObject:function(a){if(!a||p.type(a)!=="object"||a.nodeType||p.isWindow(a))return!1;try{if(a.constructor&&!n.call(a,"constructor")&&!n.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||n.call(a,d)},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},error:function(a){throw new Error(a)},parseHTML:function(a,b,c){var d;return!a||typeof a!="string"?null:(typeof b=="boolean"&&(c=b,b=0),b=b||e,(d=v.exec(a))?[b.createElement(d[1])]:(d=p.buildFragment([a],b,c?null:[]),p.merge([],(d.cacheable?p.clone(d.fragment):d.fragment).childNodes)))},parseJSON:function(b){if(!b||typeof b!="string")return null;b=p.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(w.test(b.replace(y,"@").replace(z,"]").replace(x,"")))return(new Function("return "+b))();p.error("Invalid JSON: "+b)},parseXML:function(c){var d,e;if(!c||typeof c!="string")return null;try{a.DOMParser?(e=new DOMParser,d=e.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(f){d=b}return(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&p.error("Invalid XML: "+c),d},noop:function(){},globalEval:function(b){b&&r.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(A,"ms-").replace(B,C)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,c,d){var e,f=0,g=a.length,h=g===b||p.isFunction(a);if(d){if(h){for(e in a)if(c.apply(a[e],d)===!1)break}else for(;f<g;)if(c.apply(a[f++],d)===!1)break}else if(h){for(e in a)if(c.call(a[e],e,a[e])===!1)break}else for(;f<g;)if(c.call(a[f],f,a[f++])===!1)break;return a},trim:o&&!o.call(". ")?function(a){return a==null?"":o.call(a)}:function(a){return a==null?"":(a+"").replace(t,"")},makeArray:function(a,b){var c,d=b||[];return a!=null&&(c=p.type(a),a.length==null||c==="string"||c==="function"||c==="regexp"||p.isWindow(a)?j.call(d,a):p.merge(d,a)),d},inArray:function(a,b,c){var d;if(b){if(l)return l.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=c.length,e=a.length,f=0;if(typeof d=="number")for(;f<d;f++)a[e++]=c[f];else while(c[f]!==b)a[e++]=c[f++];return a.length=e,a},grep:function(a,b,c){var d,e=[],f=0,g=a.length;c=!!c;for(;f<g;f++)d=!!b(a[f],f),c!==d&&e.push(a[f]);return e},map:function(a,c,d){var e,f,g=[],h=0,i=a.length,j=a instanceof p||i!==b&&typeof i=="number"&&(i>0&&a[0]&&a[i-1]||i===0||p.isArray(a));if(j)for(;h<i;h++)e=c(a[h],h,d),e!=null&&(g[g.length]=e);else for(f in a)e=c(a[f],f,d),e!=null&&(g[g.length]=e);return g.concat.apply([],g)},guid:1,proxy:function(a,c){var d,e,f;return typeof c=="string"&&(d=a[c],c=a,a=d),p.isFunction(a)?(e=k.call(arguments,2),f=function(){return a.apply(c,e.concat(k.call(arguments)))},f.guid=a.guid=a.guid||p.guid++,f):b},access:function(a,c,d,e,f,g,h){var i,j=d==null,k=0,l=a.length;if(d&&typeof d=="object"){for(k in d)p.access(a,c,k,d[k],1,g,e);f=1}else if(e!==b){i=h===b&&p.isFunction(e),j&&(i?(i=c,c=function(a,b,c){return i.call(p(a),c)}):(c.call(a,e),c=null));if(c)for(;k<l;k++)c(a[k],d,i?e.call(a[k],k,c(a[k],d)):e,h);f=1}return f?a:j?c.call(a):l?c(a[0],d):g},now:function(){return(new Date).getTime()}}),p.ready.promise=function(b){if(!d){d=p.Deferred();if(e.readyState==="complete")setTimeout(p.ready,1);else if(e.addEventListener)e.addEventListener("DOMContentLoaded",D,!1),a.addEventListener("load",p.ready,!1);else{e.attachEvent("onreadystatechange",D),a.attachEvent("onload",p.ready);var c=!1;try{c=a.frameElement==null&&e.documentElement}catch(f){}c&&c.doScroll&&function g(){if(!p.isReady){try{c.doScroll("left")}catch(a){return setTimeout(g,50)}p.ready()}}()}}return d.promise(b)},p.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){E["[object "+b+"]"]=b.toLowerCase()}),c=p(e);var F={};p.Callbacks=function(a){a=typeof a=="string"?F[a]||G(a):p.extend({},a);var c,d,e,f,g,h,i=[],j=!a.once&&[],k=function(b){c=a.memory&&b,d=!0,h=f||0,f=0,g=i.length,e=!0;for(;i&&h<g;h++)if(i[h].apply(b[0],b[1])===!1&&a.stopOnFalse){c=!1;break}e=!1,i&&(j?j.length&&k(j.shift()):c?i=[]:l.disable())},l={add:function(){if(i){var b=i.length;(function d(b){p.each(b,function(b,c){var e=p.type(c);e==="function"&&(!a.unique||!l.has(c))?i.push(c):c&&c.length&&e!=="string"&&d(c)})})(arguments),e?g=i.length:c&&(f=b,k(c))}return this},remove:function(){return i&&p.each(arguments,function(a,b){var c;while((c=p.inArray(b,i,c))>-1)i.splice(c,1),e&&(c<=g&&g--,c<=h&&h--)}),this},has:function(a){return p.inArray(a,i)>-1},empty:function(){return i=[],this},disable:function(){return i=j=c=b,this},disabled:function(){return!i},lock:function(){return j=b,c||l.disable(),this},locked:function(){return!j},fireWith:function(a,b){return b=b||[],b=[a,b.slice?b.slice():b],i&&(!d||j)&&(e?j.push(b):k(b)),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!d}};return l},p.extend({Deferred:function(a){var b=[["resolve","done",p.Callbacks("once memory"),"resolved"],["reject","fail",p.Callbacks("once memory"),"rejected"],["notify","progress",p.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return p.Deferred(function(c){p.each(b,function(b,d){var f=d[0],g=a[b];e[d[1]](p.isFunction(g)?function(){var a=g.apply(this,arguments);a&&p.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f+"With"](this===e?c:this,[a])}:c[f])}),a=null}).promise()},promise:function(a){return a!=null?p.extend(a,d):d}},e={};return d.pipe=d.then,p.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[a^1][2].disable,b[2][2].lock),e[f[0]]=g.fire,e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=k.call(arguments),d=c.length,e=d!==1||a&&p.isFunction(a.promise)?d:0,f=e===1?a:p.Deferred(),g=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?k.call(arguments):d,c===h?f.notifyWith(b,c):--e||f.resolveWith(b,c)}},h,i,j;if(d>1){h=new Array(d),i=new Array(d),j=new Array(d);for(;b<d;b++)c[b]&&p.isFunction(c[b].promise)?c[b].promise().done(g(b,j,c)).fail(f.reject).progress(g(b,i,h)):--e}return e||f.resolveWith(j,c),f.promise()}}),p.support=function(){var b,c,d,f,g,h,i,j,k,l,m,n=e.createElement("div");n.setAttribute("className","t"),n.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",c=n.getElementsByTagName("*"),d=n.getElementsByTagName("a")[0],d.style.cssText="top:1px;float:left;opacity:.5";if(!c||!c.length)return{};f=e.createElement("select"),g=f.appendChild(e.createElement("option")),h=n.getElementsByTagName("input")[0],b={leadingWhitespace:n.firstChild.nodeType===3,tbody:!n.getElementsByTagName("tbody").length,htmlSerialize:!!n.getElementsByTagName("link").length,style:/top/.test(d.getAttribute("style")),hrefNormalized:d.getAttribute("href")==="/a",opacity:/^0.5/.test(d.style.opacity),cssFloat:!!d.style.cssFloat,checkOn:h.value==="on",optSelected:g.selected,getSetAttribute:n.className!=="t",enctype:!!e.createElement("form").enctype,html5Clone:e.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:e.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},h.checked=!0,b.noCloneChecked=h.cloneNode(!0).checked,f.disabled=!0,b.optDisabled=!g.disabled;try{delete n.test}catch(o){b.deleteExpando=!1}!n.addEventListener&&n.attachEvent&&n.fireEvent&&(n.attachEvent("onclick",m=function(){b.noCloneEvent=!1}),n.cloneNode(!0).fireEvent("onclick"),n.detachEvent("onclick",m)),h=e.createElement("input"),h.value="t",h.setAttribute("type","radio"),b.radioValue=h.value==="t",h.setAttribute("checked","checked"),h.setAttribute("name","t"),n.appendChild(h),i=e.createDocumentFragment(),i.appendChild(n.lastChild),b.checkClone=i.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=h.checked,i.removeChild(h),i.appendChild(n);if(n.attachEvent)for(k in{submit:!0,change:!0,focusin:!0})j="on"+k,l=j in n,l||(n.setAttribute(j,"return;"),l=typeof n[j]=="function"),b[k+"Bubbles"]=l;return p(function(){var c,d,f,g,h="padding:0;margin:0;border:0;display:block;overflow:hidden;",i=e.getElementsByTagName("body")[0];if(!i)return;c=e.createElement("div"),c.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",i.insertBefore(c,i.firstChild),d=e.createElement("div"),c.appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",f=d.getElementsByTagName("td"),f[0].style.cssText="padding:0;margin:0;border:0;display:none",l=f[0].offsetHeight===0,f[0].style.display="",f[1].style.display="none",b.reliableHiddenOffsets=l&&f[0].offsetHeight===0,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",b.boxSizing=d.offsetWidth===4,b.doesNotIncludeMarginInBodyOffset=i.offsetTop!==1,a.getComputedStyle&&(b.pixelPosition=(a.getComputedStyle(d,null)||{}).top!=="1%",b.boxSizingReliable=(a.getComputedStyle(d,null)||{width:"4px"}).width==="4px",g=e.createElement("div"),g.style.cssText=d.style.cssText=h,g.style.marginRight=g.style.width="0",d.style.width="1px",d.appendChild(g),b.reliableMarginRight=!parseFloat((a.getComputedStyle(g,null)||{}).marginRight)),typeof d.style.zoom!="undefined"&&(d.innerHTML="",d.style.cssText=h+"width:1px;padding:1px;display:inline;zoom:1",b.inlineBlockNeedsLayout=d.offsetWidth===3,d.style.display="block",d.style.overflow="visible",d.innerHTML="<div></div>",d.firstChild.style.width="5px",b.shrinkWrapBlocks=d.offsetWidth!==3,c.style.zoom=1),i.removeChild(c),c=d=f=g=null}),i.removeChild(n),c=d=f=g=h=i=n=null,b}();var H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,I=/([A-Z])/g;p.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(p.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){return a=a.nodeType?p.cache[a[p.expando]]:a[p.expando],!!a&&!K(a)},data:function(a,c,d,e){if(!p.acceptData(a))return;var f,g,h=p.expando,i=typeof c=="string",j=a.nodeType,k=j?p.cache:a,l=j?a[h]:a[h]&&h;if((!l||!k[l]||!e&&!k[l].data)&&i&&d===b)return;l||(j?a[h]=l=p.deletedIds.pop()||p.guid++:l=h),k[l]||(k[l]={},j||(k[l].toJSON=p.noop));if(typeof c=="object"||typeof c=="function")e?k[l]=p.extend(k[l],c):k[l].data=p.extend(k[l].data,c);return f=k[l],e||(f.data||(f.data={}),f=f.data),d!==b&&(f[p.camelCase(c)]=d),i?(g=f[c],g==null&&(g=f[p.camelCase(c)])):g=f,g},removeData:function(a,b,c){if(!p.acceptData(a))return;var d,e,f,g=a.nodeType,h=g?p.cache:a,i=g?a[p.expando]:p.expando;if(!h[i])return;if(b){d=c?h[i]:h[i].data;if(d){p.isArray(b)||(b in d?b=[b]:(b=p.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,f=b.length;e<f;e++)delete d[b[e]];if(!(c?K:p.isEmptyObject)(d))return}}if(!c){delete h[i].data;if(!K(h[i]))return}g?p.cleanData([a],!0):p.support.deleteExpando||h!=h.window?delete h[i]:h[i]=null},_data:function(a,b,c){return p.data(a,b,c,!0)},acceptData:function(a){var b=a.nodeName&&p.noData[a.nodeName.toLowerCase()];return!b||b!==!0&&a.getAttribute("classid")===b}}),p.fn.extend({data:function(a,c){var d,e,f,g,h,i=this[0],j=0,k=null;if(a===b){if(this.length){k=p.data(i);if(i.nodeType===1&&!p._data(i,"parsedAttrs")){f=i.attributes;for(h=f.length;j<h;j++)g=f[j].name,g.indexOf("data-")||(g=p.camelCase(g.substring(5)),J(i,g,k[g]));p._data(i,"parsedAttrs",!0)}}return k}return typeof a=="object"?this.each(function(){p.data(this,a)}):(d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!",p.access(this,function(c){if(c===b)return k=this.triggerHandler("getData"+e,[d[0]]),k===b&&i&&(k=p.data(i,a),k=J(i,a,k)),k===b&&d[1]?this.data(d[0]):k;d[1]=c,this.each(function(){var b=p(this);b.triggerHandler("setData"+e,d),p.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1))},removeData:function(a){return this.each(function(){p.removeData(this,a)})}}),p.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=p._data(a,b),c&&(!d||p.isArray(c)?d=p._data(a,b,p.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=p.queue(a,b),d=c.length,e=c.shift(),f=p._queueHooks(a,b),g=function(){p.dequeue(a,b)};e==="inprogress"&&(e=c.shift(),d--),e&&(b==="fx"&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return p._data(a,c)||p._data(a,c,{empty:p.Callbacks("once memory").add(function(){p.removeData(a,b+"queue",!0),p.removeData(a,c,!0)})})}}),p.fn.extend({queue:function(a,c){var d=2;return typeof a!="string"&&(c=a,a="fx",d--),arguments.length<d?p.queue(this[0],a):c===b?this:this.each(function(){var b=p.queue(this,a,c);p._queueHooks(this,a),a==="fx"&&b[0]!=="inprogress"&&p.dequeue(this,a)})},dequeue:function(a){return this.each(function(){p.dequeue(this,a)})},delay:function(a,b){return a=p.fx?p.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){var d,e=1,f=p.Deferred(),g=this,h=this.length,i=function(){--e||f.resolveWith(g,[g])};typeof a!="string"&&(c=a,a=b),a=a||"fx";while(h--)d=p._data(g[h],a+"queueHooks"),d&&d.empty&&(e++,d.empty.add(i));return i(),f.promise(c)}});var L,M,N,O=/[\t\r\n]/g,P=/\r/g,Q=/^(?:button|input)$/i,R=/^(?:button|input|object|select|textarea)$/i,S=/^a(?:rea|)$/i,T=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,U=p.support.getSetAttribute;p.fn.extend({attr:function(a,b){return p.access(this,p.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){p.removeAttr(this,a)})},prop:function(a,b){return p.access(this,p.prop,a,b,arguments.length>1)},removeProp:function(a){return a=p.propFix[a]||a,this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,f,g,h;if(p.isFunction(a))return this.each(function(b){p(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(s);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{f=" "+e.className+" ";for(g=0,h=b.length;g<h;g++)f.indexOf(" "+b[g]+" ")<0&&(f+=b[g]+" ");e.className=p.trim(f)}}}return this},removeClass:function(a){var c,d,e,f,g,h,i;if(p.isFunction(a))return this.each(function(b){p(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(s);for(h=0,i=this.length;h<i;h++){e=this[h];if(e.nodeType===1&&e.className){d=(" "+e.className+" ").replace(O," ");for(f=0,g=c.length;f<g;f++)while(d.indexOf(" "+c[f]+" ")>=0)d=d.replace(" "+c[f]+" "," ");e.className=a?p.trim(d):""}}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";return p.isFunction(a)?this.each(function(c){p(this).toggleClass(a.call(this,c,this.className,b),b)}):this.each(function(){if(c==="string"){var e,f=0,g=p(this),h=b,i=a.split(s);while(e=i[f++])h=d?h:!g.hasClass(e),g[h?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&p._data(this,"__className__",this.className),this.className=this.className||a===!1?"":p._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(O," ").indexOf(b)>=0)return!0;return!1},val:function(a){var c,d,e,f=this[0];if(!arguments.length){if(f)return c=p.valHooks[f.type]||p.valHooks[f.nodeName.toLowerCase()],c&&"get"in c&&(d=c.get(f,"value"))!==b?d:(d=f.value,typeof d=="string"?d.replace(P,""):d==null?"":d);return}return e=p.isFunction(a),this.each(function(d){var f,g=p(this);if(this.nodeType!==1)return;e?f=a.call(this,d,g.val()):f=a,f==null?f="":typeof f=="number"?f+="":p.isArray(f)&&(f=p.map(f,function(a){return a==null?"":a+""})),c=p.valHooks[this.type]||p.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,f,"value")===b)this.value=f})}}),p.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,f=a.selectedIndex,g=[],h=a.options,i=a.type==="select-one";if(f<0)return null;c=i?f:0,d=i?f+1:h.length;for(;c<d;c++){e=h[c];if(e.selected&&(p.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!p.nodeName(e.parentNode,"optgroup"))){b=p(e).val();if(i)return b;g.push(b)}}return i&&!g.length&&h.length?p(h[f]).val():g},set:function(a,b){var c=p.makeArray(b);return p(a).find("option").each(function(){this.selected=p.inArray(p(this).val(),c)>=0}),c.length||(a.selectedIndex=-1),c}}},attrFn:{},attr:function(a,c,d,e){var f,g,h,i=a.nodeType;if(!a||i===3||i===8||i===2)return;if(e&&p.isFunction(p.fn[c]))return p(a)[c](d);if(typeof a.getAttribute=="undefined")return p.prop(a,c,d);h=i!==1||!p.isXMLDoc(a),h&&(c=c.toLowerCase(),g=p.attrHooks[c]||(T.test(c)?M:L));if(d!==b){if(d===null){p.removeAttr(a,c);return}return g&&"set"in g&&h&&(f=g.set(a,d,c))!==b?f:(a.setAttribute(c,d+""),d)}return g&&"get"in g&&h&&(f=g.get(a,c))!==null?f:(f=a.getAttribute(c),f===null?b:f)},removeAttr:function(a,b){var c,d,e,f,g=0;if(b&&a.nodeType===1){d=b.split(s);for(;g<d.length;g++)e=d[g],e&&(c=p.propFix[e]||e,f=T.test(e),f||p.attr(a,e,""),a.removeAttribute(U?e:c),f&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(Q.test(a.nodeName)&&a.parentNode)p.error("type property can't be changed");else if(!p.support.radioValue&&b==="radio"&&p.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}},value:{get:function(a,b){return L&&p.nodeName(a,"button")?L.get(a,b):b in a?a.value:null},set:function(a,b,c){if(L&&p.nodeName(a,"button"))return L.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,f,g,h=a.nodeType;if(!a||h===3||h===8||h===2)return;return g=h!==1||!p.isXMLDoc(a),g&&(c=p.propFix[c]||c,f=p.propHooks[c]),d!==b?f&&"set"in f&&(e=f.set(a,d,c))!==b?e:a[c]=d:f&&"get"in f&&(e=f.get(a,c))!==null?e:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):R.test(a.nodeName)||S.test(a.nodeName)&&a.href?0:b}}}}),M={get:function(a,c){var d,e=p.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;return b===!1?p.removeAttr(a,c):(d=p.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase())),c}},U||(N={name:!0,id:!0,coords:!0},L=p.valHooks.button={get:function(a,c){var d;return d=a.getAttributeNode(c),d&&(N[c]?d.value!=="":d.specified)?d.value:b},set:function(a,b,c){var d=a.getAttributeNode(c);return d||(d=e.createAttribute(c),a.setAttributeNode(d)),d.value=b+""}},p.each(["width","height"],function(a,b){p.attrHooks[b]=p.extend(p.attrHooks[b],{set:function(a,c){if(c==="")return a.setAttribute(b,"auto"),c}})}),p.attrHooks.contenteditable={get:L.get,set:function(a,b,c){b===""&&(b="false"),L.set(a,b,c)}}),p.support.hrefNormalized||p.each(["href","src","width","height"],function(a,c){p.attrHooks[c]=p.extend(p.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),p.support.style||(p.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=b+""}}),p.support.optSelected||(p.propHooks.selected=p.extend(p.propHooks.selected,{get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}})),p.support.enctype||(p.propFix.enctype="encoding"),p.support.checkOn||p.each(["radio","checkbox"],function(){p.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),p.each(["radio","checkbox"],function(){p.valHooks[this]=p.extend(p.valHooks[this],{set:function(a,b){if(p.isArray(b))return a.checked=p.inArray(p(a).val(),b)>=0}})});var V=/^(?:textarea|input|select)$/i,W=/^([^\.]*|)(?:\.(.+)|)$/,X=/(?:^|\s)hover(\.\S+|)\b/,Y=/^key/,Z=/^(?:mouse|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=function(a){return p.event.special.hover?a:a.replace(X,"mouseenter$1 mouseleave$1")};p.event={add:function(a,c,d,e,f){var g,h,i,j,k,l,m,n,o,q,r;if(a.nodeType===3||a.nodeType===8||!c||!d||!(g=p._data(a)))return;d.handler&&(o=d,d=o.handler,f=o.selector),d.guid||(d.guid=p.guid++),i=g.events,i||(g.events=i={}),h=g.handle,h||(g.handle=h=function(a){return typeof p!="undefined"&&(!a||p.event.triggered!==a.type)?p.event.dispatch.apply(h.elem,arguments):b},h.elem=a),c=p.trim(_(c)).split(" ");for(j=0;j<c.length;j++){k=W.exec(c[j])||[],l=k[1],m=(k[2]||"").split(".").sort(),r=p.event.special[l]||{},l=(f?r.delegateType:r.bindType)||l,r=p.event.special[l]||{},n=p.extend({type:l,origType:k[1],data:e,handler:d,guid:d.guid,selector:f,needsContext:f&&p.expr.match.needsContext.test(f),namespace:m.join(".")},o),q=i[l];if(!q){q=i[l]=[],q.delegateCount=0;if(!r.setup||r.setup.call(a,e,m,h)===!1)a.addEventListener?a.addEventListener(l,h,!1):a.attachEvent&&a.attachEvent("on"+l,h)}r.add&&(r.add.call(a,n),n.handler.guid||(n.handler.guid=d.guid)),f?q.splice(q.delegateCount++,0,n):q.push(n),p.event.global[l]=!0}a=null},global:{},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,q,r=p.hasData(a)&&p._data(a);if(!r||!(m=r.events))return;b=p.trim(_(b||"")).split(" ");for(f=0;f<b.length;f++){g=W.exec(b[f])||[],h=i=g[1],j=g[2];if(!h){for(h in m)p.event.remove(a,h+b[f],c,d,!0);continue}n=p.event.special[h]||{},h=(d?n.delegateType:n.bindType)||h,o=m[h]||[],k=o.length,j=j?new RegExp("(^|\\.)"+j.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(l=0;l<o.length;l++)q=o[l],(e||i===q.origType)&&(!c||c.guid===q.guid)&&(!j||j.test(q.namespace))&&(!d||d===q.selector||d==="**"&&q.selector)&&(o.splice(l--,1),q.selector&&o.delegateCount--,n.remove&&n.remove.call(a,q));o.length===0&&k!==o.length&&((!n.teardown||n.teardown.call(a,j,r.handle)===!1)&&p.removeEvent(a,h,r.handle),delete m[h])}p.isEmptyObject(m)&&(delete r.handle,p.removeData(a,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,f,g){if(!f||f.nodeType!==3&&f.nodeType!==8){var h,i,j,k,l,m,n,o,q,r,s=c.type||c,t=[];if($.test(s+p.event.triggered))return;s.indexOf("!")>=0&&(s=s.slice(0,-1),i=!0),s.indexOf(".")>=0&&(t=s.split("."),s=t.shift(),t.sort());if((!f||p.event.customEvent[s])&&!p.event.global[s])return;c=typeof c=="object"?c[p.expando]?c:new p.Event(s,c):new p.Event(s),c.type=s,c.isTrigger=!0,c.exclusive=i,c.namespace=t.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,m=s.indexOf(":")<0?"on"+s:"";if(!f){h=p.cache;for(j in h)h[j].events&&h[j].events[s]&&p.event.trigger(c,d,h[j].handle.elem,!0);return}c.result=b,c.target||(c.target=f),d=d!=null?p.makeArray(d):[],d.unshift(c),n=p.event.special[s]||{};if(n.trigger&&n.trigger.apply(f,d)===!1)return;q=[[f,n.bindType||s]];if(!g&&!n.noBubble&&!p.isWindow(f)){r=n.delegateType||s,k=$.test(r+s)?f:f.parentNode;for(l=f;k;k=k.parentNode)q.push([k,r]),l=k;l===(f.ownerDocument||e)&&q.push([l.defaultView||l.parentWindow||a,r])}for(j=0;j<q.length&&!c.isPropagationStopped();j++)k=q[j][0],c.type=q[j][1],o=(p._data(k,"events")||{})[c.type]&&p._data(k,"handle"),o&&o.apply(k,d),o=m&&k[m],o&&p.acceptData(k)&&o.apply&&o.apply(k,d)===!1&&c.preventDefault();return c.type=s,!g&&!c.isDefaultPrevented()&&(!n._default||n._default.apply(f.ownerDocument,d)===!1)&&(s!=="click"||!p.nodeName(f,"a"))&&p.acceptData(f)&&m&&f[s]&&(s!=="focus"&&s!=="blur"||c.target.offsetWidth!==0)&&!p.isWindow(f)&&(l=f[m],l&&(f[m]=null),p.event.triggered=s,f[s](),p.event.triggered=b,l&&(f[m]=l)),c.result}return},dispatch:function(c){c=p.event.fix(c||a.event);var d,e,f,g,h,i,j,l,m,n,o=(p._data(this,"events")||{})[c.type]||[],q=o.delegateCount,r=k.call(arguments),s=!c.exclusive&&!c.namespace,t=p.event.special[c.type]||{},u=[];r[0]=c,c.delegateTarget=this;if(t.preDispatch&&t.preDispatch.call(this,c)===!1)return;if(q&&(!c.button||c.type!=="click"))for(f=c.target;f!=this;f=f.parentNode||this)if(f.disabled!==!0||c.type!=="click"){h={},j=[];for(d=0;d<q;d++)l=o[d],m=l.selector,h[m]===b&&(h[m]=l.needsContext?p(m,this).index(f)>=0:p.find(m,this,null,[f]).length),h[m]&&j.push(l);j.length&&u.push({elem:f,matches:j})}o.length>q&&u.push({elem:this,matches:o.slice(q)});for(d=0;d<u.length&&!c.isPropagationStopped();d++){i=u[d],c.currentTarget=i.elem;for(e=0;e<i.matches.length&&!c.isImmediatePropagationStopped();e++){l=i.matches[e];if(s||!c.namespace&&!l.namespace||c.namespace_re&&c.namespace_re.test(l.namespace))c.data=l.data,c.handleObj=l,g=((p.event.special[l.origType]||{}).handle||l.handler).apply(i.elem,r),g!==b&&(c.result=g,g===!1&&(c.preventDefault(),c.stopPropagation()))}}return t.postDispatch&&t.postDispatch.call(this,c),c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,c){var d,f,g,h=c.button,i=c.fromElement;return a.pageX==null&&c.clientX!=null&&(d=a.target.ownerDocument||e,f=d.documentElement,g=d.body,a.pageX=c.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=c.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?c.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0),a}},fix:function(a){if(a[p.expando])return a;var b,c,d=a,f=p.event.fixHooks[a.type]||{},g=f.props?this.props.concat(f.props):this.props;a=p.Event(d);for(b=g.length;b;)c=g[--b],a[c]=d[c];return a.target||(a.target=d.srcElement||e),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,f.filter?f.filter(a,d):a},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){p.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=p.extend(new p.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?p.event.trigger(e,null,b):p.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},p.event.handle=p.event.dispatch,p.removeEvent=e.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]=="undefined"&&(a[d]=null),a.detachEvent(d,c))},p.Event=function(a,b){if(this instanceof p.Event)a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?bb:ba):this.type=a,b&&p.extend(this,b),this.timeStamp=a&&a.timeStamp||p.now(),this[p.expando]=!0;else return new p.Event(a,b)},p.Event.prototype={preventDefault:function(){this.isDefaultPrevented=bb;var a=this.originalEvent;if(!a)return;a.preventDefault?a.preventDefault():a.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=bb;var a=this.originalEvent;if(!a)return;a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()},isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba},p.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){p.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj,g=f.selector;if(!e||e!==d&&!p.contains(d,e))a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b;return c}}}),p.support.submitBubbles||(p.event.special.submit={setup:function(){if(p.nodeName(this,"form"))return!1;p.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=p.nodeName(c,"input")||p.nodeName(c,"button")?c.form:b;d&&!p._data(d,"_submit_attached")&&(p.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),p._data(d,"_submit_attached",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&p.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(p.nodeName(this,"form"))return!1;p.event.remove(this,"._submit")}}),p.support.changeBubbles||(p.event.special.change={setup:function(){if(V.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")p.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),p.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),p.event.simulate("change",this,a,!0)});return!1}p.event.add(this,"beforeactivate._change",function(a){var b=a.target;V.test(b.nodeName)&&!p._data(b,"_change_attached")&&(p.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&p.event.simulate("change",this.parentNode,a,!0)}),p._data(b,"_change_attached",!0))})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){return p.event.remove(this,"._change"),!V.test(this.nodeName)}}),p.support.focusinBubbles||p.each({focus:"focusin",blur:"focusout"},function(a,b){var c=0,d=function(a){p.event.simulate(b,a.target,p.event.fix(a),!0)};p.event.special[b]={setup:function(){c++===0&&e.addEventListener(a,d,!0)},teardown:function(){--c===0&&e.removeEventListener(a,d,!0)}}}),p.fn.extend({on:function(a,c,d,e,f){var g,h;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(h in a)this.on(h,c,d,a[h],f);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=ba;else if(!e)return this;return f===1&&(g=e,e=function(a){return p().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=p.guid++)),this.each(function(){p.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){var e,f;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,p(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler),this;if(typeof a=="object"){for(f in a)this.off(f,c,a[f]);return this}if(c===!1||typeof c=="function")d=c,c=b;return d===!1&&(d=ba),this.each(function(){p.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){return p(this.context).on(a,this.selector,b,c),this},die:function(a,b){return p(this.context).off(a,this.selector||"**",b),this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length===1?this.off(a,"**"):this.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){p.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return p.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||p.guid++,d=0,e=function(c){var e=(p._data(this,"lastToggle"+a.guid)||0)%d;return p._data(this,"lastToggle"+a.guid,e+1),c.preventDefault(),b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),p.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){p.fn[b]=function(a,c){return c==null&&(c=a,a=null),arguments.length>0?this.on(b,null,a,c):this.trigger(b)},Y.test(b)&&(p.event.fixHooks[b]=p.event.keyHooks),Z.test(b)&&(p.event.fixHooks[b]=p.event.mouseHooks)}),function(a,b){function bc(a,b,c,d){c=c||[],b=b||r;var e,f,i,j,k=b.nodeType;if(!a||typeof a!="string")return c;if(k!==1&&k!==9)return[];i=g(b);if(!i&&!d)if(e=P.exec(a))if(j=e[1]){if(k===9){f=b.getElementById(j);if(!f||!f.parentNode)return c;if(f.id===j)return c.push(f),c}else if(b.ownerDocument&&(f=b.ownerDocument.getElementById(j))&&h(b,f)&&f.id===j)return c.push(f),c}else{if(e[2])return w.apply(c,x.call(b.getElementsByTagName(a),0)),c;if((j=e[3])&&_&&b.getElementsByClassName)return w.apply(c,x.call(b.getElementsByClassName(j),0)),c}return bp(a.replace(L,"$1"),b,c,d,i)}function bd(a){return function(b){var c=b.nodeName.toLowerCase();return c==="input"&&b.type===a}}function be(a){return function(b){var c=b.nodeName.toLowerCase();return(c==="input"||c==="button")&&b.type===a}}function bf(a){return z(function(b){return b=+b,z(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function bg(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}function bh(a,b){var c,d,f,g,h,i,j,k=C[o][a];if(k)return b?0:k.slice(0);h=a,i=[],j=e.preFilter;while(h){if(!c||(d=M.exec(h)))d&&(h=h.slice(d[0].length)),i.push(f=[]);c=!1;if(d=N.exec(h))f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=d[0].replace(L," ");for(g in e.filter)(d=W[g].exec(h))&&(!j[g]||(d=j[g](d,r,!0)))&&(f.push(c=new q(d.shift())),h=h.slice(c.length),c.type=g,c.matches=d);if(!c)break}return b?h.length:h?bc.error(a):C(a,i).slice(0)}function bi(a,b,d){var e=b.dir,f=d&&b.dir==="parentNode",g=u++;return b.first?function(b,c,d){while(b=b[e])if(f||b.nodeType===1)return a(b,c,d)}:function(b,d,h){if(!h){var i,j=t+" "+g+" ",k=j+c;while(b=b[e])if(f||b.nodeType===1){if((i=b[o])===k)return b.sizset;if(typeof i=="string"&&i.indexOf(j)===0){if(b.sizset)return b}else{b[o]=k;if(a(b,d,h))return b.sizset=!0,b;b.sizset=!1}}}else while(b=b[e])if(f||b.nodeType===1)if(a(b,d,h))return b}}function bj(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function bk(a,b,c,d,e){var f,g=[],h=0,i=a.length,j=b!=null;for(;h<i;h++)if(f=a[h])if(!c||c(f,d,e))g.push(f),j&&b.push(h);return g}function bl(a,b,c,d,e,f){return d&&!d[o]&&(d=bl(d)),e&&!e[o]&&(e=bl(e,f)),z(function(f,g,h,i){if(f&&e)return;var j,k,l,m=[],n=[],o=g.length,p=f||bo(b||"*",h.nodeType?[h]:h,[],f),q=a&&(f||!b)?bk(p,m,a,h,i):p,r=c?e||(f?a:o||d)?[]:g:q;c&&c(q,r,h,i);if(d){l=bk(r,n),d(l,[],h,i),j=l.length;while(j--)if(k=l[j])r[n[j]]=!(q[n[j]]=k)}if(f){j=a&&r.length;while(j--)if(k=r[j])f[m[j]]=!(g[m[j]]=k)}else r=bk(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):w.apply(g,r)})}function bm(a){var b,c,d,f=a.length,g=e.relative[a[0].type],h=g||e.relative[" "],i=g?1:0,j=bi(function(a){return a===b},h,!0),k=bi(function(a){return y.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==l)||((b=c).nodeType?j(a,c,d):k(a,c,d))}];for(;i<f;i++)if(c=e.relative[a[i].type])m=[bi(bj(m),c)];else{c=e.filter[a[i].type].apply(null,a[i].matches);if(c[o]){d=++i;for(;d<f;d++)if(e.relative[a[d].type])break;return bl(i>1&&bj(m),i>1&&a.slice(0,i-1).join("").replace(L,"$1"),c,i<d&&bm(a.slice(i,d)),d<f&&bm(a=a.slice(d)),d<f&&a.join(""))}m.push(c)}return bj(m)}function bn(a,b){var d=b.length>0,f=a.length>0,g=function(h,i,j,k,m){var n,o,p,q=[],s=0,u="0",x=h&&[],y=m!=null,z=l,A=h||f&&e.find.TAG("*",m&&i.parentNode||i),B=t+=z==null?1:Math.E;y&&(l=i!==r&&i,c=g.el);for(;(n=A[u])!=null;u++){if(f&&n){for(o=0;p=a[o];o++)if(p(n,i,j)){k.push(n);break}y&&(t=B,c=++g.el)}d&&((n=!p&&n)&&s--,h&&x.push(n))}s+=u;if(d&&u!==s){for(o=0;p=b[o];o++)p(x,q,i,j);if(h){if(s>0)while(u--)!x[u]&&!q[u]&&(q[u]=v.call(k));q=bk(q)}w.apply(k,q),y&&!h&&q.length>0&&s+b.length>1&&bc.uniqueSort(k)}return y&&(t=B,l=z),x};return g.el=0,d?z(g):g}function bo(a,b,c,d){var e=0,f=b.length;for(;e<f;e++)bc(a,b[e],c,d);return c}function bp(a,b,c,d,f){var g,h,j,k,l,m=bh(a),n=m.length;if(!d&&m.length===1){h=m[0]=m[0].slice(0);if(h.length>2&&(j=h[0]).type==="ID"&&b.nodeType===9&&!f&&e.relative[h[1].type]){b=e.find.ID(j.matches[0].replace(V,""),b,f)[0];if(!b)return c;a=a.slice(h.shift().length)}for(g=W.POS.test(a)?-1:h.length-1;g>=0;g--){j=h[g];if(e.relative[k=j.type])break;if(l=e.find[k])if(d=l(j.matches[0].replace(V,""),R.test(h[0].type)&&b.parentNode||b,f)){h.splice(g,1),a=d.length&&h.join("");if(!a)return w.apply(c,x.call(d,0)),c;break}}}return i(a,m)(d,b,f,c,R.test(a)),c}function bq(){}var c,d,e,f,g,h,i,j,k,l,m=!0,n="undefined",o=("sizcache"+Math.random()).replace(".",""),q=String,r=a.document,s=r.documentElement,t=0,u=0,v=[].pop,w=[].push,x=[].slice,y=[].indexOf||function(a){var b=0,c=this.length;for(;b<c;b++)if(this[b]===a)return b;return-1},z=function(a,b){return a[o]=b==null||b,a},A=function(){var a={},b=[];return z(function(c,d){return b.push(c)>e.cacheLength&&delete a[b.shift()],a[c]=d},a)},B=A(),C=A(),D=A(),E="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",G=F.replace("w","w#"),H="([*^$|!~]?=)",I="\\["+E+"*("+F+")"+E+"*(?:"+H+E+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+G+")|)|)"+E+"*\\]",J=":("+F+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+I+")|[^:]|\\\\.)*|.*))\\)|)",K=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+E+"*((?:-\\d)?\\d*)"+E+"*\\)|)(?=[^-]|$)",L=new RegExp("^"+E+"+|((?:^|[^\\\\])(?:\\\\.)*)"+E+"+$","g"),M=new RegExp("^"+E+"*,"+E+"*"),N=new RegExp("^"+E+"*([\\x20\\t\\r\\n\\f>+~])"+E+"*"),O=new RegExp(J),P=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,Q=/^:not/,R=/[\x20\t\r\n\f]*[+~]/,S=/:not\($/,T=/h\d/i,U=/input|select|textarea|button/i,V=/\\(?!\\)/g,W={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),NAME:new RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:new RegExp("^("+F.replace("w","w*")+")"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+J),POS:new RegExp(K,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+E+"*(even|odd|(([+-]|)(\\d*)n|)"+E+"*(?:([+-]|)"+E+"*(\\d+)|))"+E+"*\\)|)","i"),needsContext:new RegExp("^"+E+"*[>+~]|"+K,"i")},X=function(a){var b=r.createElement("div");try{return a(b)}catch(c){return!1}finally{b=null}},Y=X(function(a){return a.appendChild(r.createComment("")),!a.getElementsByTagName("*").length}),Z=X(function(a){return a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==n&&a.firstChild.getAttribute("href")==="#"}),$=X(function(a){a.innerHTML="<select></select>";var b=typeof a.lastChild.getAttribute("multiple");return b!=="boolean"&&b!=="string"}),_=X(function(a){return a.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!a.getElementsByClassName||!a.getElementsByClassName("e").length?!1:(a.lastChild.className="e",a.getElementsByClassName("e").length===2)}),ba=X(function(a){a.id=o+0,a.innerHTML="<a name='"+o+"'></a><div name='"+o+"'></div>",s.insertBefore(a,s.firstChild);var b=r.getElementsByName&&r.getElementsByName(o).length===2+r.getElementsByName(o+0).length;return d=!r.getElementById(o),s.removeChild(a),b});try{x.call(s.childNodes,0)[0].nodeType}catch(bb){x=function(a){var b,c=[];for(;b=this[a];a++)c.push(b);return c}}bc.matches=function(a,b){return bc(a,null,null,b)},bc.matchesSelector=function(a,b){return bc(b,null,null,[a]).length>0},f=bc.getText=function(a){var b,c="",d=0,e=a.nodeType;if(e){if(e===1||e===9||e===11){if(typeof a.textContent=="string")return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=f(a)}else if(e===3||e===4)return a.nodeValue}else for(;b=a[d];d++)c+=f(b);return c},g=bc.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?b.nodeName!=="HTML":!1},h=bc.contains=s.contains?function(a,b){var c=a.nodeType===9?a.documentElement:a,d=b&&b.parentNode;return a===d||!!(d&&d.nodeType===1&&c.contains&&c.contains(d))}:s.compareDocumentPosition?function(a,b){return b&&!!(a.compareDocumentPosition(b)&16)}:function(a,b){while(b=b.parentNode)if(b===a)return!0;return!1},bc.attr=function(a,b){var c,d=g(a);return d||(b=b.toLowerCase()),(c=e.attrHandle[b])?c(a):d||$?a.getAttribute(b):(c=a.getAttributeNode(b),c?typeof a[b]=="boolean"?a[b]?b:null:c.specified?c.value:null:null)},e=bc.selectors={cacheLength:50,createPseudo:z,match:W,attrHandle:Z?{}:{href:function(a){return a.getAttribute("href",2)},type:function(a){return a.getAttribute("type")}},find:{ID:d?function(a,b,c){if(typeof b.getElementById!==n&&!c){var d=b.getElementById(a);return d&&d.parentNode?[d]:[]}}:function(a,c,d){if(typeof c.getElementById!==n&&!d){var e=c.getElementById(a);return e?e.id===a||typeof e.getAttributeNode!==n&&e.getAttributeNode("id").value===a?[e]:b:[]}},TAG:Y?function(a,b){if(typeof b.getElementsByTagName!==n)return b.getElementsByTagName(a)}:function(a,b){var c=b.getElementsByTagName(a);if(a==="*"){var d,e=[],f=0;for(;d=c[f];f++)d.nodeType===1&&e.push(d);return e}return c},NAME:ba&&function(a,b){if(typeof b.getElementsByName!==n)return b.getElementsByName(name)},CLASS:_&&function(a,b,c){if(typeof b.getElementsByClassName!==n&&!c)return b.getElementsByClassName(a)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(V,""),a[3]=(a[4]||a[5]||"").replace(V,""),a[2]==="~="&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),a[1]==="nth"?(a[2]||bc.error(a[0]),a[3]=+(a[3]?a[4]+(a[5]||1):2*(a[2]==="even"||a[2]==="odd")),a[4]=+(a[6]+a[7]||a[2]==="odd")):a[2]&&bc.error(a[0]),a},PSEUDO:function(a){var b,c;if(W.CHILD.test(a[0]))return null;if(a[3])a[2]=a[3];else if(b=a[4])O.test(b)&&(c=bh(b,!0))&&(c=b.indexOf(")",b.length-c)-b.length)&&(b=b.slice(0,c),a[0]=a[0].slice(0,c)),a[2]=b;return a.slice(0,3)}},filter:{ID:d?function(a){return a=a.replace(V,""),function(b){return b.getAttribute("id")===a}}:function(a){return a=a.replace(V,""),function(b){var c=typeof b.getAttributeNode!==n&&b.getAttributeNode("id");return c&&c.value===a}},TAG:function(a){return a==="*"?function(){return!0}:(a=a.replace(V,"").toLowerCase(),function(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var b=B[o][a];return b||(b=B(a,new RegExp("(^|"+E+")"+a+"("+E+"|$)"))),function(a){return b.test(a.className||typeof a.getAttribute!==n&&a.getAttribute("class")||"")}},ATTR:function(a,b,c){return function(d,e){var f=bc.attr(d,a);return f==null?b==="!=":b?(f+="",b==="="?f===c:b==="!="?f!==c:b==="^="?c&&f.indexOf(c)===0:b==="*="?c&&f.indexOf(c)>-1:b==="$="?c&&f.substr(f.length-c.length)===c:b==="~="?(" "+f+" ").indexOf(c)>-1:b==="|="?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d){return a==="nth"?function(a){var b,e,f=a.parentNode;if(c===1&&d===0)return!0;if(f){e=0;for(b=f.firstChild;b;b=b.nextSibling)if(b.nodeType===1){e++;if(a===b)break}}return e-=d,e===c||e%c===0&&e/c>=0}:function(b){var c=b;switch(a){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(a==="first")return!0;c=b;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0}}},PSEUDO:function(a,b){var c,d=e.pseudos[a]||e.setFilters[a.toLowerCase()]||bc.error("unsupported pseudo: "+a);return d[o]?d(b):d.length>1?(c=[a,a,"",b],e.setFilters.hasOwnProperty(a.toLowerCase())?z(function(a,c){var e,f=d(a,b),g=f.length;while(g--)e=y.call(a,f[g]),a[e]=!(c[e]=f[g])}):function(a){return d(a,0,c)}):d}},pseudos:{not:z(function(a){var b=[],c=[],d=i(a.replace(L,"$1"));return d[o]?z(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)if(f=g[h])a[h]=!(b[h]=f)}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:z(function(a){return function(b){return bc(a,b).length>0}}),contains:z(function(a){return function(b){return(b.textContent||b.innerText||f(b)).indexOf(a)>-1}}),enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&!!a.checked||b==="option"&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},parent:function(a){return!e.pseudos.empty(a)},empty:function(a){var b;a=a.firstChild;while(a){if(a.nodeName>"@"||(b=a.nodeType)===3||b===4)return!1;a=a.nextSibling}return!0},header:function(a){return T.test(a.nodeName)},text:function(a){var b,c;return a.nodeName.toLowerCase()==="input"&&(b=a.type)==="text"&&((c=a.getAttribute("type"))==null||c.toLowerCase()===b)},radio:bd("radio"),checkbox:bd("checkbox"),file:bd("file"),password:bd("password"),image:bd("image"),submit:be("submit"),reset:be("reset"),button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&a.type==="button"||b==="button"},input:function(a){return U.test(a.nodeName)},focus:function(a){var b=a.ownerDocument;return a===b.activeElement&&(!b.hasFocus||b.hasFocus())&&(!!a.type||!!a.href)},active:function(a){return a===a.ownerDocument.activeElement},first:bf(function(a,b,c){return[0]}),last:bf(function(a,b,c){return[b-1]}),eq:bf(function(a,b,c){return[c<0?c+b:c]}),even:bf(function(a,b,c){for(var d=0;d<b;d+=2)a.push(d);return a}),odd:bf(function(a,b,c){for(var d=1;d<b;d+=2)a.push(d);return a}),lt:bf(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:bf(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},j=s.compareDocumentPosition?function(a,b){return a===b?(k=!0,0):(!a.compareDocumentPosition||!b.compareDocumentPosition?a.compareDocumentPosition:a.compareDocumentPosition(b)&4)?-1:1}:function(a,b){if(a===b)return k=!0,0;if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,h=b.parentNode,i=g;if(g===h)return bg(a,b);if(!g)return-1;if(!h)return 1;while(i)e.unshift(i),i=i.parentNode;i=h;while(i)f.unshift(i),i=i.parentNode;c=e.length,d=f.length;for(var j=0;j<c&&j<d;j++)if(e[j]!==f[j])return bg(e[j],f[j]);return j===c?bg(a,f[j],-1):bg(e[j],b,1)},[0,0].sort(j),m=!k,bc.uniqueSort=function(a){var b,c=1;k=m,a.sort(j);if(k)for(;b=a[c];c++)b===a[c-1]&&a.splice(c--,1);return a},bc.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},i=bc.compile=function(a,b){var c,d=[],e=[],f=D[o][a];if(!f){b||(b=bh(a)),c=b.length;while(c--)f=bm(b[c]),f[o]?d.push(f):e.push(f);f=D(a,bn(e,d))}return f},r.querySelectorAll&&function(){var a,b=bp,c=/'|\\/g,d=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,e=[":focus"],f=[":active",":focus"],h=s.matchesSelector||s.mozMatchesSelector||s.webkitMatchesSelector||s.oMatchesSelector||s.msMatchesSelector;X(function(a){a.innerHTML="<select><option selected=''></option></select>",a.querySelectorAll("[selected]").length||e.push("\\["+E+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),a.querySelectorAll(":checked").length||e.push(":checked")}),X(function(a){a.innerHTML="<p test=''></p>",a.querySelectorAll("[test^='']").length&&e.push("[*^$]="+E+"*(?:\"\"|'')"),a.innerHTML="<input type='hidden'/>",a.querySelectorAll(":enabled").length||e.push(":enabled",":disabled")}),e=new RegExp(e.join("|")),bp=function(a,d,f,g,h){if(!g&&!h&&(!e||!e.test(a))){var i,j,k=!0,l=o,m=d,n=d.nodeType===9&&a;if(d.nodeType===1&&d.nodeName.toLowerCase()!=="object"){i=bh(a),(k=d.getAttribute("id"))?l=k.replace(c,"\\$&"):d.setAttribute("id",l),l="[id='"+l+"'] ",j=i.length;while(j--)i[j]=l+i[j].join("");m=R.test(a)&&d.parentNode||d,n=i.join(",")}if(n)try{return w.apply(f,x.call(m.querySelectorAll(n),0)),f}catch(p){}finally{k||d.removeAttribute("id")}}return b(a,d,f,g,h)},h&&(X(function(b){a=h.call(b,"div");try{h.call(b,"[test!='']:sizzle"),f.push("!=",J)}catch(c){}}),f=new RegExp(f.join("|")),bc.matchesSelector=function(b,c){c=c.replace(d,"='$1']");if(!g(b)&&!f.test(c)&&(!e||!e.test(c)))try{var i=h.call(b,c);if(i||a||b.document&&b.document.nodeType!==11)return i}catch(j){}return bc(c,null,null,[b]).length>0})}(),e.pseudos.nth=e.pseudos.eq,e.filters=bq.prototype=e.pseudos,e.setFilters=new bq,bc.attr=p.attr,p.find=bc,p.expr=bc.selectors,p.expr[":"]=p.expr.pseudos,p.unique=bc.uniqueSort,p.text=bc.getText,p.isXMLDoc=bc.isXML,p.contains=bc.contains}(a);var bc=/Until$/,bd=/^(?:parents|prev(?:Until|All))/,be=/^.[^:#\[\.,]*$/,bf=p.expr.match.needsContext,bg={children:!0,contents:!0,next:!0,prev:!0};p.fn.extend({find:function(a){var b,c,d,e,f,g,h=this;if(typeof a!="string")return p(a).filter(function(){for(b=0,c=h.length;b<c;b++)if(p.contains(h[b],this))return!0});g=this.pushStack("","find",a);for(b=0,c=this.length;b<c;b++){d=g.length,p.find(a,this[b],g);if(b>0)for(e=d;e<g.length;e++)for(f=0;f<d;f++)if(g[f]===g[e]){g.splice(e--,1);break}}return g},has:function(a){var b,c=p(a,this),d=c.length;return this.filter(function(){for(b=0;b<d;b++)if(p.contains(this,c[b]))return!0})},not:function(a){return this.pushStack(bj(this,a,!1),"not",a)},filter:function(a){return this.pushStack(bj(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?bf.test(a)?p(a,this.context).index(this[0])>=0:p.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c,d=0,e=this.length,f=[],g=bf.test(a)||typeof a!="string"?p(a,b||this.context):0;for(;d<e;d++){c=this[d];while(c&&c.ownerDocument&&c!==b&&c.nodeType!==11){if(g?g.index(c)>-1:p.find.matchesSelector(c,a)){f.push(c);break}c=c.parentNode}}return f=f.length>1?p.unique(f):f,this.pushStack(f,"closest",a)},index:function(a){return a?typeof a=="string"?p.inArray(this[0],p(a)):p.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?d:p.unique(d))},addBack:function(a){return this.add(a==null?this.prevObject:this.prevObject.filter(a))}}),p.fn.andSelf=p.fn.addBack,p.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return p.dir(a,"parentNode")},parentsUntil:function(a,b,c){return p.dir(a,"parentNode",c)},next:function(a){return bi(a,"nextSibling")},prev:function(a){return bi(a,"previousSibling")},nextAll:function(a){return p.dir(a,"nextSibling")},prevAll:function(a){return p.dir(a,"previousSibling")},nextUntil:function(a,b,c){return p.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return p.dir(a,"previousSibling",c)},siblings:function(a){return p.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return p.sibling(a.firstChild)},contents:function(a){return p.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:p.merge([],a.childNodes)}},function(a,b){p.fn[a]=function(c,d){var e=p.map(this,b,c);return bc.test(a)||(d=c),d&&typeof d=="string"&&(e=p.filter(d,e)),e=this.length>1&&!bg[a]?p.unique(e):e,this.length>1&&bd.test(a)&&(e=e.reverse()),this.pushStack(e,a,k.call(arguments).join(","))}}),p.extend({filter:function(a,b,c){return c&&(a=":not("+a+")"),b.length===1?p.find.matchesSelector(b[0],a)?[b[0]]:[]:p.find.matches(a,b)},dir:function(a,c,d){var e=[],f=a[c];while(f&&f.nodeType!==9&&(d===b||f.nodeType!==1||!p(f).is(d)))f.nodeType===1&&e.push(f),f=f[c];return e},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var bl="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",bm=/ jQuery\d+="(?:null|\d+)"/g,bn=/^\s+/,bo=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bp=/<([\w:]+)/,bq=/<tbody/i,br=/<|&#?\w+;/,bs=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,bu=new RegExp("<(?:"+bl+")[\\s/>]","i"),bv=/^(?:checkbox|radio)$/,bw=/checked\s*(?:[^=]|=\s*.checked.)/i,bx=/\/(java|ecma)script/i,by=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,bz={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bA=bk(e),bB=bA.appendChild(e.createElement("div"));bz.optgroup=bz.option,bz.tbody=bz.tfoot=bz.colgroup=bz.caption=bz.thead,bz.th=bz.td,p.support.htmlSerialize||(bz._default=[1,"X<div>","</div>"]),p.fn.extend({text:function(a){return p.access(this,function(a){return a===b?p.text(this):this.empty().append((this[0]&&this[0].ownerDocument||e).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(p.isFunction(a))return this.each(function(b){p(this).wrapAll(a.call(this,b))});if(this[0]){var b=p(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return p.isFunction(a)?this.each(function(b){p(this).wrapInner(a.call(this,b))}):this.each(function(){var b=p(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=p.isFunction(a);return this.each(function(c){p(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){p.nodeName(this,"body")||p(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(a,this.firstChild)})},before:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(a,this),"before",this.selector)}},after:function(){if(!bh(this[0]))return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=p.clean(arguments);return this.pushStack(p.merge(this,a),"after",this.selector)}},remove:function(a,b){var c,d=0;for(;(c=this[d])!=null;d++)if(!a||p.filter(a,[c]).length)!b&&c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),p.cleanData([c])),c.parentNode&&c.parentNode.removeChild(c);return this},empty:function(){var a,b=0;for(;(a=this[b])!=null;b++){a.nodeType===1&&p.cleanData(a.getElementsByTagName("*"));while(a.firstChild)a.removeChild(a.firstChild)}return this},clone:function(a,b){return a=a==null?!1:a,b=b==null?a:b,this.map(function(){return p.clone(this,a,b)})},html:function(a){return p.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(bm,""):b;if(typeof a=="string"&&!bs.test(a)&&(p.support.htmlSerialize||!bu.test(a))&&(p.support.leadingWhitespace||!bn.test(a))&&!bz[(bp.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(bo,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(p.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(f){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){return bh(this[0])?this.length?this.pushStack(p(p.isFunction(a)?a():a),"replaceWith",a):this:p.isFunction(a)?this.each(function(b){var c=p(this),d=c.html();c.replaceWith(a.call(this,b,d))}):(typeof a!="string"&&(a=p(a).detach()),this.each(function(){var b=this.nextSibling,c=this.parentNode;p(this).remove(),b?p(b).before(a):p(c).append(a)}))},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){a=[].concat.apply([],a);var e,f,g,h,i=0,j=a[0],k=[],l=this.length;if(!p.support.checkClone&&l>1&&typeof j=="string"&&bw.test(j))return this.each(function(){p(this).domManip(a,c,d)});if(p.isFunction(j))return this.each(function(e){var f=p(this);a[0]=j.call(this,e,c?f.html():b),f.domManip(a,c,d)});if(this[0]){e=p.buildFragment(a,this,k),g=e.fragment,f=g.firstChild,g.childNodes.length===1&&(g=f);if(f){c=c&&p.nodeName(f,"tr");for(h=e.cacheable||l-1;i<l;i++)d.call(c&&p.nodeName(this[i],"table")?bC(this[i],"tbody"):this[i],i===h?g:p.clone(g,!0,!0))}g=f=null,k.length&&p.each(k,function(a,b){b.src?p.ajax?p.ajax({url:b.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):p.error("no ajax"):p.globalEval((b.text||b.textContent||b.innerHTML||"").replace(by,"")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),p.buildFragment=function(a,c,d){var f,g,h,i=a[0];return c=c||e,c=!c.nodeType&&c[0]||c,c=c.ownerDocument||c,a.length===1&&typeof i=="string"&&i.length<512&&c===e&&i.charAt(0)==="<"&&!bt.test(i)&&(p.support.checkClone||!bw.test(i))&&(p.support.html5Clone||!bu.test(i))&&(g=!0,f=p.fragments[i],h=f!==b),f||(f=c.createDocumentFragment(),p.clean(a,c,f,d),g&&(p.fragments[i]=h&&f)),{fragment:f,cacheable:g}},p.fragments={},p.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){p.fn[a]=function(c){var d,e=0,f=[],g=p(c),h=g.length,i=this.length===1&&this[0].parentNode;if((i==null||i&&i.nodeType===11&&i.childNodes.length===1)&&h===1)return g[b](this[0]),this;for(;e<h;e++)d=(e>0?this.clone(!0):this).get(),p(g[e])[b](d),f=f.concat(d);return this.pushStack(f,a,g.selector)}}),p.extend({clone:function(a,b,c){var d,e,f,g;p.support.html5Clone||p.isXMLDoc(a)||!bu.test("<"+a.nodeName+">")?g=a.cloneNode(!0):(bB.innerHTML=a.outerHTML,bB.removeChild(g=bB.firstChild));if((!p.support.noCloneEvent||!p.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!p.isXMLDoc(a)){bE(a,g),d=bF(a),e=bF(g);for(f=0;d[f];++f)e[f]&&bE(d[f],e[f])}if(b){bD(a,g);if(c){d=bF(a),e=bF(g);for(f=0;d[f];++f)bD(d[f],e[f])}}return d=e=null,g},clean:function(a,b,c,d){var f,g,h,i,j,k,l,m,n,o,q,r,s=b===e&&bA,t=[];if(!b||typeof b.createDocumentFragment=="undefined")b=e;for(f=0;(h=a[f])!=null;f++){typeof h=="number"&&(h+="");if(!h)continue;if(typeof h=="string")if(!br.test(h))h=b.createTextNode(h);else{s=s||bk(b),l=b.createElement("div"),s.appendChild(l),h=h.replace(bo,"<$1></$2>"),i=(bp.exec(h)||["",""])[1].toLowerCase(),j=bz[i]||bz._default,k=j[0],l.innerHTML=j[1]+h+j[2];while(k--)l=l.lastChild;if(!p.support.tbody){m=bq.test(h),n=i==="table"&&!m?l.firstChild&&l.firstChild.childNodes:j[1]==="<table>"&&!m?l.childNodes:[];for(g=n.length-1;g>=0;--g)p.nodeName(n[g],"tbody")&&!n[g].childNodes.length&&n[g].parentNode.removeChild(n[g])}!p.support.leadingWhitespace&&bn.test(h)&&l.insertBefore(b.createTextNode(bn.exec(h)[0]),l.firstChild),h=l.childNodes,l.parentNode.removeChild(l)}h.nodeType?t.push(h):p.merge(t,h)}l&&(h=l=s=null);if(!p.support.appendChecked)for(f=0;(h=t[f])!=null;f++)p.nodeName(h,"input")?bG(h):typeof h.getElementsByTagName!="undefined"&&p.grep(h.getElementsByTagName("input"),bG);if(c){q=function(a){if(!a.type||bx.test(a.type))return d?d.push(a.parentNode?a.parentNode.removeChild(a):a):c.appendChild(a)};for(f=0;(h=t[f])!=null;f++)if(!p.nodeName(h,"script")||!q(h))c.appendChild(h),typeof h.getElementsByTagName!="undefined"&&(r=p.grep(p.merge([],h.getElementsByTagName("script")),q),t.splice.apply(t,[f+1,0].concat(r)),f+=r.length)}return t},cleanData:function(a,b){var c,d,e,f,g=0,h=p.expando,i=p.cache,j=p.support.deleteExpando,k=p.event.special;for(;(e=a[g])!=null;g++)if(b||p.acceptData(e)){d=e[h],c=d&&i[d];if(c){if(c.events)for(f in c.events)k[f]?p.event.remove(e,f):p.removeEvent(e,f,c.handle);i[d]&&(delete i[d],j?delete e[h]:e.removeAttribute?e.removeAttribute(h):e[h]=null,p.deletedIds.push(d))}}}}),function(){var a,b;p.uaMatch=function(a){a=a.toLowerCase();var b=/(chrome)[ \/]([\w.]+)/.exec(a)||/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||a.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},a=p.uaMatch(g.userAgent),b={},a.browser&&(b[a.browser]=!0,b.version=a.version),b.chrome?b.webkit=!0:b.webkit&&(b.safari=!0),p.browser=b,p.sub=function(){function a(b,c){return new a.fn.init(b,c)}p.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function c(c,d){return d&&d instanceof p&&!(d instanceof a)&&(d=a(d)),p.fn.init.call(this,c,d,b)},a.fn.init.prototype=a.fn;var b=a(e);return a}}();var bH,bI,bJ,bK=/alpha\([^)]*\)/i,bL=/opacity=([^)]*)/,bM=/^(top|right|bottom|left)$/,bN=/^(none|table(?!-c[ea]).+)/,bO=/^margin/,bP=new RegExp("^("+q+")(.*)$","i"),bQ=new RegExp("^("+q+")(?!px)[a-z%]+$","i"),bR=new RegExp("^([-+])=("+q+")","i"),bS={},bT={position:"absolute",visibility:"hidden",display:"block"},bU={letterSpacing:0,fontWeight:400},bV=["Top","Right","Bottom","Left"],bW=["Webkit","O","Moz","ms"],bX=p.fn.toggle;p.fn.extend({css:function(a,c){return p.access(this,function(a,c,d){return d!==b?p.style(a,c,d):p.css(a,c)},a,c,arguments.length>1)},show:function(){return b$(this,!0)},hide:function(){return b$(this)},toggle:function(a,b){var c=typeof a=="boolean";return p.isFunction(a)&&p.isFunction(b)?bX.apply(this,arguments):this.each(function(){(c?a:bZ(this))?p(this).show():p(this).hide()})}}),p.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bH(a,"opacity");return c===""?"1":c}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":p.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!a||a.nodeType===3||a.nodeType===8||!a.style)return;var f,g,h,i=p.camelCase(c),j=a.style;c=p.cssProps[i]||(p.cssProps[i]=bY(j,i)),h=p.cssHooks[c]||p.cssHooks[i];if(d===b)return h&&"get"in h&&(f=h.get(a,!1,e))!==b?f:j[c];g=typeof d,g==="string"&&(f=bR.exec(d))&&(d=(f[1]+1)*f[2]+parseFloat(p.css(a,c)),g="number");if(d==null||g==="number"&&isNaN(d))return;g==="number"&&!p.cssNumber[i]&&(d+="px");if(!h||!("set"in h)||(d=h.set(a,d,e))!==b)try{j[c]=d}catch(k){}},css:function(a,c,d,e){var f,g,h,i=p.camelCase(c);return c=p.cssProps[i]||(p.cssProps[i]=bY(a.style,i)),h=p.cssHooks[c]||p.cssHooks[i],h&&"get"in h&&(f=h.get(a,!0,e)),f===b&&(f=bH(a,c)),f==="normal"&&c in bU&&(f=bU[c]),d||e!==b?(g=parseFloat(f),d||p.isNumeric(g)?g||0:f):f},swap:function(a,b,c){var d,e,f={};for(e in b)f[e]=a.style[e],a.style[e]=b[e];d=c.call(a);for(e in b)a.style[e]=f[e];return d}}),a.getComputedStyle?bH=function(b,c){var d,e,f,g,h=a.getComputedStyle(b,null),i=b.style;return h&&(d=h[c],d===""&&!p.contains(b.ownerDocument,b)&&(d=p.style(b,c)),bQ.test(d)&&bO.test(c)&&(e=i.width,f=i.minWidth,g=i.maxWidth,i.minWidth=i.maxWidth=i.width=d,d=h.width,i.width=e,i.minWidth=f,i.maxWidth=g)),d}:e.documentElement.currentStyle&&(bH=function(a,b){var c,d,e=a.currentStyle&&a.currentStyle[b],f=a.style;return e==null&&f&&f[b]&&(e=f[b]),bQ.test(e)&&!bM.test(b)&&(c=f.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":e,e=f.pixelLeft+"px",f.left=c,d&&(a.runtimeStyle.left=d)),e===""?"auto":e}),p.each(["height","width"],function(a,b){p.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth===0&&bN.test(bH(a,"display"))?p.swap(a,bT,function(){return cb(a,b,d)}):cb(a,b,d)},set:function(a,c,d){return b_(a,c,d?ca(a,b,d,p.support.boxSizing&&p.css(a,"boxSizing")==="border-box"):0)}}}),p.support.opacity||(p.cssHooks.opacity={get:function(a,b){return bL.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=p.isNumeric(b)?"alpha(opacity="+b*100+")":"",f=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&p.trim(f.replace(bK,""))===""&&c.removeAttribute){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bK.test(f)?f.replace(bK,e):f+" "+e}}),p(function(){p.support.reliableMarginRight||(p.cssHooks.marginRight={get:function(a,b){return p.swap(a,{display:"inline-block"},function(){if(b)return bH(a,"marginRight")})}}),!p.support.pixelPosition&&p.fn.position&&p.each(["top","left"],function(a,b){p.cssHooks[b]={get:function(a,c){if(c){var d=bH(a,b);return bQ.test(d)?p(a).position()[b]+"px":d}}}})}),p.expr&&p.expr.filters&&(p.expr.filters.hidden=function(a){return a.offsetWidth===0&&a.offsetHeight===0||!p.support.reliableHiddenOffsets&&(a.style&&a.style.display||bH(a,"display"))==="none"},p.expr.filters.visible=function(a){return!p.expr.filters.hidden(a)}),p.each({margin:"",padding:"",border:"Width"},function(a,b){p.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bV[d]+b]=e[d]||e[d-2]||e[0];return f}},bO.test(a)||(p.cssHooks[a+b].set=b_)});var cd=/%20/g,ce=/\[\]$/,cf=/\r?\n/g,cg=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ch=/^(?:select|textarea)/i;p.fn.extend({serialize:function(){return p.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?p.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ch.test(this.nodeName)||cg.test(this.type))}).map(function(a,b){var c=p(this).val();return c==null?null:p.isArray(c)?p.map(c,function(a,c){return{name:b.name,value:a.replace(cf,"\r\n")}}):{name:b.name,value:c.replace(cf,"\r\n")}}).get()}}),p.param=function(a,c){var d,e=[],f=function(a,b){b=p.isFunction(b)?b():b==null?"":b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=p.ajaxSettings&&p.ajaxSettings.traditional);if(p.isArray(a)||a.jquery&&!p.isPlainObject(a))p.each(a,function(){f(this.name,this.value)});else for(d in a)ci(d,a[d],c,f);return e.join("&").replace(cd,"+")};var cj,ck,cl=/#.*$/,cm=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,cn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,co=/^(?:GET|HEAD)$/,cp=/^\/\//,cq=/\?/,cr=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,cs=/([?&])_=[^&]*/,ct=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,cu=p.fn.load,cv={},cw={},cx=["*/"]+["*"];try{ck=f.href}catch(cy){ck=e.createElement("a"),ck.href="",ck=ck.href}cj=ct.exec(ck.toLowerCase())||[],p.fn.load=function(a,c,d){if(typeof a!="string"&&cu)return cu.apply(this,arguments);if(!this.length)return this;var e,f,g,h=this,i=a.indexOf(" ");return i>=0&&(e=a.slice(i,a.length),a=a.slice(0,i)),p.isFunction(c)?(d=c,c=b):c&&typeof c=="object"&&(f="POST"),p.ajax({url:a,type:f,dataType:"html",data:c,complete:function(a,b){d&&h.each(d,g||[a.responseText,b,a])}}).done(function(a){g=arguments,h.html(e?p("<div>").append(a.replace(cr,"")).find(e):a)}),this},p.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){p.fn[b]=function(a){return this.on(b,a)}}),p.each(["get","post"],function(a,c){p[c]=function(a,d,e,f){return p.isFunction(d)&&(f=f||e,e=d,d=b),p.ajax({type:c,url:a,data:d,success:e,dataType:f})}}),p.extend({getScript:function(a,c){return p.get(a,b,c,"script")},getJSON:function(a,b,c){return p.get(a,b,c,"json")},ajaxSetup:function(a,b){return b?cB(a,p.ajaxSettings):(b=a,a=p.ajaxSettings),cB(a,b),a},ajaxSettings:{url:ck,isLocal:cn.test(cj[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":cx},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":p.parseJSON,"text xml":p.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:cz(cv),ajaxTransport:cz(cw),ajax:function(a,c){function y(a,c,f,i){var k,s,t,u,w,y=c;if(v===2)return;v=2,h&&clearTimeout(h),g=b,e=i||"",x.readyState=a>0?4:0,f&&(u=cC(l,x,f));if(a>=200&&a<300||a===304)l.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(p.lastModified[d]=w),w=x.getResponseHeader("Etag"),w&&(p.etag[d]=w)),a===304?(y="notmodified",k=!0):(k=cD(l,u),y=k.state,s=k.data,t=k.error,k=!t);else{t=y;if(!y||a)y="error",a<0&&(a=0)}x.status=a,x.statusText=(c||y)+"",k?o.resolveWith(m,[s,y,x]):o.rejectWith(m,[x,y,t]),x.statusCode(r),r=b,j&&n.trigger("ajax"+(k?"Success":"Error"),[x,l,k?s:t]),q.fireWith(m,[x,y]),j&&(n.trigger("ajaxComplete",[x,l]),--p.active||p.event.trigger("ajaxStop"))}typeof a=="object"&&(c=a,a=b),c=c||{};var d,e,f,g,h,i,j,k,l=p.ajaxSetup({},c),m=l.context||l,n=m!==l&&(m.nodeType||m instanceof p)?p(m):p.event,o=p.Deferred(),q=p.Callbacks("once memory"),r=l.statusCode||{},t={},u={},v=0,w="canceled",x={readyState:0,setRequestHeader:function(a,b){if(!v){var c=a.toLowerCase();a=u[c]=u[c]||a,t[a]=b}return this},getAllResponseHeaders:function(){return v===2?e:null},getResponseHeader:function(a){var c;if(v===2){if(!f){f={};while(c=cm.exec(e))f[c[1].toLowerCase()]=c[2]}c=f[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){return v||(l.mimeType=a),this},abort:function(a){return a=a||w,g&&g.abort(a),y(0,a),this}};o.promise(x),x.success=x.done,x.error=x.fail,x.complete=q.add,x.statusCode=function(a){if(a){var b;if(v<2)for(b in a)r[b]=[r[b],a[b]];else b=a[x.status],x.always(b)}return this},l.url=((a||l.url)+"").replace(cl,"").replace(cp,cj[1]+"//"),l.dataTypes=p.trim(l.dataType||"*").toLowerCase().split(s),l.crossDomain==null&&(i=ct.exec(l.url.toLowerCase())||!1,l.crossDomain=i&&i.join(":")+(i[3]?"":i[1]==="http:"?80:443)!==cj.join(":")+(cj[3]?"":cj[1]==="http:"?80:443)),l.data&&l.processData&&typeof l.data!="string"&&(l.data=p.param(l.data,l.traditional)),cA(cv,l,c,x);if(v===2)return x;j=l.global,l.type=l.type.toUpperCase(),l.hasContent=!co.test(l.type),j&&p.active++===0&&p.event.trigger("ajaxStart");if(!l.hasContent){l.data&&(l.url+=(cq.test(l.url)?"&":"?")+l.data,delete l.data),d=l.url;if(l.cache===!1){var z=p.now(),A=l.url.replace(cs,"$1_="+z);l.url=A+(A===l.url?(cq.test(l.url)?"&":"?")+"_="+z:"")}}(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&x.setRequestHeader("Content-Type",l.contentType),l.ifModified&&(d=d||l.url,p.lastModified[d]&&x.setRequestHeader("If-Modified-Since",p.lastModified[d]),p.etag[d]&&x.setRequestHeader("If-None-Match",p.etag[d])),x.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+(l.dataTypes[0]!=="*"?", "+cx+"; q=0.01":""):l.accepts["*"]);for(k in l.headers)x.setRequestHeader(k,l.headers[k]);if(!l.beforeSend||l.beforeSend.call(m,x,l)!==!1&&v!==2){w="abort";for(k in{success:1,error:1,complete:1})x[k](l[k]);g=cA(cw,l,c,x);if(!g)y(-1,"No Transport");else{x.readyState=1,j&&n.trigger("ajaxSend",[x,l]),l.async&&l.timeout>0&&(h=setTimeout(function(){x.abort("timeout")},l.timeout));try{v=1,g.send(t,y)}catch(B){if(v<2)y(-1,B);else throw B}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var cE=[],cF=/\?/,cG=/(=)\?(?=&|$)|\?\?/,cH=p.now();p.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=cE.pop()||p.expando+"_"+cH++;return this[a]=!0,a}}),p.ajaxPrefilter("json jsonp",function(c,d,e){var f,g,h,i=c.data,j=c.url,k=c.jsonp!==!1,l=k&&cG.test(j),m=k&&!l&&typeof i=="string"&&!(c.contentType||"").indexOf("application/x-www-form-urlencoded")&&cG.test(i);if(c.dataTypes[0]==="jsonp"||l||m)return f=c.jsonpCallback=p.isFunction(c.jsonpCallback)?c.jsonpCallback():c.jsonpCallback,g=a[f],l?c.url=j.replace(cG,"$1"+f):m?c.data=i.replace(cG,"$1"+f):k&&(c.url+=(cF.test(j)?"&":"?")+c.jsonp+"="+f),c.converters["script json"]=function(){return h||p.error(f+" was not called"),h[0]},c.dataTypes[0]="json",a[f]=function(){h=arguments},e.always(function(){a[f]=g,c[f]&&(c.jsonpCallback=d.jsonpCallback,cE.push(f)),h&&p.isFunction(g)&&g(h[0]),h=g=b}),"script"}),p.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){return p.globalEval(a),a}}}),p.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),p.ajaxTransport("script",function(a){if(a.crossDomain){var c,d=e.head||e.getElementsByTagName("head")[0]||e.documentElement;return{send:function(f,g){c=e.createElement("script"),c.async="async",a.scriptCharset&&(c.charset=a.scriptCharset),c.src=a.url,c.onload=c.onreadystatechange=function(a,e){if(e||!c.readyState||/loaded|complete/.test(c.readyState))c.onload=c.onreadystatechange=null,d&&c.parentNode&&d.removeChild(c),c=b,e||g(200,"success")},d.insertBefore(c,d.firstChild)},abort:function(){c&&c.onload(0,1)}}}});var cI,cJ=a.ActiveXObject?function(){for(var a in cI)cI[a](0,1)}:!1,cK=0;p.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&cL()||cM()}:cL,function(a){p.extend(p.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(p.ajaxSettings.xhr()),p.support.ajax&&p.ajaxTransport(function(c){if(!c.crossDomain||p.support.cors){var d;return{send:function(e,f){var g,h,i=c.xhr();c.username?i.open(c.type,c.url,c.async,c.username,c.password):i.open(c.type,c.url,c.async);if(c.xhrFields)for(h in c.xhrFields)i[h]=c.xhrFields[h];c.mimeType&&i.overrideMimeType&&i.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(h in e)i.setRequestHeader(h,e[h])}catch(j){}i.send(c.hasContent&&c.data||null),d=function(a,e){var h,j,k,l,m;try{if(d&&(e||i.readyState===4)){d=b,g&&(i.onreadystatechange=p.noop,cJ&&delete cI[g]);if(e)i.readyState!==4&&i.abort();else{h=i.status,k=i.getAllResponseHeaders(),l={},m=i.responseXML,m&&m.documentElement&&(l.xml=m);try{l.text=i.responseText}catch(a){}try{j=i.statusText}catch(n){j=""}!h&&c.isLocal&&!c.crossDomain?h=l.text?200:404:h===1223&&(h=204)}}}catch(o){e||f(-1,o)}l&&f(h,j,l,k)},c.async?i.readyState===4?setTimeout(d,0):(g=++cK,cJ&&(cI||(cI={},p(a).unload(cJ)),cI[g]=d),i.onreadystatechange=d):d()},abort:function(){d&&d(0,1)}}}});var cN,cO,cP=/^(?:toggle|show|hide)$/,cQ=new RegExp("^(?:([-+])=|)("+q+")([a-z%]*)$","i"),cR=/queueHooks$/,cS=[cY],cT={"*":[function(a,b){var c,d,e=this.createTween(a,b),f=cQ.exec(b),g=e.cur(),h=+g||0,i=1,j=20;if(f){c=+f[2],d=f[3]||(p.cssNumber[a]?"":"px");if(d!=="px"&&h){h=p.css(e.elem,a,!0)||c||1;do i=i||".5",h=h/i,p.style(e.elem,a,h+d);while(i!==(i=e.cur()/g)&&i!==1&&--j)}e.unit=d,e.start=h,e.end=f[1]?h+(f[1]+1)*c:c}return e}]};p.Animation=p.extend(cW,{tweener:function(a,b){p.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");var c,d=0,e=a.length;for(;d<e;d++)c=a[d],cT[c]=cT[c]||[],cT[c].unshift(b)},prefilter:function(a,b){b?cS.unshift(a):cS.push(a)}}),p.Tween=cZ,cZ.prototype={constructor:cZ,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(p.cssNumber[c]?"":"px")},cur:function(){var a=cZ.propHooks[this.prop];return a&&a.get?a.get(this):cZ.propHooks._default.get(this)},run:function(a){var b,c=cZ.propHooks[this.prop];return this.options.duration?this.pos=b=p.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):cZ.propHooks._default.set(this),this}},cZ.prototype.init.prototype=cZ.prototype,cZ.propHooks={_default:{get:function(a){var b;return a.elem[a.prop]==null||!!a.elem.style&&a.elem.style[a.prop]!=null?(b=p.css(a.elem,a.prop,!1,""),!b||b==="auto"?0:b):a.elem[a.prop]},set:function(a){p.fx.step[a.prop]?p.fx.step[a.prop](a):a.elem.style&&(a.elem.style[p.cssProps[a.prop]]!=null||p.cssHooks[a.prop])?p.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},cZ.propHooks.scrollTop=cZ.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},p.each(["toggle","show","hide"],function(a,b){var c=p.fn[b];p.fn[b]=function(d,e,f){return d==null||typeof d=="boolean"||!a&&p.isFunction(d)&&p.isFunction(e)?c.apply(this,arguments):this.animate(c$(b,!0),d,e,f)}}),p.fn.extend({fadeTo:function(a,b,c,d){return this.filter(bZ).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=p.isEmptyObject(a),f=p.speed(b,c,d),g=function(){var b=cW(this,p.extend({},a),f);e&&b.stop(!0)};return e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,c,d){var e=function(a){var b=a.stop;delete a.stop,b(d)};return typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,c=a!=null&&a+"queueHooks",f=p.timers,g=p._data(this);if(c)g[c]&&g[c].stop&&e(g[c]);else for(c in g)g[c]&&g[c].stop&&cR.test(c)&&e(g[c]);for(c=f.length;c--;)f[c].elem===this&&(a==null||f[c].queue===a)&&(f[c].anim.stop(d),b=!1,f.splice(c,1));(b||!d)&&p.dequeue(this,a)})}}),p.each({slideDown:c$("show"),slideUp:c$("hide"),slideToggle:c$("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){p.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),p.speed=function(a,b,c){var d=a&&typeof a=="object"?p.extend({},a):{complete:c||!c&&b||p.isFunction(a)&&a,duration:a,easing:c&&b||b&&!p.isFunction(b)&&b};d.duration=p.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in p.fx.speeds?p.fx.speeds[d.duration]:p.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";return d.old=d.complete,d.complete=function(){p.isFunction(d.old)&&d.old.call(this),d.queue&&p.dequeue(this,d.queue)},d},p.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},p.timers=[],p.fx=cZ.prototype.init,p.fx.tick=function(){var a,b=p.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||p.fx.stop()},p.fx.timer=function(a){a()&&p.timers.push(a)&&!cO&&(cO=setInterval(p.fx.tick,p.fx.interval))},p.fx.interval=13,p.fx.stop=function(){clearInterval(cO),cO=null},p.fx.speeds={slow:600,fast:200,_default:400},p.fx.step={},p.expr&&p.expr.filters&&(p.expr.filters.animated=function(a){return p.grep(p.timers,function(b){return a===b.elem}).length});var c_=/^(?:body|html)$/i;p.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){p.offset.setOffset(this,a,b)});var c,d,e,f,g,h,i,j={top:0,left:0},k=this[0],l=k&&k.ownerDocument;if(!l)return;return(d=l.body)===k?p.offset.bodyOffset(k):(c=l.documentElement,p.contains(c,k)?(typeof k.getBoundingClientRect!="undefined"&&(j=k.getBoundingClientRect()),e=da(l),f=c.clientTop||d.clientTop||0,g=c.clientLeft||d.clientLeft||0,h=e.pageYOffset||c.scrollTop,i=e.pageXOffset||c.scrollLeft,{top:j.top+h-f,left:j.left+i-g}):j)},p.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;return p.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(p.css(a,"marginTop"))||0,c+=parseFloat(p.css(a,"marginLeft"))||0),{top:b,left:c}},setOffset:function(a,b,c){var d=p.css(a,"position");d==="static"&&(a.style.position="relative");var e=p(a),f=e.offset(),g=p.css(a,"top"),h=p.css(a,"left"),i=(d==="absolute"||d==="fixed")&&p.inArray("auto",[g,h])>-1,j={},k={},l,m;i?(k=e.position(),l=k.top,m=k.left):(l=parseFloat(g)||0,m=parseFloat(h)||0),p.isFunction(b)&&(b=b.call(a,c,f)),b.top!=null&&(j.top=b.top-f.top+l),b.left!=null&&(j.left=b.left-f.left+m),"using"in b?b.using.call(a,j):e.css(j)}},p.fn.extend({position:function(){if(!this[0])return;var a=this[0],b=this.offsetParent(),c=this.offset(),d=c_.test(b[0].nodeName)?{top:0,left:0}:b.offset();return c.top-=parseFloat(p.css(a,"marginTop"))||0,c.left-=parseFloat(p.css(a,"marginLeft"))||0,d.top+=parseFloat(p.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(p.css(b[0],"borderLeftWidth"))||0,{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||e.body;while(a&&!c_.test(a.nodeName)&&p.css(a,"position")==="static")a=a.offsetParent;return a||e.body})}}),p.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);p.fn[a]=function(e){return p.access(this,function(a,e,f){var g=da(a);if(f===b)return g?c in g?g[c]:g.document.documentElement[e]:a[e];g?g.scrollTo(d?p(g).scrollLeft():f,d?f:p(g).scrollTop()):a[e]=f},a,e,arguments.length,null)}}),p.each({Height:"height",Width:"width"},function(a,c){p.each({padding:"inner"+a,content:c,"":"outer"+a},function(d,e){p.fn[e]=function(e,f){var g=arguments.length&&(d||typeof e!="boolean"),h=d||(e===!0||f===!0?"margin":"border");return p.access(this,function(c,d,e){var f;return p.isWindow(c)?c.document.documentElement["client"+a]:c.nodeType===9?(f=c.documentElement,Math.max(c.body["scroll"+a],f["scroll"+a],c.body["offset"+a],f["offset"+a],f["client"+a])):e===b?p.css(c,d,e,h):p.style(c,d,e,h)},c,g?e:b,g,null)}})}),a.jQuery=a.$=p,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return p})})(window);
diff --git a/record-and-playback/presentation_export/playback/presentation_export/lib/popcorn-complete.min.js b/record-and-playback/presentation_export/playback/presentation_export/lib/popcorn-complete.min.js
new file mode 100755
index 0000000000000000000000000000000000000000..8aeee4f2b58abed7b4b0fc7ffadfe30ae8db1cb4
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/lib/popcorn-complete.min.js
@@ -0,0 +1,160 @@
+/*
+ * popcorn.js version 1.3
+ * http://popcornjs.org
+ *
+ * Copyright 2011, Mozilla Foundation
+ * Licensed under the MIT license
+ */
+
+(function(r,f){function n(a,g){return function(){if(d.plugin.debug)return a.apply(this,arguments);try{return a.apply(this,arguments)}catch(l){d.plugin.errors.push({plugin:g,thrown:l,source:a.toString()});this.emit("pluginerror",d.plugin.errors)}}}if(f.addEventListener){var c=Array.prototype,b=Object.prototype,e=c.forEach,h=c.slice,i=b.hasOwnProperty,j=b.toString,p=r.Popcorn,m=[],o=false,q={events:{hash:{},apis:{}}},s=function(){return r.requestAnimationFrame||r.webkitRequestAnimationFrame||r.mozRequestAnimationFrame||
+r.oRequestAnimationFrame||r.msRequestAnimationFrame||function(a){r.setTimeout(a,16)}}(),d=function(a,g){return new d.p.init(a,g||null)};d.version="1.3";d.isSupported=true;d.instances=[];d.p=d.prototype={init:function(a,g){var l,k=this;if(typeof a==="function")if(f.readyState==="complete")a(f,d);else{m.push(a);if(!o){o=true;var t=function(){f.removeEventListener("DOMContentLoaded",t,false);for(var z=0,C=m.length;z<C;z++)m[z].call(f,d);m=null};f.addEventListener("DOMContentLoaded",t,false)}}else{if(typeof a===
+"string")try{l=f.querySelector(a)}catch(u){throw Error("Popcorn.js Error: Invalid media element selector: "+a);}this.media=l||a;l=this.media.nodeName&&this.media.nodeName.toLowerCase()||"video";this[l]=this.media;this.options=g||{};this.id=this.options.id||d.guid(l);if(d.byId(this.id))throw Error("Popcorn.js Error: Cannot use duplicate ID ("+this.id+")");this.isDestroyed=false;this.data={running:{cue:[]},timeUpdate:d.nop,disabled:{},events:{},hooks:{},history:[],state:{volume:this.media.volume},trackRefs:{},
+trackEvents:{byStart:[{start:-1,end:-1}],byEnd:[{start:-1,end:-1}],animating:[],startIndex:0,endIndex:0,previousUpdateTime:-1}};d.instances.push(this);var v=function(){if(k.media.currentTime<0)k.media.currentTime=0;k.media.removeEventListener("loadeddata",v,false);var z,C,E,B,w;z=k.media.duration;z=z!=z?Number.MAX_VALUE:z+1;d.addTrackEvent(k,{start:z,end:z});if(k.options.frameAnimation){k.data.timeUpdate=function(){d.timeUpdate(k,{});d.forEach(d.manifest,function(D,F){if(C=k.data.running[F]){B=C.length;
+for(var I=0;I<B;I++){E=C[I];(w=E._natives)&&w.frame&&w.frame.call(k,{},E,k.currentTime())}}});k.emit("timeupdate");!k.isDestroyed&&s(k.data.timeUpdate)};!k.isDestroyed&&s(k.data.timeUpdate)}else{k.data.timeUpdate=function(D){d.timeUpdate(k,D)};k.isDestroyed||k.media.addEventListener("timeupdate",k.data.timeUpdate,false)}};Object.defineProperty(this,"error",{get:function(){return k.media.error}});k.media.readyState>=2?v():k.media.addEventListener("loadeddata",v,false);return this}}};d.p.init.prototype=
+d.p;d.byId=function(a){for(var g=d.instances,l=g.length,k=0;k<l;k++)if(g[k].id===a)return g[k];return null};d.forEach=function(a,g,l){if(!a||!g)return{};l=l||this;var k,t;if(e&&a.forEach===e)return a.forEach(g,l);if(j.call(a)==="[object NodeList]"){k=0;for(t=a.length;k<t;k++)g.call(l,a[k],k,a);return a}for(k in a)i.call(a,k)&&g.call(l,a[k],k,a);return a};d.extend=function(a){var g=h.call(arguments,1);d.forEach(g,function(l){for(var k in l)a[k]=l[k]});return a};d.extend(d,{noConflict:function(a){if(a)r.Popcorn=
+p;return d},error:function(a){throw Error(a);},guid:function(a){d.guid.counter++;return(a?a:"")+(+new Date+d.guid.counter)},sizeOf:function(a){var g=0,l;for(l in a)g++;return g},isArray:Array.isArray||function(a){return j.call(a)==="[object Array]"},nop:function(){},position:function(a){a=a.getBoundingClientRect();var g={},l=f.documentElement,k=f.body,t,u,v;t=l.clientTop||k.clientTop||0;u=l.clientLeft||k.clientLeft||0;v=r.pageYOffset&&l.scrollTop||k.scrollTop;l=r.pageXOffset&&l.scrollLeft||k.scrollLeft;
+t=Math.ceil(a.top+v-t);u=Math.ceil(a.left+l-u);for(var z in a)g[z]=Math.round(a[z]);return d.extend({},g,{top:t,left:u})},disable:function(a,g){if(!a.data.disabled[g]){a.data.disabled[g]=true;for(var l=a.data.running[g].length-1,k;l>=0;l--){k=a.data.running[g][l];k._natives.end.call(a,null,k)}}return a},enable:function(a,g){if(a.data.disabled[g]){a.data.disabled[g]=false;for(var l=a.data.running[g].length-1,k;l>=0;l--){k=a.data.running[g][l];k._natives.start.call(a,null,k)}}return a},destroy:function(a){var g=
+a.data.events,l=a.data.trackEvents,k,t,u,v;for(t in g){k=g[t];for(u in k)delete k[u];g[t]=null}for(v in d.registryByName)d.removePlugin(a,v);l.byStart.length=0;l.byEnd.length=0;if(!a.isDestroyed){a.data.timeUpdate&&a.media.removeEventListener("timeupdate",a.data.timeUpdate,false);a.isDestroyed=true}}});d.guid.counter=1;d.extend(d.p,function(){var a={};d.forEach("load play pause currentTime playbackRate volume duration preload playbackRate autoplay loop controls muted buffered readyState seeking paused played seekable ended".split(/\s+/g),
+function(g){a[g]=function(l){var k;if(typeof this.media[g]==="function"){if(l!=null&&/play|pause/.test(g))this.media.currentTime=d.util.toSeconds(l);this.media[g]();return this}if(l!=null){k=this.media[g];this.media[g]=l;k!==l&&this.emit("attrchange",{attribute:g,previousValue:k,currentValue:l});return this}return this.media[g]}});return a}());d.forEach("enable disable".split(" "),function(a){d.p[a]=function(g){return d[a](this,g)}});d.extend(d.p,{roundTime:function(){return Math.round(this.media.currentTime)},
+exec:function(a,g,l){var k=arguments.length,t,u;try{u=d.util.toSeconds(a)}catch(v){}if(typeof u==="number")a=u;if(typeof a==="number"&&k===2){l=g;g=a;a=d.guid("cue")}else if(k===1)g=-1;else if(t=this.getTrackEvent(a)){if(typeof a==="string"&&k===2){if(typeof g==="number")l=t._natives.start;if(typeof g==="function"){l=g;g=t.start}}}else if(k>=2){if(typeof g==="string"){try{u=d.util.toSeconds(g)}catch(z){}g=u}if(typeof g==="number")l=d.nop();if(typeof g==="function"){l=g;g=-1}}d.addTrackEvent(this,
+{id:a,start:g,end:g+1,_running:false,_natives:{start:l||d.nop,end:d.nop,type:"cue"}});return this},mute:function(a){a=a==null||a===true?"muted":"unmuted";if(a==="unmuted"){this.media.muted=false;this.media.volume=this.data.state.volume}if(a==="muted"){this.data.state.volume=this.media.volume;this.media.muted=true}this.emit(a);return this},unmute:function(a){return this.mute(a==null?false:!a)},position:function(){return d.position(this.media)},toggle:function(a){return d[this.data.disabled[a]?"enable":
+"disable"](this,a)},defaults:function(a,g){if(d.isArray(a)){d.forEach(a,function(l){for(var k in l)this.defaults(k,l[k])},this);return this}if(!this.options.defaults)this.options.defaults={};this.options.defaults[a]||(this.options.defaults[a]={});d.extend(this.options.defaults[a],g);return this}});d.Events={UIEvents:"blur focus focusin focusout load resize scroll unload",MouseEvents:"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave click dblclick",Events:"loadstart progress suspend emptied stalled play pause error loadedmetadata loadeddata waiting playing canplay canplaythrough seeking seeked timeupdate ended ratechange durationchange volumechange"};
+d.Events.Natives=d.Events.UIEvents+" "+d.Events.MouseEvents+" "+d.Events.Events;q.events.apiTypes=["UIEvents","MouseEvents","Events"];(function(a,g){for(var l=q.events.apiTypes,k=a.Natives.split(/\s+/g),t=0,u=k.length;t<u;t++)g.hash[k[t]]=true;l.forEach(function(v){g.apis[v]={};for(var z=a[v].split(/\s+/g),C=z.length,E=0;E<C;E++)g.apis[v][z[E]]=true})})(d.Events,q.events);d.events={isNative:function(a){return!!q.events.hash[a]},getInterface:function(a){if(!d.events.isNative(a))return false;var g=
+q.events,l=g.apiTypes;g=g.apis;for(var k=0,t=l.length,u,v;k<t;k++){v=l[k];if(g[v][a]){u=v;break}}return u},all:d.Events.Natives.split(/\s+/g),fn:{trigger:function(a,g){var l;if(this.data.events[a]&&d.sizeOf(this.data.events[a])){if(l=d.events.getInterface(a)){l=f.createEvent(l);l.initEvent(a,true,true,r,1);this.media.dispatchEvent(l);return this}d.forEach(this.data.events[a],function(k){k.call(this,g)},this)}return this},listen:function(a,g){var l=this,k=true,t=d.events.hooks[a],u;if(!this.data.events[a]){this.data.events[a]=
+{};k=false}if(t){t.add&&t.add.call(this,{},g);if(t.bind)a=t.bind;if(t.handler){u=g;g=function(v){t.handler.call(l,v,u)}}k=true;if(!this.data.events[a]){this.data.events[a]={};k=false}}this.data.events[a][g.name||g.toString()+d.guid()]=g;!k&&d.events.all.indexOf(a)>-1&&this.media.addEventListener(a,function(v){d.forEach(l.data.events[a],function(z){typeof z==="function"&&z.call(l,v)})},false);return this},unlisten:function(a,g){if(this.data.events[a]&&this.data.events[a][g]){delete this.data.events[a][g];
+return this}this.data.events[a]=null;return this}},hooks:{canplayall:{bind:"canplaythrough",add:function(a,g){var l=false;if(this.media.readyState){g.call(this,a);l=true}this.data.hooks.canplayall={fired:l}},handler:function(a,g){if(!this.data.hooks.canplayall.fired){g.call(this,a);this.data.hooks.canplayall.fired=true}}}}};d.forEach([["trigger","emit"],["listen","on"],["unlisten","off"]],function(a){d.p[a[0]]=d.p[a[1]]=d.events.fn[a[0]]});d.addTrackEvent=function(a,g){var l,k;if(g.id)l=a.getTrackEvent(g.id);
+if(l){k=true;g=d.extend({},l,g);a.removeTrackEvent(g.id)}if(g&&g._natives&&g._natives.type&&a.options.defaults&&a.options.defaults[g._natives.type])g=d.extend({},a.options.defaults[g._natives.type],g);if(g._natives){g._id=g.id||g._id||d.guid(g._natives.type);a.data.history.push(g._id)}g.start=d.util.toSeconds(g.start,a.options.framerate);g.end=d.util.toSeconds(g.end,a.options.framerate);var t=a.data.trackEvents.byStart,u=a.data.trackEvents.byEnd,v;for(v=t.length-1;v>=0;v--)if(g.start>=t[v].start){t.splice(v+
+1,0,g);break}for(t=u.length-1;t>=0;t--)if(g.end>u[t].end){u.splice(t+1,0,g);break}if(g.end>a.media.currentTime&&g.start<=a.media.currentTime){g._running=true;a.data.running[g._natives.type].push(g);a.data.disabled[g._natives.type]||g._natives.start.call(a,null,g)}v<=a.data.trackEvents.startIndex&&g.start<=a.data.trackEvents.previousUpdateTime&&a.data.trackEvents.startIndex++;t<=a.data.trackEvents.endIndex&&g.end<a.data.trackEvents.previousUpdateTime&&a.data.trackEvents.endIndex++;this.timeUpdate(a,
+null,true);g._id&&d.addTrackEvent.ref(a,g);if(k){k=g._natives.type==="cue"?"cuechange":"trackchange";a.emit(k,{id:g.id,previousValue:{time:l.start,fn:l._natives.start},currentValue:{time:g.start,fn:g._natives.start}})}};d.addTrackEvent.ref=function(a,g){a.data.trackRefs[g._id]=g;return a};d.removeTrackEvent=function(a,g){for(var l,k,t=a.data.history.length,u=a.data.trackEvents.byStart.length,v=0,z=0,C=[],E=[],B=[],w=[];--u>-1;){l=a.data.trackEvents.byStart[v];k=a.data.trackEvents.byEnd[v];if(!l._id){C.push(l);
+E.push(k)}if(l._id){l._id!==g&&C.push(l);k._id!==g&&E.push(k);if(l._id===g){z=v;l._natives._teardown&&l._natives._teardown.call(a,l)}}v++}u=a.data.trackEvents.animating.length;v=0;if(u)for(;--u>-1;){l=a.data.trackEvents.animating[v];l._id||B.push(l);l._id&&l._id!==g&&B.push(l);v++}z<=a.data.trackEvents.startIndex&&a.data.trackEvents.startIndex--;z<=a.data.trackEvents.endIndex&&a.data.trackEvents.endIndex--;a.data.trackEvents.byStart=C;a.data.trackEvents.byEnd=E;a.data.trackEvents.animating=B;for(u=
+0;u<t;u++)a.data.history[u]!==g&&w.push(a.data.history[u]);a.data.history=w;d.removeTrackEvent.ref(a,g)};d.removeTrackEvent.ref=function(a,g){delete a.data.trackRefs[g];return a};d.getTrackEvents=function(a){var g=[];a=a.data.trackEvents.byStart;for(var l=a.length,k=0,t;k<l;k++){t=a[k];t._id&&g.push(t)}return g};d.getTrackEvents.ref=function(a){return a.data.trackRefs};d.getTrackEvent=function(a,g){return a.data.trackRefs[g]};d.getTrackEvent.ref=function(a,g){return a.data.trackRefs[g]};d.getLastTrackEventId=
+function(a){return a.data.history[a.data.history.length-1]};d.timeUpdate=function(a,g){var l=a.media.currentTime,k=a.data.trackEvents.previousUpdateTime,t=a.data.trackEvents,u=t.endIndex,v=t.startIndex,z=t.byStart.length,C=t.byEnd.length,E=d.registryByName,B,w,D;if(k<=l){for(;t.byEnd[u]&&t.byEnd[u].end<=l;){B=t.byEnd[u];w=(k=B._natives)&&k.type;if(!k||E[w]||a[w]){if(B._running===true){B._running=false;D=a.data.running[w];D.splice(D.indexOf(B),1);if(!a.data.disabled[w]){k.end.call(a,g,B);a.emit("trackend",
+d.extend({},B,{plugin:w,type:"trackend"}))}}u++}else{d.removeTrackEvent(a,B._id);return}}for(;t.byStart[v]&&t.byStart[v].start<=l;){B=t.byStart[v];w=(k=B._natives)&&k.type;if(!k||E[w]||a[w]){if(B.end>l&&B._running===false){B._running=true;a.data.running[w].push(B);if(!a.data.disabled[w]){k.start.call(a,g,B);a.emit("trackstart",d.extend({},B,{plugin:w,type:"trackstart"}))}}v++}else{d.removeTrackEvent(a,B._id);return}}}else if(k>l){for(;t.byStart[v]&&t.byStart[v].start>l;){B=t.byStart[v];w=(k=B._natives)&&
+k.type;if(!k||E[w]||a[w]){if(B._running===true){B._running=false;D=a.data.running[w];D.splice(D.indexOf(B),1);if(!a.data.disabled[w]){k.end.call(a,g,B);a.emit("trackend",d.extend({},B,{plugin:w,type:"trackend"}))}}v--}else{d.removeTrackEvent(a,B._id);return}}for(;t.byEnd[u]&&t.byEnd[u].end>l;){B=t.byEnd[u];w=(k=B._natives)&&k.type;if(!k||E[w]||a[w]){if(B.start<=l&&B._running===false){B._running=true;a.data.running[w].push(B);if(!a.data.disabled[w]){k.start.call(a,g,B);a.emit("trackstart",d.extend({},
+B,{plugin:w,type:"trackstart"}))}}u--}else{d.removeTrackEvent(a,B._id);return}}}t.endIndex=u;t.startIndex=v;t.previousUpdateTime=l;t.byStart.length<z&&t.startIndex--;t.byEnd.length<C&&t.endIndex--};d.extend(d.p,{getTrackEvents:function(){return d.getTrackEvents.call(null,this)},getTrackEvent:function(a){return d.getTrackEvent.call(null,this,a)},getLastTrackEventId:function(){return d.getLastTrackEventId.call(null,this)},removeTrackEvent:function(a){d.removeTrackEvent.call(null,this,a);return this},
+removePlugin:function(a){d.removePlugin.call(null,this,a);return this},timeUpdate:function(a){d.timeUpdate.call(null,this,a);return this},destroy:function(){d.destroy.call(null,this);return this}});d.manifest={};d.registry=[];d.registryByName={};d.plugin=function(a,g,l){if(d.protect.natives.indexOf(a.toLowerCase())>=0)d.error("'"+a+"' is a protected function name");else{var k=["start","end"],t={},u=typeof g==="function",v=["_setup","_teardown","start","end","frame"],z=function(B,w){B=B||d.nop;w=w||
+d.nop;return function(){B.apply(this,arguments);w.apply(this,arguments)}};d.manifest[a]=l=l||g.manifest||{};v.forEach(function(B){g[B]=n(g[B]||d.nop,a)});var C=function(B,w){if(!w)return this;if(w.ranges&&d.isArray(w.ranges)){d.forEach(w.ranges,function(G){G=d.extend({},w,G);delete G.ranges;this[a](G)},this);return this}var D=w._natives={},F="",I;d.extend(D,B);w._natives.type=a;w._running=false;D.start=D.start||D["in"];D.end=D.end||D.out;if(w.once)D.end=z(D.end,function(){this.removeTrackEvent(w._id)});
+D._teardown=z(function(){var G=h.call(arguments),H=this.data.running[D.type];G.unshift(null);G[1]._running&&H.splice(H.indexOf(w),1)&&D.end.apply(this,G)},D._teardown);w.compose=w.compose&&w.compose.split(" ")||[];w.effect=w.effect&&w.effect.split(" ")||[];w.compose=w.compose.concat(w.effect);w.compose.forEach(function(G){F=d.compositions[G]||{};v.forEach(function(H){D[H]=z(D[H],F[H])})});w._natives.manifest=l;if(!("start"in w))w.start=w["in"]||0;if(!w.end&&w.end!==0)w.end=w.out||Number.MAX_VALUE;
+if(!i.call(w,"toString"))w.toString=function(){var G=["start: "+w.start,"end: "+w.end,"id: "+(w.id||w._id)];w.target!=null&&G.push("target: "+w.target);return a+" ( "+G.join(", ")+" )"};if(!w.target){I="options"in l&&l.options;w.target=I&&"target"in I&&I.target}if(w._natives)w._id=d.guid(w._natives.type);w._natives._setup&&w._natives._setup.call(this,w);d.addTrackEvent(this,w);d.forEach(B,function(G,H){H!=="type"&&k.indexOf(H)===-1&&this.on(H,G)},this);return this};d.p[a]=t[a]=function(B,w){var D;
+if(B&&!w)w=B;else if(D=this.getTrackEvent(B)){w=d.extend({},D,w);d.addTrackEvent(this,w);return this}else w.id=B;this.data.running[a]=this.data.running[a]||[];D=d.extend({},this.options.defaults&&this.options.defaults[a]||{},w);return C.call(this,u?g.call(this,D):g,D)};l&&d.extend(g,{manifest:l});var E={fn:t[a],definition:g,base:g,parents:[],name:a};d.registry.push(d.extend(t,E,{type:a}));d.registryByName[a]=E;return t}};d.plugin.errors=[];d.plugin.debug=d.version==="1.3";d.removePlugin=function(a,
+g){if(!g){g=a;a=d.p;if(d.protect.natives.indexOf(g.toLowerCase())>=0){d.error("'"+g+"' is a protected function name");return}var l=d.registry.length,k;for(k=0;k<l;k++)if(d.registry[k].name===g){d.registry.splice(k,1);delete d.registryByName[g];delete d.manifest[g];delete a[g];return}}l=a.data.trackEvents.byStart;k=a.data.trackEvents.byEnd;var t=a.data.trackEvents.animating,u,v;u=0;for(v=l.length;u<v;u++){if(l[u]&&l[u]._natives&&l[u]._natives.type===g){l[u]._natives._teardown&&l[u]._natives._teardown.call(a,
+l[u]);l.splice(u,1);u--;v--;if(a.data.trackEvents.startIndex<=u){a.data.trackEvents.startIndex--;a.data.trackEvents.endIndex--}}k[u]&&k[u]._natives&&k[u]._natives.type===g&&k.splice(u,1)}u=0;for(v=t.length;u<v;u++)if(t[u]&&t[u]._natives&&t[u]._natives.type===g){t.splice(u,1);u--;v--}};d.compositions={};d.compose=function(a,g,l){d.manifest[a]=l||g.manifest||{};d.compositions[a]=g};d.plugin.effect=d.effect=d.compose;var A=/^(?:\.|#|\[)/;d.dom={debug:false,find:function(a,g){var l=null;a=a.trim();g=
+g||f;if(a){if(!A.test(a)){l=f.getElementById(a);if(l!==null)return l}try{l=g.querySelector(a)}catch(k){if(d.dom.debug)throw Error(k);}}return l}};var y=/\?/,x={url:"",data:"",dataType:"",success:d.nop,type:"GET",async:true,xhr:function(){return new r.XMLHttpRequest}};d.xhr=function(a){a.dataType=a.dataType&&a.dataType.toLowerCase()||null;if(a.dataType&&(a.dataType==="jsonp"||a.dataType==="script"))d.xhr.getJSONP(a.url,a.success,a.dataType==="script");else{a=d.extend({},x,a);a.ajax=a.xhr();if(a.ajax){if(a.type===
+"GET"&&a.data){a.url+=(y.test(a.url)?"&":"?")+a.data;a.data=null}a.ajax.open(a.type,a.url,a.async);a.ajax.send(a.data||null);return d.xhr.httpData(a)}}};d.xhr.httpData=function(a){var g,l=null,k,t=null;a.ajax.onreadystatechange=function(){if(a.ajax.readyState===4){try{l=JSON.parse(a.ajax.responseText)}catch(u){}g={xml:a.ajax.responseXML,text:a.ajax.responseText,json:l};if(!g.xml||!g.xml.documentElement){g.xml=null;try{k=new DOMParser;t=k.parseFromString(a.ajax.responseText,"text/xml");if(!t.getElementsByTagName("parsererror").length)g.xml=
+t}catch(v){}}if(a.dataType)g=g[a.dataType];a.success.call(a.ajax,g)}};return g};d.xhr.getJSONP=function(a,g,l){var k=f.head||f.getElementsByTagName("head")[0]||f.documentElement,t=f.createElement("script"),u=false,v=[];v=/(=)\?(?=&|$)|\?\?/;var z,C;if(!l){C=a.match(/(callback=[^&]*)/);if(C!==null&&C.length){v=C[1].split("=")[1];if(v==="?")v="jsonp";z=d.guid(v);a=a.replace(/(callback=[^&]*)/,"callback="+z)}else{z=d.guid("jsonp");if(v.test(a))a=a.replace(v,"$1"+z);v=a.split(/\?(.+)?/);a=v[0]+"?";if(v[1])a+=
+v[1]+"&";a+="callback="+z}window[z]=function(E){g&&g(E);u=true}}t.addEventListener("load",function(){l&&g&&g();u&&delete window[z];k.removeChild(t)},false);t.src=a;k.insertBefore(t,k.firstChild)};d.getJSONP=d.xhr.getJSONP;d.getScript=d.xhr.getScript=function(a,g){return d.xhr.getJSONP(a,g,true)};d.util={toSeconds:function(a,g){var l=/^([0-9]+:){0,2}[0-9]+([.;][0-9]+)?$/,k,t,u;if(typeof a==="number")return a;typeof a==="string"&&!l.test(a)&&d.error("Invalid time format");l=a.split(":");k=l.length-
+1;t=l[k];if(t.indexOf(";")>-1){t=t.split(";");u=0;if(g&&typeof g==="number")u=parseFloat(t[1],10)/g;l[k]=parseInt(t[0],10)+u}k=l[0];return{1:parseFloat(k,10),2:parseInt(k,10)*60+parseFloat(l[1],10),3:parseInt(k,10)*3600+parseInt(l[1],10)*60+parseFloat(l[2],10)}[l.length||1]}};d.p.cue=d.p.exec;d.protect={natives:function(a){return Object.keys?Object.keys(a):function(g){var l,k=[];for(l in g)i.call(g,l)&&k.push(l);return k}(a)}(d.p).map(function(a){return a.toLowerCase()})};d.forEach({listen:"on",unlisten:"off",
+trigger:"emit",exec:"cue"},function(a,g){var l=d.p[g];d.p[g]=function(){if(typeof console!=="undefined"&&console.warn){console.warn("Deprecated method '"+g+"', "+(a==null?"do not use.":"use '"+a+"' instead."));d.p[g]=l}return d.p[a].apply(this,[].slice.call(arguments))}});r.Popcorn=d}else{r.Popcorn={isSupported:false};for(c="byId forEach extend effects error guid sizeOf isArray nop position disable enable destroyaddTrackEvent removeTrackEvent getTrackEvents getTrackEvent getLastTrackEventId timeUpdate plugin removePlugin compose effect xhr getJSONP getScript".split(/\s+/);c.length;)r.Popcorn[c.shift()]=
+function(){}}})(window,window.document);(function(r,f){var n=r.document,c=r.location,b=/:\/\//,e=c.href.replace(c.href.split("/").slice(-1)[0],""),h=function(j,p,m){j=j||0;p=(p||j||0)+1;m=m||1;p=Math.ceil((p-j)/m)||0;var o=0,q=[];for(q.length=p;o<p;){q[o++]=j;j+=m}return q};f.sequence=function(j,p){return new f.sequence.init(j,p)};f.sequence.init=function(j,p){this.parent=n.getElementById(j);this.seqId=f.guid("__sequenced");this.queue=[];this.playlist=[];this.inOuts={ofVideos:[],ofClips:[]};this.dims={width:0,height:0};this.active=0;this.playing=
+this.cycling=false;this.times={last:0};this.events={};var m=this,o=0;f.forEach(p,function(q,s){var d=n.createElement("video");d.preload="auto";d.controls=true;d.style.display=s&&"none"||"";d.id=m.seqId+"-"+s;m.queue.push(d);var A=q["in"],y=q.out;m.inOuts.ofVideos.push({"in":A!==undefined&&A||1,out:y!==undefined&&y||0});m.inOuts.ofVideos[s].out=m.inOuts.ofVideos[s].out||m.inOuts.ofVideos[s]["in"]+2;d.src=!b.test(q.src)?e+q.src:q.src;d.setAttribute("data-sequence-owner",j);d.setAttribute("data-sequence-guid",
+m.seqId);d.setAttribute("data-sequence-id",s);d.setAttribute("data-sequence-clip",[m.inOuts.ofVideos[s]["in"],m.inOuts.ofVideos[s].out].join(":"));m.parent.appendChild(d);m.playlist.push(f("#"+d.id))});m.inOuts.ofVideos.forEach(function(q){q={"in":o,out:o+(q.out-q["in"])};m.inOuts.ofClips.push(q);o=q.out+1});f.forEach(this.queue,function(q,s){function d(){if(!s){m.dims.width=q.videoWidth;m.dims.height=q.videoHeight}q.currentTime=m.inOuts.ofVideos[s]["in"]-0.5;q.removeEventListener("canplaythrough",
+d,false);return true}q.addEventListener("canplaythrough",d,false);q.addEventListener("play",function(){m.playing=true},false);q.addEventListener("pause",function(){m.playing=false},false);q.addEventListener("timeupdate",function(A){A=A.srcElement||A.target;A=+(A.dataset&&A.dataset.sequenceId||A.getAttribute("data-sequence-id"));var y=Math.floor(q.currentTime);if(m.times.last!==y&&A===m.active){m.times.last=y;y===m.inOuts.ofVideos[A].out&&f.sequence.cycle.call(m,A)}},false)});return this};f.sequence.init.prototype=
+f.sequence.prototype;f.sequence.cycle=function(j){this.queue||f.error("Popcorn.sequence.cycle is not a public method");var p=this.queue,m=this.inOuts.ofVideos,o=p[j],q=0,s;if(p[j+1])q=j+1;if(p[j+1]){p=p[q];m=m[q];f.extend(p,{width:this.dims.width,height:this.dims.height});s=this.playlist[q];o.pause();this.active=q;this.times.last=m["in"]-1;s.currentTime(m["in"]);s[q?"play":"pause"]();this.trigger("cycle",{position:{previous:j,current:q}});if(q){o.style.display="none";p.style.display=""}this.cycling=
+false}else this.playlist[j].pause();return this};var i=["timeupdate","play","pause"];f.extend(f.sequence.prototype,{eq:function(j){return this.playlist[j]},remove:function(){this.parent.innerHTML=null},clip:function(j){return this.inOuts.ofVideos[j]},duration:function(){for(var j=0,p=this.inOuts.ofClips,m=0;m<p.length;m++)j+=p[m].out-p[m]["in"]+1;return j-1},play:function(){this.playlist[this.active].play();return this},exec:function(j,p){var m=this.active;this.inOuts.ofClips.forEach(function(o,q){if(j>=
+o["in"]&&j<=o.out)m=q});j+=this.inOuts.ofVideos[m]["in"]-this.inOuts.ofClips[m]["in"];f.addTrackEvent(this.playlist[m],{start:j-1,end:j,_running:false,_natives:{start:p||f.nop,end:f.nop,type:"exec"}});return this},listen:function(j,p){var m=this,o=this.playlist,q=o.length,s=0;if(!p)p=f.nop;if(f.Events.Natives.indexOf(j)>-1)f.forEach(o,function(d){d.listen(j,function(A){A.active=m;if(i.indexOf(j)>-1)p.call(d,A);else++s===q&&p.call(d,A)})});else{this.events[j]||(this.events[j]={});o=p.name||f.guid("__"+
+j);this.events[j][o]=p}return this},unlisten:function(){},trigger:function(j,p){var m=this;if(!(f.Events.Natives.indexOf(j)>-1)){this.events[j]&&f.forEach(this.events[j],function(o){o.call(m,{type:j},p)});return this}}});f.forEach(f.manifest,function(j,p){f.sequence.prototype[p]=function(m){var o={},q=[],s,d,A,y,x;for(s=0;s<this.inOuts.ofClips.length;s++){q=this.inOuts.ofClips[s];d=h(q["in"],q.out);A=d.indexOf(m.start);y=d.indexOf(m.end);if(A>-1)o[s]=f.extend({},q,{start:d[A],clipIdx:A});if(y>-1)o[s]=
+f.extend({},q,{end:d[y],clipIdx:y})}s=Object.keys(o).map(function(g){return+g});q=h(s[0],s[1]);for(s=0;s<q.length;s++){A={};y=q[s];var a=o[y];if(a){x=this.inOuts.ofVideos[y];d=a.clipIdx;x=h(x["in"],x.out);if(a.start){A.start=x[d];A.end=x[x.length-1]}if(a.end){A.start=x[0];A.end=x[d]}}else{A.start=this.inOuts.ofVideos[y]["in"];A.end=this.inOuts.ofVideos[y].out}this.playlist[y][p](f.extend({},m,A))}return this}})})(this,Popcorn);(function(r){document.addEventListener("DOMContentLoaded",function(){var f=document.querySelectorAll("[data-timeline-sources]");r.forEach(f,function(n,c){var b=f[c],e,h,i;if(!b.id)b.id=r.guid("__popcorn");if(b.nodeType&&b.nodeType===1){i=r("#"+b.id);e=(b.getAttribute("data-timeline-sources")||"").split(",");e[0]&&r.forEach(e,function(j){h=j.split("!");if(h.length===1){h=j.match(/(.*)[\/\\]([^\/\\]+\.\w+)$/)[2].split(".");h[0]="parse"+h[1].toUpperCase();h[1]=j}e[0]&&i[h[0]]&&i[h[0]](h[1])});i.autoplay()&&
+i.play()}})},false)})(Popcorn);(function(r,f){function n(e){e=typeof e==="string"?e:[e.language,e.region].join("-");var h=e.split("-");return{iso6391:e,language:h[0]||"",region:h[1]||""}}var c=r.navigator,b=n(c.userLanguage||c.language);f.locale={get:function(){return b},set:function(e){b=n(e);f.locale.broadcast();return b},broadcast:function(e){var h=f.instances,i=h.length,j=0,p;for(e=e||"locale:changed";j<i;j++){p=h[j];e in p.data.events&&p.trigger(e)}}}})(this,this.Popcorn);(function(r){var f=Object.prototype.hasOwnProperty;r.parsers={};r.parser=function(n,c,b){if(r.protect.natives.indexOf(n.toLowerCase())>=0)r.error("'"+n+"' is a protected function name");else{if(typeof c==="function"&&!b){b=c;c=""}if(!(typeof b!=="function"||typeof c!=="string")){var e={};e[n]=function(h,i){if(!h)return this;var j=this;r.xhr({url:h,dataType:c,success:function(p){var m,o,q=0;p=b(p).data||[];if(m=p.length){for(;q<m;q++){o=p[q];for(var s in o)f.call(o,s)&&j[s]&&j[s](o[s])}i&&i()}}});
+return this};r.extend(r.p,e);return e}}}})(Popcorn);(function(r){var f=function(b,e){b=b||r.nop;e=e||r.nop;return function(){b.apply(this,arguments);e.apply(this,arguments)}},n=/^.*\.(ogg|oga|aac|mp3|wav)($|\?)/,c=/^.*\.(ogg|oga|aac|mp3|wav|ogg|ogv|mp4|webm)($|\?)/;r.player=function(b,e){if(!r[b]){e=e||{};var h=function(i,j,p){p=p||{};var m=new Date/1E3,o=m,q=0,s=0,d=1,A=false,y={},x=typeof i==="string"?r.dom.find(i):i,a={};Object.prototype.__defineGetter__||(a=x||document.createElement("div"));for(var g in x)if(!(g in a))if(typeof x[g]==="object")a[g]=
+x[g];else if(typeof x[g]==="function")a[g]=function(k){return"length"in x[k]&&!x[k].call?x[k]:function(){return x[k].apply(x,arguments)}}(g);else r.player.defineProperty(a,g,{get:function(k){return function(){return x[k]}}(g),set:r.nop,configurable:true});var l=function(){m=new Date/1E3;if(!a.paused){a.currentTime+=m-o;a.dispatchEvent("timeupdate");setTimeout(l,10)}o=m};a.play=function(){this.paused=false;if(a.readyState>=4){o=new Date/1E3;a.dispatchEvent("play");l()}};a.pause=function(){this.paused=
+true;a.dispatchEvent("pause")};r.player.defineProperty(a,"currentTime",{get:function(){return q},set:function(k){q=+k;a.dispatchEvent("timeupdate");return q},configurable:true});r.player.defineProperty(a,"volume",{get:function(){return d},set:function(k){d=+k;a.dispatchEvent("volumechange");return d},configurable:true});r.player.defineProperty(a,"muted",{get:function(){return A},set:function(k){A=+k;a.dispatchEvent("volumechange");return A},configurable:true});r.player.defineProperty(a,"readyState",
+{get:function(){return s},set:function(k){return s=k},configurable:true});a.addEventListener=function(k,t){y[k]||(y[k]=[]);y[k].push(t);return t};a.removeEventListener=function(k,t){var u,v=y[k];if(v){for(u=y[k].length-1;u>=0;u--)t===v[u]&&v.splice(u,1);return t}};a.dispatchEvent=function(k){var t,u=k.type;if(!u){u=k;if(k=r.events.getInterface(u)){t=document.createEvent(k);t.initEvent(u,true,true,window,1)}}if(y[u])for(k=y[u].length-1;k>=0;k--)y[u][k].call(this,t,this)};a.src=j||"";a.duration=0;a.paused=
+true;a.ended=0;p&&p.events&&r.forEach(p.events,function(k,t){a.addEventListener(t,k,false)});if(e._canPlayType(x.nodeName,j)!==false)if(e._setup)e._setup.call(a,p);else{a.readyState=4;a.dispatchEvent("loadedmetadata");a.dispatchEvent("loadeddata");a.dispatchEvent("canplaythrough")}else setTimeout(function(){a.dispatchEvent("error")},0);i=new r.p.init(a,p);if(e._teardown)i.destroy=f(i.destroy,function(){e._teardown.call(a,p)});return i};h.canPlayType=e._canPlayType=e._canPlayType||r.nop;r[b]=r.player.registry[b]=
+h}};r.player.registry={};r.player.defineProperty=Object.defineProperty||function(b,e,h){b.__defineGetter__(e,h.get||r.nop);b.__defineSetter__(e,h.set||r.nop)};r.player.playerQueue=function(){var b=[],e=false;return{next:function(){e=false;b.shift();b[0]&&b[0]()},add:function(h){b.push(function(){e=true;h&&h()});!e&&b[0]()}}};r.smart=function(b,e,h){var i=["AUDIO","VIDEO"],j,p=r.dom.find(b),m;j=document.createElement("video");var o={ogg:"video/ogg",ogv:"video/ogg",oga:"audio/ogg",webm:"video/webm",
+mp4:"video/mp4",mp3:"audio/mp3"};if(p){if(i.indexOf(p.nodeName)>-1&&!e){if(typeof e==="object")h=e;return r(p,h)}if(typeof e==="string")e=[e];b=0;for(srcLength=e.length;b<srcLength;b++){m=c.exec(e[b]);m=!m||!m[1]?false:j.canPlayType(o[m[1]]);if(m){e=e[b];break}for(var q in r.player.registry)if(r.player.registry.hasOwnProperty(q))if(r.player.registry[q].canPlayType(p.nodeName,e[b]))return r[q](p,e[b],h)}if(i.indexOf(p.nodeName)===-1){j=typeof e==="string"?e:e.length?e[0]:e;b=document.createElement(n.exec(j)?
+i[0]:i[1]);b.controls=true;p.appendChild(b);p=b}h&&h.events&&h.events.error&&p.addEventListener("error",h.events.error,false);p.src=e;return r(p,h)}else r.error("Specified target "+b+" was not found.")}})(Popcorn);(function(r){var f=function(n,c){var b=0,e=0,h;r.forEach(c.classes,function(i,j){h=[];if(i==="parent")h[0]=document.querySelectorAll("#"+c.target)[0].parentNode;else h=document.querySelectorAll("#"+c.target+" "+i);b=0;for(e=h.length;b<e;b++)h[b].classList.toggle(j)})};r.compose("applyclass",{manifest:{about:{name:"Popcorn applyclass Effect",version:"0.1",author:"@scottdowne",website:"scottdowne.wordpress.com"},options:{}},_setup:function(n){n.classes={};n.applyclass=n.applyclass||"";for(var c=n.applyclass.replace(/\s/g,
+"").split(","),b=[],e=0,h=c.length;e<h;e++){b=c[e].split(":");if(b[0])n.classes[b[0]]=b[1]||""}},start:f,end:f})})(Popcorn);(function(r){var f=/(?:http:\/\/www\.|http:\/\/|www\.|\.|^)(youtu|vimeo|soundcloud|baseplayer)/,n={},c={vimeo:false,youtube:false,soundcloud:false,module:false};Object.defineProperty(n,void 0,{get:function(){return c[void 0]},set:function(b){c[void 0]=b}});r.plugin("mediaspawner",{manifest:{about:{name:"Popcorn Media Spawner Plugin",version:"0.1",author:"Matthew Schranz, @mjschranz",website:"mschranz.wordpress.com"},options:{source:{elem:"input",type:"text",label:"Media Source","default":"http://www.youtube.com/watch?v=CXDstfD9eJ0"},
+caption:{elem:"input",type:"text",label:"Media Caption","default":"Popcorn Popping",optional:true},target:"mediaspawner-container",start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},autoplay:{elem:"input",type:"checkbox",label:"Autoplay Video",optional:true},width:{elem:"input",type:"number",label:"Media Width","default":400,units:"px",optional:true},height:{elem:"input",type:"number",label:"Media Height","default":200,units:"px",optional:true}}},_setup:function(b){function e(){function o(){if(j!==
+"HTML5"&&!window.Popcorn[j])setTimeout(function(){o()},300);else{b.id=b._container.id;b._container.style.width=b.width+"px";b._container.style.height=b.height+"px";b.popcorn=r.smart("#"+b.id,b.source);j==="HTML5"&&b.popcorn.controls(true);b._container.style.width="0px";b._container.style.height="0px";b._container.style.visibility="hidden";b._container.style.overflow="hidden"}}if(j!=="HTML5"&&!window.Popcorn[j]&&!n[j]){n[j]=true;r.getScript("http://popcornjs.org/code/players/"+j+"/popcorn."+j+".js",
+function(){o()})}else o()}function h(){window.Popcorn.player?e():setTimeout(function(){h()},300)}var i=document.getElementById(b.target)||{},j,p,m;if(p=f.exec(b.source)){j=p[1];if(j==="youtu")j="youtube"}else j="HTML5";b._type=j;b._container=document.createElement("div");p=b._container;p.id="mediaSpawnerdiv-"+r.guid();b.width=b.width||400;b.height=b.height||200;if(b.caption){m=document.createElement("div");m.innerHTML=b.caption;m.style.display="none";b._capCont=m;p.appendChild(m)}i&&i.appendChild(p);
+if(!window.Popcorn.player&&!n.module){n.module=true;r.getScript("http://popcornjs.org/code/modules/player/popcorn.player.js",h)}else h()},start:function(b,e){if(e._capCont)e._capCont.style.display="";e._container.style.width=e.width+"px";e._container.style.height=e.height+"px";e._container.style.visibility="visible";e._container.style.overflow="visible";e.autoplay&&e.popcorn.play()},end:function(b,e){if(e._capCont)e._capCont.style.display="none";e._container.style.width="0px";e._container.style.height=
+"0px";e._container.style.visibility="hidden";e._container.style.overflow="hidden";e.popcorn.pause()},_teardown:function(b){b.popcorn&&b.popcorn.destory&&b.popcorn.destroy();document.getElementById(b.target)&&document.getElementById(b.target).removeChild(b._container)}})})(Popcorn,this);(function(r){r.plugin("code",function(f){var n=false,c=this,b=function(){var e=function(h){return function(i,j){var p=function(){n&&i.call(c,j);n&&h(p)};p()}};return window.webkitRequestAnimationFrame?e(window.webkitRequestAnimationFrame):window.mozRequestAnimationFrame?e(window.mozRequestAnimationFrame):e(function(h){window.setTimeout(h,16)})}();if(!f.onStart||typeof f.onStart!=="function")f.onStart=r.nop;if(f.onEnd&&typeof f.onEnd!=="function")f.onEnd=undefined;if(f.onFrame&&typeof f.onFrame!==
+"function")f.onFrame=undefined;return{start:function(e,h){h.onStart.call(c,h);if(h.onFrame){n=true;b(h.onFrame,h)}},end:function(e,h){if(h.onFrame)n=false;h.onEnd&&h.onEnd.call(c,h)}}},{about:{name:"Popcorn Code Plugin",version:"0.1",author:"David Humphrey (@humphd)",website:"http://vocamus.net/dave"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},onStart:{elem:"input",type:"function",label:"onStart"},onFrame:{elem:"input",type:"function",label:"onFrame",
+optional:true},onEnd:{elem:"input",type:"function",label:"onEnd"}}})})(Popcorn);(function(r){var f=0;r.plugin("flickr",function(n){var c,b=document.getElementById(n.target),e,h,i,j,p=n.numberofimages||4,m=n.height||"50px",o=n.width||"50px",q=n.padding||"5px",s=n.border||"0px";c=document.createElement("div");c.id="flickr"+f;c.style.width="100%";c.style.height="100%";c.style.display="none";f++;b&&b.appendChild(c);var d=function(){if(e)setTimeout(function(){d()},5);else{h="http://api.flickr.com/services/rest/?method=flickr.people.findByUsername&";h+="username="+n.username+"&api_key="+
+n.apikey+"&format=json&jsoncallback=flickr";r.getJSONP(h,function(y){e=y.user.nsid;A()})}},A=function(){h="http://api.flickr.com/services/feeds/photos_public.gne?";if(e)h+="id="+e+"&";if(n.tags)h+="tags="+n.tags+"&";h+="lang=en-us&format=json&jsoncallback=flickr";r.xhr.getJSONP(h,function(y){var x=document.createElement("div");x.innerHTML="<p style='padding:"+q+";'>"+y.title+"<p/>";r.forEach(y.items,function(a,g){if(g<p){i=document.createElement("a");i.setAttribute("href",a.link);i.setAttribute("target",
+"_blank");j=document.createElement("img");j.setAttribute("src",a.media.m);j.setAttribute("height",m);j.setAttribute("width",o);j.setAttribute("style","border:"+s+";padding:"+q);i.appendChild(j);x.appendChild(i)}else return false});c.appendChild(x)})};if(n.username&&n.apikey)d();else{e=n.userid;A()}return{start:function(){c.style.display="inline"},end:function(){c.style.display="none"},_teardown:function(y){document.getElementById(y.target)&&document.getElementById(y.target).removeChild(c)}}},{about:{name:"Popcorn Flickr Plugin",
+version:"0.2",author:"Scott Downe, Steven Weerdenburg, Annasob",website:"http://scottdowne.wordpress.com/"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},userid:{elem:"input",type:"text",label:"User ID",optional:true},tags:{elem:"input",type:"text",label:"Tags"},username:{elem:"input",type:"text",label:"Username",optional:true},apikey:{elem:"input",type:"text",label:"API Key",optional:true},target:"flickr-container",height:{elem:"input",type:"text",
+label:"Height","default":"50px",optional:true},width:{elem:"input",type:"text",label:"Width","default":"50px",optional:true},padding:{elem:"input",type:"text",label:"Padding",optional:true},border:{elem:"input",type:"text",label:"Border","default":"5px",optional:true},numberofimages:{elem:"input",type:"number","default":4,label:"Number of Images"}}})})(Popcorn);(function(r){r.plugin("footnote",{manifest:{about:{name:"Popcorn Footnote Plugin",version:"0.2",author:"@annasob, @rwaldron",website:"annasob.wordpress.com"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},text:{elem:"input",type:"text",label:"Text"},target:"footnote-container"}},_setup:function(f){var n=r.dom.find(f.target);f._container=document.createElement("div");f._container.style.display="none";f._container.innerHTML=f.text;n.appendChild(f._container)},
+start:function(f,n){n._container.style.display="inline"},end:function(f,n){n._container.style.display="none"},_teardown:function(f){var n=r.dom.find(f.target);n&&n.removeChild(f._container)}})})(Popcorn);(function(r){function f(b){return String(b).replace(/&(?!\w+;)|[<>"']/g,function(e){return c[e]||e})}function n(b,e){var h=b.container=document.createElement("div"),i=h.style,j=b.media,p=function(){var m=b.position();i.fontSize="18px";i.width=j.offsetWidth+"px";i.top=m.top+j.offsetHeight-h.offsetHeight-40+"px";i.left=m.left+"px";setTimeout(p,10)};h.id=e||"";i.position="absolute";i.color="white";i.textShadow="black 2px 2px 6px";i.fontWeight="bold";i.textAlign="center";p();b.media.parentNode.appendChild(h);
+return h}var c={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};r.plugin("text",{manifest:{about:{name:"Popcorn Text Plugin",version:"0.1",author:"@humphd"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},text:{elem:"input",type:"text",label:"Text","default":"Popcorn.js"},escape:{elem:"input",type:"checkbox",label:"Escape"},multiline:{elem:"input",type:"checkbox",label:"Multiline"}}},_setup:function(b){var e,h,i=b._container=document.createElement("div");
+i.style.display="none";if(b.target)if(e=r.dom.find(b.target)){if(["VIDEO","AUDIO"].indexOf(e.nodeName)>-1)e=n(this,b.target+"-overlay")}else e=n(this,b.target);else e=this.container?this.container:n(this);b._target=e;h=b.escape?f(b.text):b.text;h=b.multiline?h.replace(/\r?\n/gm,"<br>"):h;i.innerHTML=h||"";e.appendChild(i)},start:function(b,e){e._container.style.display="inline"},end:function(b,e){e._container.style.display="none"},_teardown:function(b){var e=b._target;e&&e.removeChild(b._container)}})})(Popcorn);var googleCallback;
+(function(r){function f(i,j,p){i=i.type?i.type.toUpperCase():"HYBRID";var m;if(i==="STAMEN-WATERCOLOR"||i==="STAMEN-TERRAIN"||i==="STAMEN-TONER")m=i.replace("STAMEN-","").toLowerCase();p=new google.maps.Map(p,{mapTypeId:m?m:google.maps.MapTypeId[i],mapTypeControlOptions:{mapTypeIds:[]}});m&&p.mapTypes.set(m,new google.maps.StamenMapType(m));p.getDiv().style.display="none";return p}var n=1,c=false,b=false,e,h;googleCallback=function(i){if(typeof google!=="undefined"&&google.maps&&google.maps.Geocoder&&
+google.maps.LatLng){e=new google.maps.Geocoder;r.getScript("//maps.stamen.com/js/tile.stamen.js",function(){b=true})}else setTimeout(function(){googleCallback(i)},1)};h=function(){if(document.body){c=true;r.getScript("//maps.google.com/maps/api/js?sensor=false&callback=googleCallback")}else setTimeout(function(){h()},1)};r.plugin("googlemap",function(i){var j,p,m,o=document.getElementById(i.target);i.type=i.type||"ROADMAP";i.zoom=i.zoom||1;i.lat=i.lat||0;i.lng=i.lng||0;c||h();j=document.createElement("div");
+j.id="actualmap"+n;j.style.width=i.width||"100%";j.style.height=i.height?i.height:o&&o.clientHeight?o.clientHeight+"px":"100%";n++;o&&o.appendChild(j);var q=function(){if(b){if(j)if(i.location)e.geocode({address:i.location},function(s,d){if(j&&d===google.maps.GeocoderStatus.OK){i.lat=s[0].geometry.location.lat();i.lng=s[0].geometry.location.lng();m=new google.maps.LatLng(i.lat,i.lng);p=f(i,m,j)}});else{m=new google.maps.LatLng(i.lat,i.lng);p=f(i,m,j)}}else setTimeout(function(){q()},5)};q();return{start:function(s,
+d){var A=this,y,x=function(){if(p){d._map=p;p.getDiv().style.display="block";google.maps.event.trigger(p,"resize");p.setCenter(m);if(d.zoom&&typeof d.zoom!=="number")d.zoom=+d.zoom;p.setZoom(d.zoom);if(d.heading&&typeof d.heading!=="number")d.heading=+d.heading;if(d.pitch&&typeof d.pitch!=="number")d.pitch=+d.pitch;if(d.type==="STREETVIEW"){p.setStreetView(y=new google.maps.StreetViewPanorama(j,{position:m,pov:{heading:d.heading=d.heading||0,pitch:d.pitch=d.pitch||0,zoom:d.zoom}}));var a=function(z,
+C){var E=google.maps.geometry.spherical.computeHeading;setTimeout(function(){var B=A.media.currentTime;if(typeof d.tween==="object"){for(var w=0,D=z.length;w<D;w++){var F=z[w];if(B>=F.interval*(w+1)/1E3&&(B<=F.interval*(w+2)/1E3||B>=F.interval*D/1E3)){u.setPosition(new google.maps.LatLng(F.position.lat,F.position.lng));u.setPov({heading:F.pov.heading||E(F,z[w+1])||0,zoom:F.pov.zoom||0,pitch:F.pov.pitch||0})}}a(z,z[0].interval)}else{w=0;for(D=z.length;w<D;w++){F=d.interval;if(B>=F*(w+1)/1E3&&(B<=F*
+(w+2)/1E3||B>=F*D/1E3)){g.setPov({heading:E(z[w],z[w+1])||0,zoom:d.zoom,pitch:d.pitch||0});g.setPosition(l[w])}}a(l,d.interval)}},C)};if(d.location&&typeof d.tween==="string"){var g=y,l=[],k=new google.maps.DirectionsService,t=new google.maps.DirectionsRenderer(g);k.route({origin:d.location,destination:d.tween,travelMode:google.maps.TravelMode.DRIVING},function(z,C){if(C==google.maps.DirectionsStatus.OK){t.setDirections(z);for(var E=z.routes[0].overview_path,B=0,w=E.length;B<w;B++)l.push(new google.maps.LatLng(E[B].lat(),
+E[B].lng()));d.interval=d.interval||1E3;a(l,10)}})}else if(typeof d.tween==="object"){var u=y;k=0;for(var v=d.tween.length;k<v;k++){d.tween[k].interval=d.tween[k].interval||1E3;a(d.tween,10)}}}d.onmaploaded&&d.onmaploaded(d,p)}else setTimeout(function(){x()},13)};x()},end:function(){if(p)p.getDiv().style.display="none"},_teardown:function(s){var d=document.getElementById(s.target);d&&d.removeChild(j);j=p=m=null;s._map=null}}},{about:{name:"Popcorn Google Map Plugin",version:"0.1",author:"@annasob",
+website:"annasob.wordpress.com"},options:{start:{elem:"input",type:"start",label:"Start"},end:{elem:"input",type:"start",label:"End"},target:"map-container",type:{elem:"select",options:["ROADMAP","SATELLITE","STREETVIEW","HYBRID","TERRAIN","STAMEN-WATERCOLOR","STAMEN-TERRAIN","STAMEN-TONER"],label:"Map Type",optional:true},zoom:{elem:"input",type:"text",label:"Zoom","default":0,optional:true},lat:{elem:"input",type:"text",label:"Lat",optional:true},lng:{elem:"input",type:"text",label:"Lng",optional:true},
+location:{elem:"input",type:"text",label:"Location","default":"Toronto, Ontario, Canada"},heading:{elem:"input",type:"text",label:"Heading","default":0,optional:true},pitch:{elem:"input",type:"text",label:"Pitch","default":1,optional:true}}})})(Popcorn);(function(r){function f(b){function e(){var p=b.getBoundingClientRect(),m=i.getBoundingClientRect();if(m.left!==p.left)i.style.left=p.left+"px";if(m.top!==p.top)i.style.top=p.top+"px"}var h=-1,i=document.createElement("div"),j=getComputedStyle(b).zIndex;i.setAttribute("data-popcorn-helper-container",true);i.style.position="absolute";i.style.zIndex=isNaN(j)?n:j+1;document.body.appendChild(i);return{element:i,start:function(){h=setInterval(e,c)},stop:function(){clearInterval(h);h=-1},destroy:function(){document.body.removeChild(i);
+h!==-1&&clearInterval(h)}}}var n=2E3,c=10;r.plugin("image",{manifest:{about:{name:"Popcorn image Plugin",version:"0.1",author:"Scott Downe",website:"http://scottdowne.wordpress.com/"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},src:{elem:"input",type:"url",label:"Image URL","default":"http://mozillapopcorn.org/wp-content/themes/popcorn/images/for_developers.png"},href:{elem:"input",type:"url",label:"Link","default":"http://mozillapopcorn.org/wp-content/themes/popcorn/images/for_developers.png",
+optional:true},target:"image-container",text:{elem:"input",type:"text",label:"Caption","default":"Popcorn.js",optional:true}}},_setup:function(b){var e=document.createElement("img"),h=document.getElementById(b.target);b.anchor=document.createElement("a");b.anchor.style.position="relative";b.anchor.style.textDecoration="none";b.anchor.style.display="none";if(h)if(["VIDEO","AUDIO"].indexOf(h.nodeName)>-1){b.trackedContainer=f(h);b.trackedContainer.element.appendChild(b.anchor)}else h&&h.appendChild(b.anchor);
+e.addEventListener("load",function(){e.style.borderStyle="none";b.anchor.href=b.href||b.src||"#";b.anchor.target="_blank";var i,j;e.style.height=h.style.height;e.style.width=h.style.width;b.anchor.appendChild(e);if(b.text){i=e.height/12+"px";j=document.createElement("div");r.extend(j.style,{color:"black",fontSize:i,fontWeight:"bold",position:"relative",textAlign:"center",width:e.style.width||e.width+"px",zIndex:"10"});j.innerHTML=b.text||"";j.style.top=(e.style.height.replace("px","")||e.height)/
+2-j.offsetHeight/2+"px";b.anchor.insertBefore(j,e)}},false);e.src=b.src},start:function(b,e){e.anchor.style.display="inline";e.trackedContainer&&e.trackedContainer.start()},end:function(b,e){e.anchor.style.display="none";e.trackedContainer&&e.trackedContainer.stop()},_teardown:function(b){if(b.trackedContainer)b.trackedContainer.destroy();else b.anchor.parentNode&&b.anchor.parentNode.removeChild(b.anchor)}})})(Popcorn);(function(r){var f=1,n=false;r.plugin("googlefeed",function(c){var b=function(){var j=false,p=0,m=document.getElementsByTagName("link"),o=m.length,q=document.head||document.getElementsByTagName("head")[0],s=document.createElement("link");if(window.GFdynamicFeedControl)n=true;else r.getScript("//www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.js",function(){n=true});for(;p<o;p++)if(m[p].href==="//www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css")j=true;if(!j){s.type=
+"text/css";s.rel="stylesheet";s.href="//www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css";q.insertBefore(s,q.firstChild)}};window.google?b():r.getScript("//www.google.com/jsapi",function(){google.load("feeds","1",{callback:function(){b()}})});var e=document.createElement("div"),h=document.getElementById(c.target),i=function(){if(n)c.feed=new GFdynamicFeedControl(c.url,e,{vertical:c.orientation.toLowerCase()==="vertical"?true:false,horizontal:c.orientation.toLowerCase()==="horizontal"?
+true:false,title:c.title=c.title||"Blog"});else setTimeout(function(){i()},5)};if(!c.orientation||c.orientation.toLowerCase()!=="vertical"&&c.orientation.toLowerCase()!=="horizontal")c.orientation="vertical";e.style.display="none";e.id="_feed"+f;e.style.width="100%";e.style.height="100%";f++;h&&h.appendChild(e);i();return{start:function(){e.setAttribute("style","display:inline")},end:function(){e.setAttribute("style","display:none")},_teardown:function(j){document.getElementById(j.target)&&document.getElementById(j.target).removeChild(e);
+delete j.feed}}},{about:{name:"Popcorn Google Feed Plugin",version:"0.1",author:"David Seifried",website:"dseifried.wordpress.com"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},target:"feed-container",url:{elem:"input",type:"url",label:"Feed URL","default":"http://planet.mozilla.org/rss20.xml"},title:{elem:"input",type:"text",label:"Title","default":"Planet Mozilla",optional:true},orientation:{elem:"select",options:["Vertical","Horizontal"],
+label:"Orientation","default":"Vertical",optional:true}}})})(Popcorn);(function(r){var f=0,n=function(c,b){var e=c.container=document.createElement("div"),h=e.style,i=c.media,j=function(){var p=c.position();h.fontSize="18px";h.width=i.offsetWidth+"px";h.top=p.top+i.offsetHeight-e.offsetHeight-40+"px";h.left=p.left+"px";setTimeout(j,10)};e.id=b||r.guid();h.position="absolute";h.color="white";h.textShadow="black 2px 2px 6px";h.fontWeight="bold";h.textAlign="center";j();c.media.parentNode.appendChild(e);return e};r.plugin("subtitle",{manifest:{about:{name:"Popcorn Subtitle Plugin",
+version:"0.1",author:"Scott Downe",website:"http://scottdowne.wordpress.com/"},options:{start:{elem:"input",type:"text",label:"Start"},end:{elem:"input",type:"text",label:"End"},target:"subtitle-container",text:{elem:"input",type:"text",label:"Text"}}},_setup:function(c){var b=document.createElement("div");b.id="subtitle-"+f++;b.style.display="none";!this.container&&(!c.target||c.target==="subtitle-container")&&n(this);c.container=c.target&&c.target!=="subtitle-container"?document.getElementById(c.target)||
+n(this,c.target):this.container;document.getElementById(c.container.id)&&document.getElementById(c.container.id).appendChild(b);c.innerContainer=b;c.showSubtitle=function(){c.innerContainer.innerHTML=c.text||""}},start:function(c,b){b.innerContainer.style.display="inline";b.showSubtitle(b,b.text)},end:function(c,b){b.innerContainer.style.display="none";b.innerContainer.innerHTML=""},_teardown:function(c){c.container.removeChild(c.innerContainer)}})})(Popcorn);(function(r){var f=false;r.plugin("twitter",{manifest:{about:{name:"Popcorn Twitter Plugin",version:"0.1",author:"Scott Downe",website:"http://scottdowne.wordpress.com/"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},src:{elem:"input",type:"text",label:"Tweet Source (# or @)","default":"@popcornjs"},target:"twitter-container",height:{elem:"input",type:"number",label:"Height","default":"200",optional:true},width:{elem:"input",type:"number",label:"Width",
+"default":"250",optional:true}}},_setup:function(n){if(!window.TWTR&&!f){f=true;r.getScript("//widgets.twimg.com/j/2/widget.js")}var c=document.getElementById(n.target);n.container=document.createElement("div");n.container.setAttribute("id",r.guid());n.container.style.display="none";c&&c.appendChild(n.container);var b=n.src||"";c=n.width||250;var e=n.height||200,h=/^@/.test(b),i={version:2,id:n.container.getAttribute("id"),rpp:30,width:c,height:e,interval:6E3,theme:{shell:{background:"#ffffff",color:"#000000"},
+tweets:{background:"#ffffff",color:"#444444",links:"#1985b5"}},features:{loop:true,timestamp:true,avatars:true,hashtags:true,toptweets:true,live:true,scrollbar:false,behavior:"default"}},j=function(p){if(window.TWTR)if(h){i.type="profile";(new TWTR.Widget(i)).render().setUser(b).start()}else{i.type="search";i.search=b;i.subject=b;(new TWTR.Widget(i)).render().start()}else setTimeout(function(){j(p)},1)};j(this)},start:function(n,c){c.container.style.display="inline"},end:function(n,c){c.container.style.display=
+"none"},_teardown:function(n){document.getElementById(n.target)&&document.getElementById(n.target).removeChild(n.container)}})})(Popcorn);(function(r){r.plugin("webpage",{manifest:{about:{name:"Popcorn Webpage Plugin",version:"0.1",author:"@annasob",website:"annasob.wordpress.com"},options:{id:{elem:"input",type:"text",label:"Id",optional:true},start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},src:{elem:"input",type:"url",label:"Webpage URL","default":"http://mozillapopcorn.org"},target:"iframe-container"}},_setup:function(f){var n=document.getElementById(f.target);f.src=f.src.replace(/^(https?:)?(\/\/)?/,
+"//");f._iframe=document.createElement("iframe");f._iframe.setAttribute("width","100%");f._iframe.setAttribute("height","100%");f._iframe.id=f.id;f._iframe.src=f.src;f._iframe.style.display="none";n&&n.appendChild(f._iframe)},start:function(f,n){n._iframe.src=n.src;n._iframe.style.display="inline"},end:function(f,n){n._iframe.style.display="none"},_teardown:function(f){document.getElementById(f.target)&&document.getElementById(f.target).removeChild(f._iframe)}})})(Popcorn);var wikiCallback;
+(function(r){r.plugin("wikipedia",{manifest:{about:{name:"Popcorn Wikipedia Plugin",version:"0.1",author:"@annasob",website:"annasob.wordpress.com"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},lang:{elem:"input",type:"text",label:"Language","default":"english",optional:true},src:{elem:"input",type:"url",label:"Wikipedia URL","default":"http://en.wikipedia.org/wiki/Cat"},title:{elem:"input",type:"text",label:"Title","default":"Cats",optional:true},
+numberofwords:{elem:"input",type:"number",label:"Number of Words","default":"200",optional:true},target:"wikipedia-container"}},_setup:function(f){var n,c=r.guid();if(!f.lang)f.lang="en";f.numberofwords=f.numberofwords||200;window["wikiCallback"+c]=function(b){f._link=document.createElement("a");f._link.setAttribute("href",f.src);f._link.setAttribute("target","_blank");f._link.innerHTML=f.title||b.parse.displaytitle;f._desc=document.createElement("p");n=b.parse.text["*"].substr(b.parse.text["*"].indexOf("<p>"));
+n=n.replace(/((<(.|\n)+?>)|(\((.*?)\) )|(\[(.*?)\]))/g,"");n=n.split(" ");f._desc.innerHTML=n.slice(0,n.length>=f.numberofwords?f.numberofwords:n.length).join(" ")+" ...";f._fired=true};f.src&&r.getScript("//"+f.lang+".wikipedia.org/w/api.php?action=parse&props=text&redirects&page="+f.src.slice(f.src.lastIndexOf("/")+1)+"&format=json&callback=wikiCallback"+c)},start:function(f,n){var c=function(){if(n._fired){if(n._link&&n._desc)if(document.getElementById(n.target)){document.getElementById(n.target).appendChild(n._link);
+document.getElementById(n.target).appendChild(n._desc);n._added=true}}else setTimeout(function(){c()},13)};c()},end:function(f,n){if(n._added){document.getElementById(n.target).removeChild(n._link);document.getElementById(n.target).removeChild(n._desc)}},_teardown:function(f){if(f._added){f._link.parentNode&&document.getElementById(f.target).removeChild(f._link);f._desc.parentNode&&document.getElementById(f.target).removeChild(f._desc);delete f.target}}})})(Popcorn);(function(r){r.plugin("mustache",function(f){var n,c,b,e;r.getScript("http://mustache.github.com/extras/mustache.js");var h=!!f.dynamic,i=typeof f.template,j=typeof f.data,p=document.getElementById(f.target);f.container=p||document.createElement("div");if(i==="function")if(h)b=f.template;else e=f.template(f);else e=i==="string"?f.template:"";if(j==="function")if(h)n=f.data;else c=f.data(f);else c=j==="string"?JSON.parse(f.data):j==="object"?f.data:"";return{start:function(m,o){var q=function(){if(window.Mustache){if(n)c=
+n(o);if(b)e=b(o);var s=Mustache.to_html(e,c).replace(/^\s*/mg,"");o.container.innerHTML=s}else setTimeout(function(){q()},10)};q()},end:function(m,o){o.container.innerHTML=""},_teardown:function(){n=c=b=e=null}}},{about:{name:"Popcorn Mustache Plugin",version:"0.1",author:"David Humphrey (@humphd)",website:"http://vocamus.net/dave"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},target:"mustache-container",template:{elem:"input",type:"text",
+label:"Template"},data:{elem:"input",type:"text",label:"Data"},dynamic:{elem:"input",type:"checkbox",label:"Dynamic","default":true}}})})(Popcorn);(function(r){function f(c,b){if(c.map)c.map.div.style.display=b;else setTimeout(function(){f(c,b)},10)}var n=1;r.plugin("openmap",function(c){var b,e,h,i,j,p,m,o,q=document.getElementById(c.target);b=document.createElement("div");b.id="openmapdiv"+n;b.style.width="100%";b.style.height="100%";n++;q&&q.appendChild(b);o=function(){if(window.OpenLayers&&window.OpenLayers.Layer.Stamen){if(c.location){location=new OpenLayers.LonLat(0,0);r.getJSONP("//tinygeocoder.com/create-api.php?q="+c.location+"&callback=jsonp",
+function(d){e=new OpenLayers.LonLat(d[1],d[0])})}else e=new OpenLayers.LonLat(c.lng,c.lat);c.type=c.type||"ROADMAP";switch(c.type){case "SATELLITE":c.map=new OpenLayers.Map({div:b,maxResolution:0.28125,tileSize:new OpenLayers.Size(512,512)});var s=new OpenLayers.Layer.WorldWind("LANDSAT","//worldwind25.arc.nasa.gov/tile/tile.aspx",2.25,4,{T:"105"});c.map.addLayer(s);i=new OpenLayers.Projection("EPSG:4326");h=new OpenLayers.Projection("EPSG:4326");break;case "TERRAIN":i=new OpenLayers.Projection("EPSG:4326");
+h=new OpenLayers.Projection("EPSG:4326");c.map=new OpenLayers.Map({div:b,projection:h});s=new OpenLayers.Layer.WMS("USGS Terraserver","//terraserver-usa.org/ogcmap.ashx?",{layers:"DRG"});c.map.addLayer(s);break;case "STAMEN-TONER":case "STAMEN-WATERCOLOR":case "STAMEN-TERRAIN":s=c.type.replace("STAMEN-","").toLowerCase();s=new OpenLayers.Layer.Stamen(s);i=new OpenLayers.Projection("EPSG:4326");h=new OpenLayers.Projection("EPSG:900913");e=e.transform(i,h);c.map=new OpenLayers.Map({div:b,projection:h,
+displayProjection:i,controls:[new OpenLayers.Control.Navigation,new OpenLayers.Control.PanPanel,new OpenLayers.Control.ZoomPanel]});c.map.addLayer(s);break;default:h=new OpenLayers.Projection("EPSG:900913");i=new OpenLayers.Projection("EPSG:4326");e=e.transform(i,h);c.map=new OpenLayers.Map({div:b,projection:h,displayProjection:i});s=new OpenLayers.Layer.OSM;c.map.addLayer(s)}if(c.map){c.map.setCenter(e,c.zoom||10);c.map.div.style.display="none"}}else setTimeout(function(){o()},50)};o();return{_setup:function(s){window.OpenLayers||
+r.getScript("//openlayers.org/api/OpenLayers.js",function(){r.getScript("//maps.stamen.com/js/tile.stamen.js")});var d=function(){if(s.map){s.zoom=s.zoom||2;if(s.zoom&&typeof s.zoom!=="number")s.zoom=+s.zoom;s.map.setCenter(e,s.zoom);if(s.markers){var A=OpenLayers.Util.extend({},OpenLayers.Feature.Vector.style["default"]),y=function(v){clickedFeature=v.feature;if(clickedFeature.attributes.text){m=new OpenLayers.Popup.FramedCloud("featurePopup",clickedFeature.geometry.getBounds().getCenterLonLat(),
+new OpenLayers.Size(120,250),clickedFeature.attributes.text,null,true,function(){p.unselect(this.feature)});clickedFeature.popup=m;m.feature=clickedFeature;s.map.addPopup(m)}},x=function(v){feature=v.feature;if(feature.popup){m.feature=null;s.map.removePopup(feature.popup);feature.popup.destroy();feature.popup=null}},a=function(v){r.getJSONP("//tinygeocoder.com/create-api.php?q="+v.location+"&callback=jsonp",function(z){z=(new OpenLayers.Geometry.Point(z[1],z[0])).transform(i,h);var C=OpenLayers.Util.extend({},
+A);if(!v.size||isNaN(v.size))v.size=14;C.pointRadius=v.size;C.graphicOpacity=1;C.externalGraphic=v.icon;z=new OpenLayers.Feature.Vector(z,null,C);if(v.text)z.attributes={text:v.text};j.addFeatures([z])})};j=new OpenLayers.Layer.Vector("Point Layer",{style:A});s.map.addLayer(j);for(var g=0,l=s.markers.length;g<l;g++){var k=s.markers[g];if(k.text)if(!p){p=new OpenLayers.Control.SelectFeature(j);s.map.addControl(p);p.activate();j.events.on({featureselected:y,featureunselected:x})}if(k.location)a(k);
+else{var t=(new OpenLayers.Geometry.Point(k.lng,k.lat)).transform(i,h),u=OpenLayers.Util.extend({},A);if(!k.size||isNaN(k.size))k.size=14;u.pointRadius=k.size;u.graphicOpacity=1;u.externalGraphic=k.icon;t=new OpenLayers.Feature.Vector(t,null,u);if(k.text)t.attributes={text:k.text};j.addFeatures([t])}}}}else setTimeout(function(){d()},13)};d()},start:function(s,d){f(d,"block")},end:function(s,d){f(d,"none")},_teardown:function(){q&&q.removeChild(b);b=map=e=h=i=j=p=m=null}}},{about:{name:"Popcorn OpenMap Plugin",
+version:"0.3",author:"@mapmeld",website:"mapadelsur.blogspot.com"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},target:"map-container",type:{elem:"select",options:["ROADMAP","SATELLITE","TERRAIN"],label:"Map Type",optional:true},zoom:{elem:"input",type:"number",label:"Zoom","default":2},lat:{elem:"input",type:"text",label:"Lat",optional:true},lng:{elem:"input",type:"text",label:"Lng",optional:true},location:{elem:"input",type:"text",label:"Location",
+"default":"Toronto, Ontario, Canada"},markers:{elem:"input",type:"text",label:"List Markers",optional:true}}})})(Popcorn);document.addEventListener("click",function(r){r=r.target;if(r.nodeName==="A"||r.parentNode&&r.parentNode.nodeName==="A")Popcorn.instances.forEach(function(f){f.options.pauseOnLinkClicked&&f.pause()})},false);(function(r){var f={},n=0,c=document.createElement("span"),b=["webkit","Moz","ms","O",""],e=["Transform","TransitionDuration","TransitionTimingFunction"],h={},i;document.getElementsByTagName("head")[0].appendChild(c);for(var j=0,p=e.length;j<p;j++)for(var m=0,o=b.length;m<o;m++){i=b[m]+e[j];if(i in c.style){h[e[j].toLowerCase()]=i;break}}document.getElementsByTagName("head")[0].appendChild(c);r.plugin("wordriver",{manifest:{about:{name:"Popcorn WordRiver Plugin"},options:{start:{elem:"input",type:"number",
+label:"Start"},end:{elem:"input",type:"number",label:"End"},target:"wordriver-container",text:{elem:"input",type:"text",label:"Text","default":"Popcorn.js"},color:{elem:"input",type:"text",label:"Color","default":"Green",optional:true}}},_setup:function(q){q._duration=q.end-q.start;var s;if(!(s=f[q.target])){s=q.target;f[s]=document.createElement("div");var d=document.getElementById(s);d&&d.appendChild(f[s]);f[s].style.height="100%";f[s].style.position="relative";s=f[s]}q._container=s;q.word=document.createElement("span");
+q.word.style.position="absolute";q.word.style.whiteSpace="nowrap";q.word.style.opacity=0;q.word.style.MozTransitionProperty="opacity, -moz-transform";q.word.style.webkitTransitionProperty="opacity, -webkit-transform";q.word.style.OTransitionProperty="opacity, -o-transform";q.word.style.transitionProperty="opacity, transform";q.word.style[h.transitionduration]="1s, "+q._duration+"s";q.word.style[h.transitiontimingfunction]="linear";q.word.innerHTML=q.text;q.word.style.color=q.color||"black"},start:function(q,
+s){s._container.appendChild(s.word);s.word.style[h.transform]="";s.word.style.fontSize=~~(30+20*Math.random())+"px";n%=s._container.offsetWidth-s.word.offsetWidth;s.word.style.left=n+"px";n+=s.word.offsetWidth+10;s.word.style[h.transform]="translateY("+(s._container.offsetHeight-s.word.offsetHeight)+"px)";s.word.style.opacity=1;setTimeout(function(){s.word.style.opacity=0},(s.end-s.start-1||1)*1E3)},end:function(q,s){s.word.style.opacity=0},_teardown:function(q){var s=document.getElementById(q.target);
+q.word.parentNode&&q._container.removeChild(q.word);f[q.target]&&!f[q.target].childElementCount&&s&&s.removeChild(f[q.target])&&delete f[q.target]}})})(Popcorn);(function(r){var f=1;r.plugin("timeline",function(n){var c=document.getElementById(n.target),b=document.createElement("div"),e,h=true;if(c&&!c.firstChild){c.appendChild(e=document.createElement("div"));e.style.width="inherit";e.style.height="inherit";e.style.overflow="auto"}else e=c.firstChild;b.style.display="none";b.id="timelineDiv"+f;n.direction=n.direction||"up";if(n.direction.toLowerCase()==="down")h=false;if(c&&e)h?e.insertBefore(b,e.firstChild):e.appendChild(b);f++;b.innerHTML="<p><span id='big' style='font-size:24px; line-height: 130%;' >"+
+n.title+"</span><br /><span id='mid' style='font-size: 16px;'>"+n.text+"</span><br />"+n.innerHTML;return{start:function(i,j){b.style.display="block";if(j.direction==="down")e.scrollTop=e.scrollHeight},end:function(){b.style.display="none"},_teardown:function(){e&&b&&e.removeChild(b)&&!e.firstChild&&c.removeChild(e)}}},{about:{name:"Popcorn Timeline Plugin",version:"0.1",author:"David Seifried @dcseifried",website:"dseifried.wordpress.com"},options:{start:{elem:"input",type:"number",label:"Start"},
+end:{elem:"input",type:"number",label:"End"},target:"feed-container",title:{elem:"input",type:"text",label:"Title"},text:{elem:"input",type:"text",label:"Text"},innerHTML:{elem:"input",type:"text",label:"HTML Code",optional:true},direction:{elem:"select",options:["DOWN","UP"],label:"Direction",optional:true}}})})(Popcorn);(function(r,f){var n={};r.plugin("documentcloud",{manifest:{about:{name:"Popcorn Document Cloud Plugin",version:"0.1",author:"@humphd, @ChrisDeCairos",website:"http://vocamus.net/dave"},options:{start:{elem:"input",type:"number",label:"Start"},end:{elem:"input",type:"number",label:"End"},target:"documentcloud-container",width:{elem:"input",type:"text",label:"Width",optional:true},height:{elem:"input",type:"text",label:"Height",optional:true},src:{elem:"input",type:"url",label:"PDF URL","default":"http://www.documentcloud.org/documents/70050-urbina-day-1-in-progress.html"},
+preload:{elem:"input",type:"checkbox",label:"Preload","default":true},page:{elem:"input",type:"number",label:"Page Number",optional:true},aid:{elem:"input",type:"number",label:"Annotation Id",optional:true}}},_setup:function(c){function b(){function m(v){c._key=v.api.getId();c._changeView=function(z){c.aid?z.pageSet.showAnnotation(z.api.getAnnotation(c.aid)):z.api.setCurrentPage(c.page)}}function o(){n[c._key]={num:1,id:c._containerId};h.loaded=true}h.loaded=false;var q=c.url.replace(/\.html$/,".js"),
+s=c.target,d=f.getElementById(s),A=f.createElement("div"),y=r.position(d),x=c.width||y.width;y=c.height||y.height;var a=c.sidebar||true,g=c.text||true,l=c.pdf||true,k=c.showAnnotations||true,t=c.zoom||700,u=c.search||true;if(!function(v){var z=false;r.forEach(h.viewers,function(C){if(C.api.getSchema().canonicalURL===v){m(C);C=n[c._key];c._containerId=C.id;C.num+=1;z=true;h.loaded=true}});return z}(c.url)){A.id=c._containerId=r.guid(s);s="#"+A.id;d.appendChild(A);i.trigger("documentready");h.load(q,
+{width:x,height:y,sidebar:a,text:g,pdf:l,showAnnotations:k,zoom:t,search:u,container:s,afterLoad:c.page||c.aid?function(v){m(v);c._changeView(v);A.style.visibility="hidden";v.elements.pages.hide();o()}:function(v){m(v);o();A.style.visibility="hidden";v.elements.pages.hide()}})}}function e(){window.DV.loaded?b():setTimeout(e,25)}var h=window.DV=window.DV||{},i=this;if(h.loading)e();else{h.loading=true;h.recordHit="//www.documentcloud.org/pixel.gif";var j=f.createElement("link"),p=f.getElementsByTagName("head")[0];
+j.rel="stylesheet";j.type="text/css";j.media="screen";j.href="//s3.documentcloud.org/viewer/viewer-datauri.css";p.appendChild(j);h.loaded=false;r.getScript("http://s3.documentcloud.org/viewer/viewer.js",function(){h.loading=false;b()})}},start:function(c,b){var e=f.getElementById(b._containerId),h=DV.viewers[b._key];(b.page||b.aid)&&h&&b._changeView(h);if(e&&h){e.style.visibility="visible";h.elements.pages.show()}},end:function(c,b){var e=f.getElementById(b._containerId);if(e&&DV.viewers[b._key]){e.style.visibility=
+"hidden";DV.viewers[b._key].elements.pages.hide()}},_teardown:function(c){var b=f.getElementById(c._containerId);if((c=c._key)&&DV.viewers[c]&&--n[c].num===0){for(DV.viewers[c].api.unload();b.hasChildNodes();)b.removeChild(b.lastChild);b.parentNode.removeChild(b)}}})})(Popcorn,window.document);(function(r){r.parser("parseJSON","JSON",function(f){var n={title:"",remote:"",data:[]};r.forEach(f.data,function(c){n.data.push(c)});return n})})(Popcorn);(function(r){r.parser("parseSBV",function(f){var n={title:"",remote:"",data:[]},c=[],b=0,e=0,h=function(q){q=q.split(":");var s=q.length-1,d;try{d=parseInt(q[s-1],10)*60+parseFloat(q[s],10);if(s===2)d+=parseInt(q[0],10)*3600}catch(A){throw"Bad cue";}return d},i=function(q,s){var d={};d[q]=s;return d};f=f.text.split(/(?:\r\n|\r|\n)/gm);for(e=f.length;b<e;){var j={},p=[],m=f[b++].split(",");try{j.start=h(m[0]);for(j.end=h(m[1]);b<e&&f[b];)p.push(f[b++]);j.text=p.join("<br />");c.push(i("subtitle",j))}catch(o){for(;b<
+e&&f[b];)b++}for(;b<e&&!f[b];)b++}n.data=c;return n})})(Popcorn);(function(r){function f(c,b){var e={};e[c]=b;return e}function n(c){c=c.split(":");try{var b=c[2].split(",");if(b.length===1)b=c[2].split(".");return parseFloat(c[0],10)*3600+parseFloat(c[1],10)*60+parseFloat(b[0],10)+parseFloat(b[1],10)/1E3}catch(e){return 0}}r.parser("parseSRT",function(c){var b={title:"",remote:"",data:[]},e=[],h=0,i=0,j,p,m,o;c=c.text.split(/(?:\r\n|\r|\n)/gm);for(h=c.length-1;h>=0&&!c[h];)h--;m=h+1;for(h=0;h<m;h++){o={};p=[];o.id=parseInt(c[h++],10);j=c[h++].split(/[\t ]*--\>[\t ]*/);
+o.start=n(j[0]);i=j[1].indexOf(" ");if(i!==-1)j[1]=j[1].substr(0,i);for(o.end=n(j[1]);h<m&&c[h];)p.push(c[h++]);o.text=p.join("\\N").replace(/\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}/gi,"");o.text=o.text.replace(/</g,"&lt;").replace(/>/g,"&gt;");o.text=o.text.replace(/&lt;(\/?(font|b|u|i|s))((\s+(\w|\w[\w\-]*\w)(\s*=\s*(?:\".*?\"|'.*?'|[^'\">\s]+))?)+\s*|\s*)(\/?)&gt;/gi,"<$1$3$7>");o.text=o.text.replace(/\\N/gi,"<br />");e.push(f("subtitle",o))}b.data=e;return b})})(Popcorn);(function(r){function f(b,e){var h=b.substr(10).split(","),i;i={start:n(h[e.start]),end:n(h[e.end])};if(i.start===-1||i.end===-1)throw"Invalid time";var j=q.call(m,/\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}/gi,""),p=j.replace,m;m=h.length;q=[];for(var o=e.text;o<m;o++)q.push(h[o]);m=q.join(",");var q=m.replace;i.text=p.call(j,/\\N/gi,"<br />");return i}function n(b){var e=b.split(":");if(b.length!==10||e.length<3)return-1;return parseInt(e[0],10)*3600+parseInt(e[1],10)*60+parseFloat(e[2],10)}function c(b,
+e){var h={};h[b]=e;return h}r.parser("parseSSA",function(b){var e={title:"",remote:"",data:[]},h=[],i=0,j;b=b.text.split(/(?:\r\n|\r|\n)/gm);for(j=b.length;i<j&&b[i]!=="[Events]";)i++;var p=b[++i].substr(8).split(", "),m={},o,q;q=0;for(o=p.length;q<o;q++)if(p[q]==="Start")m.start=q;else if(p[q]==="End")m.end=q;else if(p[q]==="Text")m.text=q;for(;++i<j&&b[i]&&b[i][0]!=="[";)try{h.push(c("subtitle",f(b[i],m)))}catch(s){}e.data=h;return e})})(Popcorn);(function(r){function f(i,j,p){var m=i.firstChild;i=n(i,p);p=[];for(var o;m;){if(m.nodeType===1)if(m.nodeName==="p")p.push(c(m,j,i));else if(m.nodeName==="div"){o=b(m.getAttribute("begin"));if(o<0)o=j;p.push.apply(p,f(m,o,i))}m=m.nextSibling}return p}function n(i,j){var p=i.getAttribute("region");return p!==null?p:j||""}function c(i,j,p){var m={};m.text=(i.textContent||i.text).replace(e,"").replace(h,"<br />");m.id=i.getAttribute("xml:id")||i.getAttribute("id");m.start=b(i.getAttribute("begin"),j);
+m.end=b(i.getAttribute("end"),j);m.target=n(i,p);if(m.end<0){m.end=b(i.getAttribute("duration"),0);if(m.end>=0)m.end+=m.start;else m.end=Number.MAX_VALUE}return{subtitle:m}}function b(i,j){var p;if(!i)return-1;try{return r.util.toSeconds(i)}catch(m){for(var o=i.length-1;o>=0&&i[o]<="9"&&i[o]>="0";)o--;p=o;o=parseFloat(i.substring(0,p));p=i.substring(p);return o*({h:3600,m:60,s:1,ms:0.0010}[p]||-1)+(j||0)}}var e=/^[\s]+|[\s]+$/gm,h=/(?:\r\n|\r|\n)/gm;r.parser("parseTTML",function(i){var j={title:"",
+remote:"",data:[]};if(!i.xml||!i.xml.documentElement)return j;i=i.xml.documentElement.firstChild;if(!i)return j;for(;i.nodeName!=="body";)i=i.nextSibling;if(i)j.data=f(i,0);return j})})(Popcorn);(function(r){r.parser("parseTTXT",function(f){var n={title:"",remote:"",data:[]},c=function(j){j=j.split(":");var p=0;try{return parseFloat(j[0],10)*60*60+parseFloat(j[1],10)*60+parseFloat(j[2],10)}catch(m){p=0}return p},b=function(j,p){var m={};m[j]=p;return m};f=f.xml.lastChild.lastChild;for(var e=Number.MAX_VALUE,h=[];f;){if(f.nodeType===1&&f.nodeName==="TextSample"){var i={};i.start=c(f.getAttribute("sampleTime"));i.text=f.getAttribute("text");if(i.text){i.end=e-0.0010;h.push(b("subtitle",i))}e=
+i.start}f=f.previousSibling}n.data=h.reverse();return n})})(Popcorn);(function(r){function f(c){var b=c.split(":");c=c.length;var e;if(c!==12&&c!==9)throw"Bad cue";c=b.length-1;try{e=parseInt(b[c-1],10)*60+parseFloat(b[c],10);if(c===2)e+=parseInt(b[0],10)*3600}catch(h){throw"Bad cue";}return e}function n(c,b){var e={};e[c]=b;return e}r.parser("parseVTT",function(c){var b={title:"",remote:"",data:[]},e=[],h=0,i=0,j,p;c=c.text.split(/(?:\r\n|\r|\n)/gm);i=c.length;if(i===0||c[0]!=="WEBVTT")return b;for(h++;h<i;){j=[];try{for(var m=h;m<i&&!c[m];)m++;h=m;var o=c[h++];m=
+void 0;var q={};if(!o||o.indexOf("--\>")===-1)throw"Bad cue";m=o.replace(/--\>/," --\> ").split(/[\t ]+/);if(m.length<2)throw"Bad cue";q.id=o;q.start=f(m[0]);q.end=f(m[2]);for(p=q;h<i&&c[h];)j.push(c[h++]);p.text=j.join("<br />");e.push(n("subtitle",p))}catch(s){for(h=h;h<i&&c[h];)h++;h=h}}b.data=e;return b})})(Popcorn);(function(r){r.parser("parseXML","XML",function(f){var n={title:"",remote:"",data:[]},c={},b=function(m){m=m.split(":");if(m.length===1)return parseFloat(m[0],10);else if(m.length===2)return parseFloat(m[0],10)+parseFloat(m[1]/12,10);else if(m.length===3)return parseInt(m[0]*60,10)+parseFloat(m[1],10)+parseFloat(m[2]/12,10);else if(m.length===4)return parseInt(m[0]*3600,10)+parseInt(m[1]*60,10)+parseFloat(m[2],10)+parseFloat(m[3]/12,10)},e=function(m){for(var o={},q=0,s=m.length;q<s;q++){var d=m.item(q).nodeName,
+A=m.item(q).nodeValue,y=c[A];if(d==="in")o.start=b(A);else if(d==="out")o.end=b(A);else if(d==="resourceid")for(var x in y){if(y.hasOwnProperty(x))if(!o[x]&&x!=="id")o[x]=y[x]}else o[d]=A}return o},h=function(m,o){var q={};q[m]=o;return q},i=function(m,o,q){var s={};r.extend(s,o,e(m.attributes),{text:m.textContent||m.text});o=m.childNodes;if(o.length<1||o.length===1&&o[0].nodeType===3)if(q)c[s.id]=s;else n.data.push(h(m.nodeName,s));else for(m=0;m<o.length;m++)o[m].nodeType===1&&i(o[m],s,q)};f=f.documentElement.childNodes;
+for(var j=0,p=f.length;j<p;j++)if(f[j].nodeType===1)f[j].nodeName==="manifest"?i(f[j],{},true):i(f[j],{},false);return n})})(Popcorn);(function(){var r=false,f=false;Popcorn.player("soundcloud",{_canPlayType:function(n,c){return/(?:http:\/\/www\.|http:\/\/|www\.|\.|^)(soundcloud)/.test(c)&&n.toLowerCase()!=="video"},_setup:function(n){function c(){r=true;SC.initialize({client_id:"PRaNFlda6Bhf5utPjUsptg"});SC.get("/resolve",{url:e.src},function(A){e.width=e.style.width?""+e.offsetWidth:"560";e.height=e.style.height?""+e.offsetHeight:"315";h.scrolling="no";h.frameborder="no";h.id="soundcloud-"+Popcorn.guid();h.src="http://w.soundcloud.com/player/?url="+
+A.uri+"&show_artwork=false&buying=false&liking=false&sharing=false";h.width="100%";h.height="100%";n.loadListener=function(){n.widget=o=SC.Widget(h.id);o.bind(SC.Widget.Events.FINISH,function(){e.pause();e.dispatchEvent("ended")});o.bind(SC.Widget.Events.PLAY_PROGRESS,function(y){j=y.currentPosition/1E3;e.dispatchEvent("timeupdate")});o.bind(SC.Widget.Events.PLAY,function(){p=m=false;e.dispatchEvent("play");e.dispatchEvent("playing");e.currentTime=j;d.next()});o.bind(SC.Widget.Events.PAUSE,function(){p=
+m=true;e.dispatchEvent("pause");d.next()});o.bind(SC.Widget.Events.READY,function(){o.getDuration(function(y){q=y/1E3;e.style.visibility="visible";e.dispatchEvent("durationchange");e.readyState=4;e.dispatchEvent("readystatechange");e.dispatchEvent("loadedmetadata");e.dispatchEvent("loadeddata");e.dispatchEvent("canplaythrough");e.dispatchEvent("load");!e.paused&&e.play()});o.getVolume(function(y){i=y/100})})};h.addEventListener("load",n.loadListener,false);e.appendChild(h)})}function b(){if(f)(function A(){setTimeout(function(){r?
+c():A()},100)})();else{f=true;Popcorn.getScript("http://w.soundcloud.com/player/api.js",function(){Popcorn.getScript("http://connect.soundcloud.com/sdk.js",function(){c()})})}}var e=this,h=document.createElement("iframe"),i=1,j=0,p=true,m=true,o,q=0,s=false,d=Popcorn.player.playerQueue();n._container=h;e.style.visibility="hidden";e.play=function(){p=false;d.add(function(){if(m)o&&o.play();else d.next()})};e.pause=function(){p=true;d.add(function(){if(m)d.next();else o&&o.pause()})};Object.defineProperties(e,
+{muted:{set:function(A){if(A){o&&o.getVolume(function(y){i=y/100});o&&o.setVolume(0);s=true}else{o&&o.setVolume(i*100);s=false}e.dispatchEvent("volumechange")},get:function(){return s}},volume:{set:function(A){o&&o.setVolume(A*100);i=A;e.dispatchEvent("volumechange")},get:function(){return s?0:i}},currentTime:{set:function(A){j=A;o&&o.seekTo(A*1E3);e.dispatchEvent("seeked");e.dispatchEvent("timeupdate")},get:function(){return j}},duration:{get:function(){return q}},paused:{get:function(){return p}}});
+r?c():b()},_teardown:function(n){var c=n.widget,b=SC.Widget.Events,e=n._container;n.destroyed=true;if(c)for(var h in b)c&&c.unbind(b[h]);else e.removeEventListener("load",n.loadEventListener,false)}})})();(function(){function r(n){var c=r.options;n=c.parser[c.strictMode?"strict":"loose"].exec(n);for(var b={},e=14;e--;)b[c.key[e]]=n[e]||"";b[c.q.name]={};b[c.key[12]].replace(c.q.parser,function(h,i,j){if(i)b[c.q.name][i]=j});return b}function f(n,c){return/player.vimeo.com\/video\/\d+/.test(c)||/vimeo.com\/\d+/.test(c)}r.options={strictMode:false,key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q:{name:"queryKey",
+parser:/(?:^|&)([^&=]*)=?([^&]*)/g},parser:{strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};Popcorn.player("vimeo",{_canPlayType:f,_setup:function(n){function c(l,k){var t=y.src.split("?")[0],u=JSON.stringify({method:l,
+value:k});if(t.substr(0,2)==="//")t=window.location.protocol+t;y.contentWindow?y.contentWindow.postMessage(u,t):o.unload()}function b(l){if(l.origin==="http://player.vimeo.com"){var k;try{k=JSON.parse(l.data)}catch(t){console.warn(t)}if(k.player_id==m){k.method&&a[k.method]&&a[k.method](k);k.event&&g[k.event]&&g[k.event](k)}}}function e(){d||(d=setInterval(function(){o.dispatchEvent("timeupdate")},i));s||(s=setInterval(function(){c("getCurrentTime")},j))}function h(){if(d){clearInterval(d);d=0}if(s){clearInterval(s);
+s=0}}var i=250,j=16,p={MEDIA_ERR_ABORTED:1,MEDIA_ERR_NETWORK:2,MEDIA_ERR_DECODE:3,MEDIA_ERR_SRC_NOT_SUPPORTED:4},m,o=this,q={q:[],queue:function(l){this.q.push(l);this.process()},process:function(){if(A)for(;this.q.length;)this.q.shift()()}},s,d,A,y=document.createElement("iframe"),x={error:null,src:o.src,NETWORK_EMPTY:0,NETWORK_IDLE:1,NETWORK_LOADING:2,NETWORK_NO_SOURCE:3,networkState:0,HAVE_NOTHING:0,HAVE_METADATA:1,HAVE_CURRENT_DATA:2,HAVE_FUTURE_DATA:3,HAVE_ENOUGH_DATA:4,readyState:0,seeking:false,
+currentTime:0,duration:NaN,paused:true,ended:false,autoplay:false,loop:false,volume:1,muted:false,width:0,height:0};Popcorn.forEach("error networkState readyState seeking duration paused ended".split(" "),function(l){Object.defineProperty(o,l,{get:function(){return x[l]}})});Object.defineProperties(o,{src:{get:function(){return x.src},set:function(l){x.src=l;o.load()}},currentTime:{get:function(){return x.currentTime},set:function(l){q.queue(function(){c("seekTo",l)});x.seeking=true;o.dispatchEvent("seeking")}},
+autoplay:{get:function(){return x.autoplay},set:function(l){x.autoplay=!!l}},loop:{get:function(){return x.loop},set:function(l){x.loop=!!l;q.queue(function(){c("setLoop",loop)})}},volume:{get:function(){return x.volume},set:function(l){x.volume=l;q.queue(function(){c("setVolume",x.muted?0:x.volume)});o.dispatchEvent("volumechange")}},muted:{get:function(){return x.muted},set:function(l){x.muted=!!l;q.queue(function(){c("setVolume",x.muted?0:x.volume)});o.dispatchEvent("volumechange")}},width:{get:function(){return y.width},
+set:function(l){y.width=l}},height:{get:function(){return y.height},set:function(l){y.height=l}}});var a={getCurrentTime:function(l){x.currentTime=parseFloat(l.value)},getDuration:function(l){x.duration=parseFloat(l.value);if(!isNaN(x.duration)){x.readyState=4;o.dispatchEvent("durationchange");o.dispatchEvent("loadedmetadata");o.dispatchEvent("loadeddata");o.dispatchEvent("canplay");o.dispatchEvent("canplaythrough")}},getVolume:function(l){x.volume=parseFloat(l.value)}},g={ready:function(){c("addEventListener",
+"loadProgress");c("addEventListener","playProgress");c("addEventListener","play");c("addEventListener","pause");c("addEventListener","finish");c("addEventListener","seek");c("getDuration");A=true;q.process();o.dispatchEvent("loadstart")},loadProgress:function(l){o.dispatchEvent("progress");x.duration=parseFloat(l.data.duration)},playProgress:function(l){x.currentTime=parseFloat(l.data.seconds)},play:function(){if(x.seeking){x.seeking=false;o.dispatchEvent("seeked")}x.paused=false;x.ended=false;e();
+o.dispatchEvent("play")},pause:function(){x.paused=true;h();o.dispatchEvent("pause")},finish:function(){x.ended=true;h();o.dispatchEvent("ended")},seek:function(l){x.currentTime=parseFloat(l.data.seconds);x.seeking=false;x.ended=false;o.dispatchEvent("timeupdate");o.dispatchEvent("seeked")}};o.load=function(){A=false;m=Popcorn.guid();var l=r(x.src),k={},t=[],u={api:1,player_id:m};if(f(o.nodeName,l.source)){Popcorn.extend(k,n);Popcorn.extend(k,l.queryKey);Popcorn.extend(k,u);l="http://player.vimeo.com/video/"+
+/\d+$/.exec(l.path)+"?";for(var v in k)k.hasOwnProperty(v)&&t.push(encodeURIComponent(v)+"="+encodeURIComponent(k[v]));l+=t.join("&");x.loop=!!l.match(/loop=1/);x.autoplay=!!l.match(/autoplay=1/);y.width=o.style.width?o.style.width:500;y.height=o.style.height?o.style.height:281;y.frameBorder=0;y.webkitAllowFullScreen=true;y.mozAllowFullScreen=true;y.allowFullScreen=true;y.src=l;o.appendChild(y)}else{l=x.MEDIA_ERR_SRC_NOT_SUPPORTED;x.error={};Popcorn.extend(x.error,p);x.error.code=l;o.dispatchEvent("error")}};
+o.unload=function(){h();window.removeEventListener("message",b,false)};o.play=function(){q.queue(function(){c("play")})};o.pause=function(){q.queue(function(){c("pause")})};setTimeout(function(){window.addEventListener("message",b,false);o.load()},0)},_teardown:function(){this.unload&&this.unload()}})})();(function(r,f){r.onYouTubePlayerAPIReady=function(){onYouTubePlayerAPIReady.ready=true;for(var c=0;c<onYouTubePlayerAPIReady.waiting.length;c++)onYouTubePlayerAPIReady.waiting[c]()};if(r.YT){r.quarantineYT=r.YT;r.YT=null}onYouTubePlayerAPIReady.waiting=[];var n=false;f.player("youtube",{_canPlayType:function(c,b){return typeof b==="string"&&/(?:http:\/\/www\.|http:\/\/|www\.|\.|^)(youtu)/.test(b)&&c.toLowerCase()!=="video"},_setup:function(c){if(!r.YT&&!n){n=true;f.getScript("//youtube.com/player_api")}var b=
+this,e=false,h=document.createElement("div"),i=0,j=true,p=false,m=0,o=false,q=100,s=f.player.playerQueue(),d=function(){f.player.defineProperty(b,"currentTime",{set:function(y){if(!c.destroyed){p=true;i=Math.round(+y*100)/100}},get:function(){return i}});f.player.defineProperty(b,"paused",{get:function(){return j}});f.player.defineProperty(b,"muted",{set:function(y){if(c.destroyed)return y;if(c.youtubeObject.isMuted()!==y){y?c.youtubeObject.mute():c.youtubeObject.unMute();o=c.youtubeObject.isMuted();
+b.dispatchEvent("volumechange")}return c.youtubeObject.isMuted()},get:function(){if(c.destroyed)return 0;return c.youtubeObject.isMuted()}});f.player.defineProperty(b,"volume",{set:function(y){if(c.destroyed)return y;if(c.youtubeObject.getVolume()/100!==y){c.youtubeObject.setVolume(y*100);q=c.youtubeObject.getVolume();b.dispatchEvent("volumechange")}return c.youtubeObject.getVolume()/100},get:function(){if(c.destroyed)return 0;return c.youtubeObject.getVolume()/100}});b.play=function(){if(!c.destroyed){j=
+false;s.add(function(){if(c.youtubeObject.getPlayerState()!==1){p=false;c.youtubeObject.playVideo()}else s.next()})}};b.pause=function(){if(!c.destroyed){j=true;s.add(function(){c.youtubeObject.getPlayerState()!==2?c.youtubeObject.pauseVideo():s.next()})}}};h.id=b.id+f.guid();c._container=h;b.appendChild(h);var A=function(){var y,x,a,g,l=true,k=function(){if(!c.destroyed){if(p)if(i===c.youtubeObject.getCurrentTime()){p=false;b.dispatchEvent("seeked");b.dispatchEvent("timeupdate")}else c.youtubeObject.seekTo(i);
+else{i=c.youtubeObject.getCurrentTime();b.dispatchEvent("timeupdate")}setTimeout(k,250)}},t=function(z){var C=c.youtubeObject.getDuration();if(isNaN(C)||C===0)setTimeout(function(){t(z*2)},z*1E3);else{b.duration=C;b.dispatchEvent("durationchange");b.dispatchEvent("loadedmetadata");b.dispatchEvent("loadeddata");b.readyState=4;k();b.dispatchEvent("canplaythrough")}};c.controls=+c.controls===0||+c.controls===1?c.controls:1;c.annotations=+c.annotations===1||+c.annotations===3?c.annotations:1;y=/^.*(?:\/|v=)(.{11})/.exec(b.src)[1];
+x=(b.src.split("?")[1]||"").replace(/v=.{11}/,"");x=x.replace(/&t=(?:(\d+)m)?(?:(\d+)s)?/,function(z,C,E){C|=0;E|=0;m=+E+C*60;return""});x=x.replace(/&start=(\d+)?/,function(z,C){C|=0;m=C;return""});e=/autoplay=1/.test(x);x=x.split(/[\&\?]/g);a={wmode:"transparent"};for(var u=0;u<x.length;u++){g=x[u].split("=");a[g[0]]=g[1]}c.youtubeObject=new YT.Player(h.id,{height:"100%",width:"100%",wmode:"transparent",playerVars:a,videoId:y,events:{onReady:function(){q=b.volume;o=b.muted;v();j=b.paused;d();c.youtubeObject.playVideo();
+b.currentTime=m},onStateChange:function(z){if(!(c.destroyed||z.data===-1))if(z.data===2){j=true;b.dispatchEvent("pause");s.next()}else if(z.data===1&&!l){j=false;b.dispatchEvent("play");b.dispatchEvent("playing");s.next()}else if(z.data===0)b.dispatchEvent("ended");else if(z.data===1&&l){l=false;if(e||!b.paused)j=false;j&&c.youtubeObject.pauseVideo();t(0.025)}},onError:function(z){if([2,100,101,150].indexOf(z.data)!==-1){b.error={customCode:z.data};b.dispatchEvent("error")}}}});var v=function(){if(!c.destroyed){if(o!==
+c.youtubeObject.isMuted()){o=c.youtubeObject.isMuted();b.dispatchEvent("volumechange")}if(q!==c.youtubeObject.getVolume()){q=c.youtubeObject.getVolume();b.dispatchEvent("volumechange")}setTimeout(v,250)}}};onYouTubePlayerAPIReady.ready?A():onYouTubePlayerAPIReady.waiting.push(A)},_teardown:function(c){c.destroyed=true;var b=c.youtubeObject;if(b){b.stopVideo();b.clearVideo&&b.clearVideo()}this.removeChild(document.getElementById(c._container.id))}})})(window,Popcorn);
diff --git a/record-and-playback/presentation_export/playback/presentation_export/lib/popcorn.chattimeline.js b/record-and-playback/presentation_export/playback/presentation_export/lib/popcorn.chattimeline.js
new file mode 100755
index 0000000000000000000000000000000000000000..d530cb7e046543cff3cee9053a6f63b27d942454
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/lib/popcorn.chattimeline.js
@@ -0,0 +1,125 @@
+// PLUGIN: Timeline
+(function ( Popcorn ) {
+
+  /**
+     * chat-timeline popcorn plug-in
+     * Adds data associated with a certain time in the video, which creates a scrolling view of each item as the video progresses
+     * Options parameter will need a start, target, title, and text
+     * -Start is the time that you want this plug-in to execute
+     * -End is the time that you want this plug-in to stop executing, tho for this plugin an end time may not be needed ( optional )
+     * -Target is the id of the DOM element that you want the timeline to appear in. This element must be in the DOM
+     * -Name is the name of the current chat message sender
+     * -Text is text is simply related text that will be displayed
+     * -direction specifies whether the timeline will grow from the top or the bottom, receives input as "UP" or "DOWN"
+     * @param {Object} options
+     *
+     * Example:
+      var p = Popcorn("#video")
+        .timeline( {
+         start: 5, // seconds
+         target: "timeline",
+         name: "Seneca",
+         text: "Welcome to seneca",
+      } )
+    *
+  */
+
+  var i = 1;
+
+  Popcorn.plugin( "chattimeline" , function( options ) {
+
+    var target = document.getElementById( options.target ),
+        contentDiv = document.createElement( "div" ),
+        goingUp = true;
+
+    contentDiv.style.display = "none";
+    contentDiv.setAttribute('aria-hidden', true);
+    contentDiv.id = "timelineDiv" + i;
+
+    //  Default to up if options.direction is non-existant or not up or down
+    options.direction = options.direction || "up";
+    if ( options.direction.toLowerCase() === "down" ) {
+
+      goingUp = false;
+    }
+
+    if ( target ) {
+      // if this isnt the first div added to the target div
+      if( goingUp ){
+        // insert the current div before the previous div inserted
+        target.insertBefore( contentDiv, target.firstChild );
+      }
+      else {
+
+        target.appendChild( contentDiv );
+      }
+
+    }
+
+    i++;
+
+    //  Default to empty if not used
+    //options.innerHTML = options.innerHTML || "";
+
+    contentDiv.innerHTML = "<strong>" + options.name + ":</strong>" + options.message;
+
+    return {
+
+      start: function( event, options ) {
+        contentDiv.style.display = "block";
+        if ($("#exposechat").is(':checked')) {
+          contentDiv.setAttribute('aria-hidden', false);
+        }
+        if( options.direction === "down" ) {
+          target.scrollTop = target.scrollHeight;
+        }
+	
+        if ($("#accEnabled").is(':checked'))
+          addTime(7);
+      },
+
+      end: function( event, options ) {
+        contentDiv.style.display = "none";
+        contentDiv.setAttribute('aria-hidden', true);
+      },
+
+      _teardown: function( options ) {
+
+        ( target && contentDiv ) && target.removeChild( contentDiv ) && !target.firstChild
+      }
+    };
+  },
+  {
+
+    options: {
+      start: {
+        elem: "input",
+        type: "number",
+        label: "Start"
+      },
+      end: {
+        elem: "input",
+        type: "number",
+        label: "End"
+      },
+      target: "feed-container",
+      name: {
+        elem: "input",
+        type: "text",
+        label: "Name"
+      },
+      message: {
+        elem: "input",
+        type: "text",
+        label: "Message"
+      },
+      direction: {
+        elem: "select",
+        options: [ "DOWN", "UP" ],
+        label: "Direction",
+        optional: true
+      }
+    }
+  });
+
+})( Popcorn );
diff --git a/record-and-playback/presentation_export/playback/presentation_export/lib/spin.min.js b/record-and-playback/presentation_export/playback/presentation_export/lib/spin.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..ebfbb1a2e2e433736a408aefcc1c34d9bcd68028
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/lib/spin.min.js
@@ -0,0 +1,2 @@
+//fgnass.github.com/spin.js#v2.0.1
+!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define(b):a.Spinner=b()}(this,function(){"use strict";function a(a,b){var c,d=document.createElement(a||"div");for(c in b)d[c]=b[c];return d}function b(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function c(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=j.substring(0,j.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return l[e]||(m.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",m.cssRules.length),l[e]=1),e}function d(a,b){var c,d,e=a.style;for(b=b.charAt(0).toUpperCase()+b.slice(1),d=0;d<k.length;d++)if(c=k[d]+b,void 0!==e[c])return c;return void 0!==e[b]?b:void 0}function e(a,b){for(var c in b)a.style[d(a,c)||c]=b[c];return a}function f(a){for(var b=1;b<arguments.length;b++){var c=arguments[b];for(var d in c)void 0===a[d]&&(a[d]=c[d])}return a}function g(a,b){return"string"==typeof a?a:a[b%a.length]}function h(a){this.opts=f(a||{},h.defaults,n)}function i(){function c(b,c){return a("<"+b+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',c)}m.addRule(".spin-vml","behavior:url(#default#VML)"),h.prototype.lines=function(a,d){function f(){return e(c("group",{coordsize:k+" "+k,coordorigin:-j+" "+-j}),{width:k,height:k})}function h(a,h,i){b(m,b(e(f(),{rotation:360/d.lines*a+"deg",left:~~h}),b(e(c("roundrect",{arcsize:d.corners}),{width:j,height:d.width,left:d.radius,top:-d.width>>1,filter:i}),c("fill",{color:g(d.color,a),opacity:d.opacity}),c("stroke",{opacity:0}))))}var i,j=d.length+d.width,k=2*j,l=2*-(d.width+d.length)+"px",m=e(f(),{position:"absolute",top:l,left:l});if(d.shadow)for(i=1;i<=d.lines;i++)h(i,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(i=1;i<=d.lines;i++)h(i);return b(a,m)},h.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d<e.childNodes.length&&(e=e.childNodes[b+d],e=e&&e.firstChild,e=e&&e.firstChild,e&&(e.opacity=c))}}var j,k=["webkit","Moz","ms","O"],l={},m=function(){var c=a("style",{type:"text/css"});return b(document.getElementsByTagName("head")[0],c),c.sheet||c.styleSheet}(),n={lines:12,length:7,width:5,radius:10,rotate:0,corners:1,color:"#000",direction:1,speed:1,trail:100,opacity:.25,fps:20,zIndex:2e9,className:"spinner",top:"50%",left:"50%",position:"absolute"};h.defaults={},f(h.prototype,{spin:function(b){this.stop();{var c=this,d=c.opts,f=c.el=e(a(0,{className:d.className}),{position:d.position,width:0,zIndex:d.zIndex});d.radius+d.length+d.width}if(e(f,{left:d.left,top:d.top}),b&&b.insertBefore(f,b.firstChild||null),f.setAttribute("role","progressbar"),c.lines(f,c.opts),!j){var g,h=0,i=(d.lines-1)*(1-d.direction)/2,k=d.fps,l=k/d.speed,m=(1-d.opacity)/(l*d.trail/100),n=l/d.lines;!function o(){h++;for(var a=0;a<d.lines;a++)g=Math.max(1-(h+(d.lines-a)*n)%l*m,d.opacity),c.opacity(f,a*d.direction+i,g,d);c.timeout=c.el&&setTimeout(o,~~(1e3/k))}()}return c},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=void 0),this},lines:function(d,f){function h(b,c){return e(a(),{position:"absolute",width:f.length+f.width+"px",height:f.width+"px",background:b,boxShadow:c,transformOrigin:"left",transform:"rotate("+~~(360/f.lines*k+f.rotate)+"deg) translate("+f.radius+"px,0)",borderRadius:(f.corners*f.width>>1)+"px"})}for(var i,k=0,l=(f.lines-1)*(1-f.direction)/2;k<f.lines;k++)i=e(a(),{position:"absolute",top:1+~(f.width/2)+"px",transform:f.hwaccel?"translate3d(0,0,0)":"",opacity:f.opacity,animation:j&&c(f.opacity,f.trail,l+k*f.direction,f.lines)+" "+1/f.speed+"s linear infinite"}),f.shadow&&b(i,e(h("#000","0 0 4px #000"),{top:"2px"})),b(d,b(i,h(g(f.color,k),"0 0 1px rgba(0,0,0,.1)")));return d},opacity:function(a,b,c){b<a.childNodes.length&&(a.childNodes[b].style.opacity=c)}});var o=e(a("group"),{behavior:"url(#default#VML)"});return!d(o,"transform")&&o.adj?i():j=d(o,"animation"),h});
\ No newline at end of file
diff --git a/record-and-playback/presentation_export/playback/presentation_export/lib/writing.js b/record-and-playback/presentation_export/playback/presentation_export/lib/writing.js
new file mode 100755
index 0000000000000000000000000000000000000000..5d27d1441e62fd0a45348593fb500c51ae63a998
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/lib/writing.js
@@ -0,0 +1,607 @@
+/**
+* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+*
+* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+*
+* This program is free software; you can redistribute it and/or modify it under the
+* terms of the GNU Lesser General Public License as published by the Free Software
+* Foundation; either version 3.0 of the License, or (at your option) any later
+* version.
+*
+* BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License along
+* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+
+// - - - START OF GLOBAL VARIABLES - - - //
+"use strict";
+
+function getUrlParameters() {
+    console.log("** Getting url params");
+    var map = {};
+    window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) { map[key] = value; });
+    return map;
+}
+
+// - - - END OF GLOBAL VARIABLES - - - //
+
+// - - - START OF JAVASCRIPT FUNCTIONS - - - //
+
+// Draw the cursor at a specific point
+function drawCursor(scaledX, scaledY, img) {
+  var containerObj = $("#slide > object");
+
+  // the offsets of the image inside its parent
+  // Note: this block is only necessary if we let the svg do the resizing
+  // of the image, see the comments in resizeSlides()
+  var imgRect = img.getBoundingClientRect();
+  var imageX = 0; //imgRect.x;
+  var imageY = 0; //imgRect.y;
+
+  // the offsets of the container that has the image inside it
+  var containerX = containerObj.offset().left;
+  var containerY = containerObj.offset().top;
+
+  // calculates the overall offsets of the image in the page
+  var imageOffsetX = containerX + imageX;
+  var imageOffsetY = containerY + imageY;
+
+  // position of the cursor relative to the container
+  var cursorXInImage = scaledX * containerObj.width();
+  var cursorYInImage = scaledY * containerObj.height();
+
+  // absolute position of the cursor in the page
+  var cursorLeft = parseInt(imageOffsetX + cursorXInImage, 10);
+  var cursorTop = parseInt(imageOffsetY + cursorYInImage, 10);
+  if (cursorLeft < 0) {
+    cursorLeft = 0;
+  }
+  if (cursorTop < 0) {
+    cursorTop = 0;
+  }
+  var cursorStyle = document.getElementById("cursor").style;
+  cursorStyle.left = cursorLeft + "px";
+  cursorStyle.top = cursorTop + "px";
+}
+
+function showCursor(show) {
+  if (show) {
+    document.getElementById("cursor").style.visibility = 'visible';
+  } else {
+    document.getElementById("cursor").style.visibility = 'hidden';
+  }
+};
+
+function setViewBox(val) {
+  if(svgobj.contentDocument) svgfile = svgobj.contentDocument.getElementById("svgfile");
+  else svgfile = svgobj.getSVGDocument('svgfile').getElementById("svgfile");
+	svgfile.setAttribute('viewBox', val);
+}
+
+function getImageAtTime(time) {
+	var curr_t = parseFloat(time);
+	var key;
+	for (key in imageAtTime) {
+		if(imageAtTime.hasOwnProperty(key)) {
+			var arry = key.split(",");
+			if ((parseFloat(arry[0]) <= curr_t) && (parseFloat(arry[1]) >= curr_t)) {
+				return imageAtTime[key];
+			}
+		}
+	}
+}
+
+function getViewboxAtTime(time) {
+	var curr_t = parseFloat(time);
+	var key;
+	for (key in vboxValues) {
+		if(vboxValues.hasOwnProperty(key)) {
+			var arry = key.split(",");
+			if(arry[1] == "end") {
+				return vboxValues[key];
+			}
+			else if ((parseFloat(arry[0]) <= curr_t) && (parseFloat(arry[1]) >= curr_t)) {
+				return vboxValues[key];
+			}
+		}
+	}
+}
+
+function getCursorAtTime(time) {
+	var coords = cursorValues[time];
+	if(coords) return coords.split(' ');
+}
+
+function removeSlideChangeAttribute() {
+	$('#video').removeAttr('slide-change');
+	Popcorn('#video').unlisten(Popcorn.play, 'removeSlideChangeAttribute');
+}
+
+// - - - END OF JAVASCRIPT FUNCTIONS - - - //
+
+
+
+function runPopcorn() {
+  console.log("** Running popcorn");
+
+  getMetadata();
+
+  if(svgobj.contentDocument) svgfile = svgobj.contentDocument.getElementById("svgfile");
+  else svgfile = svgobj.getSVGDocument('svgfile');
+
+  //making the object for requesting the read of the XML files.
+  if (window.XMLHttpRequest) {
+  	// code for IE7+, Firefox, Chrome, Opera, Safari
+  	var	xmlhttp = new XMLHttpRequest();
+  } else {
+  	// code for IE6, IE5
+  	var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+  }
+
+  // PROCESS SHAPES.SVG (in XML format).
+  console.log("** Getting shapes_svg");
+  xmlhttp.open("GET", shapes_svg, false);
+  xmlhttp.send();
+  var xmlDoc = xmlhttp.responseXML;
+
+  console.log("** Processing shapes_svg");
+  //getting all the event tags
+  var shapeelements = xmlDoc.getElementsByTagName("svg");
+
+  //get the array of values for the first shape (getDataPoints(0) is the first shape).
+  var array = $(shapeelements[0]).find("g").filter(function(){ //get all the lines from the svg file
+    return $(this).attr('class') == 'shape';
+  });
+
+  // Newer recordings have slide images identified by class="slide"
+  // because they might include images in shapes
+  var images = shapeelements[0].getElementsByClassName("slide");
+  // To handle old recordings, fetch a list of all images instead
+  if (images.length == 0) {
+    images = shapeelements[0].getElementsByTagName("image");
+  }
+
+  //create a map from timestamp to id list
+  var timestampToId = {};
+  for (var j = 0; j < array.length; j++) {
+    shapeTime = array[j].getAttribute("timestamp");
+    shapeId = array[j].getAttribute("id");
+
+    if (timestampToId[shapeTime] == undefined) {
+      timestampToId[shapeTime] = new Array(0);
+    }
+    timestampToId[shapeTime].push(shapeId);
+  }
+
+  //fill the times array with the times of the svg images.
+  for (var j = 0; j < array.length; j++) {
+    times[j] = array[j].getAttribute("timestamp");
+  }
+
+  var times_length = times.length; //get the length of the times array.
+
+  console.log("** Getting text files");
+  for(var m = 0; m < images.length; m++) {
+  	len = images[m].getAttribute("in").split(" ").length;
+  	for(var n = 0; n < len; n++) {
+  		imageAtTime[[images[m].getAttribute("in").split(" ")[n], images[m].getAttribute("out").split(" ")[n]]] = images[m].getAttribute("id");
+  	}
+
+        // the logo at the start has no text attribute
+        if (images[m].getAttribute("text")) {
+          var txtFile = false;
+          if (window.XMLHttpRequest) {
+  	    // code for IE7+, Firefox, Chrome, Opera, Safari
+  	    txtFile = new XMLHttpRequest();
+          } else {
+  	    // code for IE6, IE5
+  	    txtFile = new ActiveXObject("Microsoft.XMLHTTP");
+          }
+          var imgid = images[m].getAttribute("id"); //have to save the value because images array might go out of scope
+          txtFile.open("GET", url + "/" + images[m].getAttribute("text"), false);
+          txtFile.onreadystatechange = function() {
+              if (txtFile.readyState === 4) {
+                if (txtFile.status === 200) {
+                  slidePlainText[imgid] = $('<div/>').text(txtFile.responseText).html();
+                  //console.log("**Text file read " + imgid);
+                }
+              }
+          };
+          txtFile.send(null);
+        }
+  }
+
+  // PROCESS PANZOOMS.XML
+  console.log("** Getting panzooms.xml");
+  xmlhttp.open("GET", events_xml, false);
+  xmlhttp.send();
+  xmlDoc = xmlhttp.responseXML;
+  //getting all the event tags
+  console.log("** Processing panzooms.xml");
+  var panelements = xmlDoc.getElementsByTagName("recording");
+  var panZoomArray = panelements[0].getElementsByTagName("event");
+  viewBoxes = xmlDoc.getElementsByTagName("viewBox");
+
+  var pzlen = panZoomArray.length;
+  var second_val;
+  //fill the times array with the times of the svg images.
+  for (var k = 0;k < pzlen; k++) {
+  	if(panZoomArray[k+1] == undefined) {
+  		second_val = "end";
+  	}
+  	else second_val = panZoomArray[k+1].getAttribute("timestamp");
+  	vboxValues[[panZoomArray[k].getAttribute("timestamp"), second_val]] = viewBoxes[k].childNodes[0].data;
+  }
+
+
+  // PROCESS CURSOR.XML
+  console.log("** Getting cursor.xml");
+  xmlhttp.open("GET", cursor_xml, false);
+  xmlhttp.send();
+  xmlDoc = xmlhttp.responseXML;
+  //getting all the event tags
+  console.log("** Processing cursor.xml");
+  var curelements = xmlDoc.getElementsByTagName("recording");
+  var cursorArray = curelements[0].getElementsByTagName("event");
+  coords = xmlDoc.getElementsByTagName("cursor");
+
+  var clen = cursorArray.length;
+  //fill the times array with the times of the svg images.
+  if(cursorArray.length != 0) cursorValues["0"] = "0 0";
+  for (var m = 0; m < clen; m++) {
+  	cursorValues[cursorArray[m].getAttribute("timestamp")] = coords[m].childNodes[0].data;
+  }
+
+
+  svgobj.style.left = document.getElementById("slide").offsetLeft + "px";
+  svgobj.style.top = "0px";
+  var next_shape;
+  var shape;
+  for (var j = 0; j < array.length - 1; j++) { //iterate through all the shapes and pick out the main ones
+    var time = array[j].getAttribute("timestamp");
+    shape = array[j].getAttribute("shape");
+    next_shape = array[j+1].getAttribute("shape");
+
+  	if(shape !== next_shape) {
+  		main_shapes_ids.push(array[j].getAttribute("id"));
+  	}
+  }
+  if (array.length !== 0) {
+    main_shapes_ids.push(array[array.length-1].getAttribute("id")); //put last value into this array always!
+  }
+
+  var get_shapes_in_time = function(t) {
+    // console.log("** Getting shapes in time");
+    var shapes_in_time = timestampToId[t];
+    var shapes = [];
+    if (shapes_in_time != undefined) {
+      var shape = null;
+      for (var i = 0; i < shapes_in_time.length; i++) {
+        var id = shapes_in_time[i];
+        if(svgobj.contentDocument) shape = svgobj.contentDocument.getElementById(id);
+        else shape = svgobj.getSVGDocument('svgfile').getElementById(id);
+
+        if (shape !== null) { //if there is actually a new shape to be displayed
+          shape = shape.getAttribute("shape"); //get actual shape tag for this specific time of playback
+          shapes.push(shape);
+        }
+      }
+    }
+    return shapes;
+  };
+
+  var p = new Popcorn("#video");
+  //update 60x / second the position of the next value.
+  p.code({
+      start: 1, // start time
+      end: p.duration(),
+      onFrame: function(options) {
+        //console.log("**Popcorn video onframe");
+        if(!((p.paused() === true) && (p.seeking() === false))) {
+          var t = p.currentTime().toFixed(1); //get the time and round to 1 decimal place
+
+          current_shapes = get_shapes_in_time(t);
+
+          //redraw everything (only way to make everything elegant)
+          for (var i = 0; i < array.length; i++) {
+            var time_s = array[i].getAttribute("timestamp");
+            var time_f = parseFloat(time_s);
+
+            if(svgobj.contentDocument) shape = svgobj.contentDocument.getElementById(array[i].getAttribute("id"));
+            else shape = svgobj.getSVGDocument('svgfile').getElementById(array[i].getAttribute("id"));
+
+            var shape_i = shape.getAttribute("shape");
+            if (time_f < t) {
+              if(current_shapes.indexOf(shape_i) > -1) { //currently drawing the same shape so don't draw the older steps
+                shape.style.visibility = "hidden"; //hide older steps to shape
+              } else if(main_shapes_ids.indexOf(shape.getAttribute("id")) > -1) { //as long as it is a main shape, it can be drawn... no intermediate steps.
+                if(parseFloat(shape.getAttribute("undo")) === -1) { //As long as the undo event hasn't happened yet...
+                  shape.style.visibility = "visible";
+                } else if (parseFloat(shape.getAttribute("undo")) > t) {
+                  shape.style.visibility = "visible";
+                } else {
+                  shape.style.visibility = "hidden";
+                }
+              }
+            } else if(time_s === t) { //for the shapes with the time specific to the current time
+              // only makes visible the last drawing of a given shape
+              var idx = current_shapes.indexOf(shape_i);
+              if (idx > -1) {
+                current_shapes.splice(idx, 1);
+                idx = current_shapes.indexOf(shape_i);
+                if (idx > -1) {
+                  shape.style.visibility = "hidden";
+                } else {
+                  shape.style.visibility = "visible";
+                }
+              } else {
+                // this is an inconsistent state, since current_shapes should have at least one drawing of this shape
+                shape.style.visibility = "hidden";
+              }
+            } else { //for shapes that shouldn't be drawn yet (larger time than current time), don't draw them.
+              shape.style.visibility = "hidden";
+            }
+          }
+
+          var next_image = getImageAtTime(t); //fetch the name of the image at this time.
+          var imageXOffset = 0;
+          var imageYOffset = 0;
+
+          if(current_image && (current_image !== next_image) && (next_image !== undefined)){	//changing slide image
+            if(svgobj.contentDocument) {
+              var img = svgobj.contentDocument.getElementById(current_image);
+              if (img) {
+                img.style.visibility = "hidden";
+              }
+              var ni = svgobj.contentDocument.getElementById(next_image);
+            }
+            else {
+              var img = svgobj.getSVGDocument('svgfile').getElementById(current_image);
+              if (img) {
+                img.style.visibility = "hidden";
+              }
+              var ni = svgobj.getSVGDocument('svgfile').getElementById(next_image);
+            }
+            document.getElementById("slideText").innerHTML = ""; //destroy old plain text
+
+            ni.style.visibility = "visible";
+            document.getElementById("slideText").innerHTML = slidePlainText[next_image] + next_image; //set new plain text
+
+            if ($("#accEnabled").is(':checked')) {
+              //pause the playback on slide change
+              p.pause();
+              $('#video').attr('slide-change', 'slide-change');
+              p.listen(Popcorn.play, removeSlideChangeAttribute);
+            }
+
+            var num_current = current_image.substr(5);
+            var num_next = next_image.substr(5);
+
+            if(svgobj.contentDocument) currentcanvas = svgobj.contentDocument.getElementById("canvas" + num_current);
+            else currentcanvas = svgobj.getSVGDocument('svgfile').getElementById("canvas" + num_current);
+
+            if(currentcanvas !== null) {
+              currentcanvas.setAttribute("display", "none");
+            }
+
+            if(svgobj.contentDocument) nextcanvas = svgobj.contentDocument.getElementById("canvas" + num_next);
+            else nextcanvas = svgobj.getSVGDocument('svgfile').getElementById("canvas" + num_next);
+
+            if((nextcanvas !== undefined) && (nextcanvas != null)) {
+              nextcanvas.setAttribute("display", "");
+            }
+            previous_image = current_image;
+            current_image = next_image;
+          }
+
+          if(svgobj.contentDocument) var thisimg = svgobj.contentDocument.getElementById(current_image);
+          else var thisimg = svgobj.getSVGDocument('svgfile').getElementById(current_image);
+
+          if (thisimg) {
+            var imageWidth = parseInt(thisimg.getAttribute("width"), 10);
+            var imageHeight = parseInt(thisimg.getAttribute("height"), 10);
+
+            var vboxVal = getViewboxAtTime(t);
+            if(vboxVal !== undefined) {
+              setViewBox(vboxVal);
+            }
+
+            var cursorVal = getCursorAtTime(t);
+            if (cursorVal != null) {
+              cursorShownAt = new Date().getTime();
+              showCursor(true);
+              // width and height are divided by 2 because that's the value used as a reference
+              // when positions in cursor.xml is calculated
+              drawCursor(parseFloat(cursorVal[0]) / (imageWidth/2), parseFloat(cursorVal[1]) / (imageHeight/2), thisimg);
+
+              // hide the cursor after 3s of inactivity
+            } else if (cursorShownAt < new Date().getTime() - 3000) {
+              showCursor(false);
+            }
+
+            // store the current slide and adjust the size of the slides
+            currentImage = thisimg;
+            resizeSlides();
+          }
+       }
+    }
+  });
+};
+
+function removeLoadingScreen() {
+  spinner.stop();
+  $("#playback-content").css('visibility','visible');
+  $("#loading-recording").css('visibility','hidden');
+  $("#loading-recording").css('height','0');
+  $("#load-recording-msg").css('display','none');
+}
+
+function defineStartTime() {
+  console.log("** Defining start time");
+
+  if (params.t === undefined)
+    return 1;
+
+  var extractNumber = /\d+/g;
+  var extractUnit = /\D+/g;
+  var temp_start_time = 0;
+
+  while (true) {
+    var param1 = extractUnit.exec(params.t);
+    var param2 = extractNumber.exec(params.t);
+    if (param1 == null || param2 == null)
+      break;
+
+    var unit = String(param1).toLowerCase();
+    var value = parseInt(String(param2));
+
+    if (unit == "h")
+      value *= 3600;
+    else if (unit == "m")
+      value *= 60;
+
+    temp_start_time += value;
+  }
+
+  console.log("Start time: " + temp_start_time);
+  return temp_start_time;
+}
+
+var current_canvas = "canvas0";
+var current_image = "image0";
+var previous_image = null;
+var currentcanvas;
+var shape;
+var nextcanvas;
+var next_image;
+var next_pgid;
+var curr_pgid;
+var svgfile;
+//current time
+var t;
+var len;
+var current_shapes = [];
+//coordinates for x and y for each second
+var panAndZoomTimes = [];
+var viewBoxes = [];
+var coords = [];
+var times = [];
+// timestamp and id for drawings
+var shapeTime;
+var shapeId;
+var clearTimes = [];
+var main_shapes_ids = [];
+var vboxValues = {};
+var cursorValues = {};
+var imageAtTime = {};
+var slidePlainText = {}; //holds slide plain text for retrieval
+var cursorStyle;
+var cursorShownAt = 0;
+
+var params = getUrlParameters();
+var MEETINGID = params.meetingId;
+// var HOST = window.location.host;
+// var url = "http://" + HOST + "/presentation/" + MEETINGID;
+var url = "resources";
+var shapes_svg = url + '/shapes.svg';
+var events_xml = url + '/panzooms.xml';
+var cursor_xml = url + '/cursor.xml';
+var metadata_xml = url + '/metadata.xml';
+
+var firstLoad = true;
+var svjobjLoaded = false;
+
+var svgobj = document.createElement('object');
+svgobj.setAttribute('data', shapes_svg);
+svgobj.setAttribute('height', '100%');
+svgobj.setAttribute('width', '100%');
+
+svgobj.addEventListener('load', function() {
+  console.log("got svgobj 'load' event");
+  runPopcorn();
+
+  if (svjobjLoaded) {
+    return;
+  }
+  svjobjLoaded = true;
+
+  generateThumbnails();
+
+  var p = Popcorn("#video");
+  p.currentTime(defineStartTime());
+
+  removeLoadingScreen();
+}, false);
+
+// Fetches the metadata associated with the recording and uses it to configure
+// the playback page
+var getMetadata = function() {
+  var xmlhttp;
+  if (window.XMLHttpRequest) {// code for IE7, Firefox, Chrome, Opera, Safari
+    xmlhttp = new XMLHttpRequest();
+  } else {// code for IE6, IE5
+    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+  }
+  xmlhttp.open("GET", metadata_xml, false);
+  xmlhttp.send(null);
+
+  if (xmlhttp.responseXML)
+    var xmlDoc = xmlhttp.responseXML;
+  else {
+    var parser = new DOMParser();
+    var xmlDoc = parser.parseFromString(xmlhttp.responseText, "application/xml");
+  }
+
+  var metadata = xmlDoc.getElementsByTagName("meta");
+  if (metadata.length > 0) {
+    metadata = metadata[0];
+
+    var meetingName = metadata.getElementsByTagName("meetingName");
+    if (meetingName.length > 0) {
+      $("#recording-title").text(meetingName[0].textContent);
+      $("#recording-title").attr("title", meetingName[0].textContent);
+    }
+  }
+};
+
+document.getElementById('slide').appendChild(svgobj);
+
+var currentImage;
+
+// A small hack to hide the cursor when resizing the window, so it's not
+// misplaced while the window is being resized
+window.onresize = function(event) {
+	showCursor(false);
+  resizeSlides();
+};
+
+// Resize the container that has the slides (and whiteboard) to be the maximum
+// size possible but still maintaining the aspect ratio of the slides.
+//
+// This is done here only because of pan and zoom. Pan/zoom is done by modifiyng
+// the svg's viewBox, and that requires the container that has the svg to be the
+// exact size we want to display the slides so that parts of the svg that are outside
+// of its parent's area are hidden. If we let the svg occupy all presentation area
+// (letting the svg do the image resizing), the slides will move and zoom around the
+// entire area when pan/zoom is activated, usually displaying more of the slide
+// than we want to (i.e. more than was displayed in the conference).
+var resizeSlides = function() {
+  if (currentImage) {
+    var $slide = $("#slide");
+
+    var imageWidth = parseInt(currentImage.getAttribute("width"), 10);
+    var imageHeight = parseInt(currentImage.getAttribute("height"), 10);
+    var imgRect = currentImage.getBoundingClientRect();
+    var aspectRatio = imageWidth/imageHeight;
+    var max = aspectRatio * $slide.parent().outerHeight();
+    $slide.css("max-width", max);
+
+    var height = $slide.parent().width() / aspectRatio;
+    $slide.css("max-height", height);
+  }
+};
diff --git a/record-and-playback/presentation_export/playback/presentation_export/logo.png b/record-and-playback/presentation_export/playback/presentation_export/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..395446fcb9f6df10a87b1d16c396ab47a6379ce9
Binary files /dev/null and b/record-and-playback/presentation_export/playback/presentation_export/logo.png differ
diff --git a/record-and-playback/presentation_export/playback/presentation_export/playback.css b/record-and-playback/presentation_export/playback/presentation_export/playback.css
new file mode 100644
index 0000000000000000000000000000000000000000..78c8d5a44167aabee30308d02bad813eae20e092
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/playback.css
@@ -0,0 +1,348 @@
+/*
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/* Visually hides text
+ * see: yaccessibilityblog.com/library/css-clip-hidden-content.html
+ */
+.visually-hidden {
+	position: absolute !important;
+	clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
+	clip: rect(1px, 1px, 1px, 1px);
+	padding: 0 !important;
+	border: 0 !important;
+	height: 1px !important;
+	width: 1px !important;
+	overflow: hidden;
+}
+
+/* Foundation overrides */
+.row {
+  max-width: 100%; /* Foundation restricts the rows to ~1000px */
+}
+button, .button {
+  margin-bottom: 0; /* this has impact in the media player buttons */
+}
+body {
+  color: #111;
+  font-size: 14px;
+}
+
+/* Main containers need to fill the entire page height */
+body, #playback-content, #playback-row, #main-section, #side-section {
+  height: 100%;
+}
+
+/* Restrict the page to a minimum width */
+html, .acorn-controls {
+  min-width: 310px;
+}
+
+
+/* Swappable components have different settings depending on where they are */
+#main-section #presentation-area {
+  height: 100%;
+  margin-bottom: 5px;
+}
+#main-section #video-area, #main-section #audio-area {
+  height: 100%;
+  margin-bottom: 5px;
+  background: #fff;
+}
+#side-section #presentation-area {
+  height: 30%; /* we HAVE to set a height here, otherwise the slides won't scale properly */
+  min-height: 250px;
+}
+#side-section #video-area, #side-section #audio-area {
+  height: auto;
+}
+
+/* Some internal elements should just fill the entire size of their parents,
+   that will control their size. */
+#slide {
+  width: 100%;
+  height: 100%;
+  margin: 0 auto;
+
+  /* vertical alignment */
+  position: relative;
+  top: 50%;
+  transform: translateY(-50%);
+}
+
+#chat {
+  width: 100%;
+  height: 100%;
+}
+#video-area, #video {
+  width: 100%;
+  height: 100%;
+  /* can't set height:100% here because the height is controlled automatically
+     to maintain the aspect ratio. */
+}
+.acorn-player {
+  width: 100%;
+  height: 100%;
+}
+
+
+/* The playback bar is moved out of the video/audio area into a more
+   generic place in the page, making it look like the controls are not
+   only for audio and video, but for all playback. */
+#audio-area .acorn-controls, #video-area .acorn-controls {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  z-index: 99;
+}
+
+/* Prevent unwanted scrollbars and "leaking" elements in the page */
+body {
+  overflow: hidden;
+  /* background: #f6f6f6; */
+}
+#main-section {
+  border-right: 1px solid #e2e2e2;
+  background: #f6f6f6;
+}
+
+/* Chat style */
+#chat {
+  padding: 0 10px;
+  overflow-y: auto;
+  word-wrap: break-word;
+  background: #fff;
+
+  /* we use borders here instead of padding because the top/bottom
+     padding doesn't really work with a vertical scrollbar */
+  border-top: 5px solid #fff;
+  border-bottom: 5px solid #fff;
+}
+#chat strong {
+  color: #888;
+}
+#chat-area {
+  border-bottom: 1px solid #e2e2e2;
+}
+#chat > div {
+  margin-bottom: 4px;
+}
+
+/* Navbar style */
+#navbar {
+  height: 48px;
+  border-bottom: 1px solid #e2e2e2;
+  background: white;
+  padding: 0 10px 0 0;
+}
+#recording-title {
+  font-size: 1.45rem;
+  padding-top: 8px;
+  margin: 0;
+  color: #666666;
+  font-weight: bold;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+#navbar .sidebar-icon {
+  font-size: 1.65em;
+  margin-right: 15px;
+  padding-right: 15px;
+  padding-left: 15px;
+  border-right: 1px solid #e2e2e2;
+  float: left;
+  color: #666;
+  padding-top: 8px;
+  height: 48px;
+}
+
+/* Presentation and related elements */
+#slide {
+  background-image: url('logo.png');
+  background-size: 160px 160px;
+  background-repeat: no-repeat;
+  background-position: center center;
+}
+#cursor {
+  visibility: hidden;
+  width: 12px;
+  height: 12px;
+  transform: translate(-6px, -6px);
+  border-radius: 50%;
+  position: fixed;
+  background: red;
+  z-index: 10;
+}
+#main-section {
+  padding: 10px 10px 25px 10px;
+}
+#copyright {
+  width: 100%;
+  font-size: 0.65rem;
+  text-align: center;
+  color: #888;
+  bottom: 5px;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+
+/* Thumbnails */
+#thumbnails {
+  padding: 10px;
+  text-align: center;
+}
+#thumbnails .thumbnail-wrapper {
+	position: relative;
+	margin: 0;
+  padding: 5px 0;
+	cursor: pointer;
+}
+#thumbnails .thumbnail-wrapper.active,
+#thumbnails .thumbnail-wrapper.active:hover {
+	background-color: #D9EDF7;
+}
+#thumbnails .thumbnail-wrapper.active img,
+#thumbnails .thumbnail-wrapper.active:hover img {
+	border-color: #289ad6; /* #314b5d; */
+}
+#thumbnails .thumbnail-wrapper:hover img {
+	border-color: #289ad6; /* #314b5d; */
+}
+#thumbnails img {
+  max-height: 125px;
+  border: 1px solid #eee;
+}
+#thumbnails .thumbnail-wrapper.hovered .thumbnail-label,
+#thumbnails .thumbnail-wrapper.active .thumbnail-label {
+  display: block;
+}
+#thumbnails .thumbnail-label {
+	color: #fff;
+	background: #289ad6;
+	font-weight: bold;
+	font-size: 12px;
+	position: absolute;
+	bottom: 5px;
+	left: 0;
+  right: 0;
+	width: 50%;
+  margin: 0 auto;
+	text-align: center;
+	display: none;
+	padding: 2px 5px;
+}
+
+/* Sliding sidebar */
+.inner-wrap {
+  height: 100%;
+}
+.left-off-canvas-menu {
+  background: #fff;
+  width: 13rem;
+  border-right: 1px solid #e2e2e2;
+}
+.move-right > .inner-wrap {
+  -webkit-transform: translate3d(13rem, 0, 0);
+  -moz-transform: translate3d(13rem, 0, 0);
+  -ms-transform: translate(13rem, 0);
+  -o-transform: translate3d(13rem, 0, 0);
+  transform: translate3d(13rem, 0, 0);
+}
+ul.off-canvas-list li label {
+  background: #2a2d34;
+  color: #eee;
+}
+.exit-off-canvas {
+  box-shadow: none !important;
+}
+
+/* Video style */
+#video {
+  background-color: #f6f6f6;
+}
+
+/* Loading page with a spinner */
+#loading-recording {
+  width: 100%;
+  height: 100%;
+}
+#load-recording-msg {
+  text-align: center;
+  vertical-align: middle;
+  position: absolute;
+  bottom: 30px;
+  font-weight: bold;
+  width: 100%;
+  left: 0;
+  right: 0;
+}
+
+
+/* Small screens only */
+@media only screen and (max-width: 40em) {
+  #copyright {
+    font-size: 0.6rem;
+  }
+  #chat {
+    font-size: 12px;
+  }
+  #side-section #presentation-area {
+    min-height: 100px;
+  }
+}
+
+/* Medium screens up */
+@media only screen and (min-width: 40.063em) {
+  #side-section #presentation-area {
+    min-height: 150px;
+  }
+}
+
+/* Large screens up */
+/* @media only screen and (min-width: 64.063em) { */
+/* } */
+
+@media (orientation: portrait) {
+  #main-section, #side-section {
+    float: none;
+    width: 100%;
+  }
+  #slide {
+    /* background-size: contain; */
+  }
+  #side-section #video-area {
+    width: 60%;
+    margin: 0 auto;
+  }
+  #chat {
+    font-size: 12px;
+  }
+
+  /* show only video or only presentation, not both */
+  #side-section #video-area video, #side-section #presentation-area {
+    display: none;
+  }
+  #chat-area {
+    border: none;
+  }
+}
diff --git a/record-and-playback/presentation_export/playback/presentation_export/playback.html b/record-and-playback/presentation_export/playback/presentation_export/playback.html
new file mode 100755
index 0000000000000000000000000000000000000000..3c42b8ef88258efb15c543b0bee3c1ce726da99e
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/playback.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<!--
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+*
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+-->
+<html class="no-js" lang="en">
+
+<head>
+  <meta charset="UTF-8">
+
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>Recording Playback</title>
+
+  <link rel="stylesheet" type="text/css" href="playback/acornmediaplayer/acornmediaplayer.base.css" />
+  <link rel="stylesheet" type="text/css" href="playback/acornmediaplayer/themes/access/acorn.access.css" />
+  <link rel="stylesheet" type="text/css" href="playback/acornmediaplayer/themes/bigbluebutton/acorn.bigbluebutton.css" />
+  <link rel="stylesheet" type="text/css" href="playback/css/normalize.css" />
+  <link rel="stylesheet" type="text/css" href="playback/css/foundation.css" />
+  <link rel="stylesheet" type="text/css" href="playback/css/foundation-icons.css" />
+  <link rel="stylesheet" href="playback/playback.css">
+</head>
+
+<body>
+  <div id="loading-recording">
+    <div id="spinner"></div>
+    <p id="load-recording-msg">Initializing recording</p>
+  </div>
+  <div class="circle" id="cursor"></div>
+  <div id="playback-content" class="off-canvas-wrap" data-offcanvas>
+
+    <div class="inner-wrap">
+      <div id="navbar">
+        <a class="left-off-canvas-toggle menu-icon" href="#">
+          <i class="sidebar-icon fi-list"></i>
+        </a>
+        <h1 id="recording-title">Recording Playback</h1>
+      </div>
+
+      <aside class="left-off-canvas-menu">
+        <ul class="off-canvas-list">
+          <li><label>Slides</label></li>
+          <div id="thumbnails" role="region" aria-label="Slide thumbnails"></div>
+        </ul>
+      </aside>
+
+      <a class="exit-off-canvas"></a>
+
+      <div id="playback" role="main" class="row small-collapse">
+
+        <h2 class="show-for-sr">Presentation Slides</h2>
+        <div id="main-section" class="small-8 columns">
+          <div id="presentation-area" role="region" aria-label="Presentation" data-swap>
+            <div id="slide" role="img" aria-labelledby="slideText"></div>
+            <div id="slideText" class="show-for-sr" aria-live="polite"></div>
+          </div>
+
+          <div id="copyright">
+            Recorded with <a target="_blank" href="http://mconf.org/">Mconf</a>.
+            Use <a target="_blank" href="http://mozilla.org/firefox">Mozilla Firefox</a> to play this recording.
+          </div>
+        </div>
+
+        <div id="side-section" class="small-4 columns">
+          <h2 class="show-for-sr">Chat Messages</h2>
+          <input type="checkbox" name="exposechat" id="exposechat" value="exposechat" class="show-for-sr" checked="checked" />
+          <label for="exposechat" class="show-for-sr">Read chat messages</label>
+          <div id="chat-area">
+            <div id="chat" aria-live="polite" role="region" aria-label="Chat messages"></div>
+          </div>
+          <div id="video-area" class="clearfix" role="region" aria-label="Video" title="Click to play or pause the playback" data-swap>
+            <!--
+                <video id="webcam">You must use an HTML5 capable browser to view this page.
+                  This playback requires modern browser, please use FF, Safari, Chrome</video>
+                -->
+          </div>
+          <div id="audio-area" role="region" aria-label="Audio">
+            <!--
+                <audio id="video">You must use an HTML5 capable browser to view this page.
+                  This playback requires modern browser, please use FF, Safari, Chrome</audio>
+                -->
+          </div>
+        </div>
+      </div>
+
+    </div>
+
+    <!--
+    <div id="accInfo">
+      <input id="accEnabled" type="checkbox" value="accEnabled" />
+      <label for="accEnabled">Enable accessibility pauses</label><br/>
+      <div id="countdown" />
+    </div>
+    -->
+  </div>
+
+  <script type="text/javascript" src="playback/lib/jquery.min.js"></script>
+  <script type="text/javascript" src="playback/lib/jquery-ui.min.js"></script>
+  <script type="text/javascript" src="playback/lib/foundation.min.js"></script>
+  <script type="text/javascript" src="playback/lib/spin.min.js"></script>
+  <script type="text/javascript" src="playback/acornmediaplayer/jquery.acornmediaplayer.js"></script>
+  <script type="text/javascript" src="playback/lib/writing.js"></script>
+  <script type="text/javascript" src="playback/playback.js"></script>
+  <!-- popcorn has to be loaded after playback.js, otherwise the chat won't be displayed -->
+  <script type="text/javascript" src="playback/lib/popcorn-complete.min.js"></script>
+  <script type="text/javascript" src="playback/lib/popcorn.chattimeline.js"></script>
+  <script>
+    $(document).foundation();
+  </script>
+
+</body>
+</html>
diff --git a/record-and-playback/presentation_export/playback/presentation_export/playback.js b/record-and-playback/presentation_export/playback/presentation_export/playback.js
new file mode 100755
index 0000000000000000000000000000000000000000..b4d7d42bab8d0ee9ff9727545ceae6fecfb798cf
--- /dev/null
+++ b/record-and-playback/presentation_export/playback/presentation_export/playback.js
@@ -0,0 +1,559 @@
+/*
+
+BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+
+Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+
+This program is free software; you can redistribute it and/or modify it under the
+terms of the GNU Lesser General Public License as published by the Free Software
+Foundation; either version 3.0 of the License, or (at your option) any later
+version.
+
+BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+goToSlide = function(time) {
+  var pop = Popcorn("#video");
+  pop.currentTime(time);
+};
+
+getUrlParameters = function() {
+  var map = {};
+  var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
+    map[key] = value;
+  });
+  return map;
+};
+
+/*
+ * From: http://stackoverflow.com/questions/1634748/how-can-i-delete-a-query-string-parameter-in-javascript/4827730#4827730
+ */
+removeUrlParameter = function(url, param) {
+  var urlparts= url.split('?');
+  if (urlparts.length>=2) {
+    var prefix= encodeURIComponent(param)+'=';
+    var pars= urlparts[1].split(/[&;]/g);
+    for (var i=pars.length; i-- > 0;) {
+      if (pars[i].indexOf(prefix, 0)==0)
+        pars.splice(i, 1);
+    }
+    if (pars.length > 0) {
+      return urlparts[0]+'?'+pars.join('&');
+    } else {
+      return urlparts[0];
+    }
+  } else {
+    return url;
+  }
+}
+
+/*
+ * Converts seconds to HH:MM:SS
+ * From: http://stackoverflow.com/questions/6312993/javascript-seconds-to-time-with-format-hhmmss#6313008
+ */
+secondsToHHMMSS = function(secs) {
+  var hours   = Math.floor(secs / 3600);
+  var minutes = Math.floor((secs - (hours * 3600)) / 60);
+  var seconds = secs - (hours * 3600) - (minutes * 60);
+
+  if (hours   < 10) {hours   = "0"+hours;}
+  if (minutes < 10) {minutes = "0"+minutes;}
+  if (seconds < 10) {seconds = "0"+seconds;}
+  var time    = hours+':'+minutes+':'+seconds;
+  return time;
+}
+
+secondsToYouTubeFormat = function(secs) {
+  var hours   = Math.floor(secs / 3600);
+  var minutes = Math.floor((secs - (hours * 3600)) / 60);
+  var seconds = secs - (hours * 3600) - (minutes * 60);
+
+  var time = "";
+  if (hours > 0)   {time += hours+"h";}
+  if (minutes > 0) {time += minutes+"m";}
+  if (seconds > 0) {time += seconds+"s";}
+  if (secs == 0) {time = "0s";}
+
+  return time;
+}
+
+/*
+ * Full word version of the above function for screen readers
+ */
+secondsToHHMMSSText = function(secs) {
+  var hours   = Math.floor(secs / 3600);
+  var minutes = Math.floor((secs - (hours * 3600)) / 60);
+  var seconds = secs - (hours * 3600) - (minutes * 60);
+
+  var time = "";
+  if (hours   > 1) {time += hours   + " hours ";}
+  else if (hours   == 1) {time += hours   + " hour ";}
+  if (minutes > 1) {time += minutes + " minutes ";}
+  else if (minutes == 1) {time += minutes + " minute ";}
+  if (seconds > 1) {time += seconds + " seconds ";}
+  else if (seconds == 1) {time += seconds + " second ";}
+
+  return time;
+}
+
+replaceTimeOnUrl = function(secs) {
+  var newUrl = removeUrlParameter(document.URL, "t") + "&t=" + secondsToYouTubeFormat(secs);
+  window.history.replaceState({}, "", newUrl);
+}
+
+var params = getUrlParameters();
+var MEETINGID = params['meetingId'];
+var RECORDINGS = "./resources";
+var SLIDES_XML = RECORDINGS + '/slides_new.xml';
+var SHAPES_SVG = RECORDINGS + '/shapes.svg';
+var hasVideo = false;
+
+/*
+ * Sets the title attribute in a thumbnail.
+ */
+setTitleOnThumbnail = function($thumb) {
+  var src = $thumb.attr("src")
+  if (src !== undefined) {
+    var num = "?";
+    var name = "undefined";
+    var match = src.match(/slide-(.*).png/);
+    if (match) { num = match[1]; }
+    match = src.match(/([^/]*)\/slide-.*\.png/);
+    if (match) { name = match[1]; }
+    $thumb.attr("title", name + " (" + num + ")");
+  }
+}
+
+/*
+ * Associates several events on a thumbnail, e.g. click to change slide,
+ * mouse over/out functions, etc.
+ */
+setEventsOnThumbnail = function($thumb) {
+
+  // Note: use ceil() so it jumps to a part of the video that actually is showing
+  // this slide, while floor() would most likely jump to the previously slide
+
+  // Popcorn event to mark a thumbnail when its slide is being shown
+  var timeIn = $thumb.attr("data-in");
+  var timeOut = $thumb.attr("data-out");
+  var pop = Popcorn("#video");
+  pop.code({
+    start: timeIn,
+    end: timeOut,
+    onStart: function(options) {
+      $parent = $(".thumbnail-wrapper").removeClass("active");
+      $parent = $("#thumbnail-" + Math.ceil(options.start)).parent();
+      $parent.addClass("active");
+      animateToCurrentSlide();
+    },
+    onEnd: function(options) {
+      $parent = $("#thumbnail-" + Math.ceil(options.start)).parent();
+      $parent.removeClass("active");
+    }
+  });
+
+  // Click on thumbnail changes the slide in popcorn
+  $thumb.parent().on("click", function() {
+    var time = Math.ceil($thumb.attr("data-in"));
+    goToSlide(time);
+    replaceTimeOnUrl(time);
+  });
+
+  // Mouse over/out to show/hide the label over the thumbnail
+  $wrapper = $thumb.parent();
+  $wrapper.on("mouseover", function() {
+    $(this).addClass("hovered");
+  });
+  $wrapper.on("mouseout", function() {
+    $(this).removeClass("hovered");
+  });
+};
+
+var animateToCurrentSlide = function() {
+  var $container = $("#thumbnails").parents(".left-off-canvas-menu");
+
+  var currentThumb = $(".thumbnail-wrapper.active");
+  // animate the scroll of thumbnails to center the current slide
+  var thumbnailOffset = currentThumb.prop('offsetTop') - $container.prop('offsetTop') +
+        (currentThumb.prop('offsetHeight') - $container.prop('offsetHeight')) / 2;
+  $container.stop();
+  $container.animate({ scrollTop: thumbnailOffset }, 200);
+};
+
+/*
+ * Generates the list of thumbnails using shapes.svg
+ */
+generateThumbnails = function() {
+  console.log("== Generating thumbnails");
+  var xmlhttp;
+  if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
+    xmlhttp = new XMLHttpRequest();
+  } else {// code for IE6, IE5
+    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+  }
+  xmlhttp.open("GET", SHAPES_SVG, false);
+  xmlhttp.send(null);
+
+  if (xmlhttp.responseXML)
+    var xmlDoc = xmlhttp.responseXML;
+  else {
+    var parser = new DOMParser();
+    var xmlDoc = parser.parseFromString(xmlhttp.responseText, "image/svg+xml");
+  }
+
+  var elementsMap = {};
+  var imagesList = new Array();
+
+  xmlList = xmlDoc.getElementsByTagName("image");
+  var slideCount = 0;
+
+  console.log("== Setting title on thumbnails");
+  for (var i = 0; i < xmlList.length; i++) {
+    var element = xmlList[i];
+
+    if (!$(element).attr("xlink:href"))
+      continue;
+    var src = RECORDINGS + "/" + element.getAttribute("xlink:href");
+    if (src.match(/\/presentation\/.*slide-.*\.png/)) {
+      var timeInList = xmlList[i].getAttribute("in").split(" ");
+      var timeOutList = xmlList[i].getAttribute("out").split(" ");
+      for (var j = 0; j < timeInList.length; j++) {
+
+        var timeIn = Math.ceil(timeInList[j]);
+        var timeOut = Math.ceil(timeOutList[j]);
+
+        var img = $(document.createElement('img'));
+        img.attr("src", src);
+        img.attr("id", "thumbnail-" + timeIn);
+        img.attr("data-in", timeIn);
+        img.attr("data-out", timeOut);
+        img.addClass("thumbnail");
+        img.attr("alt", " ");
+        img.attr("aria-hidden", "true"); //doesn't need to be focusable for blind users
+
+        // a label with the time the slide starts
+        var label = $(document.createElement('span'));
+        label.addClass("thumbnail-label");
+        label.attr("aria-hidden", "true"); //doesn't need to be focusable for blind users
+        label.html(secondsToHHMMSS(timeIn));
+
+        var hiddenDesc = $(document.createElement('span'));
+        hiddenDesc.attr("id", img.attr("id") + "description");
+        hiddenDesc.attr("class", "visually-hidden");
+        hiddenDesc.html("Slide " + ++slideCount + " " + secondsToHHMMSSText(timeIn));
+
+        // a wrapper around the img and label
+        var div = $(document.createElement('div'));
+        div.addClass("thumbnail-wrapper");
+        div.attr("role", "link"); //tells accessibility software it can be clicked
+        div.attr("aria-describedby", img.attr("id") + "description");
+        div.append(img);
+        div.append(label);
+        div.append(hiddenDesc);
+
+        if (parseFloat(timeIn) == 0) {
+          div.addClass("active");
+        }
+
+        imagesList.push(timeIn);
+        elementsMap[timeIn] = div;
+
+        setEventsOnThumbnail(img);
+        setTitleOnThumbnail(img);
+      }
+    }
+  }
+
+  imagesList.sort(function(a,b){return a - b});
+  for (var i in imagesList) {
+    $("#thumbnails").append(elementsMap[imagesList[i]]);
+  }
+}
+
+google_frame_warning = function(){
+  console.log("==Google frame warning");
+  var message = "To support this playback please install 'Google Chrome Frame', or use other browser: Firefox, Safari, Chrome, Opera";
+  var line = document.createElement("p");
+  var link = document.createElement("a");
+  line.appendChild(document.createTextNode(message));
+  link.setAttribute("href", "http://www.google.com/chromeframe")
+  link.setAttribute("target", "_blank")
+  link.appendChild(document.createTextNode("Install Google Chrome Frame"));
+  document.getElementById("chat").appendChild(line);
+  document.getElementById("chat").appendChild(link);
+}
+
+function checkUrl(url)
+{
+  console.log("==Checking Url",url);
+  var http = new XMLHttpRequest();
+  http.open('HEAD', url, false);
+  try {
+    http.send();
+  } catch(e) {
+    return false;
+  }
+  return http.status==200;
+}
+
+load_video = function(){
+   console.log("==Loading video");
+   //document.getElementById("video").style.visibility = "hidden"
+   var video = document.createElement("video");
+   video.setAttribute('id','video');
+   video.setAttribute('class','webcam');
+
+   var webmsource = document.createElement("source");
+   webmsource.setAttribute('src', RECORDINGS + '/video/webcams.webm');
+   webmsource.setAttribute('type','video/webm; codecs="vp8.0, vorbis"');
+   video.appendChild(webmsource);
+
+   /*var time_manager = Popcorn("#video");
+   var pc_webcam = Popcorn("#webcam");
+   time_manager.on( "timeupdate", function() {
+    pc_webcam.currentTime( this.currentTime() );
+   });*/
+
+   video.setAttribute('data-timeline-sources', SLIDES_XML);
+   //video.setAttribute('controls','');
+   //leave auto play turned off for accessiblity support
+   //video.setAttribute('autoplay','autoplay');
+
+   document.getElementById("video-area").appendChild(video);
+}
+
+load_audio = function() {
+   console.log("Loading audio")
+   var audio = document.createElement("audio") ;
+   audio.setAttribute('id', 'video');
+
+   // The webm file will work in IE with WebM components installed,
+   // and should load faster in Chrome too
+   var webmsource = document.createElement("source");
+   webmsource.setAttribute('src', RECORDINGS + '/audio/audio.webm');
+   webmsource.setAttribute('type', 'audio/webm; codecs="vorbis"');
+
+   // Need to keep the ogg source around for compat with old recordings
+   var oggsource = document.createElement("source");
+   oggsource.setAttribute('src', RECORDINGS + '/audio/audio.ogg');
+   oggsource.setAttribute('type', 'audio/ogg; codecs="vorbis"');
+
+   // Browser Bug Workaround: The ogg file should be preferred in Firefox,
+   // since it can't seek in audio-only webm files.
+   if (navigator.userAgent.indexOf("Firefox") != -1) {
+      audio.appendChild(oggsource);
+      audio.appendChild(webmsource);
+   } else {
+      audio.appendChild(webmsource);
+      audio.appendChild(oggsource);
+   }
+
+   audio.setAttribute('data-timeline-sources', SLIDES_XML);
+   //audio.setAttribute('controls','');
+   //leave auto play turned off for accessiblity support
+   //audio.setAttribute('autoplay','autoplay');
+   document.getElementById("audio-area").appendChild(audio);
+}
+
+load_script = function(file){
+  console.log("==Loading script "+ file)
+  script = document.createElement('script');
+  script.src = file;
+  script.type = 'text/javascript';
+  document.getElementsByTagName('body').item(0).appendChild(script);
+}
+
+load_spinner = function(){
+  console.log("==Loading spinner");
+  var opts = {
+    lines: 13, // The number of lines to draw
+    length: 24, // The length of each line
+    width: 4, // The line thickness
+    radius: 24, // The radius of the inner circle
+    corners: 1, // Corner roundness (0..1)
+    rotate: 24, // The rotation offset
+    direction: 1, // 1: clockwise, -1: counterclockwise
+    color: '#000', // #rgb or #rrggbb or array of colors
+    speed: 1, // Rounds per second
+    trail: 87, // Afterglow percentage
+    shadow: false, // Whether to render a shadow
+    hwaccel: false, // Whether to use hardware acceleration
+    className: 'spinner', // The CSS class to assign to the spinner
+    zIndex: 2e9, // The z-index (defaults to 2000000000)
+    top: '50%', // Top position relative to parent
+    left: '50%' // Left position relative to parent
+  };
+  var target = document.getElementById('spinner');
+  spinner = new Spinner(opts).spin(target);
+};
+
+
+document.addEventListener("DOMContentLoaded", function() {
+  console.log("==DOM content loaded");
+  var appName = navigator.appName;
+  var appVersion = navigator.appVersion;
+  var spinner;
+
+  if (appName == "Microsoft Internet Explorer" && navigator.userAgent.match("chromeframe") == false ) {
+    google_frame_warning();
+  }
+
+  if (checkUrl(RECORDINGS + '/video/webcams.webm') == true) {
+    hasVideo = true;
+    $("#audio-area").attr("style", "display:none;");
+    load_video();
+  } else {
+    hasVideo = false;
+    $("#video-area").attr("style", "display:none;");
+    load_audio();
+  }
+
+  load_spinner();
+  console.log("==Hide playback content");
+  $("#playback-content").css('visibility', 'hidden');
+
+  //load up the acorn controls
+  console.log("==Loading acorn media player ");
+  $('#video').acornMediaPlayer({
+    theme: 'bigbluebutton',
+    volumeSlider: 'vertical'
+  });
+  $('#video').on("swap", function() {
+    swapVideoPresentation();
+  });
+
+  resizeComponents();
+}, false);
+
+var secondsToWait = 0;
+
+function addTime(time){
+  if (secondsToWait === 0) {
+    Popcorn('#video').pause();
+    window.setTimeout("Tick()", 1000);
+  }
+  secondsToWait += time;
+}
+
+function Tick() {
+  if (secondsToWait <= 0 || !($("#accEnabled").is(':checked'))) {
+    secondsToWait = 0;
+    Popcorn('#video').play();
+    $('#countdown').html(""); // remove the timer
+    return;
+  }
+
+  secondsToWait -= 1;
+  $('#countdown').html(secondsToWait);
+  window.setTimeout("Tick()", 1000);
+}
+
+// Swap the position of the DOM elements `elm1` and `elm2`.
+function swapElements(elm1, elm2) {
+  var parent1, next1,
+      parent2, next2;
+
+  parent1 = elm1.parentNode;
+  next1   = elm1.nextSibling;
+  parent2 = elm2.parentNode;
+  next2   = elm2.nextSibling;
+
+  parent1.insertBefore(elm2, next1);
+  parent2.insertBefore(elm1, next2);
+}
+
+// Swaps the positions of the presentation and the video
+function swapVideoPresentation() {
+  var pop = Popcorn("#video");
+  var wasPaused = pop.paused();
+
+  var mainSectionChild = $("#main-section").children("[data-swap]");
+  var sideSectionChild = $("#side-section").children("[data-swap]");
+  swapElements(mainSectionChild[0], sideSectionChild[0]);
+  resizeComponents();
+
+  if (!wasPaused) {
+    pop.play();
+  }
+
+  // hide the cursor so it doesn't appear in the wrong place (e.g. on top of the video)
+  // if the cursor is currently being useful, he we'll be redrawn automatically soon
+  showCursor(false);
+
+  // wait for the svg with the slides to be fully loaded and then set the current image
+  // as visible.
+  function checkSVGLoaded() {
+    var done = false;
+    var svg = document.getElementsByTagName("object")[0];
+    if (svg !== undefined && svg !== null && currentImage && svg.getSVGDocument('svgfile')) {
+      var img = svg.getSVGDocument('svgfile').getElementById(currentImage.getAttribute("id"));
+      if (img !== undefined && img !== null) {
+        img.style.visibility = "visible";
+        resizeSlides();
+        done = true;
+      }
+    }
+    if (!done) {
+      setTimeout(checkSVGLoaded, 50);
+    }
+  }
+  checkSVGLoaded();
+}
+
+// Manually resize some components we can't properly resize just using css.
+// Mostly the components in the side-section, that has more than one component that
+// need to fill 100% height.
+function resizeComponents() {
+  var availableHeight = $("body").height();
+  if (hasVideo) {
+    availableHeight -= $("#video-area .acorn-controls").outerHeight(true);
+  } else {
+    availableHeight -= $("#audio-area .acorn-controls").outerHeight(true);
+  }
+  availableHeight -= $("#navbar").outerHeight(true); // navbar
+
+  // portrait mode
+  if (window.innerHeight > window.innerWidth) {
+    var height = availableHeight * 0.6; // 60% for top bar
+    $("#main-section").outerHeight(height);
+    availableHeight -= height;
+    $("#side-section").outerHeight(availableHeight);
+
+    var chatHeight = availableHeight;
+    $("#chat-area").innerHeight(chatHeight);
+  } else {
+    // $("#playback-row").outerHeight(availableHeight);
+    $("#main-section").outerHeight(availableHeight);
+    $("#side-section").outerHeight(availableHeight);
+
+    var chatHeight = availableHeight;
+    chatHeight -= $("#side-section").children("[data-swap]").outerHeight(true);
+    $("#chat-area").innerHeight(chatHeight);
+  }
+}
+
+// Need to resize the elements in a few occasions:
+// * Once the page and all assets are fully loaded
+// * When the page is resized
+// * When the video is fully loaded
+$(window).resize(function() {
+  resizeComponents();
+});
+document.addEventListener("load", function() {
+  resizeComponents();
+}, false);
+function checkVideoLoaded() {
+  var video = $('#video')[0];
+  if (video !== undefined && video !== null && video.readyState === 4) {
+    resizeComponents();
+  } else {
+    setTimeout(checkVideoLoaded, 50);
+  }
+}
+checkVideoLoaded();
diff --git a/record-and-playback/presentation_export/scripts/presentation_export.nginx b/record-and-playback/presentation_export/scripts/presentation_export.nginx
new file mode 100644
index 0000000000000000000000000000000000000000..4f9781b65027cb8e41e16bb88b6e2ecd9852bd69
--- /dev/null
+++ b/record-and-playback/presentation_export/scripts/presentation_export.nginx
@@ -0,0 +1,27 @@
+#
+# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+#
+# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+#
+# This program is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 3.0 of the License, or (at your option) any later
+# version.
+#
+# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+#
+
+        location /playback/presentation_export {
+                root    /var/bigbluebutton;
+                index  index.html index.htm;
+        }
+
+        location /presentation_export {
+                root    /var/bigbluebutton/published;
+                index  index.html index.htm;
+        }
diff --git a/record-and-playback/presentation_export/scripts/presentation_export.yml b/record-and-playback/presentation_export/scripts/presentation_export.yml
new file mode 100644
index 0000000000000000000000000000000000000000..2bc9bb8b883dca341003298ff39bd31dd5d0fa1a
--- /dev/null
+++ b/record-and-playback/presentation_export/scripts/presentation_export.yml
@@ -0,0 +1,5 @@
+publish_dir: /var/bigbluebutton/published/presentation_export
+playback_dir: /var/bigbluebutton/playback/presentation_export
+
+presentation_published_dir: /var/bigbluebutton/published/presentation
+presentation_unpublished_dir: /var/bigbluebutton/unpublished/presentation
diff --git a/record-and-playback/presentation_export/scripts/process/presentation_export.rb b/record-and-playback/presentation_export/scripts/process/presentation_export.rb
new file mode 100755
index 0000000000000000000000000000000000000000..bac6042b4e096444637b9b1e6a7a59c52e553e6e
--- /dev/null
+++ b/record-and-playback/presentation_export/scripts/process/presentation_export.rb
@@ -0,0 +1,86 @@
+# Set encoding to utf-8
+# encoding: UTF-8
+
+#
+# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+#
+# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+#
+# This program is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 3.0 of the License, or (at your option) any later
+# version.
+#
+# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+#
+
+require File.expand_path('../../../lib/recordandplayback', __FILE__)
+require 'rubygems'
+require 'trollop'
+require 'yaml'
+
+opts = Trollop::options do
+  opt :meeting_id, "Meeting id to archive", :default => '58f4a6b3-cd07-444d-8564-59116cb53974', :type => String
+end
+
+meeting_id = opts[:meeting_id]
+
+# This script lives in scripts/archive/steps while properties.yaml lives in scripts/
+bbb_props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml'))
+recording_dir = bbb_props['recording_dir']
+
+props = YAML::load(File.open('presentation_export.yml'))
+presentation_published_dir = props['presentation_published_dir']
+presentation_unpublished_dir = props['presentation_unpublished_dir']
+playback_dir = props['playback_dir']
+
+target_dir = "#{recording_dir}/process/presentation_export/#{meeting_id}"
+if not FileTest.directory?(target_dir)
+  # this recording has never been processed
+
+  logger = Logger.new("/var/log/bigbluebutton/presentation_export/process-#{meeting_id}.log", 'daily' )
+  BigBlueButton.logger = logger
+
+  if not File.exists? "#{recording_dir}/status/published/#{meeting_id}-presentation.done"
+    BigBlueButton.logger.info "Presentation not published yet, aborting"
+    abort
+  end
+
+  FileUtils.mkdir_p "/var/log/bigbluebutton/presentation_export"
+
+  publish_dir = "#{recording_dir}/publish/presentation/#{meeting_id}"
+  if FileTest.directory?(publish_dir)
+    # this recording has already been published (or publish processed), need to
+    # figure out if it's published or unpublished
+
+    meeting_published_dir = "#{presentation_published_dir}/#{meeting_id}"
+    if not FileTest.directory?(meeting_published_dir)
+      meeting_published_dir = "#{presentation_unpublished_dir}/#{meeting_id}"
+      if not FileTest.directory?(meeting_published_dir)
+        meeting_published_dir = nil
+      end
+    end
+
+    if meeting_published_dir
+      BigBlueButton.logger.info("Processing script presentation_export.rb")
+      FileUtils.mkdir_p target_dir
+
+      resources_dir = "#{target_dir}/resources"
+      FileUtils.mkdir_p resources_dir
+      FileUtils.cp_r Dir.glob("#{meeting_published_dir}/*"), resources_dir
+
+      player_dir = "#{target_dir}/playback"
+      FileUtils.mkdir_p player_dir
+      FileUtils.cp_r Dir.glob("#{playback_dir}/*"), player_dir
+
+      process_done = File.new("#{recording_dir}/status/processed/#{meeting_id}-presentation_export.done", "w")
+      process_done.write("Processed #{meeting_id}")
+      process_done.close
+    end
+  end
+end
\ No newline at end of file
diff --git a/record-and-playback/presentation_export/scripts/publish/presentation_export.rb b/record-and-playback/presentation_export/scripts/publish/presentation_export.rb
new file mode 100755
index 0000000000000000000000000000000000000000..761e0d68f092624e3c5b123292b8db3263ec5d45
--- /dev/null
+++ b/record-and-playback/presentation_export/scripts/publish/presentation_export.rb
@@ -0,0 +1,128 @@
+# Set encoding to utf-8
+# encoding: UTF-8
+
+#
+# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
+#
+# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
+#
+# This program is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 3.0 of the License, or (at your option) any later
+# version.
+#
+# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
+#
+
+require File.expand_path('../../../lib/recordandplayback', __FILE__)
+require 'rubygems'
+require 'trollop'
+require 'yaml'
+require 'zip'
+
+opts = Trollop::options do
+  opt :meeting_id, "Meeting id to archive", :default => '58f4a6b3-cd07-444d-8564-59116cb53974', :type => String
+end
+
+$meeting_id = opts[:meeting_id]
+match = /(.*)-(.*)/.match $meeting_id
+$meeting_id = match[1]
+$playback = match[2]
+
+if ($playback == "presentation_export")
+  logger = Logger.new("/var/log/bigbluebutton/presentation_export/publish-#{$meeting_id}.log", 'daily' )
+  BigBlueButton.logger = logger
+  # This script lives in scripts/archive/steps while properties.yaml lives in scripts/
+
+  bbb_props = YAML::load(File.open('../../core/scripts/bigbluebutton.yml'))
+  simple_props = YAML::load(File.open('presentation_export.yml'))
+  BigBlueButton.logger.info("Setting recording dir")
+  recording_dir = bbb_props['recording_dir']
+  BigBlueButton.logger.info("Setting process dir")
+  process_dir = "#{recording_dir}/process/presentation_export/#{$meeting_id}"
+  BigBlueButton.logger.info("setting publish dir")
+  publish_dir = simple_props['publish_dir']
+  BigBlueButton.logger.info("setting playback host")
+  playback_host = bbb_props['playback_host']
+  BigBlueButton.logger.info("setting target dir")
+  target_dir = "#{recording_dir}/publish/presentation_export/#{$meeting_id}"
+
+  raw_archive_dir = "#{recording_dir}/raw/#{$meeting_id}"
+
+  if not FileTest.directory?(target_dir)
+    if not File.exists? "#{recording_dir}/status/published/#{$meeting_id}-presentation.done"
+      BigBlueButton.logger.info "Presentation not published yet, aborting"
+      abort
+    end
+
+    BigBlueButton.logger.info("Making dir target_dir")
+    FileUtils.mkdir_p target_dir
+
+    temp_dir = "#{target_dir}/temp"
+    FileUtils.mkdir_p temp_dir
+    zipped_directory = "#{temp_dir}/zipped"
+    FileUtils.mkdir_p zipped_directory
+
+    FileUtils.cp_r "#{process_dir}/resources", zipped_directory
+    FileUtils.cp_r "#{process_dir}/playback", zipped_directory
+    FileUtils.mv "#{zipped_directory}/playback/playback.html", zipped_directory
+
+    package_dir = "#{target_dir}/#{$meeting_id}"
+    BigBlueButton.logger.info("Making dir package_dir")
+    FileUtils.mkdir_p package_dir
+
+    BigBlueButton.logger.info("Creating the .zip file")
+
+    zipped_file = "#{package_dir}/#{$meeting_id}.zip"
+      Zip::File.open(zipped_file, Zip::File::CREATE) do |zipfile|
+      Dir["#{zipped_directory}/**/**"].reject{|f|f==zipped_file}.each do |file|
+        zipfile.add(file.sub(zipped_directory+'/', ''), file)
+      end
+    end
+    FileUtils.chmod 0644, zipped_file
+
+    BigBlueButton.logger.info("Creating metadata.xml")
+    presentation_metadata = "#{process_dir}/resources/metadata.xml"
+    BigBlueButton.logger.info "Parsing metadata on #{presentation_metadata}"
+    doc = nil
+    begin
+      doc = Nokogiri::XML(open(presentation_metadata).read)
+    rescue Exception => e
+      BigBlueButton.logger.error "Something went wrong: #{$!}"
+      raise e
+    end
+    doc.at("published").content = true;
+    doc.at("format").content = "presentation_export"
+    doc.at("link").content = "http://#{playback_host}/presentation_export/#{$meeting_id}/#{$meeting_id}.zip"
+
+    metadata_xml = File.new("#{package_dir}/metadata.xml","w")
+    metadata_xml.write(doc.to_xml(:indent => 2))
+    metadata_xml.close
+
+    # After all the processing we'll add the published format and raw sizes to the metadata file
+    BigBlueButton.add_raw_size_to_metadata(package_dir, raw_archive_dir)
+    BigBlueButton.add_playback_size_to_metadata(package_dir)
+
+    if not FileTest.directory?(publish_dir)
+      FileUtils.mkdir_p publish_dir
+    end
+    FileUtils.cp_r(package_dir, publish_dir) # Copy all the files.
+    BigBlueButton.logger.info("Finished publishing script presentation.rb successfully.")
+
+    BigBlueButton.logger.info("Removing processed files.")
+    FileUtils.rm_r(Dir.glob("#{process_dir}/*"))
+
+    BigBlueButton.logger.info("Removing published files.")
+    FileUtils.rm_r(Dir.glob("#{target_dir}/*"))
+
+    publish_done = File.new("#{recording_dir}/status/published/#{$meeting_id}-presentation_export.done", "w")
+    publish_done.write("Published #{$meeting_id}")
+    publish_done.close
+  end
+
+end
\ No newline at end of file