Merge branch 'master' into eugenia/asterix_sdk_stable
diff --git a/asterix-app/src/main/java/edu/uci/ics/asterix/api/http/servlet/AsterixSDKServlet.java b/asterix-app/src/main/java/edu/uci/ics/asterix/api/http/servlet/AsterixSDKServlet.java
new file mode 100644
index 0000000..3ae36df
--- /dev/null
+++ b/asterix-app/src/main/java/edu/uci/ics/asterix/api/http/servlet/AsterixSDKServlet.java
@@ -0,0 +1,47 @@
+package edu.uci.ics.asterix.api.http.servlet;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+
+public class AsterixSDKServlet extends HttpServlet {
+
+    @Override
+    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        
+        String requestURI = request.getRequestURI();
+        String contentType = "application/javascript";
+        if (requestURI.endsWith("html")) {
+            contentType = "text/html";
+        }
+        response.setContentType(contentType);
+        response.setCharacterEncoding("utf-8");
+
+        PrintWriter out = response.getWriter();
+
+        if (requestURI.startsWith("/sdk/static/")) {
+            InputStream is = APIServlet.class.getResourceAsStream(requestURI);
+            if (is == null) {
+                response.sendError(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+
+            InputStreamReader isr = new InputStreamReader(is);
+            StringBuilder sb = new StringBuilder();
+            BufferedReader br = new BufferedReader(isr);
+            String line = br.readLine();
+
+            while (line != null) {
+                sb.append(line);
+                sb.append("\n");
+                line = br.readLine();
+            }
+
+            out.println(sb.toString());
+
+            return;
+        }
+    }
+
+}
diff --git a/asterix-app/src/main/java/edu/uci/ics/asterix/api/http/servlet/RESTAPIServlet.java b/asterix-app/src/main/java/edu/uci/ics/asterix/api/http/servlet/RESTAPIServlet.java
index 6086bc1..25177a3 100644
--- a/asterix-app/src/main/java/edu/uci/ics/asterix/api/http/servlet/RESTAPIServlet.java
+++ b/asterix-app/src/main/java/edu/uci/ics/asterix/api/http/servlet/RESTAPIServlet.java
@@ -14,9 +14,12 @@
  */
 package edu.uci.ics.asterix.api.http.servlet;
 
-import java.io.IOException;
-import java.io.PrintWriter;
 import java.util.List;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.PrintWriter;
+import java.io.IOException;
 import java.util.logging.Level;
 
 import javax.servlet.ServletContext;
@@ -48,7 +51,6 @@
     private static final String HYRACKS_CONNECTION_ATTR = "edu.uci.ics.asterix.HYRACKS_CONNECTION";
 
     private static final String HYRACKS_DATASET_ATTR = "edu.uci.ics.asterix.HYRACKS_DATASET";
-
     @Override
     public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
         response.setContentType("application/json");
diff --git a/asterix-app/src/main/java/edu/uci/ics/asterix/hyracks/bootstrap/CCApplicationEntryPoint.java b/asterix-app/src/main/java/edu/uci/ics/asterix/hyracks/bootstrap/CCApplicationEntryPoint.java
index dc201dd..3ecb83d 100644
--- a/asterix-app/src/main/java/edu/uci/ics/asterix/hyracks/bootstrap/CCApplicationEntryPoint.java
+++ b/asterix-app/src/main/java/edu/uci/ics/asterix/hyracks/bootstrap/CCApplicationEntryPoint.java
@@ -27,6 +27,7 @@
 import edu.uci.ics.asterix.api.http.servlet.QueryResultAPIServlet;
 import edu.uci.ics.asterix.api.http.servlet.QueryStatusAPIServlet;
 import edu.uci.ics.asterix.api.http.servlet.UpdateAPIServlet;
+import edu.uci.ics.asterix.api.http.servlet.AsterixSDKServlet;
 import edu.uci.ics.asterix.common.api.AsterixThreadFactory;
 import edu.uci.ics.asterix.common.config.AsterixExternalProperties;
 import edu.uci.ics.asterix.common.config.AsterixMetadataProperties;
@@ -118,5 +119,6 @@
         context.addServlet(new ServletHolder(new QueryResultAPIServlet()), "/query/result");
         context.addServlet(new ServletHolder(new UpdateAPIServlet()), "/update");
         context.addServlet(new ServletHolder(new DDLAPIServlet()), "/ddl");
+        context.addServlet(new ServletHolder(new AsterixSDKServlet()), "/");
     }
-}
\ No newline at end of file
+}
diff --git a/asterix-app/src/main/resources/sdk/static/client.html b/asterix-app/src/main/resources/sdk/static/client.html
new file mode 100644
index 0000000..d421a7a
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/client.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
+        <script src="js/easyXDM.debug.js" type="text/javascript"></script>
+        <script src="js/asterix-api-core.js" type="text/javascript"></script>
+        <script>
+            var a = new AsterixSDK();
+            a.requestHandler();
+        </script>
+    </head>
+    <body>
+        'ello
+    </body>
+</html>
diff --git a/asterix-app/src/main/resources/sdk/static/example/data/fbm.adm b/asterix-app/src/main/resources/sdk/static/example/data/fbm.adm
new file mode 100644
index 0000000..58d7f08
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/example/data/fbm.adm
@@ -0,0 +1,15 @@
+{"message-id":1,"author-id":3,"in-response-to":2,"sender-location":point("47.16,77.75"),"message":" love sprint its shortcut-menu is awesome:)"}
+{"message-id":2,"author-id":1,"in-response-to":4,"sender-location":point("41.66,80.87"),"message":" dislike iphone its touch-screen is horrible"}
+{"message-id":3,"author-id":2,"in-response-to":4,"sender-location":point("48.09,81.01"),"message":" like samsung the plan is amazing"}
+{"message-id":4,"author-id":1,"in-response-to":2,"sender-location":point("37.73,97.04"),"message":" can't stand at&t the network is horrible:("}
+{"message-id":5,"author-id":6,"in-response-to":2,"sender-location":point("34.7,90.76"),"message":" love sprint the customization is mind-blowing"}
+{"message-id":6,"author-id":2,"in-response-to":1,"sender-location":point("31.5,75.56"),"message":" like t-mobile its platform is mind-blowing"}
+{"message-id":7,"author-id":5,"in-response-to":15,"sender-location":point("32.91,85.05"),"message":" dislike sprint the speed is horrible"}
+{"message-id":8,"author-id":1,"in-response-to":11,"sender-location":point("40.33,80.87"),"message":" like verizon the 3G is awesome:)"}
+{"message-id":9,"author-id":3,"in-response-to":12,"sender-location":point("34.45,96.48"),"message":" love verizon its wireless is good"}
+{"message-id":10,"author-id":1,"in-response-to":12,"sender-location":point("42.5,70.01"),"message":" can't stand motorola the touch-screen is terrible"}
+{"message-id":11,"author-id":1,"in-response-to":1,"sender-location":point("38.97,77.49"),"message":" can't stand at&t its plan is terrible"}
+{"message-id":12,"author-id":10,"in-response-to":6,"sender-location":point("42.26,77.76"),"message":" can't stand t-mobile its voicemail-service is OMG:("}
+{"message-id":13,"author-id":10,"in-response-to":4,"sender-location":point("42.77,78.92"),"message":" dislike iphone the voice-command is bad:("}
+{"message-id":14,"author-id":9,"in-response-to":12,"sender-location":point("41.33,85.28"),"message":" love at&t its 3G is good:)"}
+{"message-id":15,"author-id":7,"in-response-to":11,"sender-location":point("44.47,67.11"),"message":" like iphone the voicemail-service is awesome"}
diff --git a/asterix-app/src/main/resources/sdk/static/example/data/fbu.adm b/asterix-app/src/main/resources/sdk/static/example/data/fbu.adm
new file mode 100644
index 0000000..7e99ea4
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/example/data/fbu.adm
@@ -0,0 +1,10 @@
+{"id":1,"alias":"Margarita","name":"MargaritaStoddard","user-since":datetime("2012-08-20T10:10:00"),"friend-ids":{{2,3,6,10}},"employment":[{"organization-name":"Codetechno","start-date":date("2006-08-06")}]}
+{"id":2,"alias":"Isbel","name":"IsbelDull","user-since":datetime("2011-01-22T10:10:00"),"friend-ids":{{1,4}},"employment":[{"organization-name":"Hexviafind","start-date":date("2010-04-27")}]}
+{"id":3,"alias":"Emory","name":"EmoryUnk","user-since":datetime("2012-07-10T10:10:00"),"friend-ids":{{1,5,8,9}},"employment":[{"organization-name":"geomedia","start-date":date("2010-06-17"),"end-date":date("2010-01-26")}]}
+{"id":4,"alias":"Nicholas","name":"NicholasStroh","user-since":datetime("2010-12-27T10:10:00"),"friend-ids":{{2}},"employment":[{"organization-name":"Zamcorporation","start-date":date("2010-06-08")}]}
+{"id":5,"alias":"Von","name":"VonKemble","user-since":datetime("2010-01-05T10:10:00"),"friend-ids":{{3,6,10}},"employment":[{"organization-name":"Kongreen","start-date":date("2010-11-27")}]}
+{"id":6,"alias":"Willis","name":"WillisWynne","user-since":datetime("2005-01-17T10:10:00"),"friend-ids":{{1,3,7}},"employment":[{"organization-name":"jaydax","start-date":date("2009-05-15")}]}
+{"id":7,"alias":"Suzanna","name":"SuzannaTillson","user-since":datetime("2012-08-07T10:10:00"),"friend-ids":{{6}},"employment":[{"organization-name":"Labzatron","start-date":date("2011-04-19")}]}
+{"id":8,"alias":"Nila","name":"NilaMilliron","user-since":datetime("2008-01-01T10:10:00"),"friend-ids":{{3}},"employment":[{"organization-name":"Plexlane","start-date":date("2010-02-28")}]}
+{"id":9,"alias":"Woodrow","name":"WoodrowNehling","user-since":datetime("2005-09-20T10:10:00"),"friend-ids":{{3,10}},"employment":[{"organization-name":"Zuncan","start-date":date("2003-04-22"),"end-date":date("2009-12-13")}]}
+{"id":10,"alias":"Bram","name":"BramHatch","user-since":datetime("2010-10-16T10:10:00"),"friend-ids":{{1,5,9}},"employment":[{"organization-name":"physcane","start-date":date("2007-06-05"),"end-date":date("2011-11-05")}]}
diff --git a/asterix-app/src/main/resources/sdk/static/example/data/twm.adm b/asterix-app/src/main/resources/sdk/static/example/data/twm.adm
new file mode 100644
index 0000000..fa764af
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/example/data/twm.adm
@@ -0,0 +1,12 @@
+{"tweetid":"1","user":{"screen-name":"NathanGiesen@211","lang":"en","friends_count":39339,"statuses_count":473,"name":"Nathan Giesen","followers_count":49416},"sender-location":point("47.44,80.65"),"send-time":datetime("2008-04-26T10:10:00"),"referred-topics":{{"t-mobile","customization"}},"message-text":" love t-mobile its customization is good:)"}
+{"tweetid":"2","user":{"screen-name":"ColineGeyer@63","lang":"en","friends_count":121,"statuses_count":362,"name":"Coline Geyer","followers_count":17159},"sender-location":point("32.84,67.14"),"send-time":datetime("2010-05-13T10:10:00"),"referred-topics":{{"verizon","shortcut-menu"}},"message-text":" like verizon its shortcut-menu is awesome:)"}
+{"tweetid":"3","user":{"screen-name":"NathanGiesen@211","lang":"en","friends_count":39339,"statuses_count":473,"name":"Nathan Giesen","followers_count":49416},"sender-location":point("29.72,75.8"),"send-time":datetime("2006-11-04T10:10:00"),"referred-topics":{{"motorola","speed"}},"message-text":" like motorola the speed is good:)"}
+{"tweetid":"4","user":{"screen-name":"NathanGiesen@211","lang":"en","friends_count":39339,"statuses_count":473,"name":"Nathan Giesen","followers_count":49416},"sender-location":point("39.28,70.48"),"send-time":datetime("2011-12-26T10:10:00"),"referred-topics":{{"sprint","voice-command"}},"message-text":" like sprint the voice-command is mind-blowing:)"}
+{"tweetid":"5","user":{"screen-name":"NathanGiesen@211","lang":"en","friends_count":39339,"statuses_count":473,"name":"Nathan Giesen","followers_count":49416},"sender-location":point("40.09,92.69"),"send-time":datetime("2006-08-04T10:10:00"),"referred-topics":{{"motorola","speed"}},"message-text":" can't stand motorola its speed is terrible:("}
+{"tweetid":"6","user":{"screen-name":"ColineGeyer@63","lang":"en","friends_count":121,"statuses_count":362,"name":"Coline Geyer","followers_count":17159},"sender-location":point("47.51,83.99"),"send-time":datetime("2010-05-07T10:10:00"),"referred-topics":{{"iphone","voice-clarity"}},"message-text":" like iphone the voice-clarity is good:)"}
+{"tweetid":"7","user":{"screen-name":"ChangEwing_573","lang":"en","friends_count":182,"statuses_count":394,"name":"Chang Ewing","followers_count":32136},"sender-location":point("36.21,72.6"),"send-time":datetime("2011-08-25T10:10:00"),"referred-topics":{{"samsung","platform"}},"message-text":" like samsung the platform is good"}
+{"tweetid":"8","user":{"screen-name":"NathanGiesen@211","lang":"en","friends_count":39339,"statuses_count":473,"name":"Nathan Giesen","followers_count":49416},"sender-location":point("46.05,93.34"),"send-time":datetime("2005-10-14T10:10:00"),"referred-topics":{{"t-mobile","shortcut-menu"}},"message-text":" like t-mobile the shortcut-menu is awesome:)"}
+{"tweetid":"9","user":{"screen-name":"NathanGiesen@211","lang":"en","friends_count":39339,"statuses_count":473,"name":"Nathan Giesen","followers_count":49416},"sender-location":point("36.86,74.62"),"send-time":datetime("2012-07-21T10:10:00"),"referred-topics":{{"verizon","voicemail-service"}},"message-text":" love verizon its voicemail-service is awesome"}
+{"tweetid":"10","user":{"screen-name":"ColineGeyer@63","lang":"en","friends_count":121,"statuses_count":362,"name":"Coline Geyer","followers_count":17159},"sender-location":point("29.15,76.53"),"send-time":datetime("2008-01-26T10:10:00"),"referred-topics":{{"verizon","voice-clarity"}},"message-text":" hate verizon its voice-clarity is OMG:("}
+{"tweetid":"11","user":{"screen-name":"NilaMilliron_tw","lang":"en","friends_count":445,"statuses_count":164,"name":"Nila Milliron","followers_count":22649},"sender-location":point("37.59,68.42"),"send-time":datetime("2008-03-09T10:10:00"),"referred-topics":{{"iphone","platform"}},"message-text":" can't stand iphone its platform is terrible"}
+{"tweetid":"12","user":{"screen-name":"OliJackson_512","lang":"en","friends_count":445,"statuses_count":164,"name":"Oli Jackson","followers_count":22649},"sender-location":point("24.82,94.63"),"send-time":datetime("2010-02-13T10:10:00"),"referred-topics":{{"samsung","voice-command"}},"message-text":" like samsung the voice-command is amazing:)"}
diff --git a/asterix-app/src/main/resources/sdk/static/example/data/twu.adm b/asterix-app/src/main/resources/sdk/static/example/data/twu.adm
new file mode 100644
index 0000000..32a1917
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/example/data/twu.adm
@@ -0,0 +1,4 @@
+{"screen-name":"NathanGiesen@211","lang":"en","friends_count":18,"statuses_count":473,"name":"Nathan Giesen","followers_count":49416}
+{"screen-name":"ColineGeyer@63","lang":"en","friends_count":121,"statuses_count":362,"name":"Coline Geyer","followers_count":17159}
+{"screen-name":"NilaMilliron_tw","lang":"en","friends_count":445,"statuses_count":164,"name":"Nila Milliron","followers_count":22649}
+{"screen-name":"ChangEwing_573","lang":"en","friends_count":182,"statuses_count":394,"name":"Chang Ewing","followers_count":32136}
diff --git a/asterix-app/src/main/resources/sdk/static/example/demo.html b/asterix-app/src/main/resources/sdk/static/example/demo.html
new file mode 100644
index 0000000..4eaff8a
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/example/demo.html
@@ -0,0 +1,405 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <title>AsterixDB TinySocial Demo</title>
+
+    <style>
+        .pretty-printed {
+    background-color: #eeeeee;
+    margin-bottom: 1em;
+        }
+
+        .how-to-run {
+    background-color: #c8c8c8;
+    margin-bottom: 1em;
+        }
+
+        .result-output {
+    background-color: #BED8E5;
+    margin-bottom: 1em;
+        }
+
+        body {
+    font-family : "Helvetica";
+    margin-bottom: 1em;
+        }
+    </style>
+
+    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
+    <script src="../js/asterix-sdk-stable.js"></script>
+    <script src="js/demo.js"></script>
+</head>
+<body>
+    <h1>AQL: Querying TinySocial AsterixDB</h1>
+    
+    <h2>Query 0-A - Exact-Match Lookup</h2>
+    <div class="sample-query">
+
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $user in dataset FacebookUsers
+    where $user.id = 8
+    return $user;
+        </pre></div>
+
+        <div class="how-to-run"><pre><code class="javascript">
+    var expression0a = new FLWOGRExpression({ 
+        "dataverse" : "TinySocial",
+        "success"   : function(res) {
+                          $('#result0a').html(res["results"]);
+                      }
+        })
+        .bind( new ForClause("user", null, new AsterixExpression().set(["dataset FacebookUsers"])) )
+        .bind( new WhereClause(new BooleanExpression("$user.id = 8")));
+        </code></pre></div>
+
+        <div class="result-output" id="result0a">
+        </div>
+
+        <button id="run0a">Run #0-A</button>
+    </div>
+    <hr/>
+    <h2>Query 0-B - Range Scan</h2>
+    <div class="sample-query">
+        
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $user in dataset FacebookUsers
+    where $user.id >= 2 and $user.id <= 4
+    return $user;
+        </pre></div>
+        
+        <div class="how-to-run"><pre>
+        </pre></div>
+
+        <div class="result-output" id="result0b">
+        </div>
+
+        <button id="run0b">Run #0-B</button>
+    </div>
+    <hr/>
+
+    <h2>Query 1 - Other Query Filters</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $user in dataset FacebookUsers
+    where $user.user-since >= datetime('2010-07-22T00:00:00')
+    and $user.user-since <= datetime('2012-07-29T23:59:59')
+    return $user;
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result1">
+        </div>
+
+        <button id="run1">Run #1</button>
+    </div>
+    <hr/>
+
+    <h2>Query 2-A - Equijoin</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $user in dataset FacebookUsers
+    for $message in dataset FacebookMessages
+    where $message.author-id = $user.id 
+    return {
+        "uname": $user.name,
+        "message": $message.message
+    };
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result2a">
+        </div>
+
+        <button id="run2a">Run #2-A</button>
+    </div>
+    <hr/>
+
+    <h2>Query 2-B - Index join</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $user in dataset FacebookUsers
+    for $message in dataset FacebookMessages
+    where $message.author-id /*+ indexnl */  = $user.id
+    return {
+        "uname": $user.name,
+        "message": $message.message
+    };
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result2b">
+        </div>
+
+        <button id="run2b">Run #2-B</button>
+    </div>
+    <hr/>
+
+    <h2>Query 3 - Nested Outer Join</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $user in dataset FacebookUsers
+    return {
+        "uname": $user.name,
+        "messages": for $message in dataset FacebookMessages
+                    where $message.author-id = $user.id
+                    return $message.message
+    };
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result3">
+        </div>
+
+        <button id="run3">Run #3</button>
+    </div>
+    <hr/>
+
+    <h2>Query 4 - Theta Join</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $t in dataset TweetMessages
+    return {
+        "message": $t.message-text,
+        "nearby-messages": for $t2 in dataset TweetMessages
+                           where spatial-distance($t.sender-location, $t2.sender-location) <= 1
+                           return { "msgtxt":$t2.message-text}
+    };
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result4">
+        </div>
+
+        <button id="run4">Run #4</button>
+    </div>
+    <hr/>
+
+    <h2>Query 5 - Fuzzy Join</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    set simfunction "edit-distance";
+    set simthreshold "3";
+
+    for $fbu in dataset FacebookUsers
+    return {
+        "id": $fbu.id,
+        "name": $fbu.name,
+        "similar-users": for $t in dataset TweetMessages
+                         let $tu := $t.user
+                         where $tu.name ~= $fbu.name
+                        return {
+                            "twitter-screenname": $tu.screen-name,
+                            "twitter-name": $tu.name
+                        }
+    };
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result5">
+        </div>
+
+        <button id="run5">Run #5</button>
+    </div>
+    <hr/>
+
+    <h2>Query 6 - Existential Quantification</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $fbu in dataset FacebookUsers
+    where (some $e in $fbu.employment satisfies is-null($e.end-date)) 
+    return $fbu;
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result6">
+        </div>
+
+        <button id="run6">Run #6</button>
+    </div>
+    <hr/>
+
+    <h2>Query 7 - Universal Quantification</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre><pre>
+    use dataverse TinySocial;
+
+    for $fbu in dataset FacebookUsers
+    where (every $e in $fbu.employment satisfies not(is-null($e.end-date))) 
+    return $fbu;
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result7">
+        </div>
+
+        <button id="run7">Run #7</button>
+    </div>
+    <hr/>
+
+    <h2>Query 8 - Simple Aggregation</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    count(for $fbu in dataset FacebookUsers return $fbu);
+        </pre></div>
+        
+        <div class="how-to-run"><pre><code class="javascript">
+    var expression8 = new FunctionExpression({
+        "function"      : "count",
+        "expression"    : new ForClause(
+                              "fbu", null, new AsterixExpression().set(["dataset FacebookUsers"])
+                          ).bind(
+                            {"return" : new AsterixExpression().set(["$fbu"])}
+                          ),
+        "dataverse"     : "TinySocial",
+        "success"       : function(res) {
+                              $('#result8').html(res["results"]);
+                          }
+    });
+        </code></pre></div>
+
+        <div class="result-output" id="result8">
+        </div>
+
+        <button id="run8">Run #8</button>
+    </div>
+    <hr/>
+
+    <h2>Query 9-A - Grouping and Aggregation</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $t in dataset TweetMessages
+    group by $uid := $t.user.screen-name with $t
+    return {
+        "user": $uid,
+        "count": count($t)
+    };
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result9a">
+        </div>
+
+        <button id="run9a">Run #9-A</button>
+    </div>
+    <hr/>
+
+    <h2>Query 9-B - (Hash-Based) Grouping and Aggregation</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $t in dataset TweetMessages
+    /*+ hash*/
+    group by $uid := $t.user.screen-name with $t
+    return {
+        "user": $uid,
+        "count": count($t)
+    };
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result9b">
+        </div>
+
+        <button id="run9b">Run #9-B</button>
+    </div>
+    <hr/>
+
+    <h2>Query 10 - Grouping and Limits</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    for $t in dataset TweetMessages
+    group by $uid := $t.user.screen-name with $t
+    let $c := count($t)
+    order by $c desc
+    limit 3
+    return {
+        "user": $uid,
+        "count": $c
+    };
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result10">
+        </div>
+
+        <button id="run10">Run #10</button>
+    </div>
+    <hr/>
+
+    <h2>Query 11 - Left Outer Fuzzy Join</h2>
+    <div class="sample-query">
+        <div class="pretty-printed"><pre>
+    use dataverse TinySocial;
+
+    set simfunction "jaccard";
+    set simthreshold "0.3";
+
+    for $t in dataset TweetMessages
+    return {             
+        "tweet": $t,       
+        "similar-tweets": for $t2 in dataset TweetMessages
+        where  $t2.referred-topics ~= $t.referred-topics
+        and $t2.tweetid != $t.tweetid
+        return $t2.referred-topics
+    };
+        </pre></div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <div class="result-output" id="result11">
+        </div>
+
+        <button id="run11">Run #11</button>
+    </div>
+
+</body>
+</html>
diff --git a/asterix-app/src/main/resources/sdk/static/example/js/demo.js b/asterix-app/src/main/resources/sdk/static/example/js/demo.js
new file mode 100644
index 0000000..0cca153
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/example/js/demo.js
@@ -0,0 +1,321 @@
+$(document).ready(function() {
+
+    // 0A - Exact-Match Lookup
+    $('#run0a').click(function () {
+        $('#result0a').html('');
+        var expression0a = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            $('#result0a').html(res["results"]);
+                          } 
+            })
+            .bind( new ForClause("user", null, new AExpression().set("dataset FacebookUsers")) )
+            .bind( new WhereClause(new BooleanExpression("$user.id = 8")) )
+            .bind({ "return" : new AExpression().set("$user") });
+        
+        expression0a.run();
+    });
+
+    // 0B - Range Scan
+    $("#run0b").click(function() {
+        $('#result0b').html('');
+
+        var expression0b = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                              alert(JSON.stringify(res));
+                              $('#result0b').html(res["results"]);
+                          },
+            })
+            .bind( new ForClause("user", null, new AExpression().set("dataset FacebookUsers")) )
+            .bind( new WhereClause( new BooleanExpression("AND", new BooleanExpression(">=", "$user.id", 2), new BooleanExpression("<=", "$user.id", 4)) ) )
+            .bind( new ReturnClause("$user") );
+        alert(expression0b.val());
+        expression0b.run();
+
+    });
+
+    // 1 - Other Query Filters
+    $("#run1").click(function() {
+        $('#result1').html('');
+
+        var expression1 = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            alert(JSON.stringify(res));
+                            $('#result1').html(res["results"]);
+                          }
+        });
+        alert("EXPRESSION 1 " + expression1.val());
+    });
+
+    // 2A - Equijoin
+    $("#run2a").click(function() {
+        $('#result2a').html('');
+
+        var expression2a = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            alert(JSON.stringify(res));
+                            $('#result2a').html(res["results"]);
+                          }
+        });
+        alert("EXPRESSION 2a " + expression2a.val());
+    });
+
+    // 2B - Index Join
+    $("#run2b").click(function() {
+        $('#result2b').html('');
+
+        var expression2b = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            alert(JSON.stringify(res));
+                            $('#result2b').html(res["results"]);
+                          }
+        });
+        alert("EXPRESSION 2b " + expression2b.val());
+    });
+
+    // 3 - Nested Outer Join
+    $("#run3").click(function() {
+        $('#result3').html('');
+
+        var expression3 = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            alert(JSON.stringify(res));
+                            $('#result3').html(res["results"]);
+                          }
+        });
+        alert("EXPRESSION 3 " + expression3.val());
+    });
+    
+    // 4 - Theta Join
+    $("#run4").click(function() {
+        $('#result4').html('');
+
+        var expression4 = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            alert(JSON.stringify(res));
+                            $('#result4').html(res["results"]);
+                          }
+        });
+        alert("EXPRESSION 4 " + expression4.val());
+    });
+
+    // 5 - Fuzzy Join
+    $("#run5").click(function() {
+        $('#result5').html('');
+
+        var expression5 = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            alert(JSON.stringify(res));
+                            $('#result5').html(res["results"]);
+                          }
+        });
+        alert("EXPRESSION 5 " + expression5.val());
+    });
+
+    // 6 - Existential Quantification
+    $("#run6").click(function() {
+        $('#result6').html('');
+
+        var expression6 = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            alert(JSON.stringify(res));
+                            $('#result6').html(res["results"]);
+                          }
+        })
+        .bind( new ForClause (
+            "fbu", 
+            null, 
+            new AQLClause().set("dataset FacebookUsers")
+        ))
+        .bind( new WhereClause ( 
+            new QuantifiedExpression (
+                "some" , 
+                {"$e" : new AQLClause().set("$fbu.employment") },
+                new AQLClause().set("is-null($e.end-date)")
+            )
+        ))
+        .bind( new ReturnClause( new AQLClause().set("$fbu") ));
+        alert("EXPRESSION 6 " + expression6.val());
+    });
+
+    // 7 - Universal Quantification
+    $("#run7").click(function() {
+        $('#result7').html('');
+
+        var expression7 = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            alert(JSON.stringify(res));
+                            $('#result7').html(res["results"]);
+                          }
+        })
+        .bind( new ForClause (
+            "fbu", 
+            null, 
+            new AQLClause().set("dataset FacebookUsers")
+        ))
+        .bind( new WhereClause ( 
+            new QuantifiedExpression (
+                "every" , 
+                {"$e" : new AQLClause().set("$fbu.employment") },
+                new AQLClause().set("not(is-null($e.end-date))")
+            )
+        ))
+        .bind(new ReturnClause( new AQLClause().set("$fbu") ));
+        alert("EXPRESSION 7 " + expression7.val());
+    });
+
+    // 8 - Simple Aggregation
+    $('#run8').click(function () {
+
+        // Option 1: Simple, Object Syntax     
+        $('#result8').html('');   
+        var expression8 = new FunctionExpression({
+            "function"      : "count",
+            "expression"    : new ForClause("fbu", null, new AExpression().set("dataset FacebookUsers"))
+                                    .bind( new ReturnClause( new AExpression().set("$fbu") )),
+            "dataverse"     : "TinySocial",
+            "success"       : function(res) {
+                                $('#result8').html(res["results"]);
+                              }
+        });
+        alert(expression8.val());
+        // expression8.run();
+    });
+
+    // 9a - Grouping & Aggregation
+    $("#run9a").click(function() {
+        $('#result9a').html('');
+
+        var expression9a = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            $('#result9a').html(res["results"]);
+                          }
+        })
+        .bind( new ForClause("t", null, new AExpression().set("dataset TweetMessages")))
+        .bind( new GroupClause("uid", new AExpression().set("$t.user.screen-name"), "with", "t") )
+        .bind( new ReturnClause(
+            {
+                "user" : "$uid",
+                "count" : new FunctionExpression(
+                            { 
+                                "function" : "count",
+                                "expression" : new AExpression().set("$t")
+                            }
+                )
+            }
+        ));
+
+        expression9a.run();
+    });
+
+    // 9b - Hash-based Grouping & Aggregation
+    $("#run9b").click(function() {
+        $('#result9b').html('');
+
+        var expression9b = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            $('#result9b').html(res["results"]);
+                          }
+        })
+        .bind( new ForClause("t", null, new AExpression().set("dataset TweetMessages"))) 
+        .bind( new AQLClause().set("/*+ hash*/"))  
+        .bind( new GroupClause("uid", new AExpression().set("$t.user.screen-name"), "with", "t") )
+        .bind( new ReturnClause(
+            {
+                "user" : "$uid",
+                "count" : new FunctionExpression(
+                            { 
+                                "function" : "count",
+                                "expression" : new AExpression().set("$t")
+                            }
+                )
+            }
+        ));
+        
+        expression9b.run();
+    });
+    
+    // 10 - Grouping and Limits
+    $("#run10").click(function() {
+        $('#result10').html('');
+
+        var expression10 = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            $('#result10').html(res["results"]);
+                          }
+        })
+        .bind( new ForClause("t", null, new AExpression().set("dataset TweetMessages")))
+        .bind( new GroupClause("uid", new AExpression().set("$t.user.screen-name"), "with", "t") )
+        .bind( new LetClause(
+            "c", 
+            new FunctionExpression(
+                { 
+                    "function" : "count",
+                    "expression" : new AExpression().set("$t")
+                }
+            )
+        ))
+        .bind( new OrderbyClause( new AExpression().set("$c"), "desc" ) )
+        .bind( new LimitClause(new AExpression().set("3")) )
+        .bind( new ReturnClause(
+            {
+                "user" : "$uid",
+                "count" : "$c"
+            }
+        ));
+
+        expression10.run();
+    });
+
+    // 11 - Left Outer Fuzzy Join
+    $("#run11").click(function() {
+        $('#result11').html('');
+
+        var expression11 = new FLWOGRExpression({
+            "dataverse" : "TinySocial",
+            "success"   : function(res) {
+                            $('#result11').html(res["results"]);
+                          }
+        })
+        .bind( new SetStatement( "simfunction", "jaccard" ))
+        .bind( new SetStatement( "simthreshold", "0.3"))
+        .bind( new ForClause( "t", null, new AExpression().set("dataset TweetMessages") ))
+        .bind( new ReturnClause({
+            "tweet"         : new AExpression().set("$t"),       
+            "similar-tweets": new FLWOGRExpression()
+                                .bind( new ForClause( "t2", null, new AExpression().set("dataset TweetMessages") ))
+                                .bind( new AQLClause().set("where $t2.referred-topics ~= $t.referred-topics and $t2.tweetid != $t.tweetid") )
+                                .bind( new ReturnClause(new AQLClause().set("$t2.referred-topics")))
+        })); 
+        
+        expression11.run();
+    });
+
+    //$('#run0a').trigger('click');
+    //$('#run0b').trigger('click');
+    //$('#run1').trigger('click');
+    //$('#run2a').trigger('click');
+    //$('#run2b').trigger('click');
+    //$('#run3').trigger('click');
+    //$('#run4').trigger('click');
+    //$('#run5').trigger('click');
+    //$('#run6').trigger('click');
+    //$('#run7').trigger('click');
+    //$('#run8').trigger('click');
+    $('#run9a').trigger('click');
+    $('#run9b').trigger('click');
+    $('#run10').trigger('click');
+    $('#run11').trigger('click');
+});
diff --git a/asterix-app/src/main/resources/sdk/static/js/asterix-api-core.js b/asterix-app/src/main/resources/sdk/static/js/asterix-api-core.js
new file mode 100644
index 0000000..1fa99b6
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/js/asterix-api-core.js
@@ -0,0 +1,516 @@
+// AsterixSDK 
+// Core Object for REST API communication
+// Handles callbacks to client applications, communication to REST API, and 
+// endpoint selection. Initializes an RPC consumer object.
+// 
+// Usage:
+// var a = new AsterixSDK();
+function AsterixSDK() {
+    
+    // Asterix SDK request handler initialization
+    // TODO Depending on configuration, may need multiples of these...
+    this.xhr = new easyXDM.Rpc({
+        remote: "http://localhost:19101/sdk/static/client.html"
+    }, {
+        remote: {
+            post: {}
+        }
+    });
+    
+
+    // Asterix SDK => send
+    // Posts a message containing an API endpoint, json data,
+    // and a UI callback function.
+    //
+    // @param handler [Asterix REST Controller], a handler object
+    // that provides REST request information. 
+    //
+    // Anticipated Usage:
+    //
+    // var a = AsterixSDK();
+    // var e = Expression;
+    // var h = AsterixRestController.bindExpression(e);
+    // a.send(h);
+    myThis = this;
+    this.callbacks = {
+        "sync" : function() { alert("default sync"); },
+        "async" : function() {}
+    };
+    this.send = function(handler, cb) {
+        myThis.callbacks = cb;
+        this.handler = handler;
+        this.extras = handler["extras"];
+        this.xhr.post(
+            handler["endpoint"],
+            handler["apiData"],
+            this.branch          
+        );
+    };
+
+
+    // TODO DOC
+    this.branch = function(response) {
+        if (response && response["error-code"]) {
+           
+            alert("Error [Code" + response["error-code"][0] + "]: " + response["error-code"][1]);
+            
+        } else if (response && response["results"]) {
+            var fn_callback = myThis.callbacks["sync"];
+            fn_callback(response, myThis.extras);
+            
+        } else if (response["handle"]) {
+            
+            var fn_callback = this.callbacks["async"];
+            fn_callback(response, extra);
+            
+        } else if (response["status"]) {
+                
+            var fn_callback = this.callbacks["sync"];
+            fn_callback(response, extra);
+        }
+    }
+
+        
+    // Asterix SDK => requestHandler
+    // Handlers remote requests to Asterix REST API
+    // using the easyXDM RPC protocol
+    // Usually should only be called by client side, could be overridden
+    // TODO Get rid of jQuery ajax notation in favor of xmlhttprequest pure js
+    this.requestHandler = function() {
+        var rpc = new easyXDM.Rpc({}, {
+            local: {
+                post: {
+                    method: function(url, data, fn, fnError){ 
+                        $.ajax({
+                            type : 'GET',
+                            url : url,
+                            data : data,
+                            dataType : "json",
+                            success : function(res) {
+                                fn(res);
+                            }
+                        });
+                    }
+                }
+            }
+        });
+    }
+
+
+    // Asterix SDK => bindingHandler
+    // AsterixExpression form handler where a new REST API point is bound. Takes as input any
+    // AsterixExpression, each of which is bindable.
+    this.bindingHandler = new AsterixExpression();
+    this.bind = this.bindingHandler.bind;
+}
+
+// AsterixExpression => Base AQL Syntax Class
+//
+// Components: 
+//      boundTo -> a "next" expression
+function AsterixExpression() {
+    this.init();
+    return this;
+}
+
+AsterixExpression.prototype.init = function () {
+    this.dataverse = ""; // TODO This shouldn't make it to send
+    this.boundTo = {};
+    this.clauses = [];
+    this.ui_callback_on_success = function() {};
+    this.ui_callback_on_success_async = function() {};
+};
+
+// AsterixExpression => bind
+//
+// Binds a "next" AsterixExpression to this one.
+//
+// @param expression [AsterixExpression] MUST be instanceof AsterixExpression
+// TODO Check if it has a bind method or things will get messy.
+AsterixExpression.prototype.bind = function(expression) {
+    // If expression is an AsterixExpression, it becomes base
+    if (expression instanceof AsterixExpression) {
+        this.boundTo = expression;
+    } else if (expression instanceof AsterixClause) {
+        this.clauses.push(expression.val());
+    }
+    return this;
+};
+
+// AsterixExpression => send
+//
+// @param arc [AsterixRESTController]
+// TODO: Arc parameter is temporary
+AsterixExpression.prototype.send = function(arc) {
+    // Hackiest of hacks
+    var g = new AsterixSDK();
+    g.send(arc, arc["callback"]);
+};
+
+// AsterixExpression => clear
+//
+// Clears clauses array
+AsterixExpression.prototype.clear = function() {
+    this.clauses.length = 0;
+    return this;
+};
+
+// AsterixExpression => value
+//
+// Retrieves string value of current expression
+AsterixExpression.prototype.val = function() {
+    return this.clauses.join("\n"); 
+};
+
+// AsterixExpression => success
+//
+// @param method [FUNCTION]
+// @param isSynchronous [BOOLEAN]
+AsterixExpression.prototype.success = function(fn, isSync) {
+    if (isSync) {
+        this.ui_callback_on_success = fn;
+    } else { 
+        this.ui_callback_on_success_async = fn;
+    }
+    return this;
+};
+
+// AsterixExpression => set
+// Pushes statements onto the clause stack
+//
+// TODO typecheck
+// @param statements_arr [ARRAY]
+AsterixExpression.prototype.set = function(statements_arr) {
+    for (var i = 0; i < statements_arr.length; i++) {
+        this.clauses.push(statements_arr[i]);
+    }
+    return this;
+};
+
+// AsterixExpression => dataverse
+//
+// Sets the dataverse for a given api call
+AsterixExpression.prototype.use_dataverse = function(dv) {
+    this.dataverse = dv;
+    this.clauses.push("use dataverse " + dv + ";");
+    return this; 
+};
+
+AsterixExpression.prototype.return = function(return_object) {
+    var components = [];
+    for (var key in return_object) {
+        components.push('"' + key + '" : ' + return_object[key]);
+    }
+    
+    var return_expression = 'return { ' + components.join(', ') + ' }'; 
+    this.clauses.push(return_expression);
+    return this;
+};
+
+//////////////
+
+inherit(FLWOGRExpression, AsterixExpression);
+
+function FLWOGRExpression() { 
+    AsterixExpression.prototype.init.call(this);
+    return this; 
+} // ( ForClause | LetClause ) ( Clause )* "return" Expression
+
+
+/*
+function CreateExpression() { 
+    AsterixExpression.prototype.init.call(this);
+    return this; 
+} // "create" ( "type" | "nodegroup" | "external" <DATASET> | <DATASET> | "index" | "dataverse" 
+
+
+
+
+function LegacyExpression() { 
+    AsterixExpression.prototype.init.call(this);
+    return this; 
+} // Legacy for old AsterixAPI version: handle hardcoded strings. Will phase out.
+
+function FunctionCallExpr() {
+    AsterixExpression.prototype.init.call(this);
+    return this; 
+} //( <IDENTIFIER> | <DATASET> ) <LEFTPAREN> ( Expression ( "," Expression )* )? <RIGHTPAREN>
+
+inherit(CreateExpression, AsterixExpression);
+inherit(LegacyExpression, AsterixExpression);
+inherit(FunctionCallExpr, AsterixExpression);
+
+CreateExpression.prototype.send = function() {
+    myThis = this;
+    var arc = new AsterixRESTController();
+    arc.DDL(
+        { "ddl" : myThis.val() },
+        {
+            "sync" : function () {}, // TODO This should be a default value out of the AsterixExpression base
+            "async" : function () {}
+        }
+    );
+
+    // Call AsterixExpression core send method
+    AsterixExpression.prototype.send.call(this, arc);
+};
+
+// LegacyExpression
+// Handles hardcoded query strings from prior versions
+// of this API. Can be useful for debugging.
+LegacyExpression.prototype.send = function(endpoint, json) {
+    
+    var arc = {
+        "endpoint" : endpoint,
+        "apiData" : json, 
+        "callback" : {
+            "sync" : this.ui_callback_on_success,
+            "async" : this.ui_callback_on_success_async
+        },
+        "extras" : this.extras
+    };
+
+    AsterixExpression.prototype.send.call(this, arc);
+}
+
+LegacyExpression.prototype.extra = function(extras) {
+    this.extras = extras;
+    return this;
+}
+
+// TODO DOC
+FunctionCallExpr.prototype.set = function(identifier, expressions) {
+    var expression_clause = identifier + "(";
+    expression_clause += expressions[0].val();
+    for (var e = 1; e < expressions.length; e++) {
+        expression_clause += "," + expressions[e].val();
+    }
+    expression_clause += ")";
+
+    AsterixExpression.prototype.set.call(this, expression_clause);
+    return this; 
+} //( <IDENTIFIER> | <DATASET> ) <LEFTPAREN> ( Expression ( "," Expression )* )? <RIGHTPAREN>
+
+//
+// Clauses
+//
+function AsterixClause() {
+    this.clause = "";
+    return this;
+}
+
+AsterixClause.prototype.val = function() {
+    return this.clause;
+};
+
+AsterixClause.prototype.set = function(clause) {
+    this.clause = clause;
+    return this;
+};
+
+function ForClause() {}         // "for" Variable ( "at" Variable )? "in" ( Expression )
+function LetClause() {}         // "let" Variable ":=" Expression
+function WhereClause() {}       // "where" Expression
+function OrderbyClause() {}     // ( "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )* )
+function GroupClause() {}       //  "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* 
+                                //      ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
+function LimitClause() {}       // "limit" Expression ( "offset" Expression )?
+function DistinctClause() {}    // "distinct" "by" Expression ( "," Expression )*
+
+inherit(ForClause, AsterixClause);
+inherit(LetClause, AsterixClause);
+inherit(WhereClause, AsterixClause);
+inherit(OrderbyClause, AsterixClause);
+inherit(GroupClause, AsterixClause);
+inherit(LimitClause, AsterixClause);
+inherit(DistinctClause, AsterixClause);
+
+// ForClause
+//
+// Grammar:
+// "for" Variable ( "at" Variable )? "in" ( Expression )
+//
+// @param for_variable [String], REQUIRED, first variable in clause 
+// @param at_variable [String], NOT REQUIRED, first variable in clause
+// @param expression [AsterixExpression], REQUIRED, expression to evaluate
+//
+// TODO Error Checking
+function ForClause(for_variable, at_variable, expression) {
+    
+    // at_variable is optional, check if defined
+    var at = typeof at_variable ? a : null;
+
+    // Prepare clause
+    var clause = "for $" + for_variable;
+    if (at != null) {
+        clause += " at $" + at_variable;
+    }
+    clause += " in " + expression.val();
+   
+    // Set prototype
+    AsterixClause.prototype.set.call(this, clause);
+    return this;
+}
+
+// LetClause
+//
+// Grammar:
+// "let" Variable ":=" Expression
+//  
+// TODO error checking
+// @param let_variable [String], REQUIRED
+// @param expression [AsterixExpression], REQUIRED
+LetClause.prototype.set = function(let_variable, expression) { 
+    var clause = "let $" + let_variable + " := " + expression.val();
+   
+    AsterixClause.prototype.set.call(this, clause);
+    return this;
+};
+
+// TODO
+WhereClause.prototype.set = function(clause) {
+    AsterixClause.prototype.set.call(this, clause); 
+    return this;
+};
+
+// TODO
+OrderbyClause.prototype.set = function(clause) {
+    AsterixClause.prototype.set.call(this, clause); 
+    return this;
+};
+
+// GroupClause
+//
+// Grammer:
+// "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* 
+// ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? 
+// "with" VariableRef ( "," VariableRef )*
+GroupClause.prototype.set = function(clause) {
+    AsterixClause.prototype.set.call(this, clause); 
+    return this;
+};
+
+// TODO
+LimitClause.prototype.set = function(clause) {
+    AsterixClause.prototype.set.call(this, clause); 
+    return this;
+};
+
+// TODO
+DistinctClause.prototype.set = function(clause)  {
+    AsterixClause.prototype.set.call(this, clause); 
+    return this;
+};
+
+
+
+
+// Asterix REST Controller
+//
+// Asterix REST Controller
+// Handles interactions with remote database using a request handler
+function AsterixRESTController() {
+   
+    // bindExpression
+    // Prepares an expression for query the asterix API
+    // TODO: Future expressions will do some kind of parsing on queries, for now
+    // a keyword is used to return the appropriate handler
+    // keywords: ddl, update, query, query_status, query_result
+    //
+    // @param expression [AsterixExpression], an expression or one of its
+    // subclasses
+    // @param handler [AsterixRESTController], a handler to pass to the SDK
+    // remote method call
+    this.bindExpression = function(expression, handler_type) {
+        
+        // TODO Expression handler
+
+        // Parse handler, to be replaced with something more elegant
+        switch (handler_type)
+        {
+            case "ddl":
+                break;
+            case "update":
+                break;
+            case "query":
+                break;
+            case "query_status":
+                break;
+            case "query_result":
+                break;
+            default:
+                this.onHandlerInitError();
+        }
+    };
+
+    // onHandlerInitError
+    // Method for handling expression binding errors in the controller.
+    this.onHandlerInitError = function() {
+        alert("AsterixSDK / AsterixRESTController / bindExpressionError: Could not determine api endpoint, incorrect keyword");
+    }
+
+    // REST DDL API
+    this.DDL = function(data, callback) {
+        this.endpoint = "http://localhost:19101/ddl";
+        this.apiData = data;
+        this.callback = callback;
+    };
+
+}
+
+AsterixRESTController.prototype.Update = function(json, data, callback) {
+    var endpoint = "http://localhost:19101/update";
+}
+
+
+AsterixRESTController.prototype.Query = function(json, data, callback) {
+    var endpoint = "http://localhost:19101/query";
+}
+
+
+AsterixRESTController.prototype.QueryStatus = function(json, data, callback) {
+    var endpoint = "http://localhost:19101/query/status";
+}
+
+
+AsterixRESTController.prototype.QueryResult = function(json, data, callback) {
+    var endpoint = "http://localhost:19101/query/result";
+}
+
+function AsterixSDKJQueryHandler(json, endpoint, callback) {
+    $.ajax({
+        type : 'GET',
+        url : endpoint,
+        data : json,
+        dataType : "json",
+        success : function(data) {
+            alert(JSON.stringify(data));
+        }
+    });
+}
+
+// Helper Functions
+AsterixSDK.prototype.rectangle = function(bounds) {
+   var lower_left = 'create-point(' + bounds["sw"]["lat"] + ',' + bounds["sw"]["lng"] + ')';
+   var upper_right = 'create-point(' + bounds["ne"]["lat"] + ',' + bounds["ne"]["lng"] + ')';
+
+   var rectangle_statement = 'create-rectangle(' + lower_left + ', ' + upper_right + ')';
+   //FunctionCallExpr.prototype.set = function(identifier, expressions) {
+   //TODO
+   return rectangle_statement;
+};*/
+
+ 
+///////////////
+// Utilities //
+///////////////
+
+// Inherit with the proxy pattern
+// Source: https://gist.github.com/jeremyckahn/5552373
+//
+// LEGACY: Will change to Firefox's preferred object creation method :)
+function inherit(inherits, inheritsFrom) {
+    function proxy() {};
+    proxy.prototype = inheritsFrom.prototype;
+    inherits.prototype = new proxy();
+}
diff --git a/asterix-app/src/main/resources/sdk/static/js/asterix-sdk-stable.js b/asterix-app/src/main/resources/sdk/static/js/asterix-sdk-stable.js
new file mode 100644
index 0000000..7989a9e
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/js/asterix-sdk-stable.js
@@ -0,0 +1,590 @@
+// Temporary AsterixExpression Placeholder
+function AExpression () {
+    this._properties = {};
+    this._success = function() {};
+
+    return this;
+}
+
+
+AExpression.prototype.bind = function(options) {
+    var options = options || {};
+
+    if (options.hasOwnProperty("dataverse")) {
+        this._properties["dataverse"] = options["dataverse"];
+    }
+
+    if (options.hasOwnProperty("success")) {
+        this._success = options["success"];
+    }
+
+    if (options.hasOwnProperty("return")) {
+        this._properties["return"] = " return " + options["return"].val();
+    }
+};
+
+
+AExpression.prototype.run = function() {
+    var success_fn = this._success;
+
+    $.ajax({
+        type : 'GET',
+        url : "http://localhost:19101/query",
+        data : {"query" : this.val()},
+        dataType : "json",
+        success : function(data) {     
+            success_fn(data);
+        }
+    });
+
+    return this;
+};
+
+
+AExpression.prototype.val = function() { 
+
+    var value = "";
+
+    // If there is a dataverse defined, provide it.
+    if (this._properties.hasOwnProperty("dataverse")) {
+        value += "use dataverse " + this._properties["dataverse"] + ";\n";
+    };
+
+    if (this._properties.hasOwnProperty("value")) {
+        value += this._properties["value"];
+    }
+
+    return value;
+};
+
+// @param expressionValue [String]
+AExpression.prototype.set = function(expressionValue) {
+    this._properties["value"] = expressionValue; 
+    return this;
+};
+
+
+AExpression.prototype.error = function(msg) {
+    return "Asterix FunctionExpression Error: " + msg;
+};
+
+
+// FunctionExpression
+// Parent: AsterixExpression
+// 
+// @param   options [Various], 
+// @key     function [String], a function to be applid to the expression
+// @key     expression [AsterixExpression or AsterixClause] an AsterixExpression/Clause to which the fn will be applied
+function FunctionExpression(options) {
+    
+    // Initialize superclass
+    AExpression.call(this);
+
+    // Possible to initialize a function epxression without inputs, or with them
+    this.bind(options);
+
+    // Return object
+    return this;
+}
+
+
+FunctionExpression.prototype = Object.create(AExpression.prototype);
+FunctionExpression.prototype.constructor = FunctionExpression;
+
+
+FunctionExpression.prototype.bind = function(options) {
+
+    AExpression.prototype.bind.call(this, options);
+    
+    var options = options || {};
+
+    if (options.hasOwnProperty("function")) {
+        this._properties["function"] = options["function"];
+    }
+
+    if (options.hasOwnProperty("expression")) {
+        this._properties["expression"] = options["expression"];
+    }
+
+    return this;
+};
+
+FunctionExpression.prototype.val = function () { 
+    return this._properties["function"] + "(" + this._properties["expression"].val() + ")";
+};
+
+
+// FLWOGR         ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
+// Clause         ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
+// 
+// WhereClause    ::= "where" Expression
+// OrderbyClause  ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
+//
+// GroupClause    ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
+// LimitClause    ::= "limit" Expression ( "offset" Expression )?
+// DistinctClause ::= "distinct" "by" Expression ( "," Expression )*
+
+
+// FLWOGRExpression
+//
+// FLWOGRExpression ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
+function FLWOGRExpression (options) {
+    // Initialize superclass
+    AExpression.call(this);
+
+    this._properties["clauses"] = [];
+    this._properties["minSize"] = 0;
+
+    // Bind options and return
+    this.bind(options);
+    return this;
+}
+
+
+FLWOGRExpression.prototype = Object.create(AExpression.prototype);
+FLWOGRExpression.prototype.constructor = FLWOGRExpression;
+
+
+FLWOGRExpression.prototype.bind = function(options) {
+    AExpression.prototype.bind.call(this, options);
+
+    var options = options || {};
+
+    if (options instanceof SetStatement) {
+         this._properties["clauses"].push(options);
+         this._properties["minSize"] += 1;
+    }
+
+    if (this._properties["clauses"].length <= this._properties["minSize"]) {
+        // Needs to start with for or let clause
+        if (options instanceof ForClause || options instanceof LetClause) {
+            this._properties["clauses"].push(options);
+        }
+    } else {
+        if (options instanceof AQLClause) {
+            this._properties["clauses"].push(options);
+        }
+    }
+
+    return this;
+};
+
+
+FLWOGRExpression.prototype.val = function() {
+    var value = AExpression.prototype.val.call(this);
+
+    var clauseValues = [];
+    for (var c in this._properties["clauses"]) {
+        clauseValues.push(this._properties["clauses"][c].val());
+    }
+
+    return value + clauseValues.join("\n");// + ";";
+};
+
+
+// AQLClause
+//
+// Base Clause  ::= ForClause | LetClause | WhereClause | OrderbyClause | GroupClause | LimitClause | DistinctClause
+function AQLClause() {
+    this._properties = {};
+    this._properties["clause"] = "";
+}
+
+AQLClause.prototype.val = function() {
+    var value = this._properties["clause"];
+
+    if (this._properties.hasOwnProperty("return")) {
+        value += " return " + this._properties["return"].val();
+    }
+ 
+    return value;
+};
+
+AQLClause.prototype.bind = function(options) {
+    var options = options || {};
+
+    if (options.hasOwnProperty("return")) {
+        this._properties["return"] = options["return"];
+    }
+
+    return this;
+};
+
+AQLClause.prototype.set = function(value) {
+    this._properties["clause"] = value;
+    return this;
+};
+
+
+// ForClause
+//
+// Grammar:
+// "for" Variable ( "at" Variable )? "in" ( Expression )
+//
+// @param for_variable [String], REQUIRED, first variable in clause 
+// @param at_variable [String], NOT REQUIRED, first variable in clause
+// @param expression [AsterixExpression], REQUIRED, expression to evaluate
+//
+// TODO Error Checking
+function ForClause(for_variable, at_variable, expression) {
+    AQLClause.call(this);
+  
+    // at_variable is optional, check if defined
+    var at = typeof at_variable ? at_variable : null;
+
+    // Prepare clause
+    this._properties["clause"] = "for $" + for_variable;
+    if (at != null) {
+        this._properties["clause"] += " at $" + at_variable;
+    }
+    this._properties["clause"] += " in " + expression.val();
+    return this;
+}
+
+ForClause.prototype = Object.create(AQLClause.prototype);
+ForClause.prototype.constructor = ForClause;
+
+
+// LetClause
+//
+// Grammar:
+// LetClause      ::= "let" Variable ":=" Expression
+//
+// @param let_variable [String]
+// @param expression [AExpression]
+//
+// TODO Vigorous error checking
+function LetClause(let_variable, expression) {
+    AQLClause.call(this);
+    
+    this._properties["clause"] = "let $" + let_variable + " := ";
+    this._properties["clause"] += expression.val();
+    
+    return this; 
+}
+
+LetClause.prototype = Object.create(AQLClause.prototype);
+LetClause.prototype.constructor = LetClause;
+
+
+// ReturnClause
+//
+// Grammar:
+// return [AQLExpression]
+function ReturnClause(expression) {
+    AQLClause.call(this);
+
+    this._properties["clause"] = "return ";
+    if (expression instanceof AExpression || expression instanceof AQLClause) {
+        this._properties["clause"] += expression.val();
+    } else if ( Object.getPrototypeOf( expression ) === Object.prototype ) {
+        
+        this._properties["clause"] += "{";
+        var returnStatements = [];
+        for (returnValue in expression) {
+           
+            if (expression[returnValue] instanceof AExpression) { 
+                returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue].val());            
+            } else if (typeof expression[returnValue] == "string") {          
+                returnStatements.push('"' + returnValue + '" ' + " : " + expression[returnValue]);   
+            }
+        }
+        this._properties["clause"] += returnStatements.join(",\n");
+        this._properties["clause"] += "}";  
+    
+    } else {
+        this._properties["clause"] += new AExpression().set(expression).val();
+    }
+
+    return this;
+}
+
+ReturnClause.prototype = Object.create(AQLClause.prototype);
+ReturnClause.prototype.constructor = ReturnClause;
+
+ReturnClause.prototype.val = function () {
+    return this._properties["clause"];  
+};
+
+
+// WhereClause
+//
+// Grammar: 
+// ::= "where" Expression
+// 
+// @param expression [BooleanExpression], pushes this expression onto the stack
+function WhereClause(expression) {
+    AQLClause.call(this);
+
+    this._properties["stack"] = [];
+
+    this.bind(expression);
+
+    return this;
+}
+
+
+WhereClause.prototype = Object.create(AQLClause.prototype);
+WhereClause.prototype.constructor = WhereClause;
+
+
+WhereClause.prototype.bind = function(expression) {
+    if (expression instanceof AExpression) {
+        this._properties["stack"].push(expression);
+    }
+};
+
+
+WhereClause.prototype.val = function() {
+    var value = "where ";   
+
+    var count = this._properties["stack"].length - 1;
+    while (count >= 0) {
+        value += this._properties["stack"][count].val() + " ";
+        count -= 1;
+    }
+    
+    return value;
+};
+
+
+// LimitClause
+// Grammar:
+// LimitClause    ::= "limit" Expression ( "offset" Expression )?
+// 
+// @param   limitExpression [REQUIRED, AQLExpression]
+// @param   offsetExpression [OPTIONAL, AQLExpression]
+function LimitClause(limitExpression, offsetExpression) {
+
+    AQLClause.call(this);
+  
+    // limitExpression required
+    this._properties["clause"] = "limit " + limitExpression.val();
+
+    // Optional: Offset
+    var offset = typeof offsetExpression ? offsetExpression : null;
+    if (offset != null) {
+        this._properties["clause"] += " offset " + offsetExpression.val();
+    }
+
+    return this;
+}
+
+LimitClause.prototype = Object.create(AQLClause.prototype);
+LimitClause.prototype.constructor = LimitClause;
+
+
+// OrderbyClause
+//
+// Grammar:
+// OrderbyClause  ::= "order" "by" Expression ( ( "asc" ) | ( "desc" ) )? ( "," Expression ( ( "asc" ) | ( "desc" ) )? )*
+//
+// @params AQLExpressions and asc/desc strings, in any quantity. At least one required. 
+function OrderbyClause() {
+    
+    AQLClause.call(this);
+
+    // At least one argument expression is required, and first should be expression
+    if (arguments.length == 0 || !(arguments[0] instanceof AExpression)) {
+        // TODO Not sure which error to throw for an empty OrderBy but this should fail.
+        alert("Order By Error");
+        this._properties["clause"] = null;
+        return this;    
+    } 
+
+    var expc = 0;
+    var expressions = [];    
+
+    while (expc < arguments.length) {
+      
+        var expression = "";
+
+        if (arguments[expc] instanceof AExpression) {
+            expression += arguments[expc].val();
+        }
+
+        var next = expc + 1;
+        if (next < arguments.length && (arguments[next] == "asc" || arguments[next] == "desc")) {
+            expc++;
+            expression += " " + arguments[expc];
+        }
+        
+        expressions.push(expression);
+      
+        expc++;
+    }
+
+    this._properties["clause"] = "order by " + expressions.join(", ");
+    return this;
+}
+
+OrderbyClause.prototype = Object.create(AQLClause.prototype);
+OrderbyClause.prototype.constructor = OrderbyClause;
+
+
+// GroupClause
+//
+// Grammar:
+// GroupClause    ::= "group" "by" ( Variable ":=" )? Expression ( "," ( Variable ":=" )? Expression )* ( "decor" Variable ":=" Expression ( "," "decor" Variable ":=" Expression )* )? "with" VariableRef ( "," VariableRef )*
+function GroupClause() {
+    AQLClause.call(this);
+
+    if (arguments.length == 0) {
+        // TODO Not sure which error to throw for an empty GroupBy but this should fail.
+        alert("Group Error");
+        this._properties["clause"] = null;
+        return this;    
+    } 
+
+    var expc = 0;
+    var expressions = [];
+    var variableRefs = [];
+    var isDecor = false;
+
+    while (expc < arguments.length) {
+
+        if (arguments[expc] instanceof AExpression) {
+
+            isDecor = false;
+            expressions.push(arguments[expc].val());
+
+        } else if (typeof arguments[expc] == "string") {       
+            
+            // Special keywords, decor & with
+            if (arguments[expc] == "decor") {
+                isDecor = true;
+            } else if (arguments[expc] == "with") {
+                isDecor = false;
+                expc++;
+                while (expc < arguments.length) {
+                    variableRefs.push("$" + arguments[expc]);
+                    expc++;
+                }
+            
+            // Variables and variable refs
+            } else {
+                
+                var nextc = expc + 1;
+                var expression = "";
+            
+                if (isDecor) {
+                    expression += "decor "; 
+                    isDecor = false;
+                }
+
+                expression += "$" + arguments[expc] + " := " + arguments[nextc].val();
+                expressions.push(expression);
+                expc++;
+            }
+        }
+
+        expc++;
+    }
+
+    this._properties["clause"] = "group by " + expressions.join(", ") + " with " + variableRefs.join(", ");
+    return this;
+}
+
+GroupClause.prototype = Object.create(AQLClause.prototype);
+GroupClause.prototype.constructor = GroupClause;
+
+// BooleanExpression
+// 
+// TODO
+function BooleanExpression(expression) {
+    this.value = expression;
+    alert("Debugging Bool: " + arguments.length + " " + expression);
+} 
+
+BooleanExpression.prototype.val = function() {
+    return this.value;
+}
+
+
+// SetStatement
+//
+// Grammar
+// "set" Identifier StringLiteral
+function SetStatement (identifier, stringLiteral) {
+    AExpression.call(this);
+
+    var statement = "set " + identifier + ' "' + stringLiteral + '";';
+
+    AExpression.prototype.set.call(this, statement);
+
+    return this;
+}
+
+SetStatement.prototype = Object.create(AExpression.prototype);
+SetStatement.prototype.constructor = SetStatement;
+
+
+// Quantified Expression
+// 
+// Grammar
+// QuantifiedExpression ::= ( ( "some" ) | ( "every" ) ) Variable "in" Expression ( "," Variable "in" Expression )* "satisfies" Expression
+// 
+// @param String some/every
+// @param [AExpression]
+// @param [Aexpression] satisfiesExpression
+function QuantifiedExpression (keyword, expressions, satisfiesExpression) {
+    AExpression.call(this);
+
+    var expression = keyword + " ";
+    var varsInExpressions = [];
+
+    for (var varInExpression in expressions) {
+        varsInExpressions.push(varInExpression + " in " + expressions[varInExpression].val()); 
+    } 
+    expression += varsInExpressions.join(", ") + " satisfies " + satisfiesExpression.val();
+    
+    AExpression.prototype.set.call(this, expression);
+
+    return this;
+}
+
+QuantifiedExpression.prototype = Object.create(AExpression.prototype);
+QuantifiedExpression.prototype.constructor = QuantifiedExpression;
+
+QuantifiedExpression.prototype.val = function() {
+    var value = AExpression.prototype.val.call(this);
+    return "(" + value + ")";    
+};
+
+
+// Functions that can be used to call core expressions/clauses more cleanly
+function AFLWOGR () {
+
+}
+
+function AClause () {
+
+}
+
+function ALetClause () {
+
+}
+
+function AWhereClause () {
+
+}
+
+function AOrderbyClause () {
+
+}
+
+function AGroupClause () {
+
+}
+
+function ALimitClause () {
+
+}
+
+function ADistinctClause () {
+
+}
+
+function AVariable () {
+
+}
diff --git a/asterix-app/src/main/resources/sdk/static/js/easyXDM.debug.js b/asterix-app/src/main/resources/sdk/static/js/easyXDM.debug.js
new file mode 100644
index 0000000..61b9738
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/js/easyXDM.debug.js
@@ -0,0 +1,2871 @@
+/**
+ * easyXDM
+ * http://easyxdm.net/
+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+(function (window, document, location, setTimeout, decodeURIComponent, encodeURIComponent) {

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global JSON, XMLHttpRequest, window, escape, unescape, ActiveXObject */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+var global = this;

+var channelId = Math.floor(Math.random() * 10000); // randomize the initial id in case of multiple closures loaded 

+var emptyFn = Function.prototype;

+var reURI = /^((http.?:)\/\/([^:\/\s]+)(:\d+)*)/; // returns groups for protocol (2), domain (3) and port (4) 

+var reParent = /[\-\w]+\/\.\.\//; // matches a foo/../ expression 

+var reDoubleSlash = /([^:])\/\//g; // matches // anywhere but in the protocol

+var namespace = ""; // stores namespace under which easyXDM object is stored on the page (empty if object is global)

+var easyXDM = {};

+var _easyXDM = window.easyXDM; // map over global easyXDM in case of overwrite

+var IFRAME_PREFIX = "easyXDM_";

+var HAS_NAME_PROPERTY_BUG;

+var useHash = false; // whether to use the hash over the query

+var flashVersion; // will be set if using flash

+var HAS_FLASH_THROTTLED_BUG;

+var _trace = emptyFn;

+

+

+// http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting

+function isHostMethod(object, property){

+    var t = typeof object[property];

+    return t == 'function' ||

+    (!!(t == 'object' && object[property])) ||

+    t == 'unknown';

+}

+

+function isHostObject(object, property){

+    return !!(typeof(object[property]) == 'object' && object[property]);

+}

+

+// end

+

+// http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/

+function isArray(o){

+    return Object.prototype.toString.call(o) === '[object Array]';

+}

+

+// end

+function hasFlash(){

+    var name = "Shockwave Flash", mimeType = "application/x-shockwave-flash";

+    

+    if (!undef(navigator.plugins) && typeof navigator.plugins[name] == "object") {

+        // adapted from the swfobject code

+        var description = navigator.plugins[name].description;

+        if (description && !undef(navigator.mimeTypes) && navigator.mimeTypes[mimeType] && navigator.mimeTypes[mimeType].enabledPlugin) {

+            flashVersion = description.match(/\d+/g);

+        }

+    }

+    if (!flashVersion) {

+        var flash;

+        try {

+            flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");

+            flashVersion = Array.prototype.slice.call(flash.GetVariable("$version").match(/(\d+),(\d+),(\d+),(\d+)/), 1);

+            flash = null;

+        } 

+        catch (notSupportedException) {

+        }

+    }

+    if (!flashVersion) {

+        return false;

+    }

+    var major = parseInt(flashVersion[0], 10), minor = parseInt(flashVersion[1], 10);

+    HAS_FLASH_THROTTLED_BUG = major > 9 && minor > 0;

+    return true;

+}

+

+/*

+ * Cross Browser implementation for adding and removing event listeners.

+ */

+var on, un;

+if (isHostMethod(window, "addEventListener")) {

+    on = function(target, type, listener){

+        _trace("adding listener " + type);

+        target.addEventListener(type, listener, false);

+    };

+    un = function(target, type, listener){

+        _trace("removing listener " + type);

+        target.removeEventListener(type, listener, false);

+    };

+}

+else if (isHostMethod(window, "attachEvent")) {

+    on = function(object, sEvent, fpNotify){

+        _trace("adding listener " + sEvent);

+        object.attachEvent("on" + sEvent, fpNotify);

+    };

+    un = function(object, sEvent, fpNotify){

+        _trace("removing listener " + sEvent);

+        object.detachEvent("on" + sEvent, fpNotify);

+    };

+}

+else {

+    throw new Error("Browser not supported");

+}

+

+/*

+ * Cross Browser implementation of DOMContentLoaded.

+ */

+var domIsReady = false, domReadyQueue = [], readyState;

+if ("readyState" in document) {

+    // If browser is WebKit-powered, check for both 'loaded' (legacy browsers) and

+    // 'interactive' (HTML5 specs, recent WebKit builds) states.

+    // https://bugs.webkit.org/show_bug.cgi?id=45119

+    readyState = document.readyState;

+    domIsReady = readyState == "complete" || (~ navigator.userAgent.indexOf('AppleWebKit/') && (readyState == "loaded" || readyState == "interactive"));

+}

+else {

+    // If readyState is not supported in the browser, then in order to be able to fire whenReady functions apropriately

+    // when added dynamically _after_ DOM load, we have to deduce wether the DOM is ready or not.

+    // We only need a body to add elements to, so the existence of document.body is enough for us.

+    domIsReady = !!document.body;

+}

+

+function dom_onReady(){

+    if (domIsReady) {

+        return;

+    }

+    domIsReady = true;

+    _trace("firing dom_onReady");

+    for (var i = 0; i < domReadyQueue.length; i++) {

+        domReadyQueue[i]();

+    }

+    domReadyQueue.length = 0;

+}

+

+

+if (!domIsReady) {

+    if (isHostMethod(window, "addEventListener")) {

+        on(document, "DOMContentLoaded", dom_onReady);

+    }

+    else {

+        on(document, "readystatechange", function(){

+            if (document.readyState == "complete") {

+                dom_onReady();

+            }

+        });

+        if (document.documentElement.doScroll && window === top) {

+            var doScrollCheck = function(){

+                if (domIsReady) {

+                    return;

+                }

+                // http://javascript.nwbox.com/IEContentLoaded/

+                try {

+                    document.documentElement.doScroll("left");

+                } 

+                catch (e) {

+                    setTimeout(doScrollCheck, 1);

+                    return;

+                }

+                dom_onReady();

+            };

+            doScrollCheck();

+        }

+    }

+    

+    // A fallback to window.onload, that will always work

+    on(window, "load", dom_onReady);

+}

+/**

+ * This will add a function to the queue of functions to be run once the DOM reaches a ready state.

+ * If functions are added after this event then they will be executed immediately.

+ * @param {function} fn The function to add

+ * @param {Object} scope An optional scope for the function to be called with.

+ */

+function whenReady(fn, scope){

+    if (domIsReady) {

+        fn.call(scope);

+        return;

+    }

+    domReadyQueue.push(function(){

+        fn.call(scope);

+    });

+}

+

+/**

+ * Returns an instance of easyXDM from the parent window with

+ * respect to the namespace.

+ *

+ * @return An instance of easyXDM (in the parent window)

+ */

+function getParentObject(){

+    var obj = parent;

+    if (namespace !== "") {

+        for (var i = 0, ii = namespace.split("."); i < ii.length; i++) {

+            if (!obj) {

+                throw new Error(ii.slice(0, i + 1).join('.') + ' is not an object');

+            }

+            obj = obj[ii[i]];

+        }

+    }

+    if (!obj || !obj.easyXDM) {

+        throw new Error('Could not find easyXDM in parent.' + namespace);

+    }

+    return obj.easyXDM;

+}

+

+/**

+ * Removes easyXDM variable from the global scope. It also returns control

+ * of the easyXDM variable to whatever code used it before.

+ *

+ * @param {String} ns A string representation of an object that will hold

+ *                    an instance of easyXDM.

+ * @return An instance of easyXDM

+ */

+function noConflict(ns){

+    if (typeof ns != "string" || !ns) {

+        throw new Error('namespace must be a non-empty string');

+    }

+    _trace("Settings namespace to '" + ns + "'");

+    

+    window.easyXDM = _easyXDM;

+    namespace = ns;

+    if (namespace) {

+        IFRAME_PREFIX = "easyXDM_" + namespace.replace(".", "_") + "_";

+    }

+    return easyXDM;

+}

+

+/*

+ * Methods for working with URLs

+ */

+/**

+ * Get the domain name from a url.

+ * @param {String} url The url to extract the domain from.

+ * @return The domain part of the url.

+ * @type {String}

+ */

+function getDomainName(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    return url.match(reURI)[3];

+}

+

+/**

+ * Get the port for a given URL, or "" if none

+ * @param {String} url The url to extract the port from.

+ * @return The port part of the url.

+ * @type {String}

+ */

+function getPort(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    return url.match(reURI)[4] || "";

+}

+

+/**

+ * Returns  a string containing the schema, domain and if present the port

+ * @param {String} url The url to extract the location from

+ * @return {String} The location part of the url

+ */

+function getLocation(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    if (/^file/.test(url)) {

+        throw new Error("The file:// protocol is not supported");

+    }

+    var m = url.toLowerCase().match(reURI);

+    var proto = m[2], domain = m[3], port = m[4] || "";

+    if ((proto == "http:" && port == ":80") || (proto == "https:" && port == ":443")) {

+        port = "";

+    }

+    return proto + "//" + domain + port;

+}

+

+/**

+ * Resolves a relative url into an absolute one.

+ * @param {String} url The path to resolve.

+ * @return {String} The resolved url.

+ */

+function resolveUrl(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    

+    // replace all // except the one in proto with /

+    url = url.replace(reDoubleSlash, "$1/");

+    

+    // If the url is a valid url we do nothing

+    if (!url.match(/^(http||https):\/\//)) {

+        // If this is a relative path

+        var path = (url.substring(0, 1) === "/") ? "" : location.pathname;

+        if (path.substring(path.length - 1) !== "/") {

+            path = path.substring(0, path.lastIndexOf("/") + 1);

+        }

+        

+        url = location.protocol + "//" + location.host + path + url;

+    }

+    

+    // reduce all 'xyz/../' to just '' 

+    while (reParent.test(url)) {

+        url = url.replace(reParent, "");

+    }

+    

+    _trace("resolved url '" + url + "'");

+    return url;

+}

+

+/**

+ * Appends the parameters to the given url.<br/>

+ * The base url can contain existing query parameters.

+ * @param {String} url The base url.

+ * @param {Object} parameters The parameters to add.

+ * @return {String} A new valid url with the parameters appended.

+ */

+function appendQueryParameters(url, parameters){

+    if (!parameters) {

+        throw new Error("parameters is undefined or null");

+    }

+    

+    var hash = "", indexOf = url.indexOf("#");

+    if (indexOf !== -1) {

+        hash = url.substring(indexOf);

+        url = url.substring(0, indexOf);

+    }

+    var q = [];

+    for (var key in parameters) {

+        if (parameters.hasOwnProperty(key)) {

+            q.push(key + "=" + encodeURIComponent(parameters[key]));

+        }

+    }

+    return url + (useHash ? "#" : (url.indexOf("?") == -1 ? "?" : "&")) + q.join("&") + hash;

+}

+

+

+// build the query object either from location.query, if it contains the xdm_e argument, or from location.hash

+var query = (function(input){

+    input = input.substring(1).split("&");

+    var data = {}, pair, i = input.length;

+    while (i--) {

+        pair = input[i].split("=");

+        data[pair[0]] = decodeURIComponent(pair[1]);

+    }

+    return data;

+}(/xdm_e=/.test(location.search) ? location.search : location.hash));

+

+/*

+ * Helper methods

+ */

+/**

+ * Helper for checking if a variable/property is undefined

+ * @param {Object} v The variable to test

+ * @return {Boolean} True if the passed variable is undefined

+ */

+function undef(v){

+    return typeof v === "undefined";

+}

+

+/**

+ * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.

+ * @return {JSON} A valid JSON conforming object, or null if not found.

+ */

+var getJSON = function(){

+    var cached = {};

+    var obj = {

+        a: [1, 2, 3]

+    }, json = "{\"a\":[1,2,3]}";

+    

+    if (typeof JSON != "undefined" && typeof JSON.stringify === "function" && JSON.stringify(obj).replace((/\s/g), "") === json) {

+        // this is a working JSON instance

+        return JSON;

+    }

+    if (Object.toJSON) {

+        if (Object.toJSON(obj).replace((/\s/g), "") === json) {

+            // this is a working stringify method

+            cached.stringify = Object.toJSON;

+        }

+    }

+    

+    if (typeof String.prototype.evalJSON === "function") {

+        obj = json.evalJSON();

+        if (obj.a && obj.a.length === 3 && obj.a[2] === 3) {

+            // this is a working parse method           

+            cached.parse = function(str){

+                return str.evalJSON();

+            };

+        }

+    }

+    

+    if (cached.stringify && cached.parse) {

+        // Only memoize the result if we have valid instance

+        getJSON = function(){

+            return cached;

+        };

+        return cached;

+    }

+    return null;

+};

+

+/**

+ * Applies properties from the source object to the target object.<br/>

+ * @param {Object} target The target of the properties.

+ * @param {Object} source The source of the properties.

+ * @param {Boolean} noOverwrite Set to True to only set non-existing properties.

+ */

+function apply(destination, source, noOverwrite){

+    var member;

+    for (var prop in source) {

+        if (source.hasOwnProperty(prop)) {

+            if (prop in destination) {

+                member = source[prop];

+                if (typeof member === "object") {

+                    apply(destination[prop], member, noOverwrite);

+                }

+                else if (!noOverwrite) {

+                    destination[prop] = source[prop];

+                }

+            }

+            else {

+                destination[prop] = source[prop];

+            }

+        }

+    }

+    return destination;

+}

+

+// This tests for the bug in IE where setting the [name] property using javascript causes the value to be redirected into [submitName].

+function testForNamePropertyBug(){

+    var form = document.body.appendChild(document.createElement("form")), input = form.appendChild(document.createElement("input"));

+    input.name = IFRAME_PREFIX + "TEST" + channelId; // append channelId in order to avoid caching issues

+    HAS_NAME_PROPERTY_BUG = input !== form.elements[input.name];

+    document.body.removeChild(form);

+    _trace("HAS_NAME_PROPERTY_BUG: " + HAS_NAME_PROPERTY_BUG);

+}

+

+/**

+ * Creates a frame and appends it to the DOM.

+ * @param config {object} This object can have the following properties

+ * <ul>

+ * <li> {object} prop The properties that should be set on the frame. This should include the 'src' property.</li>

+ * <li> {object} attr The attributes that should be set on the frame.</li>

+ * <li> {DOMElement} container Its parent element (Optional).</li>

+ * <li> {function} onLoad A method that should be called with the frames contentWindow as argument when the frame is fully loaded. (Optional)</li>

+ * </ul>

+ * @return The frames DOMElement

+ * @type DOMElement

+ */

+function createFrame(config){

+    _trace("creating frame: " + config.props.src);

+    if (undef(HAS_NAME_PROPERTY_BUG)) {

+        testForNamePropertyBug();

+    }

+    var frame;

+    // This is to work around the problems in IE6/7 with setting the name property. 

+    // Internally this is set as 'submitName' instead when using 'iframe.name = ...'

+    // This is not required by easyXDM itself, but is to facilitate other use cases 

+    if (HAS_NAME_PROPERTY_BUG) {

+        frame = document.createElement("<iframe name=\"" + config.props.name + "\"/>");

+    }

+    else {

+        frame = document.createElement("IFRAME");

+        frame.name = config.props.name;

+    }

+    

+    frame.id = frame.name = config.props.name;

+    delete config.props.name;

+    

+    if (typeof config.container == "string") {

+        config.container = document.getElementById(config.container);

+    }

+    

+    if (!config.container) {

+        // This needs to be hidden like this, simply setting display:none and the like will cause failures in some browsers.

+        apply(frame.style, {

+            position: "absolute",

+            top: "-2000px",

+            // Avoid potential horizontal scrollbar

+            left: "0px"

+        });

+        config.container = document.body;

+    }

+    

+    // HACK: IE cannot have the src attribute set when the frame is appended

+    //       into the container, so we set it to "javascript:false" as a

+    //       placeholder for now.  If we left the src undefined, it would

+    //       instead default to "about:blank", which causes SSL mixed-content

+    //       warnings in IE6 when on an SSL parent page.

+    var src = config.props.src;

+    config.props.src = "javascript:false";

+    

+    // transfer properties to the frame

+    apply(frame, config.props);

+    

+    frame.border = frame.frameBorder = 0;

+    frame.allowTransparency = true;

+    config.container.appendChild(frame);

+    

+    if (config.onLoad) {

+        on(frame, "load", config.onLoad);

+    }

+    

+    // set the frame URL to the proper value (we previously set it to

+    // "javascript:false" to work around the IE issue mentioned above)

+    if(config.usePost) {

+        var form = config.container.appendChild(document.createElement('form')), input;

+        form.target = frame.name;

+        form.action = src;

+        form.method = 'POST';

+        if (typeof(config.usePost) === 'object') {

+            for (var i in config.usePost) {

+                if (config.usePost.hasOwnProperty(i)) {

+                    if (HAS_NAME_PROPERTY_BUG) {

+                        input = document.createElement('<input name="' + i + '"/>');

+                    } else {

+                        input = document.createElement("INPUT");

+                        input.name = i;

+                    }

+                    input.value = config.usePost[i];

+                    form.appendChild(input);

+                }

+            }

+        }

+        form.submit();

+        form.parentNode.removeChild(form);

+    } else {

+        frame.src = src;

+    }

+    config.props.src = src;

+    

+    return frame;

+}

+

+/**

+ * Check whether a domain is allowed using an Access Control List.

+ * The ACL can contain * and ? as wildcards, or can be regular expressions.

+ * If regular expressions they need to begin with ^ and end with $.

+ * @param {Array/String} acl The list of allowed domains

+ * @param {String} domain The domain to test.

+ * @return {Boolean} True if the domain is allowed, false if not.

+ */

+function checkAcl(acl, domain){

+    // normalize into an array

+    if (typeof acl == "string") {

+        acl = [acl];

+    }

+    var re, i = acl.length;

+    while (i--) {

+        re = acl[i];

+        re = new RegExp(re.substr(0, 1) == "^" ? re : ("^" + re.replace(/(\*)/g, ".$1").replace(/\?/g, ".") + "$"));

+        if (re.test(domain)) {

+            return true;

+        }

+    }

+    return false;

+}

+

+/*

+ * Functions related to stacks

+ */

+/**

+ * Prepares an array of stack-elements suitable for the current configuration

+ * @param {Object} config The Transports configuration. See easyXDM.Socket for more.

+ * @return {Array} An array of stack-elements with the TransportElement at index 0.

+ */

+function prepareTransportStack(config){

+    var protocol = config.protocol, stackEls;

+    config.isHost = config.isHost || undef(query.xdm_p);

+    useHash = config.hash || false;

+    _trace("preparing transport stack");

+    

+    if (!config.props) {

+        config.props = {};

+    }

+    if (!config.isHost) {

+        _trace("using parameters from query");

+        config.channel = query.xdm_c.replace(/["'<>\\]/g, "");

+        config.secret = query.xdm_s;

+        config.remote = query.xdm_e.replace(/["'<>\\]/g, "");

+        ;

+        protocol = query.xdm_p;

+        if (config.acl && !checkAcl(config.acl, config.remote)) {

+            throw new Error("Access denied for " + config.remote);

+        }

+    }

+    else {

+        config.remote = resolveUrl(config.remote);

+        config.channel = config.channel || "default" + channelId++;

+        config.secret = Math.random().toString(16).substring(2);

+        if (undef(protocol)) {

+            if (getLocation(location.href) == getLocation(config.remote)) {

+                /*

+                 * Both documents has the same origin, lets use direct access.

+                 */

+                protocol = "4";

+            }

+            else if (isHostMethod(window, "postMessage") || isHostMethod(document, "postMessage")) {

+                /*

+                 * This is supported in IE8+, Firefox 3+, Opera 9+, Chrome 2+ and Safari 4+

+                 */

+                protocol = "1";

+            }

+            else if (config.swf && isHostMethod(window, "ActiveXObject") && hasFlash()) {

+                /*

+                 * The Flash transport superseedes the NixTransport as the NixTransport has been blocked by MS

+                 */

+                protocol = "6";

+            }

+            else if (navigator.product === "Gecko" && "frameElement" in window && navigator.userAgent.indexOf('WebKit') == -1) {

+                /*

+                 * This is supported in Gecko (Firefox 1+)

+                 */

+                protocol = "5";

+            }

+            else if (config.remoteHelper) {

+                /*

+                 * This is supported in all browsers that retains the value of window.name when

+                 * navigating from one domain to another, and where parent.frames[foo] can be used

+                 * to get access to a frame from the same domain

+                 */

+                protocol = "2";

+            }

+            else {

+                /*

+                 * This is supported in all browsers where [window].location is writable for all

+                 * The resize event will be used if resize is supported and the iframe is not put

+                 * into a container, else polling will be used.

+                 */

+                protocol = "0";

+            }

+            _trace("selecting protocol: " + protocol);

+        }

+        else {

+            _trace("using protocol: " + protocol);

+        }

+    }

+    config.protocol = protocol; // for conditional branching

+    switch (protocol) {

+        case "0":// 0 = HashTransport

+            apply(config, {

+                interval: 100,

+                delay: 2000,

+                useResize: true,

+                useParent: false,

+                usePolling: false

+            }, true);

+            if (config.isHost) {

+                if (!config.local) {

+                    _trace("looking for image to use as local");

+                    // If no local is set then we need to find an image hosted on the current domain

+                    var domain = location.protocol + "//" + location.host, images = document.body.getElementsByTagName("img"), image;

+                    var i = images.length;

+                    while (i--) {

+                        image = images[i];

+                        if (image.src.substring(0, domain.length) === domain) {

+                            config.local = image.src;

+                            break;

+                        }

+                    }

+                    if (!config.local) {

+                        _trace("no image found, defaulting to using the window");

+                        // If no local was set, and we are unable to find a suitable file, then we resort to using the current window 

+                        config.local = window;

+                    }

+                }

+                

+                var parameters = {

+                    xdm_c: config.channel,

+                    xdm_p: 0

+                };

+                

+                if (config.local === window) {

+                    // We are using the current window to listen to

+                    config.usePolling = true;

+                    config.useParent = true;

+                    config.local = location.protocol + "//" + location.host + location.pathname + location.search;

+                    parameters.xdm_e = config.local;

+                    parameters.xdm_pa = 1; // use parent

+                }

+                else {

+                    parameters.xdm_e = resolveUrl(config.local);

+                }

+                

+                if (config.container) {

+                    config.useResize = false;

+                    parameters.xdm_po = 1; // use polling

+                }

+                config.remote = appendQueryParameters(config.remote, parameters);

+            }

+            else {

+                apply(config, {

+                    channel: query.xdm_c,

+                    remote: query.xdm_e,

+                    useParent: !undef(query.xdm_pa),

+                    usePolling: !undef(query.xdm_po),

+                    useResize: config.useParent ? false : config.useResize

+                });

+            }

+            stackEls = [new easyXDM.stack.HashTransport(config), new easyXDM.stack.ReliableBehavior({}), new easyXDM.stack.QueueBehavior({

+                encode: true,

+                maxLength: 4000 - config.remote.length

+            }), new easyXDM.stack.VerifyBehavior({

+                initiate: config.isHost

+            })];

+            break;

+        case "1":

+            stackEls = [new easyXDM.stack.PostMessageTransport(config)];

+            break;

+        case "2":

+            config.remoteHelper = resolveUrl(config.remoteHelper);

+            stackEls = [new easyXDM.stack.NameTransport(config), new easyXDM.stack.QueueBehavior(), new easyXDM.stack.VerifyBehavior({

+                initiate: config.isHost

+            })];

+            break;

+        case "3":

+            stackEls = [new easyXDM.stack.NixTransport(config)];

+            break;

+        case "4":

+            stackEls = [new easyXDM.stack.SameOriginTransport(config)];

+            break;

+        case "5":

+            stackEls = [new easyXDM.stack.FrameElementTransport(config)];

+            break;

+        case "6":

+            if (!flashVersion) {

+                hasFlash();

+            }

+            stackEls = [new easyXDM.stack.FlashTransport(config)];

+            break;

+    }

+    // this behavior is responsible for buffering outgoing messages, and for performing lazy initialization

+    stackEls.push(new easyXDM.stack.QueueBehavior({

+        lazy: config.lazy,

+        remove: true

+    }));

+    return stackEls;

+}

+

+/**

+ * Chains all the separate stack elements into a single usable stack.<br/>

+ * If an element is missing a necessary method then it will have a pass-through method applied.

+ * @param {Array} stackElements An array of stack elements to be linked.

+ * @return {easyXDM.stack.StackElement} The last element in the chain.

+ */

+function chainStack(stackElements){

+    var stackEl, defaults = {

+        incoming: function(message, origin){

+            this.up.incoming(message, origin);

+        },

+        outgoing: function(message, recipient){

+            this.down.outgoing(message, recipient);

+        },

+        callback: function(success){

+            this.up.callback(success);

+        },

+        init: function(){

+            this.down.init();

+        },

+        destroy: function(){

+            this.down.destroy();

+        }

+    };

+    for (var i = 0, len = stackElements.length; i < len; i++) {

+        stackEl = stackElements[i];

+        apply(stackEl, defaults, true);

+        if (i !== 0) {

+            stackEl.down = stackElements[i - 1];

+        }

+        if (i !== len - 1) {

+            stackEl.up = stackElements[i + 1];

+        }

+    }

+    return stackEl;

+}

+

+/**

+ * This will remove a stackelement from its stack while leaving the stack functional.

+ * @param {Object} element The elment to remove from the stack.

+ */

+function removeFromStack(element){

+    element.up.down = element.down;

+    element.down.up = element.up;

+    element.up = element.down = null;

+}

+

+/*

+ * Export the main object and any other methods applicable

+ */

+/** 

+ * @class easyXDM

+ * A javascript library providing cross-browser, cross-domain messaging/RPC.

+ * @version 2.4.17.1

+ * @singleton

+ */

+apply(easyXDM, {

+    /**

+     * The version of the library

+     * @type {string}

+     */

+    version: "2.4.17.1",

+    /**

+     * This is a map containing all the query parameters passed to the document.

+     * All the values has been decoded using decodeURIComponent.

+     * @type {object}

+     */

+    query: query,

+    /**

+     * @private

+     */

+    stack: {},

+    /**

+     * Applies properties from the source object to the target object.<br/>

+     * @param {object} target The target of the properties.

+     * @param {object} source The source of the properties.

+     * @param {boolean} noOverwrite Set to True to only set non-existing properties.

+     */

+    apply: apply,

+    

+    /**

+     * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.

+     * @return {JSON} A valid JSON conforming object, or null if not found.

+     */

+    getJSONObject: getJSON,

+    /**

+     * This will add a function to the queue of functions to be run once the DOM reaches a ready state.

+     * If functions are added after this event then they will be executed immediately.

+     * @param {function} fn The function to add

+     * @param {object} scope An optional scope for the function to be called with.

+     */

+    whenReady: whenReady,

+    /**

+     * Removes easyXDM variable from the global scope. It also returns control

+     * of the easyXDM variable to whatever code used it before.

+     *

+     * @param {String} ns A string representation of an object that will hold

+     *                    an instance of easyXDM.

+     * @return An instance of easyXDM

+     */

+    noConflict: noConflict

+});

+

+// Expose helper functions so we can test them

+apply(easyXDM, {

+    checkAcl: checkAcl,

+    getDomainName: getDomainName,

+    getLocation: getLocation,

+    appendQueryParameters: appendQueryParameters

+});

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global console, _FirebugCommandLine,  easyXDM, window, escape, unescape, isHostObject, undef, _trace, domIsReady, emptyFn, namespace */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+var debug = {

+    _deferred: [],

+    flush: function(){

+        this.trace("... deferred messages ...");

+        for (var i = 0, len = this._deferred.length; i < len; i++) {

+            this.trace(this._deferred[i]);

+        }

+        this._deferred.length = 0;

+        this.trace("... end of deferred messages ...");

+    },

+    getTime: function(){

+        var d = new Date(), h = d.getHours() + "", m = d.getMinutes() + "", s = d.getSeconds() + "", ms = d.getMilliseconds() + "", zeros = "000";

+        if (h.length == 1) {

+            h = "0" + h;

+        }

+        if (m.length == 1) {

+            m = "0" + m;

+        }

+        if (s.length == 1) {

+            s = "0" + s;

+        }

+        ms = zeros.substring(ms.length) + ms;

+        return h + ":" + m + ":" + s + "." + ms;

+    },

+    /**

+     * Logs the message to console.log if available

+     * @param {String} msg The message to log

+     */

+    log: function(msg){

+        // Uses memoizing to cache the implementation

+        if (!isHostObject(window, "console") || undef(console.log)) {

+            /**

+             * Sets log to be an empty function since we have no output available

+             * @ignore

+             */

+            this.log = emptyFn;

+        }

+        else {

+            /**

+             * Sets log to be a wrapper around console.log

+             * @ignore

+             * @param {String} msg

+             */

+            this.log = function(msg){

+                console.log(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ": " + msg);

+            };

+        }

+        this.log(msg);

+    },

+    /**

+     * Will try to trace the given message either to a DOMElement with the id "log",

+     * or by using console.info.

+     * @param {String} msg The message to trace

+     */

+    trace: function(msg){

+        // Uses memoizing to cache the implementation

+        if (!domIsReady) {

+            if (this._deferred.length === 0) {

+                easyXDM.whenReady(debug.flush, debug);

+            }

+            this._deferred.push(msg);

+            this.log(msg);

+        }

+        else {

+            var el = document.getElementById("log");

+            // is there a log element present?

+            if (el) {

+                /**

+                 * Sets trace to be a function that outputs the messages to the DOMElement with id "log"

+                 * @ignore

+                 * @param {String} msg

+                 */

+                this.trace = function(msg){

+                    try {

+                        el.appendChild(document.createElement("div")).appendChild(document.createTextNode(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg));

+                        el.scrollTop = el.scrollHeight;

+                    } 

+                    catch (e) {

+                        //In case we are unloading

+                    }

+                };

+            }

+            else if (isHostObject(window, "console") && !undef(console.info)) {

+                /**

+                 * Sets trace to be a wrapper around console.info

+                 * @ignore

+                 * @param {String} msg

+                 */

+                this.trace = function(msg){

+                    console.info(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg);

+                };

+            }

+            else {

+                /**

+                 * Create log window

+                 * @ignore

+                 */

+                var domain = location.host, windowname = domain.replace(/[\-.:]/g, "") + "easyxdm_log", logWin;

+                try {

+                    logWin = window.open("", windowname, "width=800,height=200,status=0,navigation=0,scrollbars=1");

+                } 

+                catch (e) {

+                }

+                if (logWin) {

+                    var doc = logWin.document;

+                    el = doc.getElementById("log");

+                    if (!el) {

+                        doc.write("<html><head><title>easyXDM log " + domain + "</title></head>");

+                        doc.write("<body><div id=\"log\"></div></body></html>");

+                        doc.close();

+                        el = doc.getElementById("log");

+                    }

+                    this.trace = function(msg){

+                        try {

+                            el.appendChild(doc.createElement("div")).appendChild(doc.createTextNode(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg));

+                            el.scrollTop = el.scrollHeight;

+                        } 

+                        catch (e) {

+                            //In case we are unloading

+                        }

+                    };

+                    this.trace("---- new logger at " + location.href);

+                }

+                

+                if (!el) {

+                    // We are unable to use any logging

+                    this.trace = emptyFn;

+                }

+            }

+            this.trace(msg);

+        }

+    },

+    /**

+     * Creates a method usable for tracing.

+     * @param {String} name The name the messages should be marked with

+     * @return {Function} A function that accepts a single string as argument.

+     */

+    getTracer: function(name){

+        return function(msg){

+            debug.trace(name + ": " + msg);

+        };

+    }

+};

+debug.log("easyXDM present on '" + location.href);

+easyXDM.Debug = debug;

+_trace = debug.getTracer("{Private}");

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, isHostObject, isHostMethod, un, on, createFrame, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/** 

+ * @class easyXDM.DomHelper

+ * Contains methods for dealing with the DOM

+ * @singleton

+ */

+easyXDM.DomHelper = {

+    /**

+     * Provides a consistent interface for adding eventhandlers

+     * @param {Object} target The target to add the event to

+     * @param {String} type The name of the event

+     * @param {Function} listener The listener

+     */

+    on: on,

+    /**

+     * Provides a consistent interface for removing eventhandlers

+     * @param {Object} target The target to remove the event from

+     * @param {String} type The name of the event

+     * @param {Function} listener The listener

+     */

+    un: un,

+    /**

+     * Checks for the presence of the JSON object.

+     * If it is not present it will use the supplied path to load the JSON2 library.

+     * This should be called in the documents head right after the easyXDM script tag.

+     * http://json.org/json2.js

+     * @param {String} path A valid path to json2.js

+     */

+    requiresJSON: function(path){

+        if (!isHostObject(window, "JSON")) {

+            debug.log("loading external JSON");

+            // we need to encode the < in order to avoid an illegal token error

+            // when the script is inlined in a document.

+            document.write('<' + 'script type="text/javascript" src="' + path + '"><' + '/script>');

+        }

+        else {

+            debug.log("native JSON found");

+        }

+    }

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+(function(){

+    // The map containing the stored functions

+    var _map = {};

+    

+    /**

+     * @class easyXDM.Fn

+     * This contains methods related to function handling, such as storing callbacks.

+     * @singleton

+     * @namespace easyXDM

+     */

+    easyXDM.Fn = {

+        /**

+         * Stores a function using the given name for reference

+         * @param {String} name The name that the function should be referred by

+         * @param {Function} fn The function to store

+         * @namespace easyXDM.fn

+         */

+        set: function(name, fn){

+            this._trace("storing function " + name);

+            _map[name] = fn;

+        },

+        /**

+         * Retrieves the function referred to by the given name

+         * @param {String} name The name of the function to retrieve

+         * @param {Boolean} del If the function should be deleted after retrieval

+         * @return {Function} The stored function

+         * @namespace easyXDM.fn

+         */

+        get: function(name, del){

+            this._trace("retrieving function " + name);

+            var fn = _map[name];

+            if (!fn) {

+                this._trace(name + " not found");

+            }

+            

+            if (del) {

+                delete _map[name];

+            }

+            return fn;

+        }

+    };

+    

+    easyXDM.Fn._trace = debug.getTracer("easyXDM.Fn");

+}());

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, chainStack, prepareTransportStack, getLocation, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.Socket

+ * This class creates a transport channel between two domains that is usable for sending and receiving string-based messages.<br/>

+ * The channel is reliable, supports queueing, and ensures that the message originates from the expected domain.<br/>

+ * Internally different stacks will be used depending on the browsers features and the available parameters.

+ * <h2>How to set up</h2>

+ * Setting up the provider:

+ * <pre><code>

+ * var socket = new easyXDM.Socket({

+ * &nbsp; local: "name.html",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket

+ * &nbsp; &nbsp; socket.postMessage("foo-message");

+ * &nbsp; },

+ * &nbsp; onMessage: function(message, origin) {

+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * Setting up the consumer:

+ * <pre><code>

+ * var socket = new easyXDM.Socket({

+ * &nbsp; remote: "http:&#47;&#47;remotedomain/page.html",

+ * &nbsp; remoteHelper: "http:&#47;&#47;remotedomain/name.html",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket

+ * &nbsp; &nbsp; socket.postMessage("foo-message");

+ * &nbsp; },

+ * &nbsp; onMessage: function(message, origin) {

+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * If you are unable to upload the <code>name.html</code> file to the consumers domain then remove the <code>remoteHelper</code> property

+ * and easyXDM will fall back to using the HashTransport instead of the NameTransport when not able to use any of the primary transports.

+ * @namespace easyXDM

+ * @constructor

+ * @cfg {String/Window} local The url to the local name.html document, a local static file, or a reference to the local window.

+ * @cfg {Boolean} lazy (Consumer only) Set this to true if you want easyXDM to defer creating the transport until really needed. 

+ * @cfg {String} remote (Consumer only) The url to the providers document.

+ * @cfg {String} remoteHelper (Consumer only) The url to the remote name.html file. This is to support NameTransport as a fallback. Optional.

+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.  Optional, defaults to 2000.

+ * @cfg {Number} interval The interval used when polling for messages. Optional, defaults to 300.

+ * @cfg {String} channel (Consumer only) The name of the channel to use. Can be used to set consistent iframe names. Must be unique. Optional.

+ * @cfg {Function} onMessage The method that should handle incoming messages.<br/> This method should accept two arguments, the message as a string, and the origin as a string. Optional.

+ * @cfg {Function} onReady A method that should be called when the transport is ready. Optional.

+ * @cfg {DOMElement|String} container (Consumer only) The element, or the id of the element that the primary iframe should be inserted into. If not set then the iframe will be positioned off-screen. Optional.

+ * @cfg {Array/String} acl (Provider only) Here you can specify which '[protocol]://[domain]' patterns that should be allowed to act as the consumer towards this provider.<br/>

+ * This can contain the wildcards ? and *.  Examples are 'http://example.com', '*.foo.com' and '*dom?.com'. If you want to use reqular expressions then you pattern needs to start with ^ and end with $.

+ * If none of the patterns match an Error will be thrown.  

+ * @cfg {Object} props (Consumer only) Additional properties that should be applied to the iframe. This can also contain nested objects e.g: <code>{style:{width:"100px", height:"100px"}}</code>. 

+ * Properties such as 'name' and 'src' will be overrided. Optional.

+ */

+easyXDM.Socket = function(config){

+    var trace = debug.getTracer("easyXDM.Socket");

+    trace("constructor");

+    

+    // create the stack

+    var stack = chainStack(prepareTransportStack(config).concat([{

+        incoming: function(message, origin){

+            config.onMessage(message, origin);

+        },

+        callback: function(success){

+            if (config.onReady) {

+                config.onReady(success);

+            }

+        }

+    }])), recipient = getLocation(config.remote);

+    

+    // set the origin

+    this.origin = getLocation(config.remote);

+	

+    /**

+     * Initiates the destruction of the stack.

+     */

+    this.destroy = function(){

+        stack.destroy();

+    };

+    

+    /**

+     * Posts a message to the remote end of the channel

+     * @param {String} message The message to send

+     */

+    this.postMessage = function(message){

+        stack.outgoing(message, recipient);

+    };

+    

+    stack.init();

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef,, chainStack, prepareTransportStack, debug, getLocation */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/** 

+ * @class easyXDM.Rpc

+ * Creates a proxy object that can be used to call methods implemented on the remote end of the channel, and also to provide the implementation

+ * of methods to be called from the remote end.<br/>

+ * The instantiated object will have methods matching those specified in <code>config.remote</code>.<br/>

+ * This requires the JSON object present in the document, either natively, using json.org's json2 or as a wrapper around library spesific methods.

+ * <h2>How to set up</h2>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; &#47;&#47; this configuration is equal to that used by the Socket.

+ * &nbsp; remote: "http:&#47;&#47;remotedomain/...",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the proxy

+ * &nbsp; &nbsp; rpc.foo(...

+ * &nbsp; }

+ * },{

+ * &nbsp; local: {..},

+ * &nbsp; remote: {..}

+ * });

+ * </code></pre>

+ * 

+ * <h2>Exposing functions (procedures)</h2>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {

+ * &nbsp; &nbsp; nameOfMethod: {

+ * &nbsp; &nbsp; &nbsp; method: function(arg1, arg2, success, error){

+ * &nbsp; &nbsp; &nbsp; &nbsp; ...

+ * &nbsp; &nbsp; &nbsp; }

+ * &nbsp; &nbsp; },

+ * &nbsp; &nbsp; &#47;&#47; with shorthand notation 

+ * &nbsp; &nbsp; nameOfAnotherMethod:  function(arg1, arg2, success, error){

+ * &nbsp; &nbsp; }

+ * &nbsp; },

+ * &nbsp; remote: {...}

+ * });

+ * </code></pre>

+

+ * The function referenced by  [method] will receive the passed arguments followed by the callback functions <code>success</code> and <code>error</code>.<br/>

+ * To send a successfull result back you can use

+ *     <pre><code>

+ *     return foo;

+ *     </pre></code>

+ * or

+ *     <pre><code>

+ *     success(foo);

+ *     </pre></code>

+ *  To return an error you can use

+ *     <pre><code>

+ *     throw new Error("foo error");

+ *     </code></pre>

+ * or

+ *     <pre><code>

+ *     error("foo error");

+ *     </code></pre>

+ *

+ * <h2>Defining remotely exposed methods (procedures/notifications)</h2>

+ * The definition of the remote end is quite similar:

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {...},

+ * &nbsp; remote: {

+ * &nbsp; &nbsp; nameOfMethod: {}

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * To call a remote method use

+ * <pre><code>

+ * rpc.nameOfMethod("arg1", "arg2", function(value) {

+ * &nbsp; alert("success: " + value);

+ * }, function(message) {

+ * &nbsp; alert("error: " + message + );

+ * });

+ * </code></pre>

+ * Both the <code>success</code> and <code>errror</code> callbacks are optional.<br/>

+ * When called with no callback a JSON-RPC 2.0 notification will be executed.

+ * Be aware that you will not be notified of any errors with this method.

+ * <br/>

+ * <h2>Specifying a custom serializer</h2>

+ * If you do not want to use the JSON2 library for non-native JSON support, but instead capabilities provided by some other library

+ * then you can specify a custom serializer using <code>serializer: foo</code>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {...},

+ * &nbsp; remote: {...},

+ * &nbsp; serializer : {

+ * &nbsp; &nbsp; parse: function(string){ ... },

+ * &nbsp; &nbsp; stringify: function(object) {...}

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * If <code>serializer</code> is set then the class will not attempt to use the native implementation.

+ * @namespace easyXDM

+ * @constructor

+ * @param {Object} config The underlying transports configuration. See easyXDM.Socket for available parameters.

+ * @param {Object} jsonRpcConfig The description of the interface to implement.

+ */

+easyXDM.Rpc = function(config, jsonRpcConfig){

+    var trace = debug.getTracer("easyXDM.Rpc");

+    trace("constructor");

+    

+    // expand shorthand notation

+    if (jsonRpcConfig.local) {

+        for (var method in jsonRpcConfig.local) {

+            if (jsonRpcConfig.local.hasOwnProperty(method)) {

+                var member = jsonRpcConfig.local[method];

+                if (typeof member === "function") {

+                    jsonRpcConfig.local[method] = {

+                        method: member

+                    };

+                }

+            }

+        }

+    }

+	

+    // create the stack

+    var stack = chainStack(prepareTransportStack(config).concat([new easyXDM.stack.RpcBehavior(this, jsonRpcConfig), {

+        callback: function(success){

+            if (config.onReady) {

+                config.onReady(success);

+            }

+        }

+    }]));

+	

+    // set the origin 

+    this.origin = getLocation(config.remote);

+	

+    

+    /**

+     * Initiates the destruction of the stack.

+     */

+    this.destroy = function(){

+        stack.destroy();

+    };

+    

+    stack.init();

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, getParentObject, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.SameOriginTransport

+ * SameOriginTransport is a transport class that can be used when both domains have the same origin.<br/>

+ * This can be useful for testing and for when the main application supports both internal and external sources.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote document to communicate with.

+ */

+easyXDM.stack.SameOriginTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.SameOriginTransport");

+    trace("constructor");

+    var pub, frame, send, targetOrigin;

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            send(message);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            

+            if (config.isHost) {

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: location.protocol + "//" + location.host + location.pathname,

+                        xdm_c: config.channel,

+                        xdm_p: 4 // 4 = SameOriginTransport

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+                easyXDM.Fn.set(config.channel, function(sendFn){

+                    send = sendFn;

+                    setTimeout(function(){

+                        pub.up.callback(true);

+                    }, 0);

+                    return function(msg){

+                        pub.up.incoming(msg, targetOrigin);

+                    };

+                });

+            }

+            else {

+                send = getParentObject().Fn.get(config.channel, true)(function(msg){

+                    pub.up.incoming(msg, targetOrigin);

+                });

+                setTimeout(function(){

+                    pub.up.callback(true);

+                }, 0);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global global, easyXDM, window, getLocation, appendQueryParameters, createFrame, debug, apply, whenReady, IFRAME_PREFIX, namespace, resolveUrl, getDomainName, HAS_FLASH_THROTTLED_BUG, getPort, query*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.FlashTransport

+ * FlashTransport is a transport class that uses an SWF with LocalConnection to pass messages back and forth.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote domain to communicate with.

+ * @cfg {String} secret the pre-shared secret used to secure the communication.

+ * @cfg {String} swf The path to the swf file

+ * @cfg {Boolean} swfNoThrottle Set this to true if you want to take steps to avoid beeing throttled when hidden.

+ * @cfg {String || DOMElement} swfContainer Set this if you want to control where the swf is placed

+ */

+easyXDM.stack.FlashTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.FlashTransport");

+    trace("constructor");

+    if (!config.swf) {

+        throw new Error("Path to easyxdm.swf is missing");

+    }

+    var pub, // the public interface

+ frame, send, targetOrigin, swf, swfContainer;

+    

+    function onMessage(message, origin){

+        setTimeout(function(){

+            trace("received message");

+            pub.up.incoming(message, targetOrigin);

+        }, 0);

+    }

+    

+    /**

+     * This method adds the SWF to the DOM and prepares the initialization of the channel

+     */

+    function addSwf(domain){

+        trace("creating factory with SWF from " + domain);

+        // the differentiating query argument is needed in Flash9 to avoid a caching issue where LocalConnection would throw an error.

+        var url = config.swf + "?host=" + config.isHost;

+        var id = "easyXDM_swf_" + Math.floor(Math.random() * 10000);

+        

+        // prepare the init function that will fire once the swf is ready

+        easyXDM.Fn.set("flash_loaded" + domain.replace(/[\-.]/g, "_"), function(){

+            easyXDM.stack.FlashTransport[domain].swf = swf = swfContainer.firstChild;

+            var queue = easyXDM.stack.FlashTransport[domain].queue;

+            for (var i = 0; i < queue.length; i++) {

+                queue[i]();

+            }

+            queue.length = 0;

+        });

+        

+        if (config.swfContainer) {

+            swfContainer = (typeof config.swfContainer == "string") ? document.getElementById(config.swfContainer) : config.swfContainer;

+        }

+        else {

+            // create the container that will hold the swf

+            swfContainer = document.createElement('div');

+            

+            // http://bugs.adobe.com/jira/browse/FP-4796

+            // http://tech.groups.yahoo.com/group/flexcoders/message/162365

+            // https://groups.google.com/forum/#!topic/easyxdm/mJZJhWagoLc

+            apply(swfContainer.style, HAS_FLASH_THROTTLED_BUG && config.swfNoThrottle ? {

+                height: "20px",

+                width: "20px",

+                position: "fixed",

+                right: 0,

+                top: 0

+            } : {

+                height: "1px",

+                width: "1px",

+                position: "absolute",

+                overflow: "hidden",

+                right: 0,

+                top: 0

+            });

+            document.body.appendChild(swfContainer);

+        }

+        

+        // create the object/embed

+        var flashVars = "callback=flash_loaded" + domain.replace(/[\-.]/g, "_") + "&proto=" + global.location.protocol + "&domain=" + getDomainName(global.location.href) + "&port=" + getPort(global.location.href) + "&ns=" + namespace;

+        flashVars += "&log=true";

+        swfContainer.innerHTML = "<object height='20' width='20' type='application/x-shockwave-flash' id='" + id + "' data='" + url + "'>" +

+        "<param name='allowScriptAccess' value='always'></param>" +

+        "<param name='wmode' value='transparent'>" +

+        "<param name='movie' value='" +

+        url +

+        "'></param>" +

+        "<param name='flashvars' value='" +

+        flashVars +

+        "'></param>" +

+        "<embed type='application/x-shockwave-flash' FlashVars='" +

+        flashVars +

+        "' allowScriptAccess='always' wmode='transparent' src='" +

+        url +

+        "' height='1' width='1'></embed>" +

+        "</object>";

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            swf.postMessage(config.channel, message.toString());

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            try {

+                swf.destroyChannel(config.channel);

+            } 

+            catch (e) {

+            }

+            swf = null;

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            

+            targetOrigin = config.remote;

+            

+            // Prepare the code that will be run after the swf has been intialized

+            easyXDM.Fn.set("flash_" + config.channel + "_init", function(){

+                setTimeout(function(){

+                    trace("firing onReady");

+                    pub.up.callback(true);

+                });

+            });

+            

+            // set up the omMessage handler

+            easyXDM.Fn.set("flash_" + config.channel + "_onMessage", onMessage);

+            

+            config.swf = resolveUrl(config.swf); // reports have been made of requests gone rogue when using relative paths

+            var swfdomain = getDomainName(config.swf);

+            var fn = function(){

+                // set init to true in case the fn was called was invoked from a separate instance

+                easyXDM.stack.FlashTransport[swfdomain].init = true;

+                swf = easyXDM.stack.FlashTransport[swfdomain].swf;

+                // create the channel

+                swf.createChannel(config.channel, config.secret, getLocation(config.remote), config.isHost);

+                

+                if (config.isHost) {

+                    // if Flash is going to be throttled and we want to avoid this

+                    if (HAS_FLASH_THROTTLED_BUG && config.swfNoThrottle) {

+                        apply(config.props, {

+                            position: "fixed",

+                            right: 0,

+                            top: 0,

+                            height: "20px",

+                            width: "20px"

+                        });

+                    }

+                    // set up the iframe

+                    apply(config.props, {

+                        src: appendQueryParameters(config.remote, {

+                            xdm_e: getLocation(location.href),

+                            xdm_c: config.channel,

+                            xdm_p: 6, // 6 = FlashTransport

+                            xdm_s: config.secret

+                        }),

+                        name: IFRAME_PREFIX + config.channel + "_provider"

+                    });

+                    frame = createFrame(config);

+                }

+            };

+            

+            if (easyXDM.stack.FlashTransport[swfdomain] && easyXDM.stack.FlashTransport[swfdomain].init) {

+                // if the swf is in place and we are the consumer

+                fn();

+            }

+            else {

+                // if the swf does not yet exist

+                if (!easyXDM.stack.FlashTransport[swfdomain]) {

+                    // add the queue to hold the init fn's

+                    easyXDM.stack.FlashTransport[swfdomain] = {

+                        queue: [fn]

+                    };

+                    addSwf(swfdomain);

+                }

+                else {

+                    easyXDM.stack.FlashTransport[swfdomain].queue.push(fn);

+                }

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.PostMessageTransport

+ * PostMessageTransport is a transport class that uses HTML5 postMessage for communication.<br/>

+ * <a href="http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx</a><br/>

+ * <a href="https://developer.mozilla.org/en/DOM/window.postMessage">https://developer.mozilla.org/en/DOM/window.postMessage</a>

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote domain to communicate with.

+ */

+easyXDM.stack.PostMessageTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.PostMessageTransport");

+    trace("constructor");

+    var pub, // the public interface

+ frame, // the remote frame, if any

+ callerWindow, // the window that we will call with

+ targetOrigin; // the domain to communicate with

+    /**

+     * Resolves the origin from the event object

+     * @private

+     * @param {Object} event The messageevent

+     * @return {String} The scheme, host and port of the origin

+     */

+    function _getOrigin(event){

+        if (event.origin) {

+            // This is the HTML5 property

+            return getLocation(event.origin);

+        }

+        if (event.uri) {

+            // From earlier implementations 

+            return getLocation(event.uri);

+        }

+        if (event.domain) {

+            // This is the last option and will fail if the 

+            // origin is not using the same schema as we are

+            return location.protocol + "//" + event.domain;

+        }

+        throw "Unable to retrieve the origin of the event";

+    }

+    

+    /**

+     * This is the main implementation for the onMessage event.<br/>

+     * It checks the validity of the origin and passes the message on if appropriate.

+     * @private

+     * @param {Object} event The messageevent

+     */

+    function _window_onMessage(event){

+        var origin = _getOrigin(event);

+        trace("received message '" + event.data + "' from " + origin);

+        if (origin == targetOrigin && event.data.substring(0, config.channel.length + 1) == config.channel + " ") {

+            pub.up.incoming(event.data.substring(config.channel.length + 1), origin);

+        }

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            callerWindow.postMessage(config.channel + " " + message, domain || targetOrigin);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            un(window, "message", _window_onMessage);

+            if (frame) {

+                callerWindow = null;

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            if (config.isHost) {

+                // add the event handler for listening

+                var waitForReady = function(event){  

+                    if (event.data == config.channel + "-ready") {

+                        trace("firing onReady");

+                        // replace the eventlistener

+                        callerWindow = ("postMessage" in frame.contentWindow) ? frame.contentWindow : frame.contentWindow.document;

+                        un(window, "message", waitForReady);

+                        on(window, "message", _window_onMessage);

+                        setTimeout(function(){

+                            pub.up.callback(true);

+                        }, 0);

+                    }

+                };

+                on(window, "message", waitForReady);

+                

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: getLocation(location.href),

+                        xdm_c: config.channel,

+                        xdm_p: 1 // 1 = PostMessage

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+            }

+            else {

+                // add the event handler for listening

+                on(window, "message", _window_onMessage);

+                callerWindow = ("postMessage" in window.parent) ? window.parent : window.parent.document;

+                callerWindow.postMessage(config.channel + "-ready", targetOrigin);

+                

+                setTimeout(function(){

+                    pub.up.callback(true);

+                }, 0);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, apply, query, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.FrameElementTransport

+ * FrameElementTransport is a transport class that can be used with Gecko-browser as these allow passing variables using the frameElement property.<br/>

+ * Security is maintained as Gecho uses Lexical Authorization to determine under which scope a function is running.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote document to communicate with.

+ */

+easyXDM.stack.FrameElementTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.FrameElementTransport");

+    trace("constructor");

+    var pub, frame, send, targetOrigin;

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            send.call(this, message);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            

+            if (config.isHost) {

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: getLocation(location.href),

+                        xdm_c: config.channel,

+                        xdm_p: 5 // 5 = FrameElementTransport

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+                frame.fn = function(sendFn){

+                    delete frame.fn;

+                    send = sendFn;

+                    setTimeout(function(){

+                        pub.up.callback(true);

+                    }, 0);

+                    // remove the function so that it cannot be used to overwrite the send function later on

+                    return function(msg){

+                        pub.up.incoming(msg, targetOrigin);

+                    };

+                };

+            }

+            else {

+                // This is to mitigate origin-spoofing

+                if (document.referrer && getLocation(document.referrer) != query.xdm_e) {

+                    window.top.location = query.xdm_e;

+                }

+                send = window.frameElement.fn(function(msg){

+                    pub.up.incoming(msg, targetOrigin);

+                });

+                pub.up.callback(true);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, getLocation, appendQueryParameters, resolveUrl, createFrame, debug, un, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.NameTransport

+ * NameTransport uses the window.name property to relay data.

+ * The <code>local</code> parameter needs to be set on both the consumer and provider,<br/>

+ * and the <code>remoteHelper</code> parameter needs to be set on the consumer.

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remoteHelper The url to the remote instance of hash.html - this is only needed for the host.

+ * @namespace easyXDM.stack

+ */

+easyXDM.stack.NameTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.NameTransport");

+    trace("constructor");

+    if (config.isHost && undef(config.remoteHelper)) {

+        trace("missing remoteHelper");

+        throw new Error("missing remoteHelper");

+    }

+    

+    var pub; // the public interface

+    var isHost, callerWindow, remoteWindow, readyCount, callback, remoteOrigin, remoteUrl;

+    

+    function _sendMessage(message){

+        var url = config.remoteHelper + (isHost ? "#_3" : "#_2") + config.channel;

+        trace("sending message " + message);

+        trace("navigating to  '" + url + "'");

+        callerWindow.contentWindow.sendMessage(message, url);

+    }

+    

+    function _onReady(){

+        if (isHost) {

+            if (++readyCount === 2 || !isHost) {

+                pub.up.callback(true);

+            }

+        }

+        else {

+            _sendMessage("ready");

+            trace("calling onReady");

+            pub.up.callback(true);

+        }

+    }

+    

+    function _onMessage(message){

+        trace("received message " + message);

+        pub.up.incoming(message, remoteOrigin);

+    }

+    

+    function _onLoad(){

+        if (callback) {

+            setTimeout(function(){

+                callback(true);

+            }, 0);

+        }

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            callback = fn;

+            _sendMessage(message);

+        },

+        destroy: function(){

+            trace("destroy");

+            callerWindow.parentNode.removeChild(callerWindow);

+            callerWindow = null;

+            if (isHost) {

+                remoteWindow.parentNode.removeChild(remoteWindow);

+                remoteWindow = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            isHost = config.isHost;

+            readyCount = 0;

+            remoteOrigin = getLocation(config.remote);

+            config.local = resolveUrl(config.local);

+            

+            if (isHost) {

+                // Register the callback

+                easyXDM.Fn.set(config.channel, function(message){

+                    trace("received initial message " + message);

+                    if (isHost && message === "ready") {

+                        // Replace the handler

+                        easyXDM.Fn.set(config.channel, _onMessage);

+                        _onReady();

+                    }

+                });

+                

+                // Set up the frame that points to the remote instance

+                remoteUrl = appendQueryParameters(config.remote, {

+                    xdm_e: config.local,

+                    xdm_c: config.channel,

+                    xdm_p: 2

+                });

+                apply(config.props, {

+                    src: remoteUrl + '#' + config.channel,

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                remoteWindow = createFrame(config);

+            }

+            else {

+                config.remoteHelper = config.remote;

+                easyXDM.Fn.set(config.channel, _onMessage);

+            }

+            

+            // Set up the iframe that will be used for the transport

+            var onLoad = function(){

+                // Remove the handler

+                var w = callerWindow || this;

+                un(w, "load", onLoad);

+                easyXDM.Fn.set(config.channel + "_load", _onLoad);

+                (function test(){

+                    if (typeof w.contentWindow.sendMessage == "function") {

+                        _onReady();

+                    }

+                    else {

+                        setTimeout(test, 50);

+                    }

+                }());

+            };

+            

+            callerWindow = createFrame({

+                props: {

+                    src: config.local + "#_4" + config.channel

+                },

+                onLoad: onLoad

+            });

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.HashTransport

+ * HashTransport is a transport class that uses the IFrame URL Technique for communication.<br/>

+ * <a href="http://msdn.microsoft.com/en-us/library/bb735305.aspx">http://msdn.microsoft.com/en-us/library/bb735305.aspx</a><br/>

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String/Window} local The url to the local file used for proxying messages, or the local window.

+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.

+ * @cfg {Number} interval The interval used when polling for messages.

+ */

+easyXDM.stack.HashTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.HashTransport");

+    trace("constructor");

+    var pub;

+    var me = this, isHost, _timer, pollInterval, _lastMsg, _msgNr, _listenerWindow, _callerWindow;

+    var useParent, _remoteOrigin;

+    

+    function _sendMessage(message){

+        trace("sending message '" + (_msgNr + 1) + " " + message + "' to " + _remoteOrigin);

+        if (!_callerWindow) {

+            trace("no caller window");

+            return;

+        }

+        var url = config.remote + "#" + (_msgNr++) + "_" + message;

+        ((isHost || !useParent) ? _callerWindow.contentWindow : _callerWindow).location = url;

+    }

+    

+    function _handleHash(hash){

+        _lastMsg = hash;

+        trace("received message '" + _lastMsg + "' from " + _remoteOrigin);

+        pub.up.incoming(_lastMsg.substring(_lastMsg.indexOf("_") + 1), _remoteOrigin);

+    }

+    

+    /**

+     * Checks location.hash for a new message and relays this to the receiver.

+     * @private

+     */

+    function _pollHash(){

+        if (!_listenerWindow) {

+            return;

+        }

+        var href = _listenerWindow.location.href, hash = "", indexOf = href.indexOf("#");

+        if (indexOf != -1) {

+            hash = href.substring(indexOf);

+        }

+        if (hash && hash != _lastMsg) {

+            trace("poll: new message");

+            _handleHash(hash);

+        }

+    }

+    

+    function _attachListeners(){

+        trace("starting polling");

+        _timer = setInterval(_pollHash, pollInterval);

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain){

+            _sendMessage(message);

+        },

+        destroy: function(){

+            window.clearInterval(_timer);

+            if (isHost || !useParent) {

+                _callerWindow.parentNode.removeChild(_callerWindow);

+            }

+            _callerWindow = null;

+        },

+        onDOMReady: function(){

+            isHost = config.isHost;

+            pollInterval = config.interval;

+            _lastMsg = "#" + config.channel;

+            _msgNr = 0;

+            useParent = config.useParent;

+            _remoteOrigin = getLocation(config.remote);

+            if (isHost) {

+                apply(config.props, {

+                    src: config.remote,

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                if (useParent) {

+                    config.onLoad = function(){

+                        _listenerWindow = window;

+                        _attachListeners();

+                        pub.up.callback(true);

+                    };

+                }

+                else {

+                    var tries = 0, max = config.delay / 50;

+                    (function getRef(){

+                        if (++tries > max) {

+                            trace("unable to get reference to _listenerWindow, giving up");

+                            throw new Error("Unable to reference listenerwindow");

+                        }

+                        try {

+                            _listenerWindow = _callerWindow.contentWindow.frames[IFRAME_PREFIX + config.channel + "_consumer"];

+                        } 

+                        catch (ex) {

+                        }

+                        if (_listenerWindow) {

+                            _attachListeners();

+                            trace("got a reference to _listenerWindow");

+                            pub.up.callback(true);

+                        }

+                        else {

+                            setTimeout(getRef, 50);

+                        }

+                    }());

+                }

+                _callerWindow = createFrame(config);

+            }

+            else {

+                _listenerWindow = window;

+                _attachListeners();

+                if (useParent) {

+                    _callerWindow = parent;

+                    pub.up.callback(true);

+                }

+                else {

+                    apply(config, {

+                        props: {

+                            src: config.remote + "#" + config.channel + new Date(),

+                            name: IFRAME_PREFIX + config.channel + "_consumer"

+                        },

+                        onLoad: function(){

+                            pub.up.callback(true);

+                        }

+                    });

+                    _callerWindow = createFrame(config);

+                }

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.ReliableBehavior

+ * This is a behavior that tries to make the underlying transport reliable by using acknowledgements.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration.

+ */

+easyXDM.stack.ReliableBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.ReliableBehavior");

+    trace("constructor");

+    var pub, // the public interface

+ callback; // the callback to execute when we have a confirmed success/failure

+    var idOut = 0, idIn = 0, currentMessage = "";

+    

+    return (pub = {

+        incoming: function(message, origin){

+            trace("incoming: " + message);

+            var indexOf = message.indexOf("_"), ack = message.substring(0, indexOf).split(",");

+            message = message.substring(indexOf + 1);

+            

+            if (ack[0] == idOut) {

+                trace("message delivered");

+                currentMessage = "";

+                if (callback) {

+                    callback(true);

+                    callback = null;

+                }

+            }

+            if (message.length > 0) {

+                trace("sending ack, and passing on " + message);

+                pub.down.outgoing(ack[1] + "," + idOut + "_" + currentMessage, origin);

+                if (idIn != ack[1]) {

+                    idIn = ack[1];

+                    pub.up.incoming(message, origin);

+                }

+            }

+            

+        },

+        outgoing: function(message, origin, fn){

+            currentMessage = message;

+            callback = fn;

+            pub.down.outgoing(idIn + "," + (++idOut) + "_" + message, origin);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug, undef, removeFromStack*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.QueueBehavior

+ * This is a behavior that enables queueing of messages. <br/>

+ * It will buffer incoming messages and dispach these as fast as the underlying transport allows.

+ * This will also fragment/defragment messages so that the outgoing message is never bigger than the

+ * set length.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration. Optional.

+ * @cfg {Number} maxLength The maximum length of each outgoing message. Set this to enable fragmentation.

+ */

+easyXDM.stack.QueueBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.QueueBehavior");

+    trace("constructor");

+    var pub, queue = [], waiting = true, incoming = "", destroying, maxLength = 0, lazy = false, doFragment = false;

+    

+    function dispatch(){

+        if (config.remove && queue.length === 0) {

+            trace("removing myself from the stack");

+            removeFromStack(pub);

+            return;

+        }

+        if (waiting || queue.length === 0 || destroying) {

+            return;

+        }

+        trace("dispatching from queue");

+        waiting = true;

+        var message = queue.shift();

+        

+        pub.down.outgoing(message.data, message.origin, function(success){

+            waiting = false;

+            if (message.callback) {

+                setTimeout(function(){

+                    message.callback(success);

+                }, 0);

+            }

+            dispatch();

+        });

+    }

+    return (pub = {

+        init: function(){

+            if (undef(config)) {

+                config = {};

+            }

+            if (config.maxLength) {

+                maxLength = config.maxLength;

+                doFragment = true;

+            }

+            if (config.lazy) {

+                lazy = true;

+            }

+            else {

+                pub.down.init();

+            }

+        },

+        callback: function(success){

+            waiting = false;

+            var up = pub.up; // in case dispatch calls removeFromStack

+            dispatch();

+            up.callback(success);

+        },

+        incoming: function(message, origin){

+            if (doFragment) {

+                var indexOf = message.indexOf("_"), seq = parseInt(message.substring(0, indexOf), 10);

+                incoming += message.substring(indexOf + 1);

+                if (seq === 0) {

+                    trace("received the last fragment");

+                    if (config.encode) {

+                        incoming = decodeURIComponent(incoming);

+                    }

+                    pub.up.incoming(incoming, origin);

+                    incoming = "";

+                }

+                else {

+                    trace("waiting for more fragments, seq=" + message);

+                }

+            }

+            else {

+                pub.up.incoming(message, origin);

+            }

+        },

+        outgoing: function(message, origin, fn){

+            if (config.encode) {

+                message = encodeURIComponent(message);

+            }

+            var fragments = [], fragment;

+            if (doFragment) {

+                // fragment into chunks

+                while (message.length !== 0) {

+                    fragment = message.substring(0, maxLength);

+                    message = message.substring(fragment.length);

+                    fragments.push(fragment);

+                }

+                // enqueue the chunks

+                while ((fragment = fragments.shift())) {

+                    trace("enqueuing");

+                    queue.push({

+                        data: fragments.length + "_" + fragment,

+                        origin: origin,

+                        callback: fragments.length === 0 ? fn : null

+                    });

+                }

+            }

+            else {

+                queue.push({

+                    data: message,

+                    origin: origin,

+                    callback: fn

+                });

+            }

+            if (lazy) {

+                pub.down.init();

+            }

+            else {

+                dispatch();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            destroying = true;

+            pub.down.destroy();

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.VerifyBehavior

+ * This behavior will verify that communication with the remote end is possible, and will also sign all outgoing,

+ * and verify all incoming messages. This removes the risk of someone hijacking the iframe to send malicious messages.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration.

+ * @cfg {Boolean} initiate If the verification should be initiated from this end.

+ */

+easyXDM.stack.VerifyBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.VerifyBehavior");

+    trace("constructor");

+    if (undef(config.initiate)) {

+        throw new Error("settings.initiate is not set");

+    }

+    var pub, mySecret, theirSecret, verified = false;

+    

+    function startVerification(){

+        trace("requesting verification");

+        mySecret = Math.random().toString(16).substring(2);

+        pub.down.outgoing(mySecret);

+    }

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var indexOf = message.indexOf("_");

+            if (indexOf === -1) {

+                if (message === mySecret) {

+                    trace("verified, calling callback");

+                    pub.up.callback(true);

+                }

+                else if (!theirSecret) {

+                    trace("returning secret");

+                    theirSecret = message;

+                    if (!config.initiate) {

+                        startVerification();

+                    }

+                    pub.down.outgoing(message);

+                }

+            }

+            else {

+                if (message.substring(0, indexOf) === theirSecret) {

+                    pub.up.incoming(message.substring(indexOf + 1), origin);

+                }

+            }

+        },

+        outgoing: function(message, origin, fn){

+            pub.down.outgoing(mySecret + "_" + message, origin, fn);

+        },

+        callback: function(success){

+            if (config.initiate) {

+                startVerification();

+            }

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, getJSON, debug, emptyFn, isArray */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.RpcBehavior

+ * This uses JSON-RPC 2.0 to expose local methods and to invoke remote methods and have responses returned over the the string based transport stack.<br/>

+ * Exposed methods can return values synchronous, asyncronous, or bet set up to not return anything.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} proxy The object to apply the methods to.

+ * @param {Object} config The definition of the local and remote interface to implement.

+ * @cfg {Object} local The local interface to expose.

+ * @cfg {Object} remote The remote methods to expose through the proxy.

+ * @cfg {Object} serializer The serializer to use for serializing and deserializing the JSON. Should be compatible with the HTML5 JSON object. Optional, will default to JSON.

+ */

+easyXDM.stack.RpcBehavior = function(proxy, config){

+    var trace = debug.getTracer("easyXDM.stack.RpcBehavior");

+    var pub, serializer = config.serializer || getJSON();

+    var _callbackCounter = 0, _callbacks = {};

+    

+    /**

+     * Serializes and sends the message

+     * @private

+     * @param {Object} data The JSON-RPC message to be sent. The jsonrpc property will be added.

+     */

+    function _send(data){

+        data.jsonrpc = "2.0";

+        pub.down.outgoing(serializer.stringify(data));

+    }

+    

+    /**

+     * Creates a method that implements the given definition

+     * @private

+     * @param {Object} The method configuration

+     * @param {String} method The name of the method

+     * @return {Function} A stub capable of proxying the requested method call

+     */

+    function _createMethod(definition, method){

+        var slice = Array.prototype.slice;

+        

+        trace("creating method " + method);

+        return function(){

+            trace("executing method " + method);

+            var l = arguments.length, callback, message = {

+                method: method

+            };

+            

+            if (l > 0 && typeof arguments[l - 1] === "function") {

+                //with callback, procedure

+                if (l > 1 && typeof arguments[l - 2] === "function") {

+                    // two callbacks, success and error

+                    callback = {

+                        success: arguments[l - 2],

+                        error: arguments[l - 1]

+                    };

+                    message.params = slice.call(arguments, 0, l - 2);

+                }

+                else {

+                    // single callback, success

+                    callback = {

+                        success: arguments[l - 1]

+                    };

+                    message.params = slice.call(arguments, 0, l - 1);

+                }

+                _callbacks["" + (++_callbackCounter)] = callback;

+                message.id = _callbackCounter;

+            }

+            else {

+                // no callbacks, a notification

+                message.params = slice.call(arguments, 0);

+            }

+            if (definition.namedParams && message.params.length === 1) {

+                message.params = message.params[0];

+            }

+            // Send the method request

+            _send(message);

+        };

+    }

+    

+    /**

+     * Executes the exposed method

+     * @private

+     * @param {String} method The name of the method

+     * @param {Number} id The callback id to use

+     * @param {Function} method The exposed implementation

+     * @param {Array} params The parameters supplied by the remote end

+     */

+    function _executeMethod(method, id, fn, params){

+        if (!fn) {

+            trace("requested to execute non-existent procedure " + method);

+            if (id) {

+                _send({

+                    id: id,

+                    error: {

+                        code: -32601,

+                        message: "Procedure not found."

+                    }

+                });

+            }

+            return;

+        }

+        

+        trace("requested to execute procedure " + method);

+        var success, error;

+        if (id) {

+            success = function(result){

+                success = emptyFn;

+                _send({

+                    id: id,

+                    result: result

+                });

+            };

+            error = function(message, data){

+                error = emptyFn;

+                var msg = {

+                    id: id,

+                    error: {

+                        code: -32099,

+                        message: message

+                    }

+                };

+                if (data) {

+                    msg.error.data = data;

+                }

+                _send(msg);

+            };

+        }

+        else {

+            success = error = emptyFn;

+        }

+        // Call local method

+        if (!isArray(params)) {

+            params = [params];

+        }

+        try {

+            var result = fn.method.apply(fn.scope, params.concat([success, error]));

+            if (!undef(result)) {

+                success(result);

+            }

+        } 

+        catch (ex1) {

+            error(ex1.message);

+        }

+    }

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var data = serializer.parse(message);

+            if (data.method) {

+                trace("received request to execute method " + data.method + (data.id ? (" using callback id " + data.id) : ""));

+                // A method call from the remote end

+                if (config.handle) {

+                    config.handle(data, _send);

+                }

+                else {

+                    _executeMethod(data.method, data.id, config.local[data.method], data.params);

+                }

+            }

+            else {

+                trace("received return value destined to callback with id " + data.id);

+                // A method response from the other end

+                var callback = _callbacks[data.id];

+                if (data.error) {

+                    if (callback.error) {

+                        callback.error(data.error);

+                    }

+                    else {

+                        trace("unhandled error returned.");

+                    }

+                }

+                else if (callback.success) {

+                    callback.success(data.result);

+                }

+                delete _callbacks[data.id];

+            }

+        },

+        init: function(){

+            trace("init");

+            if (config.remote) {

+                trace("creating stubs");

+                // Implement the remote sides exposed methods

+                for (var method in config.remote) {

+                    if (config.remote.hasOwnProperty(method)) {

+                        proxy[method] = _createMethod(config.remote[method], method);

+                    }

+                }

+            }

+            pub.down.init();

+        },

+        destroy: function(){

+            trace("destroy");

+            for (var method in config.remote) {

+                if (config.remote.hasOwnProperty(method) && proxy.hasOwnProperty(method)) {

+                    delete proxy[method];

+                }

+            }

+            pub.down.destroy();

+        }

+    });

+};

+global.easyXDM = easyXDM;

+})(window, document, location, window.setTimeout, decodeURIComponent, encodeURIComponent);

diff --git a/asterix-examples/src/main/resources/cherry/css/bootstrap-responsive.css b/asterix-examples/src/main/resources/cherry/css/bootstrap-responsive.css
new file mode 100755
index 0000000..fcd72f7
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/css/bootstrap-responsive.css
@@ -0,0 +1,1109 @@
+/*!
+ * Bootstrap Responsive v2.3.1
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+
+.clearfix {
+  *zoom: 1;
+}
+
+.clearfix:before,
+.clearfix:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.clearfix:after {
+  clear: both;
+}
+
+.hide-text {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+
+.input-block-level {
+  display: block;
+  width: 100%;
+  min-height: 30px;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+@-ms-viewport {
+  width: device-width;
+}
+
+.hidden {
+  display: none;
+  visibility: hidden;
+}
+
+.visible-phone {
+  display: none !important;
+}
+
+.visible-tablet {
+  display: none !important;
+}
+
+.hidden-desktop {
+  display: none !important;
+}
+
+.visible-desktop {
+  display: inherit !important;
+}
+
+@media (min-width: 768px) and (max-width: 979px) {
+  .hidden-desktop {
+    display: inherit !important;
+  }
+  .visible-desktop {
+    display: none !important ;
+  }
+  .visible-tablet {
+    display: inherit !important;
+  }
+  .hidden-tablet {
+    display: none !important;
+  }
+}
+
+@media (max-width: 767px) {
+  .hidden-desktop {
+    display: inherit !important;
+  }
+  .visible-desktop {
+    display: none !important;
+  }
+  .visible-phone {
+    display: inherit !important;
+  }
+  .hidden-phone {
+    display: none !important;
+  }
+}
+
+.visible-print {
+  display: none !important;
+}
+
+@media print {
+  .visible-print {
+    display: inherit !important;
+  }
+  .hidden-print {
+    display: none !important;
+  }
+}
+
+@media (min-width: 1200px) {
+  .row {
+    margin-left: -30px;
+    *zoom: 1;
+  }
+  .row:before,
+  .row:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row:after {
+    clear: both;
+  }
+  [class*="span"] {
+    float: left;
+    min-height: 1px;
+    margin-left: 30px;
+  }
+  .container,
+  .navbar-static-top .container,
+  .navbar-fixed-top .container,
+  .navbar-fixed-bottom .container {
+    width: 1170px;
+  }
+  .span12 {
+    width: 1170px;
+  }
+  .span11 {
+    width: 1070px;
+  }
+  .span10 {
+    width: 970px;
+  }
+  .span9 {
+    width: 870px;
+  }
+  .span8 {
+    width: 770px;
+  }
+  .span7 {
+    width: 670px;
+  }
+  .span6 {
+    width: 570px;
+  }
+  .span5 {
+    width: 470px;
+  }
+  .span4 {
+    width: 370px;
+  }
+  .span3 {
+    width: 270px;
+  }
+  .span2 {
+    width: 170px;
+  }
+  .span1 {
+    width: 70px;
+  }
+  .offset12 {
+    margin-left: 1230px;
+  }
+  .offset11 {
+    margin-left: 1130px;
+  }
+  .offset10 {
+    margin-left: 1030px;
+  }
+  .offset9 {
+    margin-left: 930px;
+  }
+  .offset8 {
+    margin-left: 830px;
+  }
+  .offset7 {
+    margin-left: 730px;
+  }
+  .offset6 {
+    margin-left: 630px;
+  }
+  .offset5 {
+    margin-left: 530px;
+  }
+  .offset4 {
+    margin-left: 430px;
+  }
+  .offset3 {
+    margin-left: 330px;
+  }
+  .offset2 {
+    margin-left: 230px;
+  }
+  .offset1 {
+    margin-left: 130px;
+  }
+  .row-fluid {
+    width: 100%;
+    *zoom: 1;
+  }
+  .row-fluid:before,
+  .row-fluid:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row-fluid:after {
+    clear: both;
+  }
+  .row-fluid [class*="span"] {
+    display: block;
+    float: left;
+    width: 100%;
+    min-height: 30px;
+    margin-left: 2.564102564102564%;
+    *margin-left: 2.5109110747408616%;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .row-fluid [class*="span"]:first-child {
+    margin-left: 0;
+  }
+  .row-fluid .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 2.564102564102564%;
+  }
+  .row-fluid .span12 {
+    width: 100%;
+    *width: 99.94680851063829%;
+  }
+  .row-fluid .span11 {
+    width: 91.45299145299145%;
+    *width: 91.39979996362975%;
+  }
+  .row-fluid .span10 {
+    width: 82.90598290598291%;
+    *width: 82.8527914166212%;
+  }
+  .row-fluid .span9 {
+    width: 74.35897435897436%;
+    *width: 74.30578286961266%;
+  }
+  .row-fluid .span8 {
+    width: 65.81196581196582%;
+    *width: 65.75877432260411%;
+  }
+  .row-fluid .span7 {
+    width: 57.26495726495726%;
+    *width: 57.21176577559556%;
+  }
+  .row-fluid .span6 {
+    width: 48.717948717948715%;
+    *width: 48.664757228587014%;
+  }
+  .row-fluid .span5 {
+    width: 40.17094017094017%;
+    *width: 40.11774868157847%;
+  }
+  .row-fluid .span4 {
+    width: 31.623931623931625%;
+    *width: 31.570740134569924%;
+  }
+  .row-fluid .span3 {
+    width: 23.076923076923077%;
+    *width: 23.023731587561375%;
+  }
+  .row-fluid .span2 {
+    width: 14.52991452991453%;
+    *width: 14.476723040552828%;
+  }
+  .row-fluid .span1 {
+    width: 5.982905982905983%;
+    *width: 5.929714493544281%;
+  }
+  .row-fluid .offset12 {
+    margin-left: 105.12820512820512%;
+    *margin-left: 105.02182214948171%;
+  }
+  .row-fluid .offset12:first-child {
+    margin-left: 102.56410256410257%;
+    *margin-left: 102.45771958537915%;
+  }
+  .row-fluid .offset11 {
+    margin-left: 96.58119658119658%;
+    *margin-left: 96.47481360247316%;
+  }
+  .row-fluid .offset11:first-child {
+    margin-left: 94.01709401709402%;
+    *margin-left: 93.91071103837061%;
+  }
+  .row-fluid .offset10 {
+    margin-left: 88.03418803418803%;
+    *margin-left: 87.92780505546462%;
+  }
+  .row-fluid .offset10:first-child {
+    margin-left: 85.47008547008548%;
+    *margin-left: 85.36370249136206%;
+  }
+  .row-fluid .offset9 {
+    margin-left: 79.48717948717949%;
+    *margin-left: 79.38079650845607%;
+  }
+  .row-fluid .offset9:first-child {
+    margin-left: 76.92307692307693%;
+    *margin-left: 76.81669394435352%;
+  }
+  .row-fluid .offset8 {
+    margin-left: 70.94017094017094%;
+    *margin-left: 70.83378796144753%;
+  }
+  .row-fluid .offset8:first-child {
+    margin-left: 68.37606837606839%;
+    *margin-left: 68.26968539734497%;
+  }
+  .row-fluid .offset7 {
+    margin-left: 62.393162393162385%;
+    *margin-left: 62.28677941443899%;
+  }
+  .row-fluid .offset7:first-child {
+    margin-left: 59.82905982905982%;
+    *margin-left: 59.72267685033642%;
+  }
+  .row-fluid .offset6 {
+    margin-left: 53.84615384615384%;
+    *margin-left: 53.739770867430444%;
+  }
+  .row-fluid .offset6:first-child {
+    margin-left: 51.28205128205128%;
+    *margin-left: 51.175668303327875%;
+  }
+  .row-fluid .offset5 {
+    margin-left: 45.299145299145295%;
+    *margin-left: 45.1927623204219%;
+  }
+  .row-fluid .offset5:first-child {
+    margin-left: 42.73504273504273%;
+    *margin-left: 42.62865975631933%;
+  }
+  .row-fluid .offset4 {
+    margin-left: 36.75213675213675%;
+    *margin-left: 36.645753773413354%;
+  }
+  .row-fluid .offset4:first-child {
+    margin-left: 34.18803418803419%;
+    *margin-left: 34.081651209310785%;
+  }
+  .row-fluid .offset3 {
+    margin-left: 28.205128205128204%;
+    *margin-left: 28.0987452264048%;
+  }
+  .row-fluid .offset3:first-child {
+    margin-left: 25.641025641025642%;
+    *margin-left: 25.53464266230224%;
+  }
+  .row-fluid .offset2 {
+    margin-left: 19.65811965811966%;
+    *margin-left: 19.551736679396257%;
+  }
+  .row-fluid .offset2:first-child {
+    margin-left: 17.094017094017094%;
+    *margin-left: 16.98763411529369%;
+  }
+  .row-fluid .offset1 {
+    margin-left: 11.11111111111111%;
+    *margin-left: 11.004728132387708%;
+  }
+  .row-fluid .offset1:first-child {
+    margin-left: 8.547008547008547%;
+    *margin-left: 8.440625568285142%;
+  }
+  input,
+  textarea,
+  .uneditable-input {
+    margin-left: 0;
+  }
+  .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 30px;
+  }
+  input.span12,
+  textarea.span12,
+  .uneditable-input.span12 {
+    width: 1156px;
+  }
+  input.span11,
+  textarea.span11,
+  .uneditable-input.span11 {
+    width: 1056px;
+  }
+  input.span10,
+  textarea.span10,
+  .uneditable-input.span10 {
+    width: 956px;
+  }
+  input.span9,
+  textarea.span9,
+  .uneditable-input.span9 {
+    width: 856px;
+  }
+  input.span8,
+  textarea.span8,
+  .uneditable-input.span8 {
+    width: 756px;
+  }
+  input.span7,
+  textarea.span7,
+  .uneditable-input.span7 {
+    width: 656px;
+  }
+  input.span6,
+  textarea.span6,
+  .uneditable-input.span6 {
+    width: 556px;
+  }
+  input.span5,
+  textarea.span5,
+  .uneditable-input.span5 {
+    width: 456px;
+  }
+  input.span4,
+  textarea.span4,
+  .uneditable-input.span4 {
+    width: 356px;
+  }
+  input.span3,
+  textarea.span3,
+  .uneditable-input.span3 {
+    width: 256px;
+  }
+  input.span2,
+  textarea.span2,
+  .uneditable-input.span2 {
+    width: 156px;
+  }
+  input.span1,
+  textarea.span1,
+  .uneditable-input.span1 {
+    width: 56px;
+  }
+  .thumbnails {
+    margin-left: -30px;
+  }
+  .thumbnails > li {
+    margin-left: 30px;
+  }
+  .row-fluid .thumbnails {
+    margin-left: 0;
+  }
+}
+
+@media (min-width: 768px) and (max-width: 979px) {
+  .row {
+    margin-left: -20px;
+    *zoom: 1;
+  }
+  .row:before,
+  .row:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row:after {
+    clear: both;
+  }
+  [class*="span"] {
+    float: left;
+    min-height: 1px;
+    margin-left: 20px;
+  }
+  .container,
+  .navbar-static-top .container,
+  .navbar-fixed-top .container,
+  .navbar-fixed-bottom .container {
+    width: 724px;
+  }
+  .span12 {
+    width: 724px;
+  }
+  .span11 {
+    width: 662px;
+  }
+  .span10 {
+    width: 600px;
+  }
+  .span9 {
+    width: 538px;
+  }
+  .span8 {
+    width: 476px;
+  }
+  .span7 {
+    width: 414px;
+  }
+  .span6 {
+    width: 352px;
+  }
+  .span5 {
+    width: 290px;
+  }
+  .span4 {
+    width: 228px;
+  }
+  .span3 {
+    width: 166px;
+  }
+  .span2 {
+    width: 104px;
+  }
+  .span1 {
+    width: 42px;
+  }
+  .offset12 {
+    margin-left: 764px;
+  }
+  .offset11 {
+    margin-left: 702px;
+  }
+  .offset10 {
+    margin-left: 640px;
+  }
+  .offset9 {
+    margin-left: 578px;
+  }
+  .offset8 {
+    margin-left: 516px;
+  }
+  .offset7 {
+    margin-left: 454px;
+  }
+  .offset6 {
+    margin-left: 392px;
+  }
+  .offset5 {
+    margin-left: 330px;
+  }
+  .offset4 {
+    margin-left: 268px;
+  }
+  .offset3 {
+    margin-left: 206px;
+  }
+  .offset2 {
+    margin-left: 144px;
+  }
+  .offset1 {
+    margin-left: 82px;
+  }
+  .row-fluid {
+    width: 100%;
+    *zoom: 1;
+  }
+  .row-fluid:before,
+  .row-fluid:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row-fluid:after {
+    clear: both;
+  }
+  .row-fluid [class*="span"] {
+    display: block;
+    float: left;
+    width: 100%;
+    min-height: 30px;
+    margin-left: 2.7624309392265194%;
+    *margin-left: 2.709239449864817%;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .row-fluid [class*="span"]:first-child {
+    margin-left: 0;
+  }
+  .row-fluid .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 2.7624309392265194%;
+  }
+  .row-fluid .span12 {
+    width: 100%;
+    *width: 99.94680851063829%;
+  }
+  .row-fluid .span11 {
+    width: 91.43646408839778%;
+    *width: 91.38327259903608%;
+  }
+  .row-fluid .span10 {
+    width: 82.87292817679558%;
+    *width: 82.81973668743387%;
+  }
+  .row-fluid .span9 {
+    width: 74.30939226519337%;
+    *width: 74.25620077583166%;
+  }
+  .row-fluid .span8 {
+    width: 65.74585635359117%;
+    *width: 65.69266486422946%;
+  }
+  .row-fluid .span7 {
+    width: 57.18232044198895%;
+    *width: 57.12912895262725%;
+  }
+  .row-fluid .span6 {
+    width: 48.61878453038674%;
+    *width: 48.56559304102504%;
+  }
+  .row-fluid .span5 {
+    width: 40.05524861878453%;
+    *width: 40.00205712942283%;
+  }
+  .row-fluid .span4 {
+    width: 31.491712707182323%;
+    *width: 31.43852121782062%;
+  }
+  .row-fluid .span3 {
+    width: 22.92817679558011%;
+    *width: 22.87498530621841%;
+  }
+  .row-fluid .span2 {
+    width: 14.3646408839779%;
+    *width: 14.311449394616199%;
+  }
+  .row-fluid .span1 {
+    width: 5.801104972375691%;
+    *width: 5.747913483013988%;
+  }
+  .row-fluid .offset12 {
+    margin-left: 105.52486187845304%;
+    *margin-left: 105.41847889972962%;
+  }
+  .row-fluid .offset12:first-child {
+    margin-left: 102.76243093922652%;
+    *margin-left: 102.6560479605031%;
+  }
+  .row-fluid .offset11 {
+    margin-left: 96.96132596685082%;
+    *margin-left: 96.8549429881274%;
+  }
+  .row-fluid .offset11:first-child {
+    margin-left: 94.1988950276243%;
+    *margin-left: 94.09251204890089%;
+  }
+  .row-fluid .offset10 {
+    margin-left: 88.39779005524862%;
+    *margin-left: 88.2914070765252%;
+  }
+  .row-fluid .offset10:first-child {
+    margin-left: 85.6353591160221%;
+    *margin-left: 85.52897613729868%;
+  }
+  .row-fluid .offset9 {
+    margin-left: 79.8342541436464%;
+    *margin-left: 79.72787116492299%;
+  }
+  .row-fluid .offset9:first-child {
+    margin-left: 77.07182320441989%;
+    *margin-left: 76.96544022569647%;
+  }
+  .row-fluid .offset8 {
+    margin-left: 71.2707182320442%;
+    *margin-left: 71.16433525332079%;
+  }
+  .row-fluid .offset8:first-child {
+    margin-left: 68.50828729281768%;
+    *margin-left: 68.40190431409427%;
+  }
+  .row-fluid .offset7 {
+    margin-left: 62.70718232044199%;
+    *margin-left: 62.600799341718584%;
+  }
+  .row-fluid .offset7:first-child {
+    margin-left: 59.94475138121547%;
+    *margin-left: 59.838368402492065%;
+  }
+  .row-fluid .offset6 {
+    margin-left: 54.14364640883978%;
+    *margin-left: 54.037263430116376%;
+  }
+  .row-fluid .offset6:first-child {
+    margin-left: 51.38121546961326%;
+    *margin-left: 51.27483249088986%;
+  }
+  .row-fluid .offset5 {
+    margin-left: 45.58011049723757%;
+    *margin-left: 45.47372751851417%;
+  }
+  .row-fluid .offset5:first-child {
+    margin-left: 42.81767955801105%;
+    *margin-left: 42.71129657928765%;
+  }
+  .row-fluid .offset4 {
+    margin-left: 37.01657458563536%;
+    *margin-left: 36.91019160691196%;
+  }
+  .row-fluid .offset4:first-child {
+    margin-left: 34.25414364640884%;
+    *margin-left: 34.14776066768544%;
+  }
+  .row-fluid .offset3 {
+    margin-left: 28.45303867403315%;
+    *margin-left: 28.346655695309746%;
+  }
+  .row-fluid .offset3:first-child {
+    margin-left: 25.69060773480663%;
+    *margin-left: 25.584224756083227%;
+  }
+  .row-fluid .offset2 {
+    margin-left: 19.88950276243094%;
+    *margin-left: 19.783119783707537%;
+  }
+  .row-fluid .offset2:first-child {
+    margin-left: 17.12707182320442%;
+    *margin-left: 17.02068884448102%;
+  }
+  .row-fluid .offset1 {
+    margin-left: 11.32596685082873%;
+    *margin-left: 11.219583872105325%;
+  }
+  .row-fluid .offset1:first-child {
+    margin-left: 8.56353591160221%;
+    *margin-left: 8.457152932878806%;
+  }
+  input,
+  textarea,
+  .uneditable-input {
+    margin-left: 0;
+  }
+  .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 20px;
+  }
+  input.span12,
+  textarea.span12,
+  .uneditable-input.span12 {
+    width: 710px;
+  }
+  input.span11,
+  textarea.span11,
+  .uneditable-input.span11 {
+    width: 648px;
+  }
+  input.span10,
+  textarea.span10,
+  .uneditable-input.span10 {
+    width: 586px;
+  }
+  input.span9,
+  textarea.span9,
+  .uneditable-input.span9 {
+    width: 524px;
+  }
+  input.span8,
+  textarea.span8,
+  .uneditable-input.span8 {
+    width: 462px;
+  }
+  input.span7,
+  textarea.span7,
+  .uneditable-input.span7 {
+    width: 400px;
+  }
+  input.span6,
+  textarea.span6,
+  .uneditable-input.span6 {
+    width: 338px;
+  }
+  input.span5,
+  textarea.span5,
+  .uneditable-input.span5 {
+    width: 276px;
+  }
+  input.span4,
+  textarea.span4,
+  .uneditable-input.span4 {
+    width: 214px;
+  }
+  input.span3,
+  textarea.span3,
+  .uneditable-input.span3 {
+    width: 152px;
+  }
+  input.span2,
+  textarea.span2,
+  .uneditable-input.span2 {
+    width: 90px;
+  }
+  input.span1,
+  textarea.span1,
+  .uneditable-input.span1 {
+    width: 28px;
+  }
+}
+
+@media (max-width: 767px) {
+  body {
+    padding-right: 20px;
+    padding-left: 20px;
+  }
+  .navbar-fixed-top,
+  .navbar-fixed-bottom,
+  .navbar-static-top {
+    margin-right: -20px;
+    margin-left: -20px;
+  }
+  .container-fluid {
+    padding: 0;
+  }
+  .dl-horizontal dt {
+    float: none;
+    width: auto;
+    clear: none;
+    text-align: left;
+  }
+  .dl-horizontal dd {
+    margin-left: 0;
+  }
+  .container {
+    width: auto;
+  }
+  .row-fluid {
+    width: 100%;
+  }
+  .row,
+  .thumbnails {
+    margin-left: 0;
+  }
+  .thumbnails > li {
+    float: none;
+    margin-left: 0;
+  }
+  [class*="span"],
+  .uneditable-input[class*="span"],
+  .row-fluid [class*="span"] {
+    display: block;
+    float: none;
+    width: 100%;
+    margin-left: 0;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .span12,
+  .row-fluid .span12 {
+    width: 100%;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .row-fluid [class*="offset"]:first-child {
+    margin-left: 0;
+  }
+  .input-large,
+  .input-xlarge,
+  .input-xxlarge,
+  input[class*="span"],
+  select[class*="span"],
+  textarea[class*="span"],
+  .uneditable-input {
+    display: block;
+    width: 100%;
+    min-height: 30px;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .input-prepend input,
+  .input-append input,
+  .input-prepend input[class*="span"],
+  .input-append input[class*="span"] {
+    display: inline-block;
+    width: auto;
+  }
+  .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 0;
+  }
+  .modal {
+    position: fixed;
+    top: 20px;
+    right: 20px;
+    left: 20px;
+    width: auto;
+    margin: 0;
+  }
+  .modal.fade {
+    top: -100px;
+  }
+  .modal.fade.in {
+    top: 20px;
+  }
+}
+
+@media (max-width: 480px) {
+  .nav-collapse {
+    -webkit-transform: translate3d(0, 0, 0);
+  }
+  .page-header h1 small {
+    display: block;
+    line-height: 20px;
+  }
+  input[type="checkbox"],
+  input[type="radio"] {
+    border: 1px solid #ccc;
+  }
+  .form-horizontal .control-label {
+    float: none;
+    width: auto;
+    padding-top: 0;
+    text-align: left;
+  }
+  .form-horizontal .controls {
+    margin-left: 0;
+  }
+  .form-horizontal .control-list {
+    padding-top: 0;
+  }
+  .form-horizontal .form-actions {
+    padding-right: 10px;
+    padding-left: 10px;
+  }
+  .media .pull-left,
+  .media .pull-right {
+    display: block;
+    float: none;
+    margin-bottom: 10px;
+  }
+  .media-object {
+    margin-right: 0;
+    margin-left: 0;
+  }
+  .modal {
+    top: 10px;
+    right: 10px;
+    left: 10px;
+  }
+  .modal-header .close {
+    padding: 10px;
+    margin: -10px;
+  }
+  .carousel-caption {
+    position: static;
+  }
+}
+
+@media (max-width: 979px) {
+  body {
+    padding-top: 0;
+  }
+  .navbar-fixed-top,
+  .navbar-fixed-bottom {
+    position: static;
+  }
+  .navbar-fixed-top {
+    margin-bottom: 20px;
+  }
+  .navbar-fixed-bottom {
+    margin-top: 20px;
+  }
+  .navbar-fixed-top .navbar-inner,
+  .navbar-fixed-bottom .navbar-inner {
+    padding: 5px;
+  }
+  .navbar .container {
+    width: auto;
+    padding: 0;
+  }
+  .navbar .brand {
+    padding-right: 10px;
+    padding-left: 10px;
+    margin: 0 0 0 -5px;
+  }
+  .nav-collapse {
+    clear: both;
+  }
+  .nav-collapse .nav {
+    float: none;
+    margin: 0 0 10px;
+  }
+  .nav-collapse .nav > li {
+    float: none;
+  }
+  .nav-collapse .nav > li > a {
+    margin-bottom: 2px;
+  }
+  .nav-collapse .nav > .divider-vertical {
+    display: none;
+  }
+  .nav-collapse .nav .nav-header {
+    color: #777777;
+    text-shadow: none;
+  }
+  .nav-collapse .nav > li > a,
+  .nav-collapse .dropdown-menu a {
+    padding: 9px 15px;
+    font-weight: bold;
+    color: #777777;
+    -webkit-border-radius: 3px;
+       -moz-border-radius: 3px;
+            border-radius: 3px;
+  }
+  .nav-collapse .btn {
+    padding: 4px 10px 4px;
+    font-weight: normal;
+    -webkit-border-radius: 4px;
+       -moz-border-radius: 4px;
+            border-radius: 4px;
+  }
+  .nav-collapse .dropdown-menu li + li a {
+    margin-bottom: 2px;
+  }
+  .nav-collapse .nav > li > a:hover,
+  .nav-collapse .nav > li > a:focus,
+  .nav-collapse .dropdown-menu a:hover,
+  .nav-collapse .dropdown-menu a:focus {
+    background-color: #f2f2f2;
+  }
+  .navbar-inverse .nav-collapse .nav > li > a,
+  .navbar-inverse .nav-collapse .dropdown-menu a {
+    color: #999999;
+  }
+  .navbar-inverse .nav-collapse .nav > li > a:hover,
+  .navbar-inverse .nav-collapse .nav > li > a:focus,
+  .navbar-inverse .nav-collapse .dropdown-menu a:hover,
+  .navbar-inverse .nav-collapse .dropdown-menu a:focus {
+    background-color: #111111;
+  }
+  .nav-collapse.in .btn-group {
+    padding: 0;
+    margin-top: 5px;
+  }
+  .nav-collapse .dropdown-menu {
+    position: static;
+    top: auto;
+    left: auto;
+    display: none;
+    float: none;
+    max-width: none;
+    padding: 0;
+    margin: 0 15px;
+    background-color: transparent;
+    border: none;
+    -webkit-border-radius: 0;
+       -moz-border-radius: 0;
+            border-radius: 0;
+    -webkit-box-shadow: none;
+       -moz-box-shadow: none;
+            box-shadow: none;
+  }
+  .nav-collapse .open > .dropdown-menu {
+    display: block;
+  }
+  .nav-collapse .dropdown-menu:before,
+  .nav-collapse .dropdown-menu:after {
+    display: none;
+  }
+  .nav-collapse .dropdown-menu .divider {
+    display: none;
+  }
+  .nav-collapse .nav > li > .dropdown-menu:before,
+  .nav-collapse .nav > li > .dropdown-menu:after {
+    display: none;
+  }
+  .nav-collapse .navbar-form,
+  .nav-collapse .navbar-search {
+    float: none;
+    padding: 10px 15px;
+    margin: 10px 0;
+    border-top: 1px solid #f2f2f2;
+    border-bottom: 1px solid #f2f2f2;
+    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+       -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  }
+  .navbar-inverse .nav-collapse .navbar-form,
+  .navbar-inverse .nav-collapse .navbar-search {
+    border-top-color: #111111;
+    border-bottom-color: #111111;
+  }
+  .navbar .nav-collapse .nav.pull-right {
+    float: none;
+    margin-left: 0;
+  }
+  .nav-collapse,
+  .nav-collapse.collapse {
+    height: 0;
+    overflow: hidden;
+  }
+  .navbar .btn-navbar {
+    display: block;
+  }
+  .navbar-static .navbar-inner {
+    padding-right: 10px;
+    padding-left: 10px;
+  }
+}
+
+@media (min-width: 980px) {
+  .nav-collapse.collapse {
+    height: auto !important;
+    overflow: visible !important;
+  }
+}
diff --git a/asterix-examples/src/main/resources/cherry/css/bootstrap-responsive.min.css b/asterix-examples/src/main/resources/cherry/css/bootstrap-responsive.min.css
new file mode 100755
index 0000000..d1b7f4b
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/css/bootstrap-responsive.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap Responsive v2.3.1
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}
diff --git a/asterix-examples/src/main/resources/cherry/css/bootstrap.css b/asterix-examples/src/main/resources/cherry/css/bootstrap.css
new file mode 100755
index 0000000..2f56af3
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/css/bootstrap.css
@@ -0,0 +1,6158 @@
+/*!
+ * Bootstrap v2.3.1
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+
+.clearfix {
+  *zoom: 1;
+}
+
+.clearfix:before,
+.clearfix:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.clearfix:after {
+  clear: both;
+}
+
+.hide-text {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+
+.input-block-level {
+  display: block;
+  width: 100%;
+  min-height: 30px;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+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 {
+  width: auto\9;
+  height: auto;
+  max-width: 100%;
+  vertical-align: middle;
+  border: 0;
+  -ms-interpolation-mode: bicubic;
+}
+
+#map_canvas img,
+.google-maps img {
+  max-width: none;
+}
+
+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,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+  cursor: pointer;
+  -webkit-appearance: button;
+}
+
+label,
+select,
+button,
+input[type="button"],
+input[type="reset"],
+input[type="submit"],
+input[type="radio"],
+input[type="checkbox"] {
+  cursor: pointer;
+}
+
+input[type="search"] {
+  -webkit-box-sizing: content-box;
+     -moz-box-sizing: content-box;
+          box-sizing: content-box;
+  -webkit-appearance: textfield;
+}
+
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button {
+  -webkit-appearance: none;
+}
+
+textarea {
+  overflow: auto;
+  vertical-align: top;
+}
+
+@media print {
+  * {
+    color: #000 !important;
+    text-shadow: none !important;
+    background: transparent !important;
+    box-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 #999;
+    page-break-inside: avoid;
+  }
+  thead {
+    display: table-header-group;
+  }
+  tr,
+  img {
+    page-break-inside: avoid;
+  }
+  img {
+    max-width: 100% !important;
+  }
+  @page  {
+    margin: 0.5cm;
+  }
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3;
+  }
+  h2,
+  h3 {
+    page-break-after: avoid;
+  }
+}
+
+body {
+  margin: 0;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 14px;
+  line-height: 20px;
+  color: #333333;
+  background-color: #ffffff;
+}
+
+a {
+  color: #0088cc;
+  text-decoration: none;
+}
+
+a:hover,
+a:focus {
+  color: #005580;
+  text-decoration: underline;
+}
+
+.img-rounded {
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+}
+
+.img-polaroid {
+  padding: 4px;
+  background-color: #fff;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.img-circle {
+  -webkit-border-radius: 500px;
+     -moz-border-radius: 500px;
+          border-radius: 500px;
+}
+
+.row {
+  margin-left: -20px;
+  *zoom: 1;
+}
+
+.row:before,
+.row:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.row:after {
+  clear: both;
+}
+
+[class*="span"] {
+  float: left;
+  min-height: 1px;
+  margin-left: 20px;
+}
+
+.container,
+.navbar-static-top .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;
+  line-height: 0;
+  content: "";
+}
+
+.row-fluid:after {
+  clear: both;
+}
+
+.row-fluid [class*="span"] {
+  display: block;
+  float: left;
+  width: 100%;
+  min-height: 30px;
+  margin-left: 2.127659574468085%;
+  *margin-left: 2.074468085106383%;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.row-fluid [class*="span"]:first-child {
+  margin-left: 0;
+}
+
+.row-fluid .controls-row [class*="span"] + [class*="span"] {
+  margin-left: 2.127659574468085%;
+}
+
+.row-fluid .span12 {
+  width: 100%;
+  *width: 99.94680851063829%;
+}
+
+.row-fluid .span11 {
+  width: 91.48936170212765%;
+  *width: 91.43617021276594%;
+}
+
+.row-fluid .span10 {
+  width: 82.97872340425532%;
+  *width: 82.92553191489361%;
+}
+
+.row-fluid .span9 {
+  width: 74.46808510638297%;
+  *width: 74.41489361702126%;
+}
+
+.row-fluid .span8 {
+  width: 65.95744680851064%;
+  *width: 65.90425531914893%;
+}
+
+.row-fluid .span7 {
+  width: 57.44680851063829%;
+  *width: 57.39361702127659%;
+}
+
+.row-fluid .span6 {
+  width: 48.93617021276595%;
+  *width: 48.88297872340425%;
+}
+
+.row-fluid .span5 {
+  width: 40.42553191489362%;
+  *width: 40.37234042553192%;
+}
+
+.row-fluid .span4 {
+  width: 31.914893617021278%;
+  *width: 31.861702127659576%;
+}
+
+.row-fluid .span3 {
+  width: 23.404255319148934%;
+  *width: 23.351063829787233%;
+}
+
+.row-fluid .span2 {
+  width: 14.893617021276595%;
+  *width: 14.840425531914894%;
+}
+
+.row-fluid .span1 {
+  width: 6.382978723404255%;
+  *width: 6.329787234042553%;
+}
+
+.row-fluid .offset12 {
+  margin-left: 104.25531914893617%;
+  *margin-left: 104.14893617021275%;
+}
+
+.row-fluid .offset12:first-child {
+  margin-left: 102.12765957446808%;
+  *margin-left: 102.02127659574467%;
+}
+
+.row-fluid .offset11 {
+  margin-left: 95.74468085106382%;
+  *margin-left: 95.6382978723404%;
+}
+
+.row-fluid .offset11:first-child {
+  margin-left: 93.61702127659574%;
+  *margin-left: 93.51063829787232%;
+}
+
+.row-fluid .offset10 {
+  margin-left: 87.23404255319149%;
+  *margin-left: 87.12765957446807%;
+}
+
+.row-fluid .offset10:first-child {
+  margin-left: 85.1063829787234%;
+  *margin-left: 84.99999999999999%;
+}
+
+.row-fluid .offset9 {
+  margin-left: 78.72340425531914%;
+  *margin-left: 78.61702127659572%;
+}
+
+.row-fluid .offset9:first-child {
+  margin-left: 76.59574468085106%;
+  *margin-left: 76.48936170212764%;
+}
+
+.row-fluid .offset8 {
+  margin-left: 70.2127659574468%;
+  *margin-left: 70.10638297872339%;
+}
+
+.row-fluid .offset8:first-child {
+  margin-left: 68.08510638297872%;
+  *margin-left: 67.9787234042553%;
+}
+
+.row-fluid .offset7 {
+  margin-left: 61.70212765957446%;
+  *margin-left: 61.59574468085106%;
+}
+
+.row-fluid .offset7:first-child {
+  margin-left: 59.574468085106375%;
+  *margin-left: 59.46808510638297%;
+}
+
+.row-fluid .offset6 {
+  margin-left: 53.191489361702125%;
+  *margin-left: 53.085106382978715%;
+}
+
+.row-fluid .offset6:first-child {
+  margin-left: 51.063829787234035%;
+  *margin-left: 50.95744680851063%;
+}
+
+.row-fluid .offset5 {
+  margin-left: 44.68085106382979%;
+  *margin-left: 44.57446808510638%;
+}
+
+.row-fluid .offset5:first-child {
+  margin-left: 42.5531914893617%;
+  *margin-left: 42.4468085106383%;
+}
+
+.row-fluid .offset4 {
+  margin-left: 36.170212765957444%;
+  *margin-left: 36.06382978723405%;
+}
+
+.row-fluid .offset4:first-child {
+  margin-left: 34.04255319148936%;
+  *margin-left: 33.93617021276596%;
+}
+
+.row-fluid .offset3 {
+  margin-left: 27.659574468085104%;
+  *margin-left: 27.5531914893617%;
+}
+
+.row-fluid .offset3:first-child {
+  margin-left: 25.53191489361702%;
+  *margin-left: 25.425531914893618%;
+}
+
+.row-fluid .offset2 {
+  margin-left: 19.148936170212764%;
+  *margin-left: 19.04255319148936%;
+}
+
+.row-fluid .offset2:first-child {
+  margin-left: 17.02127659574468%;
+  *margin-left: 16.914893617021278%;
+}
+
+.row-fluid .offset1 {
+  margin-left: 10.638297872340425%;
+  *margin-left: 10.53191489361702%;
+}
+
+.row-fluid .offset1:first-child {
+  margin-left: 8.51063829787234%;
+  *margin-left: 8.404255319148938%;
+}
+
+[class*="span"].hide,
+.row-fluid [class*="span"].hide {
+  display: none;
+}
+
+[class*="span"].pull-right,
+.row-fluid [class*="span"].pull-right {
+  float: right;
+}
+
+.container {
+  margin-right: auto;
+  margin-left: auto;
+  *zoom: 1;
+}
+
+.container:before,
+.container:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.container:after {
+  clear: both;
+}
+
+.container-fluid {
+  padding-right: 20px;
+  padding-left: 20px;
+  *zoom: 1;
+}
+
+.container-fluid:before,
+.container-fluid:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.container-fluid:after {
+  clear: both;
+}
+
+p {
+  margin: 0 0 10px;
+}
+
+.lead {
+  margin-bottom: 20px;
+  font-size: 21px;
+  font-weight: 200;
+  line-height: 30px;
+}
+
+small {
+  font-size: 85%;
+}
+
+strong {
+  font-weight: bold;
+}
+
+em {
+  font-style: italic;
+}
+
+cite {
+  font-style: normal;
+}
+
+.muted {
+  color: #999999;
+}
+
+a.muted:hover,
+a.muted:focus {
+  color: #808080;
+}
+
+.text-warning {
+  color: #c09853;
+}
+
+a.text-warning:hover,
+a.text-warning:focus {
+  color: #a47e3c;
+}
+
+.text-error {
+  color: #b94a48;
+}
+
+a.text-error:hover,
+a.text-error:focus {
+  color: #953b39;
+}
+
+.text-info {
+  color: #3a87ad;
+}
+
+a.text-info:hover,
+a.text-info:focus {
+  color: #2d6987;
+}
+
+.text-success {
+  color: #468847;
+}
+
+a.text-success:hover,
+a.text-success:focus {
+  color: #356635;
+}
+
+.text-left {
+  text-align: left;
+}
+
+.text-right {
+  text-align: right;
+}
+
+.text-center {
+  text-align: center;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+  margin: 10px 0;
+  font-family: inherit;
+  font-weight: bold;
+  line-height: 20px;
+  color: inherit;
+  text-rendering: optimizelegibility;
+}
+
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small {
+  font-weight: normal;
+  line-height: 1;
+  color: #999999;
+}
+
+h1,
+h2,
+h3 {
+  line-height: 40px;
+}
+
+h1 {
+  font-size: 38.5px;
+}
+
+h2 {
+  font-size: 31.5px;
+}
+
+h3 {
+  font-size: 24.5px;
+}
+
+h4 {
+  font-size: 17.5px;
+}
+
+h5 {
+  font-size: 14px;
+}
+
+h6 {
+  font-size: 11.9px;
+}
+
+h1 small {
+  font-size: 24.5px;
+}
+
+h2 small {
+  font-size: 17.5px;
+}
+
+h3 small {
+  font-size: 14px;
+}
+
+h4 small {
+  font-size: 14px;
+}
+
+.page-header {
+  padding-bottom: 9px;
+  margin: 20px 0 30px;
+  border-bottom: 1px solid #eeeeee;
+}
+
+ul,
+ol {
+  padding: 0;
+  margin: 0 0 10px 25px;
+}
+
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+  margin-bottom: 0;
+}
+
+li {
+  line-height: 20px;
+}
+
+ul.unstyled,
+ol.unstyled {
+  margin-left: 0;
+  list-style: none;
+}
+
+ul.inline,
+ol.inline {
+  margin-left: 0;
+  list-style: none;
+}
+
+ul.inline > li,
+ol.inline > li {
+  display: inline-block;
+  *display: inline;
+  padding-right: 5px;
+  padding-left: 5px;
+  *zoom: 1;
+}
+
+dl {
+  margin-bottom: 20px;
+}
+
+dt,
+dd {
+  line-height: 20px;
+}
+
+dt {
+  font-weight: bold;
+}
+
+dd {
+  margin-left: 10px;
+}
+
+.dl-horizontal {
+  *zoom: 1;
+}
+
+.dl-horizontal:before,
+.dl-horizontal:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.dl-horizontal:after {
+  clear: both;
+}
+
+.dl-horizontal dt {
+  float: left;
+  width: 160px;
+  overflow: hidden;
+  clear: left;
+  text-align: right;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.dl-horizontal dd {
+  margin-left: 180px;
+}
+
+hr {
+  margin: 20px 0;
+  border: 0;
+  border-top: 1px solid #eeeeee;
+  border-bottom: 1px solid #ffffff;
+}
+
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #999999;
+}
+
+abbr.initialism {
+  font-size: 90%;
+  text-transform: uppercase;
+}
+
+blockquote {
+  padding: 0 0 0 15px;
+  margin: 0 0 20px;
+  border-left: 5px solid #eeeeee;
+}
+
+blockquote p {
+  margin-bottom: 0;
+  font-size: 17.5px;
+  font-weight: 300;
+  line-height: 1.25;
+}
+
+blockquote small {
+  display: block;
+  line-height: 20px;
+  color: #999999;
+}
+
+blockquote small:before {
+  content: '\2014 \00A0';
+}
+
+blockquote.pull-right {
+  float: right;
+  padding-right: 15px;
+  padding-left: 0;
+  border-right: 5px solid #eeeeee;
+  border-left: 0;
+}
+
+blockquote.pull-right p,
+blockquote.pull-right small {
+  text-align: right;
+}
+
+blockquote.pull-right small:before {
+  content: '';
+}
+
+blockquote.pull-right small:after {
+  content: '\00A0 \2014';
+}
+
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+  content: "";
+}
+
+address {
+  display: block;
+  margin-bottom: 20px;
+  font-style: normal;
+  line-height: 20px;
+}
+
+code,
+pre {
+  padding: 0 3px 2px;
+  font-family: Monaco, Menlo, Consolas, "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;
+  white-space: nowrap;
+  background-color: #f7f7f9;
+  border: 1px solid #e1e1e8;
+}
+
+pre {
+  display: block;
+  padding: 9.5px;
+  margin: 0 0 10px;
+  font-size: 13px;
+  line-height: 20px;
+  word-break: break-all;
+  word-wrap: break-word;
+  white-space: pre;
+  white-space: pre-wrap;
+  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;
+}
+
+pre.prettyprint {
+  margin-bottom: 20px;
+}
+
+pre code {
+  padding: 0;
+  color: inherit;
+  white-space: pre;
+  white-space: pre-wrap;
+  background-color: transparent;
+  border: 0;
+}
+
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll;
+}
+
+form {
+  margin: 0 0 20px;
+}
+
+fieldset {
+  padding: 0;
+  margin: 0;
+  border: 0;
+}
+
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: 20px;
+  font-size: 21px;
+  line-height: 40px;
+  color: #333333;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5;
+}
+
+legend small {
+  font-size: 15px;
+  color: #999999;
+}
+
+label,
+input,
+button,
+select,
+textarea {
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 20px;
+}
+
+input,
+button,
+select,
+textarea {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+
+label {
+  display: block;
+  margin-bottom: 5px;
+}
+
+select,
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="week"],
+input[type="number"],
+input[type="email"],
+input[type="url"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+.uneditable-input {
+  display: inline-block;
+  height: 20px;
+  padding: 4px 6px;
+  margin-bottom: 10px;
+  font-size: 14px;
+  line-height: 20px;
+  color: #555555;
+  vertical-align: middle;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+input,
+textarea,
+.uneditable-input {
+  width: 206px;
+}
+
+textarea {
+  height: auto;
+}
+
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="datetime"],
+input[type="datetime-local"],
+input[type="date"],
+input[type="month"],
+input[type="time"],
+input[type="week"],
+input[type="number"],
+input[type="email"],
+input[type="url"],
+input[type="search"],
+input[type="tel"],
+input[type="color"],
+.uneditable-input {
+  background-color: #ffffff;
+  border: 1px solid #cccccc;
+  -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;
+       -o-transition: border linear 0.2s, box-shadow linear 0.2s;
+          transition: border linear 0.2s, box-shadow linear 0.2s;
+}
+
+textarea:focus,
+input[type="text"]:focus,
+input[type="password"]:focus,
+input[type="datetime"]:focus,
+input[type="datetime-local"]:focus,
+input[type="date"]:focus,
+input[type="month"]:focus,
+input[type="time"]:focus,
+input[type="week"]:focus,
+input[type="number"]:focus,
+input[type="email"]:focus,
+input[type="url"]:focus,
+input[type="search"]:focus,
+input[type="tel"]:focus,
+input[type="color"]:focus,
+.uneditable-input:focus {
+  border-color: rgba(82, 168, 236, 0.8);
+  outline: 0;
+  outline: thin dotted \9;
+  /* IE6-9 */
+
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+}
+
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 4px 0 0;
+  margin-top: 1px \9;
+  *margin-top: 0;
+  line-height: normal;
+}
+
+input[type="file"],
+input[type="image"],
+input[type="submit"],
+input[type="reset"],
+input[type="button"],
+input[type="radio"],
+input[type="checkbox"] {
+  width: auto;
+}
+
+select,
+input[type="file"] {
+  height: 30px;
+  /* In IE7, the height of the select element cannot be changed by height, only font-size */
+
+  *margin-top: 4px;
+  /* For IE7, add top margin to align select with labels */
+
+  line-height: 30px;
+}
+
+select {
+  width: 220px;
+  background-color: #ffffff;
+  border: 1px solid #cccccc;
+}
+
+select[multiple],
+select[size] {
+  height: auto;
+}
+
+select:focus,
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  outline: thin dotted #333;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+
+.uneditable-input,
+.uneditable-textarea {
+  color: #999999;
+  cursor: not-allowed;
+  background-color: #fcfcfc;
+  border-color: #cccccc;
+  -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);
+}
+
+.uneditable-input {
+  overflow: hidden;
+  white-space: nowrap;
+}
+
+.uneditable-textarea {
+  width: auto;
+  height: auto;
+}
+
+input:-moz-placeholder,
+textarea:-moz-placeholder {
+  color: #999999;
+}
+
+input:-ms-input-placeholder,
+textarea:-ms-input-placeholder {
+  color: #999999;
+}
+
+input::-webkit-input-placeholder,
+textarea::-webkit-input-placeholder {
+  color: #999999;
+}
+
+.radio,
+.checkbox {
+  min-height: 20px;
+  padding-left: 20px;
+}
+
+.radio input[type="radio"],
+.checkbox input[type="checkbox"] {
+  float: left;
+  margin-left: -20px;
+}
+
+.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-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[class*="span"],
+.row-fluid input[class*="span"],
+.row-fluid select[class*="span"],
+.row-fluid textarea[class*="span"],
+.row-fluid .uneditable-input[class*="span"] {
+  float: none;
+  margin-left: 0;
+}
+
+.input-append input[class*="span"],
+.input-append .uneditable-input[class*="span"],
+.input-prepend input[class*="span"],
+.input-prepend .uneditable-input[class*="span"],
+.row-fluid input[class*="span"],
+.row-fluid select[class*="span"],
+.row-fluid textarea[class*="span"],
+.row-fluid .uneditable-input[class*="span"],
+.row-fluid .input-prepend [class*="span"],
+.row-fluid .input-append [class*="span"] {
+  display: inline-block;
+}
+
+input,
+textarea,
+.uneditable-input {
+  margin-left: 0;
+}
+
+.controls-row [class*="span"] + [class*="span"] {
+  margin-left: 20px;
+}
+
+input.span12,
+textarea.span12,
+.uneditable-input.span12 {
+  width: 926px;
+}
+
+input.span11,
+textarea.span11,
+.uneditable-input.span11 {
+  width: 846px;
+}
+
+input.span10,
+textarea.span10,
+.uneditable-input.span10 {
+  width: 766px;
+}
+
+input.span9,
+textarea.span9,
+.uneditable-input.span9 {
+  width: 686px;
+}
+
+input.span8,
+textarea.span8,
+.uneditable-input.span8 {
+  width: 606px;
+}
+
+input.span7,
+textarea.span7,
+.uneditable-input.span7 {
+  width: 526px;
+}
+
+input.span6,
+textarea.span6,
+.uneditable-input.span6 {
+  width: 446px;
+}
+
+input.span5,
+textarea.span5,
+.uneditable-input.span5 {
+  width: 366px;
+}
+
+input.span4,
+textarea.span4,
+.uneditable-input.span4 {
+  width: 286px;
+}
+
+input.span3,
+textarea.span3,
+.uneditable-input.span3 {
+  width: 206px;
+}
+
+input.span2,
+textarea.span2,
+.uneditable-input.span2 {
+  width: 126px;
+}
+
+input.span1,
+textarea.span1,
+.uneditable-input.span1 {
+  width: 46px;
+}
+
+.controls-row {
+  *zoom: 1;
+}
+
+.controls-row:before,
+.controls-row:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.controls-row:after {
+  clear: both;
+}
+
+.controls-row [class*="span"],
+.row-fluid .controls-row [class*="span"] {
+  float: left;
+}
+
+.controls-row .checkbox[class*="span"],
+.controls-row .radio[class*="span"] {
+  padding-top: 5px;
+}
+
+input[disabled],
+select[disabled],
+textarea[disabled],
+input[readonly],
+select[readonly],
+textarea[readonly] {
+  cursor: not-allowed;
+  background-color: #eeeeee;
+}
+
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"][readonly],
+input[type="checkbox"][readonly] {
+  background-color: transparent;
+}
+
+.control-group.warning .control-label,
+.control-group.warning .help-block,
+.control-group.warning .help-inline {
+  color: #c09853;
+}
+
+.control-group.warning .checkbox,
+.control-group.warning .radio,
+.control-group.warning input,
+.control-group.warning select,
+.control-group.warning textarea {
+  color: #c09853;
+}
+
+.control-group.warning input,
+.control-group.warning select,
+.control-group.warning textarea {
+  border-color: #c09853;
+  -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);
+}
+
+.control-group.warning input:focus,
+.control-group.warning select:focus,
+.control-group.warning textarea:focus {
+  border-color: #a47e3c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
+     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 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 .control-label,
+.control-group.error .help-block,
+.control-group.error .help-inline {
+  color: #b94a48;
+}
+
+.control-group.error .checkbox,
+.control-group.error .radio,
+.control-group.error input,
+.control-group.error select,
+.control-group.error textarea {
+  color: #b94a48;
+}
+
+.control-group.error input,
+.control-group.error select,
+.control-group.error textarea {
+  border-color: #b94a48;
+  -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);
+}
+
+.control-group.error input:focus,
+.control-group.error select:focus,
+.control-group.error textarea:focus {
+  border-color: #953b39;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
+     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 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 .control-label,
+.control-group.success .help-block,
+.control-group.success .help-inline {
+  color: #468847;
+}
+
+.control-group.success .checkbox,
+.control-group.success .radio,
+.control-group.success input,
+.control-group.success select,
+.control-group.success textarea {
+  color: #468847;
+}
+
+.control-group.success input,
+.control-group.success select,
+.control-group.success textarea {
+  border-color: #468847;
+  -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);
+}
+
+.control-group.success input:focus,
+.control-group.success select:focus,
+.control-group.success textarea:focus {
+  border-color: #356635;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
+     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 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;
+}
+
+.control-group.info .control-label,
+.control-group.info .help-block,
+.control-group.info .help-inline {
+  color: #3a87ad;
+}
+
+.control-group.info .checkbox,
+.control-group.info .radio,
+.control-group.info input,
+.control-group.info select,
+.control-group.info textarea {
+  color: #3a87ad;
+}
+
+.control-group.info input,
+.control-group.info select,
+.control-group.info textarea {
+  border-color: #3a87ad;
+  -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);
+}
+
+.control-group.info input:focus,
+.control-group.info select:focus,
+.control-group.info textarea:focus {
+  border-color: #2d6987;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
+     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3;
+}
+
+.control-group.info .input-prepend .add-on,
+.control-group.info .input-append .add-on {
+  color: #3a87ad;
+  background-color: #d9edf7;
+  border-color: #3a87ad;
+}
+
+input:focus:invalid,
+textarea:focus:invalid,
+select:focus:invalid {
+  color: #b94a48;
+  border-color: #ee5f5b;
+}
+
+input:focus:invalid:focus,
+textarea:focus:invalid:focus,
+select:focus: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: 19px 20px 20px;
+  margin-top: 20px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border-top: 1px solid #e5e5e5;
+  *zoom: 1;
+}
+
+.form-actions:before,
+.form-actions:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.form-actions:after {
+  clear: both;
+}
+
+.help-block,
+.help-inline {
+  color: #595959;
+}
+
+.help-block {
+  display: block;
+  margin-bottom: 10px;
+}
+
+.help-inline {
+  display: inline-block;
+  *display: inline;
+  padding-left: 5px;
+  vertical-align: middle;
+  *zoom: 1;
+}
+
+.input-append,
+.input-prepend {
+  display: inline-block;
+  margin-bottom: 10px;
+  font-size: 0;
+  white-space: nowrap;
+  vertical-align: middle;
+}
+
+.input-append input,
+.input-prepend input,
+.input-append select,
+.input-prepend select,
+.input-append .uneditable-input,
+.input-prepend .uneditable-input,
+.input-append .dropdown-menu,
+.input-prepend .dropdown-menu,
+.input-append .popover,
+.input-prepend .popover {
+  font-size: 14px;
+}
+
+.input-append input,
+.input-prepend input,
+.input-append select,
+.input-prepend select,
+.input-append .uneditable-input,
+.input-prepend .uneditable-input {
+  position: relative;
+  margin-bottom: 0;
+  *margin-left: 0;
+  vertical-align: top;
+  -webkit-border-radius: 0 4px 4px 0;
+     -moz-border-radius: 0 4px 4px 0;
+          border-radius: 0 4px 4px 0;
+}
+
+.input-append input:focus,
+.input-prepend input:focus,
+.input-append select:focus,
+.input-prepend select:focus,
+.input-append .uneditable-input:focus,
+.input-prepend .uneditable-input:focus {
+  z-index: 2;
+}
+
+.input-append .add-on,
+.input-prepend .add-on {
+  display: inline-block;
+  width: auto;
+  height: 20px;
+  min-width: 16px;
+  padding: 4px 5px;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 20px;
+  text-align: center;
+  text-shadow: 0 1px 0 #ffffff;
+  background-color: #eeeeee;
+  border: 1px solid #ccc;
+}
+
+.input-append .add-on,
+.input-prepend .add-on,
+.input-append .btn,
+.input-prepend .btn,
+.input-append .btn-group > .dropdown-toggle,
+.input-prepend .btn-group > .dropdown-toggle {
+  vertical-align: top;
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.input-append .active,
+.input-prepend .active {
+  background-color: #a9dba9;
+  border-color: #46a546;
+}
+
+.input-prepend .add-on,
+.input-prepend .btn {
+  margin-right: -1px;
+}
+
+.input-prepend .add-on:first-child,
+.input-prepend .btn:first-child {
+  -webkit-border-radius: 4px 0 0 4px;
+     -moz-border-radius: 4px 0 0 4px;
+          border-radius: 4px 0 0 4px;
+}
+
+.input-append input,
+.input-append select,
+.input-append .uneditable-input {
+  -webkit-border-radius: 4px 0 0 4px;
+     -moz-border-radius: 4px 0 0 4px;
+          border-radius: 4px 0 0 4px;
+}
+
+.input-append input + .btn-group .btn:last-child,
+.input-append select + .btn-group .btn:last-child,
+.input-append .uneditable-input + .btn-group .btn:last-child {
+  -webkit-border-radius: 0 4px 4px 0;
+     -moz-border-radius: 0 4px 4px 0;
+          border-radius: 0 4px 4px 0;
+}
+
+.input-append .add-on,
+.input-append .btn,
+.input-append .btn-group {
+  margin-left: -1px;
+}
+
+.input-append .add-on:last-child,
+.input-append .btn:last-child,
+.input-append .btn-group:last-child > .dropdown-toggle {
+  -webkit-border-radius: 0 4px 4px 0;
+     -moz-border-radius: 0 4px 4px 0;
+          border-radius: 0 4px 4px 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 input + .btn-group .btn,
+.input-prepend.input-append select + .btn-group .btn,
+.input-prepend.input-append .uneditable-input + .btn-group .btn {
+  -webkit-border-radius: 0 4px 4px 0;
+     -moz-border-radius: 0 4px 4px 0;
+          border-radius: 0 4px 4px 0;
+}
+
+.input-prepend.input-append .add-on:first-child,
+.input-prepend.input-append .btn:first-child {
+  margin-right: -1px;
+  -webkit-border-radius: 4px 0 0 4px;
+     -moz-border-radius: 4px 0 0 4px;
+          border-radius: 4px 0 0 4px;
+}
+
+.input-prepend.input-append .add-on:last-child,
+.input-prepend.input-append .btn:last-child {
+  margin-left: -1px;
+  -webkit-border-radius: 0 4px 4px 0;
+     -moz-border-radius: 0 4px 4px 0;
+          border-radius: 0 4px 4px 0;
+}
+
+.input-prepend.input-append .btn-group:first-child {
+  margin-left: 0;
+}
+
+input.search-query {
+  padding-right: 14px;
+  padding-right: 4px \9;
+  padding-left: 14px;
+  padding-left: 4px \9;
+  /* IE7-8 doesn't have border-radius, so don't indent the padding */
+
+  margin-bottom: 0;
+  -webkit-border-radius: 15px;
+     -moz-border-radius: 15px;
+          border-radius: 15px;
+}
+
+/* Allow for input prepend/append in search forms */
+
+.form-search .input-append .search-query,
+.form-search .input-prepend .search-query {
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.form-search .input-append .search-query {
+  -webkit-border-radius: 14px 0 0 14px;
+     -moz-border-radius: 14px 0 0 14px;
+          border-radius: 14px 0 0 14px;
+}
+
+.form-search .input-append .btn {
+  -webkit-border-radius: 0 14px 14px 0;
+     -moz-border-radius: 0 14px 14px 0;
+          border-radius: 0 14px 14px 0;
+}
+
+.form-search .input-prepend .search-query {
+  -webkit-border-radius: 0 14px 14px 0;
+     -moz-border-radius: 0 14px 14px 0;
+          border-radius: 0 14px 14px 0;
+}
+
+.form-search .input-prepend .btn {
+  -webkit-border-radius: 14px 0 0 14px;
+     -moz-border-radius: 14px 0 0 14px;
+          border-radius: 14px 0 0 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;
+  *display: inline;
+  margin-bottom: 0;
+  vertical-align: middle;
+  *zoom: 1;
+}
+
+.form-search .hide,
+.form-inline .hide,
+.form-horizontal .hide {
+  display: none;
+}
+
+.form-search label,
+.form-inline label,
+.form-search .btn-group,
+.form-inline .btn-group {
+  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-right: 3px;
+  margin-left: 0;
+}
+
+.control-group {
+  margin-bottom: 10px;
+}
+
+legend + .control-group {
+  margin-top: 20px;
+  -webkit-margin-top-collapse: separate;
+}
+
+.form-horizontal .control-group {
+  margin-bottom: 20px;
+  *zoom: 1;
+}
+
+.form-horizontal .control-group:before,
+.form-horizontal .control-group:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.form-horizontal .control-group:after {
+  clear: both;
+}
+
+.form-horizontal .control-label {
+  float: left;
+  width: 160px;
+  padding-top: 5px;
+  text-align: right;
+}
+
+.form-horizontal .controls {
+  *display: inline-block;
+  *padding-left: 20px;
+  margin-left: 180px;
+  *margin-left: 0;
+}
+
+.form-horizontal .controls:first-child {
+  *padding-left: 180px;
+}
+
+.form-horizontal .help-block {
+  margin-bottom: 0;
+}
+
+.form-horizontal input + .help-block,
+.form-horizontal select + .help-block,
+.form-horizontal textarea + .help-block,
+.form-horizontal .uneditable-input + .help-block,
+.form-horizontal .input-prepend + .help-block,
+.form-horizontal .input-append + .help-block {
+  margin-top: 10px;
+}
+
+.form-horizontal .form-actions {
+  padding-left: 180px;
+}
+
+table {
+  max-width: 100%;
+  background-color: transparent;
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+.table {
+  width: 100%;
+  margin-bottom: 20px;
+}
+
+.table th,
+.table td {
+  padding: 8px;
+  line-height: 20px;
+  text-align: left;
+  vertical-align: top;
+  border-top: 1px solid #dddddd;
+}
+
+.table th {
+  font-weight: bold;
+}
+
+.table thead th {
+  vertical-align: bottom;
+}
+
+.table caption + thead tr:first-child th,
+.table caption + thead tr:first-child td,
+.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 .table {
+  background-color: #ffffff;
+}
+
+.table-condensed th,
+.table-condensed td {
+  padding: 4px 5px;
+}
+
+.table-bordered {
+  border: 1px solid #dddddd;
+  border-collapse: separate;
+  *border-collapse: collapse;
+  border-left: 0;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+.table-bordered th,
+.table-bordered td {
+  border-left: 1px solid #dddddd;
+}
+
+.table-bordered caption + thead tr:first-child th,
+.table-bordered caption + tbody tr:first-child th,
+.table-bordered caption + tbody tr:first-child td,
+.table-bordered colgroup + thead tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child td,
+.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,
+.table-bordered tbody:first-child tr:first-child > th:first-child {
+  -webkit-border-top-left-radius: 4px;
+          border-top-left-radius: 4px;
+  -moz-border-radius-topleft: 4px;
+}
+
+.table-bordered thead:first-child tr:first-child > th:last-child,
+.table-bordered tbody:first-child tr:first-child > td:last-child,
+.table-bordered tbody:first-child tr:first-child > th:last-child {
+  -webkit-border-top-right-radius: 4px;
+          border-top-right-radius: 4px;
+  -moz-border-radius-topright: 4px;
+}
+
+.table-bordered thead:last-child tr:last-child > th:first-child,
+.table-bordered tbody:last-child tr:last-child > td:first-child,
+.table-bordered tbody:last-child tr:last-child > th:first-child,
+.table-bordered tfoot:last-child tr:last-child > td:first-child,
+.table-bordered tfoot:last-child tr:last-child > th:first-child {
+  -webkit-border-bottom-left-radius: 4px;
+          border-bottom-left-radius: 4px;
+  -moz-border-radius-bottomleft: 4px;
+}
+
+.table-bordered thead:last-child tr:last-child > th:last-child,
+.table-bordered tbody:last-child tr:last-child > td:last-child,
+.table-bordered tbody:last-child tr:last-child > th:last-child,
+.table-bordered tfoot:last-child tr:last-child > td:last-child,
+.table-bordered tfoot:last-child tr:last-child > th:last-child {
+  -webkit-border-bottom-right-radius: 4px;
+          border-bottom-right-radius: 4px;
+  -moz-border-radius-bottomright: 4px;
+}
+
+.table-bordered tfoot + tbody:last-child tr:last-child td:first-child {
+  -webkit-border-bottom-left-radius: 0;
+          border-bottom-left-radius: 0;
+  -moz-border-radius-bottomleft: 0;
+}
+
+.table-bordered tfoot + tbody:last-child tr:last-child td:last-child {
+  -webkit-border-bottom-right-radius: 0;
+          border-bottom-right-radius: 0;
+  -moz-border-radius-bottomright: 0;
+}
+
+.table-bordered caption + thead tr:first-child th:first-child,
+.table-bordered caption + tbody tr:first-child td:first-child,
+.table-bordered colgroup + thead tr:first-child th:first-child,
+.table-bordered colgroup + tbody tr:first-child td:first-child {
+  -webkit-border-top-left-radius: 4px;
+          border-top-left-radius: 4px;
+  -moz-border-radius-topleft: 4px;
+}
+
+.table-bordered caption + thead tr:first-child th:last-child,
+.table-bordered caption + tbody tr:first-child td:last-child,
+.table-bordered colgroup + thead tr:first-child th:last-child,
+.table-bordered colgroup + tbody tr:first-child td:last-child {
+  -webkit-border-top-right-radius: 4px;
+          border-top-right-radius: 4px;
+  -moz-border-radius-topright: 4px;
+}
+
+.table-striped tbody > tr:nth-child(odd) > td,
+.table-striped tbody > tr:nth-child(odd) > th {
+  background-color: #f9f9f9;
+}
+
+.table-hover tbody tr:hover > td,
+.table-hover tbody tr:hover > th {
+  background-color: #f5f5f5;
+}
+
+table td[class*="span"],
+table th[class*="span"],
+.row-fluid table td[class*="span"],
+.row-fluid table th[class*="span"] {
+  display: table-cell;
+  float: none;
+  margin-left: 0;
+}
+
+.table td.span1,
+.table th.span1 {
+  float: none;
+  width: 44px;
+  margin-left: 0;
+}
+
+.table td.span2,
+.table th.span2 {
+  float: none;
+  width: 124px;
+  margin-left: 0;
+}
+
+.table td.span3,
+.table th.span3 {
+  float: none;
+  width: 204px;
+  margin-left: 0;
+}
+
+.table td.span4,
+.table th.span4 {
+  float: none;
+  width: 284px;
+  margin-left: 0;
+}
+
+.table td.span5,
+.table th.span5 {
+  float: none;
+  width: 364px;
+  margin-left: 0;
+}
+
+.table td.span6,
+.table th.span6 {
+  float: none;
+  width: 444px;
+  margin-left: 0;
+}
+
+.table td.span7,
+.table th.span7 {
+  float: none;
+  width: 524px;
+  margin-left: 0;
+}
+
+.table td.span8,
+.table th.span8 {
+  float: none;
+  width: 604px;
+  margin-left: 0;
+}
+
+.table td.span9,
+.table th.span9 {
+  float: none;
+  width: 684px;
+  margin-left: 0;
+}
+
+.table td.span10,
+.table th.span10 {
+  float: none;
+  width: 764px;
+  margin-left: 0;
+}
+
+.table td.span11,
+.table th.span11 {
+  float: none;
+  width: 844px;
+  margin-left: 0;
+}
+
+.table td.span12,
+.table th.span12 {
+  float: none;
+  width: 924px;
+  margin-left: 0;
+}
+
+.table tbody tr.success > td {
+  background-color: #dff0d8;
+}
+
+.table tbody tr.error > td {
+  background-color: #f2dede;
+}
+
+.table tbody tr.warning > td {
+  background-color: #fcf8e3;
+}
+
+.table tbody tr.info > td {
+  background-color: #d9edf7;
+}
+
+.table-hover tbody tr.success:hover > td {
+  background-color: #d0e9c6;
+}
+
+.table-hover tbody tr.error:hover > td {
+  background-color: #ebcccc;
+}
+
+.table-hover tbody tr.warning:hover > td {
+  background-color: #faf2cc;
+}
+
+.table-hover tbody tr.info:hover > td {
+  background-color: #c4e3f3;
+}
+
+[class^="icon-"],
+[class*=" icon-"] {
+  display: inline-block;
+  width: 14px;
+  height: 14px;
+  margin-top: 1px;
+  *margin-right: .3em;
+  line-height: 14px;
+  vertical-align: text-top;
+  background-image: url("../img/glyphicons-halflings.png");
+  background-position: 14px 14px;
+  background-repeat: no-repeat;
+}
+
+/* White icons with optional class, or on hover/focus/active states of certain elements */
+
+.icon-white,
+.nav-pills > .active > a > [class^="icon-"],
+.nav-pills > .active > a > [class*=" icon-"],
+.nav-list > .active > a > [class^="icon-"],
+.nav-list > .active > a > [class*=" icon-"],
+.navbar-inverse .nav > .active > a > [class^="icon-"],
+.navbar-inverse .nav > .active > a > [class*=" icon-"],
+.dropdown-menu > li > a:hover > [class^="icon-"],
+.dropdown-menu > li > a:focus > [class^="icon-"],
+.dropdown-menu > li > a:hover > [class*=" icon-"],
+.dropdown-menu > li > a:focus > [class*=" icon-"],
+.dropdown-menu > .active > a > [class^="icon-"],
+.dropdown-menu > .active > a > [class*=" icon-"],
+.dropdown-submenu:hover > a > [class^="icon-"],
+.dropdown-submenu:focus > a > [class^="icon-"],
+.dropdown-submenu:hover > a > [class*=" icon-"],
+.dropdown-submenu:focus > a > [class*=" icon-"] {
+  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 {
+  width: 16px;
+  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 {
+  width: 16px;
+  background-position: -384px -120px;
+}
+
+.icon-folder-open {
+  width: 16px;
+  background-position: -408px -120px;
+}
+
+.icon-resize-vertical {
+  background-position: -432px -119px;
+}
+
+.icon-resize-horizontal {
+  background-position: -456px -118px;
+}
+
+.icon-hdd {
+  background-position: 0 -144px;
+}
+
+.icon-bullhorn {
+  background-position: -24px -144px;
+}
+
+.icon-bell {
+  background-position: -48px -144px;
+}
+
+.icon-certificate {
+  background-position: -72px -144px;
+}
+
+.icon-thumbs-up {
+  background-position: -96px -144px;
+}
+
+.icon-thumbs-down {
+  background-position: -120px -144px;
+}
+
+.icon-hand-right {
+  background-position: -144px -144px;
+}
+
+.icon-hand-left {
+  background-position: -168px -144px;
+}
+
+.icon-hand-up {
+  background-position: -192px -144px;
+}
+
+.icon-hand-down {
+  background-position: -216px -144px;
+}
+
+.icon-circle-arrow-right {
+  background-position: -240px -144px;
+}
+
+.icon-circle-arrow-left {
+  background-position: -264px -144px;
+}
+
+.icon-circle-arrow-up {
+  background-position: -288px -144px;
+}
+
+.icon-circle-arrow-down {
+  background-position: -312px -144px;
+}
+
+.icon-globe {
+  background-position: -336px -144px;
+}
+
+.icon-wrench {
+  background-position: -360px -144px;
+}
+
+.icon-tasks {
+  background-position: -384px -144px;
+}
+
+.icon-filter {
+  background-position: -408px -144px;
+}
+
+.icon-briefcase {
+  background-position: -432px -144px;
+}
+
+.icon-fullscreen {
+  background-position: -456px -144px;
+}
+
+.dropup,
+.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-top: 4px solid #000000;
+  border-right: 4px solid transparent;
+  border-left: 4px solid transparent;
+  content: "";
+}
+
+.dropdown .caret {
+  margin-top: 8px;
+  margin-left: 2px;
+}
+
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: 1000;
+  display: none;
+  float: left;
+  min-width: 160px;
+  padding: 5px 0;
+  margin: 2px 0 0;
+  list-style: none;
+  background-color: #ffffff;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  *border-right-width: 2px;
+  *border-bottom-width: 2px;
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+  -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;
+}
+
+.dropdown-menu.pull-right {
+  right: 0;
+  left: auto;
+}
+
+.dropdown-menu .divider {
+  *width: 100%;
+  height: 1px;
+  margin: 9px 1px;
+  *margin: -5px 0 5px;
+  overflow: hidden;
+  background-color: #e5e5e5;
+  border-bottom: 1px solid #ffffff;
+}
+
+.dropdown-menu > li > a {
+  display: block;
+  padding: 3px 20px;
+  clear: both;
+  font-weight: normal;
+  line-height: 20px;
+  color: #333333;
+  white-space: nowrap;
+}
+
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus,
+.dropdown-submenu:hover > a,
+.dropdown-submenu:focus > a {
+  color: #ffffff;
+  text-decoration: none;
+  background-color: #0081c2;
+  background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
+  background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
+  background-image: -o-linear-gradient(top, #0088cc, #0077b3);
+  background-image: linear-gradient(to bottom, #0088cc, #0077b3);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);
+}
+
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  color: #ffffff;
+  text-decoration: none;
+  background-color: #0081c2;
+  background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
+  background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
+  background-image: -o-linear-gradient(top, #0088cc, #0077b3);
+  background-image: linear-gradient(to bottom, #0088cc, #0077b3);
+  background-repeat: repeat-x;
+  outline: 0;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);
+}
+
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  color: #999999;
+}
+
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  text-decoration: none;
+  cursor: default;
+  background-color: transparent;
+  background-image: none;
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.open {
+  *z-index: 1000;
+}
+
+.open > .dropdown-menu {
+  display: block;
+}
+
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto;
+}
+
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+  border-top: 0;
+  border-bottom: 4px solid #000000;
+  content: "";
+}
+
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+  top: auto;
+  bottom: 100%;
+  margin-bottom: 1px;
+}
+
+.dropdown-submenu {
+  position: relative;
+}
+
+.dropdown-submenu > .dropdown-menu {
+  top: 0;
+  left: 100%;
+  margin-top: -6px;
+  margin-left: -1px;
+  -webkit-border-radius: 0 6px 6px 6px;
+     -moz-border-radius: 0 6px 6px 6px;
+          border-radius: 0 6px 6px 6px;
+}
+
+.dropdown-submenu:hover > .dropdown-menu {
+  display: block;
+}
+
+.dropup .dropdown-submenu > .dropdown-menu {
+  top: auto;
+  bottom: 0;
+  margin-top: 0;
+  margin-bottom: -2px;
+  -webkit-border-radius: 5px 5px 5px 0;
+     -moz-border-radius: 5px 5px 5px 0;
+          border-radius: 5px 5px 5px 0;
+}
+
+.dropdown-submenu > a:after {
+  display: block;
+  float: right;
+  width: 0;
+  height: 0;
+  margin-top: 5px;
+  margin-right: -10px;
+  border-color: transparent;
+  border-left-color: #cccccc;
+  border-style: solid;
+  border-width: 5px 0 5px 5px;
+  content: " ";
+}
+
+.dropdown-submenu:hover > a:after {
+  border-left-color: #ffffff;
+}
+
+.dropdown-submenu.pull-left {
+  float: none;
+}
+
+.dropdown-submenu.pull-left > .dropdown-menu {
+  left: -100%;
+  margin-left: 10px;
+  -webkit-border-radius: 6px 0 6px 6px;
+     -moz-border-radius: 6px 0 6px 6px;
+          border-radius: 6px 0 6px 6px;
+}
+
+.dropdown .dropdown-menu .nav-header {
+  padding-right: 20px;
+  padding-left: 20px;
+}
+
+.typeahead {
+  z-index: 1051;
+  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 #e3e3e3;
+  -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 {
+  opacity: 0;
+  -webkit-transition: opacity 0.15s linear;
+     -moz-transition: opacity 0.15s linear;
+       -o-transition: opacity 0.15s linear;
+          transition: opacity 0.15s linear;
+}
+
+.fade.in {
+  opacity: 1;
+}
+
+.collapse {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  -webkit-transition: height 0.35s ease;
+     -moz-transition: height 0.35s ease;
+       -o-transition: height 0.35s ease;
+          transition: height 0.35s ease;
+}
+
+.collapse.in {
+  height: auto;
+}
+
+.close {
+  float: right;
+  font-size: 20px;
+  font-weight: bold;
+  line-height: 20px;
+  color: #000000;
+  text-shadow: 0 1px 0 #ffffff;
+  opacity: 0.2;
+  filter: alpha(opacity=20);
+}
+
+.close:hover,
+.close:focus {
+  color: #000000;
+  text-decoration: none;
+  cursor: pointer;
+  opacity: 0.4;
+  filter: alpha(opacity=40);
+}
+
+button.close {
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+  -webkit-appearance: none;
+}
+
+.btn {
+  display: inline-block;
+  *display: inline;
+  padding: 4px 12px;
+  margin-bottom: 0;
+  *margin-left: .3em;
+  font-size: 14px;
+  line-height: 20px;
+  color: #333333;
+  text-align: center;
+  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+  vertical-align: middle;
+  cursor: pointer;
+  background-color: #f5f5f5;
+  *background-color: #e6e6e6;
+  background-image: -moz-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(to bottom, #ffffff, #e6e6e6);
+  background-repeat: repeat-x;
+  border: 1px solid #cccccc;
+  *border: 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);
+  border-bottom-color: #b3b3b3;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+  *zoom: 1;
+  -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);
+}
+
+.btn:hover,
+.btn:focus,
+.btn:active,
+.btn.active,
+.btn.disabled,
+.btn[disabled] {
+  color: #333333;
+  background-color: #e6e6e6;
+  *background-color: #d9d9d9;
+}
+
+.btn:active,
+.btn.active {
+  background-color: #cccccc \9;
+}
+
+.btn:first-child {
+  *margin-left: 0;
+}
+
+.btn:hover,
+.btn:focus {
+  color: #333333;
+  text-decoration: none;
+  background-position: 0 -15px;
+  -webkit-transition: background-position 0.1s linear;
+     -moz-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;
+  outline: 0;
+  -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);
+}
+
+.btn.disabled,
+.btn[disabled] {
+  cursor: default;
+  background-image: none;
+  opacity: 0.65;
+  filter: alpha(opacity=65);
+  -webkit-box-shadow: none;
+     -moz-box-shadow: none;
+          box-shadow: none;
+}
+
+.btn-large {
+  padding: 11px 19px;
+  font-size: 17.5px;
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+}
+
+.btn-large [class^="icon-"],
+.btn-large [class*=" icon-"] {
+  margin-top: 4px;
+}
+
+.btn-small {
+  padding: 2px 10px;
+  font-size: 11.9px;
+  -webkit-border-radius: 3px;
+     -moz-border-radius: 3px;
+          border-radius: 3px;
+}
+
+.btn-small [class^="icon-"],
+.btn-small [class*=" icon-"] {
+  margin-top: 0;
+}
+
+.btn-mini [class^="icon-"],
+.btn-mini [class*=" icon-"] {
+  margin-top: -1px;
+}
+
+.btn-mini {
+  padding: 0 6px;
+  font-size: 10.5px;
+  -webkit-border-radius: 3px;
+     -moz-border-radius: 3px;
+          border-radius: 3px;
+}
+
+.btn-block {
+  display: block;
+  width: 100%;
+  padding-right: 0;
+  padding-left: 0;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.btn-block + .btn-block {
+  margin-top: 5px;
+}
+
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+  width: 100%;
+}
+
+.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 {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #006dcc;
+  *background-color: #0044cc;
+  background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
+  background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
+  background-image: -o-linear-gradient(top, #0088cc, #0044cc);
+  background-image: linear-gradient(to bottom, #0088cc, #0044cc);
+  background-repeat: repeat-x;
+  border-color: #0044cc #0044cc #002a80;
+  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(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-primary:hover,
+.btn-primary:focus,
+.btn-primary:active,
+.btn-primary.active,
+.btn-primary.disabled,
+.btn-primary[disabled] {
+  color: #ffffff;
+  background-color: #0044cc;
+  *background-color: #003bb3;
+}
+
+.btn-primary:active,
+.btn-primary.active {
+  background-color: #003399 \9;
+}
+
+.btn-warning {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #faa732;
+  *background-color: #f89406;
+  background-image: -moz-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(to bottom, #fbb450, #f89406);
+  background-repeat: repeat-x;
+  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(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-warning:hover,
+.btn-warning:focus,
+.btn-warning:active,
+.btn-warning.active,
+.btn-warning.disabled,
+.btn-warning[disabled] {
+  color: #ffffff;
+  background-color: #f89406;
+  *background-color: #df8505;
+}
+
+.btn-warning:active,
+.btn-warning.active {
+  background-color: #c67605 \9;
+}
+
+.btn-danger {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #da4f49;
+  *background-color: #bd362f;
+  background-image: -moz-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(to bottom, #ee5f5b, #bd362f);
+  background-repeat: repeat-x;
+  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(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-danger:hover,
+.btn-danger:focus,
+.btn-danger:active,
+.btn-danger.active,
+.btn-danger.disabled,
+.btn-danger[disabled] {
+  color: #ffffff;
+  background-color: #bd362f;
+  *background-color: #a9302a;
+}
+
+.btn-danger:active,
+.btn-danger.active {
+  background-color: #942a25 \9;
+}
+
+.btn-success {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #5bb75b;
+  *background-color: #51a351;
+  background-image: -moz-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(to bottom, #62c462, #51a351);
+  background-repeat: repeat-x;
+  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(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-success:hover,
+.btn-success:focus,
+.btn-success:active,
+.btn-success.active,
+.btn-success.disabled,
+.btn-success[disabled] {
+  color: #ffffff;
+  background-color: #51a351;
+  *background-color: #499249;
+}
+
+.btn-success:active,
+.btn-success.active {
+  background-color: #408140 \9;
+}
+
+.btn-info {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #49afcd;
+  *background-color: #2f96b4;
+  background-image: -moz-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(to bottom, #5bc0de, #2f96b4);
+  background-repeat: repeat-x;
+  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(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-info:hover,
+.btn-info:focus,
+.btn-info:active,
+.btn-info.active,
+.btn-info.disabled,
+.btn-info[disabled] {
+  color: #ffffff;
+  background-color: #2f96b4;
+  *background-color: #2a85a0;
+}
+
+.btn-info:active,
+.btn-info.active {
+  background-color: #24748c \9;
+}
+
+.btn-inverse {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #363636;
+  *background-color: #222222;
+  background-image: -moz-linear-gradient(top, #444444, #222222);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));
+  background-image: -webkit-linear-gradient(top, #444444, #222222);
+  background-image: -o-linear-gradient(top, #444444, #222222);
+  background-image: linear-gradient(to bottom, #444444, #222222);
+  background-repeat: repeat-x;
+  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(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.btn-inverse:hover,
+.btn-inverse:focus,
+.btn-inverse:active,
+.btn-inverse.active,
+.btn-inverse.disabled,
+.btn-inverse[disabled] {
+  color: #ffffff;
+  background-color: #222222;
+  *background-color: #151515;
+}
+
+.btn-inverse:active,
+.btn-inverse.active {
+  background-color: #080808 \9;
+}
+
+button.btn,
+input[type="submit"].btn {
+  *padding-top: 3px;
+  *padding-bottom: 3px;
+}
+
+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-link,
+.btn-link:active,
+.btn-link[disabled] {
+  background-color: transparent;
+  background-image: none;
+  -webkit-box-shadow: none;
+     -moz-box-shadow: none;
+          box-shadow: none;
+}
+
+.btn-link {
+  color: #0088cc;
+  cursor: pointer;
+  border-color: transparent;
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.btn-link:hover,
+.btn-link:focus {
+  color: #005580;
+  text-decoration: underline;
+  background-color: transparent;
+}
+
+.btn-link[disabled]:hover,
+.btn-link[disabled]:focus {
+  color: #333333;
+  text-decoration: none;
+}
+
+.btn-group {
+  position: relative;
+  display: inline-block;
+  *display: inline;
+  *margin-left: .3em;
+  font-size: 0;
+  white-space: nowrap;
+  vertical-align: middle;
+  *zoom: 1;
+}
+
+.btn-group:first-child {
+  *margin-left: 0;
+}
+
+.btn-group + .btn-group {
+  margin-left: 5px;
+}
+
+.btn-toolbar {
+  margin-top: 10px;
+  margin-bottom: 10px;
+  font-size: 0;
+}
+
+.btn-toolbar > .btn + .btn,
+.btn-toolbar > .btn-group + .btn,
+.btn-toolbar > .btn + .btn-group {
+  margin-left: 5px;
+}
+
+.btn-group > .btn {
+  position: relative;
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.btn-group > .btn + .btn {
+  margin-left: -1px;
+}
+
+.btn-group > .btn,
+.btn-group > .dropdown-menu,
+.btn-group > .popover {
+  font-size: 14px;
+}
+
+.btn-group > .btn-mini {
+  font-size: 10.5px;
+}
+
+.btn-group > .btn-small {
+  font-size: 11.9px;
+}
+
+.btn-group > .btn-large {
+  font-size: 17.5px;
+}
+
+.btn-group > .btn:first-child {
+  margin-left: 0;
+  -webkit-border-bottom-left-radius: 4px;
+          border-bottom-left-radius: 4px;
+  -webkit-border-top-left-radius: 4px;
+          border-top-left-radius: 4px;
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-topleft: 4px;
+}
+
+.btn-group > .btn:last-child,
+.btn-group > .dropdown-toggle {
+  -webkit-border-top-right-radius: 4px;
+          border-top-right-radius: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+          border-bottom-right-radius: 4px;
+  -moz-border-radius-topright: 4px;
+  -moz-border-radius-bottomright: 4px;
+}
+
+.btn-group > .btn.large:first-child {
+  margin-left: 0;
+  -webkit-border-bottom-left-radius: 6px;
+          border-bottom-left-radius: 6px;
+  -webkit-border-top-left-radius: 6px;
+          border-top-left-radius: 6px;
+  -moz-border-radius-bottomleft: 6px;
+  -moz-border-radius-topleft: 6px;
+}
+
+.btn-group > .btn.large:last-child,
+.btn-group > .large.dropdown-toggle {
+  -webkit-border-top-right-radius: 6px;
+          border-top-right-radius: 6px;
+  -webkit-border-bottom-right-radius: 6px;
+          border-bottom-right-radius: 6px;
+  -moz-border-radius-topright: 6px;
+  -moz-border-radius-bottomright: 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 > .btn + .dropdown-toggle {
+  *padding-top: 5px;
+  padding-right: 8px;
+  *padding-bottom: 5px;
+  padding-left: 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);
+}
+
+.btn-group > .btn-mini + .dropdown-toggle {
+  *padding-top: 2px;
+  padding-right: 5px;
+  *padding-bottom: 2px;
+  padding-left: 5px;
+}
+
+.btn-group > .btn-small + .dropdown-toggle {
+  *padding-top: 5px;
+  *padding-bottom: 4px;
+}
+
+.btn-group > .btn-large + .dropdown-toggle {
+  *padding-top: 7px;
+  padding-right: 12px;
+  *padding-bottom: 7px;
+  padding-left: 12px;
+}
+
+.btn-group.open .dropdown-toggle {
+  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);
+}
+
+.btn-group.open .btn.dropdown-toggle {
+  background-color: #e6e6e6;
+}
+
+.btn-group.open .btn-primary.dropdown-toggle {
+  background-color: #0044cc;
+}
+
+.btn-group.open .btn-warning.dropdown-toggle {
+  background-color: #f89406;
+}
+
+.btn-group.open .btn-danger.dropdown-toggle {
+  background-color: #bd362f;
+}
+
+.btn-group.open .btn-success.dropdown-toggle {
+  background-color: #51a351;
+}
+
+.btn-group.open .btn-info.dropdown-toggle {
+  background-color: #2f96b4;
+}
+
+.btn-group.open .btn-inverse.dropdown-toggle {
+  background-color: #222222;
+}
+
+.btn .caret {
+  margin-top: 8px;
+  margin-left: 0;
+}
+
+.btn-large .caret {
+  margin-top: 6px;
+}
+
+.btn-large .caret {
+  border-top-width: 5px;
+  border-right-width: 5px;
+  border-left-width: 5px;
+}
+
+.btn-mini .caret,
+.btn-small .caret {
+  margin-top: 8px;
+}
+
+.dropup .btn-large .caret {
+  border-bottom-width: 5px;
+}
+
+.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;
+}
+
+.btn-group-vertical {
+  display: inline-block;
+  *display: inline;
+  /* IE7 inline-block hack */
+
+  *zoom: 1;
+}
+
+.btn-group-vertical > .btn {
+  display: block;
+  float: none;
+  max-width: 100%;
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.btn-group-vertical > .btn + .btn {
+  margin-top: -1px;
+  margin-left: 0;
+}
+
+.btn-group-vertical > .btn:first-child {
+  -webkit-border-radius: 4px 4px 0 0;
+     -moz-border-radius: 4px 4px 0 0;
+          border-radius: 4px 4px 0 0;
+}
+
+.btn-group-vertical > .btn:last-child {
+  -webkit-border-radius: 0 0 4px 4px;
+     -moz-border-radius: 0 0 4px 4px;
+          border-radius: 0 0 4px 4px;
+}
+
+.btn-group-vertical > .btn-large:first-child {
+  -webkit-border-radius: 6px 6px 0 0;
+     -moz-border-radius: 6px 6px 0 0;
+          border-radius: 6px 6px 0 0;
+}
+
+.btn-group-vertical > .btn-large:last-child {
+  -webkit-border-radius: 0 0 6px 6px;
+     -moz-border-radius: 0 0 6px 6px;
+          border-radius: 0 0 6px 6px;
+}
+
+.alert {
+  padding: 8px 35px 8px 14px;
+  margin-bottom: 20px;
+  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;
+}
+
+.alert,
+.alert h4 {
+  color: #c09853;
+}
+
+.alert h4 {
+  margin: 0;
+}
+
+.alert .close {
+  position: relative;
+  top: -2px;
+  right: -21px;
+  line-height: 20px;
+}
+
+.alert-success {
+  color: #468847;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+}
+
+.alert-success h4 {
+  color: #468847;
+}
+
+.alert-danger,
+.alert-error {
+  color: #b94a48;
+  background-color: #f2dede;
+  border-color: #eed3d7;
+}
+
+.alert-danger h4,
+.alert-error h4 {
+  color: #b94a48;
+}
+
+.alert-info {
+  color: #3a87ad;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+}
+
+.alert-info h4 {
+  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-bottom: 20px;
+  margin-left: 0;
+  list-style: none;
+}
+
+.nav > li > a {
+  display: block;
+}
+
+.nav > li > a:hover,
+.nav > li > a:focus {
+  text-decoration: none;
+  background-color: #eeeeee;
+}
+
+.nav > li > a > img {
+  max-width: none;
+}
+
+.nav > .pull-right {
+  float: right;
+}
+
+.nav-header {
+  display: block;
+  padding: 3px 15px;
+  font-size: 11px;
+  font-weight: bold;
+  line-height: 20px;
+  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-right: 15px;
+  padding-left: 15px;
+  margin-bottom: 0;
+}
+
+.nav-list > li > a,
+.nav-list .nav-header {
+  margin-right: -15px;
+  margin-left: -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,
+.nav-list > .active > a:focus {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
+  background-color: #0088cc;
+}
+
+.nav-list [class^="icon-"],
+.nav-list [class*=" icon-"] {
+  margin-right: 2px;
+}
+
+.nav-list .divider {
+  *width: 100%;
+  height: 1px;
+  margin: 9px 1px;
+  *margin: -5px 0 5px;
+  overflow: hidden;
+  background-color: #e5e5e5;
+  border-bottom: 1px solid #ffffff;
+}
+
+.nav-tabs,
+.nav-pills {
+  *zoom: 1;
+}
+
+.nav-tabs:before,
+.nav-pills:before,
+.nav-tabs:after,
+.nav-pills:after {
+  display: table;
+  line-height: 0;
+  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: 20px;
+  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,
+.nav-tabs > li > a:focus {
+  border-color: #eeeeee #eeeeee #dddddd;
+}
+
+.nav-tabs > .active > a,
+.nav-tabs > .active > a:hover,
+.nav-tabs > .active > a:focus {
+  color: #555555;
+  cursor: default;
+  background-color: #ffffff;
+  border: 1px solid #ddd;
+  border-bottom-color: transparent;
+}
+
+.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,
+.nav-pills > .active > a:focus {
+  color: #ffffff;
+  background-color: #0088cc;
+}
+
+.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-top-right-radius: 4px;
+          border-top-right-radius: 4px;
+  -webkit-border-top-left-radius: 4px;
+          border-top-left-radius: 4px;
+  -moz-border-radius-topright: 4px;
+  -moz-border-radius-topleft: 4px;
+}
+
+.nav-tabs.nav-stacked > li:last-child > a {
+  -webkit-border-bottom-right-radius: 4px;
+          border-bottom-right-radius: 4px;
+  -webkit-border-bottom-left-radius: 4px;
+          border-bottom-left-radius: 4px;
+  -moz-border-radius-bottomright: 4px;
+  -moz-border-radius-bottomleft: 4px;
+}
+
+.nav-tabs.nav-stacked > li > a:hover,
+.nav-tabs.nav-stacked > li > a:focus {
+  z-index: 2;
+  border-color: #ddd;
+}
+
+.nav-pills.nav-stacked > li > a {
+  margin-bottom: 3px;
+}
+
+.nav-pills.nav-stacked > li:last-child > a {
+  margin-bottom: 1px;
+}
+
+.nav-tabs .dropdown-menu {
+  -webkit-border-radius: 0 0 6px 6px;
+     -moz-border-radius: 0 0 6px 6px;
+          border-radius: 0 0 6px 6px;
+}
+
+.nav-pills .dropdown-menu {
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+}
+
+.nav .dropdown-toggle .caret {
+  margin-top: 6px;
+  border-top-color: #0088cc;
+  border-bottom-color: #0088cc;
+}
+
+.nav .dropdown-toggle:hover .caret,
+.nav .dropdown-toggle:focus .caret {
+  border-top-color: #005580;
+  border-bottom-color: #005580;
+}
+
+/* move down carets for tabs */
+
+.nav-tabs .dropdown-toggle .caret {
+  margin-top: 8px;
+}
+
+.nav .active .dropdown-toggle .caret {
+  border-top-color: #fff;
+  border-bottom-color: #fff;
+}
+
+.nav-tabs .active .dropdown-toggle .caret {
+  border-top-color: #555555;
+  border-bottom-color: #555555;
+}
+
+.nav > .dropdown.active > a:hover,
+.nav > .dropdown.active > a:focus {
+  cursor: pointer;
+}
+
+.nav-tabs .open .dropdown-toggle,
+.nav-pills .open .dropdown-toggle,
+.nav > li.dropdown.open.active > a:hover,
+.nav > li.dropdown.open.active > a:focus {
+  color: #ffffff;
+  background-color: #999999;
+  border-color: #999999;
+}
+
+.nav li.dropdown.open .caret,
+.nav li.dropdown.open.active .caret,
+.nav li.dropdown.open a:hover .caret,
+.nav li.dropdown.open a:focus .caret {
+  border-top-color: #ffffff;
+  border-bottom-color: #ffffff;
+  opacity: 1;
+  filter: alpha(opacity=100);
+}
+
+.tabs-stacked .open > a:hover,
+.tabs-stacked .open > a:focus {
+  border-color: #999999;
+}
+
+.tabbable {
+  *zoom: 1;
+}
+
+.tabbable:before,
+.tabbable:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.tabbable:after {
+  clear: both;
+}
+
+.tab-content {
+  overflow: auto;
+}
+
+.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,
+.tabs-below > .nav-tabs > li > a:focus {
+  border-top-color: #ddd;
+  border-bottom-color: transparent;
+}
+
+.tabs-below > .nav-tabs > .active > a,
+.tabs-below > .nav-tabs > .active > a:hover,
+.tabs-below > .nav-tabs > .active > a:focus {
+  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,
+.tabs-left > .nav-tabs > li > a:focus {
+  border-color: #eeeeee #dddddd #eeeeee #eeeeee;
+}
+
+.tabs-left > .nav-tabs .active > a,
+.tabs-left > .nav-tabs .active > a:hover,
+.tabs-left > .nav-tabs .active > a:focus {
+  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,
+.tabs-right > .nav-tabs > li > a:focus {
+  border-color: #eeeeee #eeeeee #eeeeee #dddddd;
+}
+
+.tabs-right > .nav-tabs .active > a,
+.tabs-right > .nav-tabs .active > a:hover,
+.tabs-right > .nav-tabs .active > a:focus {
+  border-color: #ddd #ddd #ddd transparent;
+  *border-left-color: #ffffff;
+}
+
+.nav > .disabled > a {
+  color: #999999;
+}
+
+.nav > .disabled > a:hover,
+.nav > .disabled > a:focus {
+  text-decoration: none;
+  cursor: default;
+  background-color: transparent;
+}
+
+.navbar {
+  *position: relative;
+  *z-index: 2;
+  margin-bottom: 20px;
+  overflow: visible;
+}
+
+.navbar-inner {
+  min-height: 40px;
+  padding-right: 20px;
+  padding-left: 20px;
+  background-color: #fafafa;
+  background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));
+  background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2);
+  background-image: -o-linear-gradient(top, #ffffff, #f2f2f2);
+  background-image: linear-gradient(to bottom, #ffffff, #f2f2f2);
+  background-repeat: repeat-x;
+  border: 1px solid #d4d4d4;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);
+  *zoom: 1;
+  -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
+     -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
+          box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
+}
+
+.navbar-inner:before,
+.navbar-inner:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.navbar-inner:after {
+  clear: both;
+}
+
+.navbar .container {
+  width: auto;
+}
+
+.nav-collapse.collapse {
+  height: auto;
+  overflow: visible;
+}
+
+.navbar .brand {
+  display: block;
+  float: left;
+  padding: 10px 20px 10px;
+  margin-left: -20px;
+  font-size: 20px;
+  font-weight: 200;
+  color: #777777;
+  text-shadow: 0 1px 0 #ffffff;
+}
+
+.navbar .brand:hover,
+.navbar .brand:focus {
+  text-decoration: none;
+}
+
+.navbar-text {
+  margin-bottom: 0;
+  line-height: 40px;
+  color: #777777;
+}
+
+.navbar-link {
+  color: #777777;
+}
+
+.navbar-link:hover,
+.navbar-link:focus {
+  color: #333333;
+}
+
+.navbar .divider-vertical {
+  height: 40px;
+  margin: 0 9px;
+  border-right: 1px solid #ffffff;
+  border-left: 1px solid #f2f2f2;
+}
+
+.navbar .btn,
+.navbar .btn-group {
+  margin-top: 5px;
+}
+
+.navbar .btn-group .btn,
+.navbar .input-prepend .btn,
+.navbar .input-append .btn,
+.navbar .input-prepend .btn-group,
+.navbar .input-append .btn-group {
+  margin-top: 0;
+}
+
+.navbar-form {
+  margin-bottom: 0;
+  *zoom: 1;
+}
+
+.navbar-form:before,
+.navbar-form:after {
+  display: table;
+  line-height: 0;
+  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,
+.navbar-form .btn {
+  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: 5px;
+  white-space: nowrap;
+}
+
+.navbar-form .input-append input,
+.navbar-form .input-prepend input {
+  margin-top: 0;
+}
+
+.navbar-search {
+  position: relative;
+  float: left;
+  margin-top: 5px;
+  margin-bottom: 0;
+}
+
+.navbar-search .search-query {
+  padding: 4px 14px;
+  margin-bottom: 0;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 13px;
+  font-weight: normal;
+  line-height: 1;
+  -webkit-border-radius: 15px;
+     -moz-border-radius: 15px;
+          border-radius: 15px;
+}
+
+.navbar-static-top {
+  position: static;
+  margin-bottom: 0;
+}
+
+.navbar-static-top .navbar-inner {
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 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-static-top .navbar-inner {
+  border-width: 0 0 1px;
+}
+
+.navbar-fixed-bottom .navbar-inner {
+  border-width: 1px 0 0;
+}
+
+.navbar-fixed-top .navbar-inner,
+.navbar-fixed-bottom .navbar-inner {
+  padding-right: 0;
+  padding-left: 0;
+  -webkit-border-radius: 0;
+     -moz-border-radius: 0;
+          border-radius: 0;
+}
+
+.navbar-static-top .container,
+.navbar-fixed-top .container,
+.navbar-fixed-bottom .container {
+  width: 940px;
+}
+
+.navbar-fixed-top {
+  top: 0;
+}
+
+.navbar-fixed-top .navbar-inner,
+.navbar-static-top .navbar-inner {
+  -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
+     -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
+          box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
+}
+
+.navbar-fixed-bottom {
+  bottom: 0;
+}
+
+.navbar-fixed-bottom .navbar-inner {
+  -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
+     -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
+          box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
+}
+
+.navbar .nav {
+  position: relative;
+  left: 0;
+  display: block;
+  float: left;
+  margin: 0 10px 0 0;
+}
+
+.navbar .nav.pull-right {
+  float: right;
+  margin-right: 0;
+}
+
+.navbar .nav > li {
+  float: left;
+}
+
+.navbar .nav > li > a {
+  float: none;
+  padding: 10px 15px 10px;
+  color: #777777;
+  text-decoration: none;
+  text-shadow: 0 1px 0 #ffffff;
+}
+
+.navbar .nav .dropdown-toggle .caret {
+  margin-top: 8px;
+}
+
+.navbar .nav > li > a:focus,
+.navbar .nav > li > a:hover {
+  color: #333333;
+  text-decoration: none;
+  background-color: transparent;
+}
+
+.navbar .nav > .active > a,
+.navbar .nav > .active > a:hover,
+.navbar .nav > .active > a:focus {
+  color: #555555;
+  text-decoration: none;
+  background-color: #e5e5e5;
+  -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+     -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+          box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+}
+
+.navbar .btn-navbar {
+  display: none;
+  float: right;
+  padding: 7px 10px;
+  margin-right: 5px;
+  margin-left: 5px;
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #ededed;
+  *background-color: #e5e5e5;
+  background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));
+  background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5);
+  background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5);
+  background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5);
+  background-repeat: repeat-x;
+  border-color: #e5e5e5 #e5e5e5 #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(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);
+  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);
+}
+
+.navbar .btn-navbar:hover,
+.navbar .btn-navbar:focus,
+.navbar .btn-navbar:active,
+.navbar .btn-navbar.active,
+.navbar .btn-navbar.disabled,
+.navbar .btn-navbar[disabled] {
+  color: #ffffff;
+  background-color: #e5e5e5;
+  *background-color: #d9d9d9;
+}
+
+.navbar .btn-navbar:active,
+.navbar .btn-navbar.active {
+  background-color: #cccccc \9;
+}
+
+.navbar .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;
+}
+
+.navbar .nav > li > .dropdown-menu:before {
+  position: absolute;
+  top: -7px;
+  left: 9px;
+  display: inline-block;
+  border-right: 7px solid transparent;
+  border-bottom: 7px solid #ccc;
+  border-left: 7px solid transparent;
+  border-bottom-color: rgba(0, 0, 0, 0.2);
+  content: '';
+}
+
+.navbar .nav > li > .dropdown-menu:after {
+  position: absolute;
+  top: -6px;
+  left: 10px;
+  display: inline-block;
+  border-right: 6px solid transparent;
+  border-bottom: 6px solid #ffffff;
+  border-left: 6px solid transparent;
+  content: '';
+}
+
+.navbar-fixed-bottom .nav > li > .dropdown-menu:before {
+  top: auto;
+  bottom: -7px;
+  border-top: 7px solid #ccc;
+  border-bottom: 0;
+  border-top-color: rgba(0, 0, 0, 0.2);
+}
+
+.navbar-fixed-bottom .nav > li > .dropdown-menu:after {
+  top: auto;
+  bottom: -6px;
+  border-top: 6px solid #ffffff;
+  border-bottom: 0;
+}
+
+.navbar .nav li.dropdown > a:hover .caret,
+.navbar .nav li.dropdown > a:focus .caret {
+  border-top-color: #333333;
+  border-bottom-color: #333333;
+}
+
+.navbar .nav li.dropdown.open > .dropdown-toggle,
+.navbar .nav li.dropdown.active > .dropdown-toggle,
+.navbar .nav li.dropdown.open.active > .dropdown-toggle {
+  color: #555555;
+  background-color: #e5e5e5;
+}
+
+.navbar .nav li.dropdown > .dropdown-toggle .caret {
+  border-top-color: #777777;
+  border-bottom-color: #777777;
+}
+
+.navbar .nav li.dropdown.open > .dropdown-toggle .caret,
+.navbar .nav li.dropdown.active > .dropdown-toggle .caret,
+.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret {
+  border-top-color: #555555;
+  border-bottom-color: #555555;
+}
+
+.navbar .pull-right > li > .dropdown-menu,
+.navbar .nav > li > .dropdown-menu.pull-right {
+  right: 0;
+  left: auto;
+}
+
+.navbar .pull-right > li > .dropdown-menu:before,
+.navbar .nav > li > .dropdown-menu.pull-right:before {
+  right: 12px;
+  left: auto;
+}
+
+.navbar .pull-right > li > .dropdown-menu:after,
+.navbar .nav > li > .dropdown-menu.pull-right:after {
+  right: 13px;
+  left: auto;
+}
+
+.navbar .pull-right > li > .dropdown-menu .dropdown-menu,
+.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu {
+  right: 100%;
+  left: auto;
+  margin-right: -1px;
+  margin-left: 0;
+  -webkit-border-radius: 6px 0 6px 6px;
+     -moz-border-radius: 6px 0 6px 6px;
+          border-radius: 6px 0 6px 6px;
+}
+
+.navbar-inverse .navbar-inner {
+  background-color: #1b1b1b;
+  background-image: -moz-linear-gradient(top, #222222, #111111);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));
+  background-image: -webkit-linear-gradient(top, #222222, #111111);
+  background-image: -o-linear-gradient(top, #222222, #111111);
+  background-image: linear-gradient(to bottom, #222222, #111111);
+  background-repeat: repeat-x;
+  border-color: #252525;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);
+}
+
+.navbar-inverse .brand,
+.navbar-inverse .nav > li > a {
+  color: #999999;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+
+.navbar-inverse .brand:hover,
+.navbar-inverse .nav > li > a:hover,
+.navbar-inverse .brand:focus,
+.navbar-inverse .nav > li > a:focus {
+  color: #ffffff;
+}
+
+.navbar-inverse .brand {
+  color: #999999;
+}
+
+.navbar-inverse .navbar-text {
+  color: #999999;
+}
+
+.navbar-inverse .nav > li > a:focus,
+.navbar-inverse .nav > li > a:hover {
+  color: #ffffff;
+  background-color: transparent;
+}
+
+.navbar-inverse .nav .active > a,
+.navbar-inverse .nav .active > a:hover,
+.navbar-inverse .nav .active > a:focus {
+  color: #ffffff;
+  background-color: #111111;
+}
+
+.navbar-inverse .navbar-link {
+  color: #999999;
+}
+
+.navbar-inverse .navbar-link:hover,
+.navbar-inverse .navbar-link:focus {
+  color: #ffffff;
+}
+
+.navbar-inverse .divider-vertical {
+  border-right-color: #222222;
+  border-left-color: #111111;
+}
+
+.navbar-inverse .nav li.dropdown.open > .dropdown-toggle,
+.navbar-inverse .nav li.dropdown.active > .dropdown-toggle,
+.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle {
+  color: #ffffff;
+  background-color: #111111;
+}
+
+.navbar-inverse .nav li.dropdown > a:hover .caret,
+.navbar-inverse .nav li.dropdown > a:focus .caret {
+  border-top-color: #ffffff;
+  border-bottom-color: #ffffff;
+}
+
+.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret {
+  border-top-color: #999999;
+  border-bottom-color: #999999;
+}
+
+.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret,
+.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret,
+.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret {
+  border-top-color: #ffffff;
+  border-bottom-color: #ffffff;
+}
+
+.navbar-inverse .navbar-search .search-query {
+  color: #ffffff;
+  background-color: #515151;
+  border-color: #111111;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
+     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
+          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);
+  -webkit-transition: none;
+     -moz-transition: none;
+       -o-transition: none;
+          transition: none;
+}
+
+.navbar-inverse .navbar-search .search-query:-moz-placeholder {
+  color: #cccccc;
+}
+
+.navbar-inverse .navbar-search .search-query:-ms-input-placeholder {
+  color: #cccccc;
+}
+
+.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder {
+  color: #cccccc;
+}
+
+.navbar-inverse .navbar-search .search-query:focus,
+.navbar-inverse .navbar-search .search-query.focused {
+  padding: 5px 15px;
+  color: #333333;
+  text-shadow: 0 1px 0 #ffffff;
+  background-color: #ffffff;
+  border: 0;
+  outline: 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);
+}
+
+.navbar-inverse .btn-navbar {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #0e0e0e;
+  *background-color: #040404;
+  background-image: -moz-linear-gradient(top, #151515, #040404);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));
+  background-image: -webkit-linear-gradient(top, #151515, #040404);
+  background-image: -o-linear-gradient(top, #151515, #040404);
+  background-image: linear-gradient(to bottom, #151515, #040404);
+  background-repeat: repeat-x;
+  border-color: #040404 #040404 #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(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+}
+
+.navbar-inverse .btn-navbar:hover,
+.navbar-inverse .btn-navbar:focus,
+.navbar-inverse .btn-navbar:active,
+.navbar-inverse .btn-navbar.active,
+.navbar-inverse .btn-navbar.disabled,
+.navbar-inverse .btn-navbar[disabled] {
+  color: #ffffff;
+  background-color: #040404;
+  *background-color: #000000;
+}
+
+.navbar-inverse .btn-navbar:active,
+.navbar-inverse .btn-navbar.active {
+  background-color: #000000 \9;
+}
+
+.breadcrumb {
+  padding: 8px 15px;
+  margin: 0 0 20px;
+  list-style: none;
+  background-color: #f5f5f5;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+}
+
+.breadcrumb > li {
+  display: inline-block;
+  *display: inline;
+  text-shadow: 0 1px 0 #ffffff;
+  *zoom: 1;
+}
+
+.breadcrumb > li > .divider {
+  padding: 0 5px;
+  color: #ccc;
+}
+
+.breadcrumb > .active {
+  color: #999999;
+}
+
+.pagination {
+  margin: 20px 0;
+}
+
+.pagination ul {
+  display: inline-block;
+  *display: inline;
+  margin-bottom: 0;
+  margin-left: 0;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  *zoom: 1;
+  -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 ul > li {
+  display: inline;
+}
+
+.pagination ul > li > a,
+.pagination ul > li > span {
+  float: left;
+  padding: 4px 12px;
+  line-height: 20px;
+  text-decoration: none;
+  background-color: #ffffff;
+  border: 1px solid #dddddd;
+  border-left-width: 0;
+}
+
+.pagination ul > li > a:hover,
+.pagination ul > li > a:focus,
+.pagination ul > .active > a,
+.pagination ul > .active > span {
+  background-color: #f5f5f5;
+}
+
+.pagination ul > .active > a,
+.pagination ul > .active > span {
+  color: #999999;
+  cursor: default;
+}
+
+.pagination ul > .disabled > span,
+.pagination ul > .disabled > a,
+.pagination ul > .disabled > a:hover,
+.pagination ul > .disabled > a:focus {
+  color: #999999;
+  cursor: default;
+  background-color: transparent;
+}
+
+.pagination ul > li:first-child > a,
+.pagination ul > li:first-child > span {
+  border-left-width: 1px;
+  -webkit-border-bottom-left-radius: 4px;
+          border-bottom-left-radius: 4px;
+  -webkit-border-top-left-radius: 4px;
+          border-top-left-radius: 4px;
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-topleft: 4px;
+}
+
+.pagination ul > li:last-child > a,
+.pagination ul > li:last-child > span {
+  -webkit-border-top-right-radius: 4px;
+          border-top-right-radius: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+          border-bottom-right-radius: 4px;
+  -moz-border-radius-topright: 4px;
+  -moz-border-radius-bottomright: 4px;
+}
+
+.pagination-centered {
+  text-align: center;
+}
+
+.pagination-right {
+  text-align: right;
+}
+
+.pagination-large ul > li > a,
+.pagination-large ul > li > span {
+  padding: 11px 19px;
+  font-size: 17.5px;
+}
+
+.pagination-large ul > li:first-child > a,
+.pagination-large ul > li:first-child > span {
+  -webkit-border-bottom-left-radius: 6px;
+          border-bottom-left-radius: 6px;
+  -webkit-border-top-left-radius: 6px;
+          border-top-left-radius: 6px;
+  -moz-border-radius-bottomleft: 6px;
+  -moz-border-radius-topleft: 6px;
+}
+
+.pagination-large ul > li:last-child > a,
+.pagination-large ul > li:last-child > span {
+  -webkit-border-top-right-radius: 6px;
+          border-top-right-radius: 6px;
+  -webkit-border-bottom-right-radius: 6px;
+          border-bottom-right-radius: 6px;
+  -moz-border-radius-topright: 6px;
+  -moz-border-radius-bottomright: 6px;
+}
+
+.pagination-mini ul > li:first-child > a,
+.pagination-small ul > li:first-child > a,
+.pagination-mini ul > li:first-child > span,
+.pagination-small ul > li:first-child > span {
+  -webkit-border-bottom-left-radius: 3px;
+          border-bottom-left-radius: 3px;
+  -webkit-border-top-left-radius: 3px;
+          border-top-left-radius: 3px;
+  -moz-border-radius-bottomleft: 3px;
+  -moz-border-radius-topleft: 3px;
+}
+
+.pagination-mini ul > li:last-child > a,
+.pagination-small ul > li:last-child > a,
+.pagination-mini ul > li:last-child > span,
+.pagination-small ul > li:last-child > span {
+  -webkit-border-top-right-radius: 3px;
+          border-top-right-radius: 3px;
+  -webkit-border-bottom-right-radius: 3px;
+          border-bottom-right-radius: 3px;
+  -moz-border-radius-topright: 3px;
+  -moz-border-radius-bottomright: 3px;
+}
+
+.pagination-small ul > li > a,
+.pagination-small ul > li > span {
+  padding: 2px 10px;
+  font-size: 11.9px;
+}
+
+.pagination-mini ul > li > a,
+.pagination-mini ul > li > span {
+  padding: 0 6px;
+  font-size: 10.5px;
+}
+
+.pager {
+  margin: 20px 0;
+  text-align: center;
+  list-style: none;
+  *zoom: 1;
+}
+
+.pager:before,
+.pager:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.pager:after {
+  clear: both;
+}
+
+.pager li {
+  display: inline;
+}
+
+.pager li > a,
+.pager li > span {
+  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 li > a:hover,
+.pager li > a:focus {
+  text-decoration: none;
+  background-color: #f5f5f5;
+}
+
+.pager .next > a,
+.pager .next > span {
+  float: right;
+}
+
+.pager .previous > a,
+.pager .previous > span {
+  float: left;
+}
+
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+  color: #999999;
+  cursor: default;
+  background-color: #fff;
+}
+
+.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: 10%;
+  left: 50%;
+  z-index: 1050;
+  width: 560px;
+  margin-left: -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;
+  outline: none;
+  -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 {
+  top: -25%;
+  -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;
+     -moz-transition: opacity 0.3s linear, top 0.3s ease-out;
+       -o-transition: opacity 0.3s linear, top 0.3s ease-out;
+          transition: opacity 0.3s linear, top 0.3s ease-out;
+}
+
+.modal.fade.in {
+  top: 10%;
+}
+
+.modal-header {
+  padding: 9px 15px;
+  border-bottom: 1px solid #eee;
+}
+
+.modal-header .close {
+  margin-top: 2px;
+}
+
+.modal-header h3 {
+  margin: 0;
+  line-height: 30px;
+}
+
+.modal-body {
+  position: relative;
+  max-height: 400px;
+  padding: 15px;
+  overflow-y: auto;
+}
+
+.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;
+  *zoom: 1;
+  -webkit-box-shadow: inset 0 1px 0 #ffffff;
+     -moz-box-shadow: inset 0 1px 0 #ffffff;
+          box-shadow: inset 0 1px 0 #ffffff;
+}
+
+.modal-footer:before,
+.modal-footer:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.modal-footer:after {
+  clear: both;
+}
+
+.modal-footer .btn + .btn {
+  margin-bottom: 0;
+  margin-left: 5px;
+}
+
+.modal-footer .btn-group .btn + .btn {
+  margin-left: -1px;
+}
+
+.modal-footer .btn-block + .btn-block {
+  margin-left: 0;
+}
+
+.tooltip {
+  position: absolute;
+  z-index: 1030;
+  display: block;
+  font-size: 11px;
+  line-height: 1.4;
+  opacity: 0;
+  filter: alpha(opacity=0);
+  visibility: visible;
+}
+
+.tooltip.in {
+  opacity: 0.8;
+  filter: alpha(opacity=80);
+}
+
+.tooltip.top {
+  padding: 5px 0;
+  margin-top: -3px;
+}
+
+.tooltip.right {
+  padding: 0 5px;
+  margin-left: 3px;
+}
+
+.tooltip.bottom {
+  padding: 5px 0;
+  margin-top: 3px;
+}
+
+.tooltip.left {
+  padding: 0 5px;
+  margin-left: -3px;
+}
+
+.tooltip-inner {
+  max-width: 200px;
+  padding: 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;
+  border-color: transparent;
+  border-style: solid;
+}
+
+.tooltip.top .tooltip-arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-top-color: #000000;
+  border-width: 5px 5px 0;
+}
+
+.tooltip.right .tooltip-arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-right-color: #000000;
+  border-width: 5px 5px 5px 0;
+}
+
+.tooltip.left .tooltip-arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-left-color: #000000;
+  border-width: 5px 0 5px 5px;
+}
+
+.tooltip.bottom .tooltip-arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-bottom-color: #000000;
+  border-width: 0 5px 5px;
+}
+
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1010;
+  display: none;
+  max-width: 276px;
+  padding: 1px;
+  text-align: left;
+  white-space: normal;
+  background-color: #ffffff;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  -webkit-border-radius: 6px;
+     -moz-border-radius: 6px;
+          border-radius: 6px;
+  -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;
+}
+
+.popover.top {
+  margin-top: -10px;
+}
+
+.popover.right {
+  margin-left: 10px;
+}
+
+.popover.bottom {
+  margin-top: 10px;
+}
+
+.popover.left {
+  margin-left: -10px;
+}
+
+.popover-title {
+  padding: 8px 14px;
+  margin: 0;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 18px;
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ebebeb;
+  -webkit-border-radius: 5px 5px 0 0;
+     -moz-border-radius: 5px 5px 0 0;
+          border-radius: 5px 5px 0 0;
+}
+
+.popover-title:empty {
+  display: none;
+}
+
+.popover-content {
+  padding: 9px 14px;
+}
+
+.popover .arrow,
+.popover .arrow:after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+
+.popover .arrow {
+  border-width: 11px;
+}
+
+.popover .arrow:after {
+  border-width: 10px;
+  content: "";
+}
+
+.popover.top .arrow {
+  bottom: -11px;
+  left: 50%;
+  margin-left: -11px;
+  border-top-color: #999;
+  border-top-color: rgba(0, 0, 0, 0.25);
+  border-bottom-width: 0;
+}
+
+.popover.top .arrow:after {
+  bottom: 1px;
+  margin-left: -10px;
+  border-top-color: #ffffff;
+  border-bottom-width: 0;
+}
+
+.popover.right .arrow {
+  top: 50%;
+  left: -11px;
+  margin-top: -11px;
+  border-right-color: #999;
+  border-right-color: rgba(0, 0, 0, 0.25);
+  border-left-width: 0;
+}
+
+.popover.right .arrow:after {
+  bottom: -10px;
+  left: 1px;
+  border-right-color: #ffffff;
+  border-left-width: 0;
+}
+
+.popover.bottom .arrow {
+  top: -11px;
+  left: 50%;
+  margin-left: -11px;
+  border-bottom-color: #999;
+  border-bottom-color: rgba(0, 0, 0, 0.25);
+  border-top-width: 0;
+}
+
+.popover.bottom .arrow:after {
+  top: 1px;
+  margin-left: -10px;
+  border-bottom-color: #ffffff;
+  border-top-width: 0;
+}
+
+.popover.left .arrow {
+  top: 50%;
+  right: -11px;
+  margin-top: -11px;
+  border-left-color: #999;
+  border-left-color: rgba(0, 0, 0, 0.25);
+  border-right-width: 0;
+}
+
+.popover.left .arrow:after {
+  right: 1px;
+  bottom: -10px;
+  border-left-color: #ffffff;
+  border-right-width: 0;
+}
+
+.thumbnails {
+  margin-left: -20px;
+  list-style: none;
+  *zoom: 1;
+}
+
+.thumbnails:before,
+.thumbnails:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.thumbnails:after {
+  clear: both;
+}
+
+.row-fluid .thumbnails {
+  margin-left: 0;
+}
+
+.thumbnails > li {
+  float: left;
+  margin-bottom: 20px;
+  margin-left: 20px;
+}
+
+.thumbnail {
+  display: block;
+  padding: 4px;
+  line-height: 20px;
+  border: 1px solid #ddd;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
+     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
+          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055);
+  -webkit-transition: all 0.2s ease-in-out;
+     -moz-transition: all 0.2s ease-in-out;
+       -o-transition: all 0.2s ease-in-out;
+          transition: all 0.2s ease-in-out;
+}
+
+a.thumbnail:hover,
+a.thumbnail:focus {
+  border-color: #0088cc;
+  -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-right: auto;
+  margin-left: auto;
+}
+
+.thumbnail .caption {
+  padding: 9px;
+  color: #555555;
+}
+
+.media,
+.media-body {
+  overflow: hidden;
+  *overflow: visible;
+  zoom: 1;
+}
+
+.media,
+.media .media {
+  margin-top: 15px;
+}
+
+.media:first-child {
+  margin-top: 0;
+}
+
+.media-object {
+  display: block;
+}
+
+.media-heading {
+  margin: 0 0 5px;
+}
+
+.media > .pull-left {
+  margin-right: 10px;
+}
+
+.media > .pull-right {
+  margin-left: 10px;
+}
+
+.media-list {
+  margin-left: 0;
+  list-style: none;
+}
+
+.label,
+.badge {
+  display: inline-block;
+  padding: 2px 4px;
+  font-size: 11.844px;
+  font-weight: bold;
+  line-height: 14px;
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  white-space: nowrap;
+  vertical-align: baseline;
+  background-color: #999999;
+}
+
+.label {
+  -webkit-border-radius: 3px;
+     -moz-border-radius: 3px;
+          border-radius: 3px;
+}
+
+.badge {
+  padding-right: 9px;
+  padding-left: 9px;
+  -webkit-border-radius: 9px;
+     -moz-border-radius: 9px;
+          border-radius: 9px;
+}
+
+.label:empty,
+.badge:empty {
+  display: none;
+}
+
+a.label:hover,
+a.label:focus,
+a.badge:hover,
+a.badge:focus {
+  color: #ffffff;
+  text-decoration: none;
+  cursor: pointer;
+}
+
+.label-important,
+.badge-important {
+  background-color: #b94a48;
+}
+
+.label-important[href],
+.badge-important[href] {
+  background-color: #953b39;
+}
+
+.label-warning,
+.badge-warning {
+  background-color: #f89406;
+}
+
+.label-warning[href],
+.badge-warning[href] {
+  background-color: #c67605;
+}
+
+.label-success,
+.badge-success {
+  background-color: #468847;
+}
+
+.label-success[href],
+.badge-success[href] {
+  background-color: #356635;
+}
+
+.label-info,
+.badge-info {
+  background-color: #3a87ad;
+}
+
+.label-info[href],
+.badge-info[href] {
+  background-color: #2d6987;
+}
+
+.label-inverse,
+.badge-inverse {
+  background-color: #333333;
+}
+
+.label-inverse[href],
+.badge-inverse[href] {
+  background-color: #1a1a1a;
+}
+
+.btn .label,
+.btn .badge {
+  position: relative;
+  top: -1px;
+}
+
+.btn-mini .label,
+.btn-mini .badge {
+  top: 0;
+}
+
+@-webkit-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+@-moz-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+@-ms-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+@-o-keyframes progress-bar-stripes {
+  from {
+    background-position: 0 0;
+  }
+  to {
+    background-position: 40px 0;
+  }
+}
+
+@keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+
+.progress {
+  height: 20px;
+  margin-bottom: 20px;
+  overflow: hidden;
+  background-color: #f7f7f7;
+  background-image: -moz-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(to bottom, #f5f5f5, #f9f9f9);
+  background-repeat: repeat-x;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', 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);
+}
+
+.progress .bar {
+  float: left;
+  width: 0;
+  height: 100%;
+  font-size: 12px;
+  color: #ffffff;
+  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: -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(to bottom, #149bdf, #0480be);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', 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;
+          box-sizing: border-box;
+  -webkit-transition: width 0.6s ease;
+     -moz-transition: width 0.6s ease;
+       -o-transition: width 0.6s ease;
+          transition: width 0.6s ease;
+}
+
+.progress .bar + .bar {
+  -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+     -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+          box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+}
+
+.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: -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;
+      -ms-animation: progress-bar-stripes 2s linear infinite;
+       -o-animation: progress-bar-stripes 2s linear infinite;
+          animation: progress-bar-stripes 2s linear infinite;
+}
+
+.progress-danger .bar,
+.progress .bar-danger {
+  background-color: #dd514c;
+  background-image: -moz-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(to bottom, #ee5f5b, #c43c35);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);
+}
+
+.progress-danger.progress-striped .bar,
+.progress-striped .bar-danger {
+  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: -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,
+.progress .bar-success {
+  background-color: #5eb95e;
+  background-image: -moz-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(to bottom, #62c462, #57a957);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);
+}
+
+.progress-success.progress-striped .bar,
+.progress-striped .bar-success {
+  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: -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,
+.progress .bar-info {
+  background-color: #4bb1cf;
+  background-image: -moz-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(to bottom, #5bc0de, #339bb9);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);
+}
+
+.progress-info.progress-striped .bar,
+.progress-striped .bar-info {
+  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: -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,
+.progress .bar-warning {
+  background-color: #faa732;
+  background-image: -moz-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(to bottom, #fbb450, #f89406);
+  background-repeat: repeat-x;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
+}
+
+.progress-warning.progress-striped .bar,
+.progress-striped .bar-warning {
+  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: -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: 20px;
+}
+
+.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-toggle {
+  cursor: pointer;
+}
+
+.accordion-inner {
+  padding: 9px 15px;
+  border-top: 1px solid #e5e5e5;
+}
+
+.carousel {
+  position: relative;
+  margin-bottom: 20px;
+  line-height: 1;
+}
+
+.carousel-inner {
+  position: relative;
+  width: 100%;
+  overflow: hidden;
+}
+
+.carousel-inner > .item {
+  position: relative;
+  display: none;
+  -webkit-transition: 0.6s ease-in-out left;
+     -moz-transition: 0.6s ease-in-out left;
+       -o-transition: 0.6s ease-in-out left;
+          transition: 0.6s ease-in-out left;
+}
+
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  display: block;
+  line-height: 1;
+}
+
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  display: block;
+}
+
+.carousel-inner > .active {
+  left: 0;
+}
+
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+
+.carousel-inner > .next {
+  left: 100%;
+}
+
+.carousel-inner > .prev {
+  left: -100%;
+}
+
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+  left: 0;
+}
+
+.carousel-inner > .active.left {
+  left: -100%;
+}
+
+.carousel-inner > .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 {
+  right: 15px;
+  left: auto;
+}
+
+.carousel-control:hover,
+.carousel-control:focus {
+  color: #ffffff;
+  text-decoration: none;
+  opacity: 0.9;
+  filter: alpha(opacity=90);
+}
+
+.carousel-indicators {
+  position: absolute;
+  top: 15px;
+  right: 15px;
+  z-index: 5;
+  margin: 0;
+  list-style: none;
+}
+
+.carousel-indicators li {
+  display: block;
+  float: left;
+  width: 10px;
+  height: 10px;
+  margin-left: 5px;
+  text-indent: -999px;
+  background-color: #ccc;
+  background-color: rgba(255, 255, 255, 0.25);
+  border-radius: 5px;
+}
+
+.carousel-indicators .active {
+  background-color: #fff;
+}
+
+.carousel-caption {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  padding: 15px;
+  background: #333333;
+  background: rgba(0, 0, 0, 0.75);
+}
+
+.carousel-caption h4,
+.carousel-caption p {
+  line-height: 20px;
+  color: #ffffff;
+}
+
+.carousel-caption h4 {
+  margin: 0 0 5px;
+}
+
+.carousel-caption p {
+  margin-bottom: 0;
+}
+
+.hero-unit {
+  padding: 60px;
+  margin-bottom: 30px;
+  font-size: 18px;
+  font-weight: 200;
+  line-height: 30px;
+  color: inherit;
+  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;
+  letter-spacing: -1px;
+  color: inherit;
+}
+
+.hero-unit li {
+  line-height: 30px;
+}
+
+.pull-right {
+  float: right;
+}
+
+.pull-left {
+  float: left;
+}
+
+.hide {
+  display: none;
+}
+
+.show {
+  display: block;
+}
+
+.invisible {
+  visibility: hidden;
+}
+
+.affix {
+  position: fixed;
+}
diff --git a/asterix-examples/src/main/resources/cherry/css/bootstrap.min.css b/asterix-examples/src/main/resources/cherry/css/bootstrap.min.css
new file mode 100755
index 0000000..c10c7f4
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/css/bootstrap.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap v2.3.1
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}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{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}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,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-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 #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .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;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;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}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-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 .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-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)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.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-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[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-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)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),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 .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-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)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),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 .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-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)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),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}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-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)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus: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:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 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 input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 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;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{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-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.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 #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.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,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{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{width:16px;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{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.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-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-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}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;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 #e3e3e3;-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{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border: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);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-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)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .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;outline:0;-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)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.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{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;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(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-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(to bottom,#fbb450,#f89406);background-repeat:repeat-x;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(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-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(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;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(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-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(to bottom,#62c462,#51a351);background-repeat:repeat-x;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(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-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(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;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(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;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(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}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-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright: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>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left: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)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{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)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;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}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{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-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-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,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;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:20px;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,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.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,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.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-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.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,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{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,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.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,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;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,.navbar-form .btn{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:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius: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-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #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(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);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)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .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}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline: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)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;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(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-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 ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{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 li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;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;outline:0;-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{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-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}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.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;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-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}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-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-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-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(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',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)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;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:-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(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',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;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.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:-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;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-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(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{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:-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,.progress .bar-success{background-color:#5eb95e;background-image:-moz-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(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{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:-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,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-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(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{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:-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,.progress .bar-warning{background-color:#faa732;background-image:-moz-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(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{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:-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:20px}.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-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.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:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}
diff --git a/asterix-examples/src/main/resources/cherry/css/jquery.dataTables.css b/asterix-examples/src/main/resources/cherry/css/jquery.dataTables.css
new file mode 100755
index 0000000..7da7fae
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/css/jquery.dataTables.css
@@ -0,0 +1,221 @@
+
+/*
+ * Table
+ */
+table.dataTable {
+	margin: 0 auto;
+	clear: both;
+	width: 100%;
+}
+
+table.dataTable thead th {
+	padding: 3px 18px 3px 10px;
+	border-bottom: 1px solid black;
+	font-weight: bold;
+	cursor: pointer;
+	*cursor: hand;
+}
+
+table.dataTable tfoot th {
+	padding: 3px 18px 3px 10px;
+	border-top: 1px solid black;
+	font-weight: bold;
+}
+
+table.dataTable td {
+	padding: 3px 10px;
+}
+
+table.dataTable td.center,
+table.dataTable td.dataTables_empty {
+	text-align: center;
+}
+
+table.dataTable tr.odd { background-color: #E2E4FF; }
+table.dataTable tr.even { background-color: white; }
+
+table.dataTable tr.odd td.sorting_1 { background-color: #D3D6FF; }
+table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; }
+table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; }
+table.dataTable tr.even td.sorting_1 { background-color: #EAEBFF; }
+table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; }
+table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; }
+
+
+/*
+ * Table wrapper
+ */
+.dataTables_wrapper {
+	position: relative;
+	clear: both;
+	*zoom: 1;
+}
+
+
+/*
+ * Page length menu
+ */
+.dataTables_length {
+	float: left;
+}
+
+
+/*
+ * Filter
+ */
+.dataTables_filter {
+	float: right;
+	text-align: right;
+}
+
+
+/*
+ * Table information
+ */
+.dataTables_info {
+	clear: both;
+	float: left;
+}
+
+
+/*
+ * Pagination
+ */
+.dataTables_paginate {
+	float: right;
+	text-align: right;
+}
+
+/* Two button pagination - previous / next */
+.paginate_disabled_previous,
+.paginate_enabled_previous,
+.paginate_disabled_next,
+.paginate_enabled_next {
+	height: 19px;
+	float: left;
+	cursor: pointer;
+	*cursor: hand;
+	color: #111 !important;
+}
+.paginate_disabled_previous:hover,
+.paginate_enabled_previous:hover,
+.paginate_disabled_next:hover,
+.paginate_enabled_next:hover {
+	text-decoration: none !important;
+}
+.paginate_disabled_previous:active,
+.paginate_enabled_previous:active,
+.paginate_disabled_next:active,
+.paginate_enabled_next:active {
+	outline: none;
+}
+
+.paginate_disabled_previous,
+.paginate_disabled_next {
+	color: #666 !important;
+}
+.paginate_disabled_previous,
+.paginate_enabled_previous {
+	padding-left: 23px;
+}
+.paginate_disabled_next,
+.paginate_enabled_next {
+	padding-right: 23px;
+	margin-left: 10px;
+}
+
+.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; }
+.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; }
+.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; }
+
+.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; }
+.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; }
+.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; }
+
+/* Full number pagination */
+.paging_full_numbers {
+	height: 22px;
+	line-height: 22px;
+}
+.paging_full_numbers a:active {
+	outline: none
+}
+.paging_full_numbers a:hover {
+	text-decoration: none;
+}
+
+.paging_full_numbers a.paginate_button,
+.paging_full_numbers a.paginate_active {
+	border: 1px solid #aaa;
+	-webkit-border-radius: 5px;
+	-moz-border-radius: 5px;
+	border-radius: 5px;
+	padding: 2px 5px;
+	margin: 0 3px;
+	cursor: pointer;
+	*cursor: hand;
+	color: #333 !important;
+}
+
+.paging_full_numbers a.paginate_button {
+	background-color: #ddd;
+}
+
+.paging_full_numbers a.paginate_button:hover {
+	background-color: #ccc;
+	text-decoration: none !important;
+}
+
+.paging_full_numbers a.paginate_active {
+	background-color: #99B3FF;
+}
+
+
+/*
+ * Processing indicator
+ */
+.dataTables_processing {
+	position: absolute;
+	top: 50%;
+	left: 50%;
+	width: 250px;
+	height: 30px;
+	margin-left: -125px;
+	margin-top: -15px;
+	padding: 14px 0 2px 0;
+	border: 1px solid #ddd;
+	text-align: center;
+	color: #999;
+	font-size: 14px;
+	background-color: white;
+}
+
+
+/*
+ * Sorting
+ */
+.sorting { background: url('../images/sort_both.png') no-repeat center right; }
+.sorting_asc { background: url('../images/sort_asc.png') no-repeat center right; }
+.sorting_desc { background: url('../images/sort_desc.png') no-repeat center right; }
+
+.sorting_asc_disabled { background: url('../images/sort_asc_disabled.png') no-repeat center right; }
+.sorting_desc_disabled { background: url('../images/sort_desc_disabled.png') no-repeat center right; }
+ 
+table.dataTable thead th:active,
+table.dataTable thead td:active {
+	outline: none;
+}
+
+
+/*
+ * Scrolling
+ */
+.dataTables_scroll {
+	clear: both;
+}
+
+.dataTables_scrollBody {
+	*margin-top: -1px;
+	-webkit-overflow-scrolling: touch;
+}
+
diff --git a/asterix-examples/src/main/resources/cherry/examples/cherry.html b/asterix-examples/src/main/resources/cherry/examples/cherry.html
new file mode 100755
index 0000000..e8facae
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/examples/cherry.html
@@ -0,0 +1,196 @@
+<!DOCTYPE html>
+<html style="width: 100%; height: 100%;">
+  <head>
+    <title>ASTERIX Demo</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+
+    <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/themes/base/jquery-ui.css"
+        rel="stylesheet" type="text/css"/>
+    <link href="../css/jquery.dataTables.css" rel="stylesheet" type="text/css"/>
+    <link href="../css/bootstrap.min.css" rel="stylesheet" media="screen">
+
+    <link rel="shortcut icon" type="image/png" href="../img/mobile.png">
+
+    <script src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"
+        type="text/javascript"></script> 
+    <script src="http://code.jquery.com/jquery.min.js" type="text/javascript"></script>
+    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js"
+        type="text/javascript"></script>
+  
+    <script src="../js/bootstrap.min.js"></script>
+    <script type="text/javascript" src="../js/geostats.js" ></script>
+
+    <script src="../../core/js/easyXDM/easyXDM.debug.js"></script>
+    <script src="http://localhost:19101/sdk/static/js/asterix-api-core.js"></script>
+    <script src="../js/asterix-api-core.js" type="text/javascript"></script>
+    <script src="../js/cherry.js" type="text/javascript"></script>
+    <style type="text/css">
+        .column-section {
+            border-top: 2px solid #aaa;
+            margin-top: 10px;
+        }
+
+        .section-title {
+            background: #ddd;
+            padding: 5px 0;
+        }
+
+        .section-title span {
+            margin-left: 10px;
+            font-weight: bold;
+        }
+        
+        .control {
+            margin: 0;
+        }
+        
+        #map_canvas img {
+            max-width: none;
+        }
+        
+        #legend-holder {
+            background: white;
+            padding: 10px;
+            margin: 10px;
+            text-align: center;
+        }
+        
+        #review-handles-dropdown {
+            padding: 10px;
+        }
+
+    </style>
+  </head>
+  <body style="width: 100%; height: 100%;">
+    
+    <!-- Nav -->
+    <div class="navbar">
+      <div class="navbar-inner">
+        <a class="brand" href="#" style="padding: 0.25em;"><img src="../img/asterixlogo.png" height="30" width="72"></a>
+        <ul class="nav">
+          <li id="explore-active" class="active"><a id="explore-mode" href="#">Explore</a></li>
+          <li id="review-active" ><a id="review-mode" href="#">Review</a></li>
+        </ul>
+      </div>
+    </div>    
+
+    <!-- Search Box -->
+    <div class="container-fluid">
+    
+      <div class="row">
+
+        <!-- Search Bar -->
+        <div class="span4 well" id="explore-well">
+          <div class="column-section" id="location">
+            <div class="section-title"><span>Location</span></div>
+            <!--<div class="section-controls">-->
+              <input class="textbox" type="text" id="location-text-box">
+              <div class="btn-group" data-toggle="buttons-radio">
+                <button type="button" class="btn" id="location-button">Location</button>
+                <button type="button" class="btn" id="selection-button">Selection</button>
+              </div>
+            <!-- </div>-->
+          </div><!-- end #location-->
+
+          <div class="column-section" id="date">
+            <div class="section-title"><span>Date</span></div>
+            <div class="section-controls">
+                <span style="white-space:nowrap; display: block; overflow:hidden;">
+                    <label for="start-date">Start Date</label><input type="text" class="textbox" id="start-date">
+                </span>
+              <input type="text" class="textbox" id="end-date">
+              <label for="end-date">End Date</label>
+            </div>
+          </div><!-- end #date-->
+
+          <div class="column-section" id="keyword">
+            <div class="section-title"><span>Keyword</span></div>
+            <div class="section-controls">
+              <input type="text" class="textbox" id="keyword-textbox" value="verizon">
+            </div>
+          </div><!-- end #keyword-->
+
+          <div class="column-section" id="grid">
+            <div class="section-title"><span>Grid: Latitude &amp; Longitude</span></div>
+            <div class="section-controls">
+
+              <div class="grid-slider"  id="grid-lat-slider"></div>
+              <div class="control-label">Latitude: <span id="gridlat">3.0</span></div>
+
+              <div class="grid-slider" id="grid-lng-slider"></div>
+              <div class="control-label">Longitude: <span id="gridlng">3.0</span></div>
+            </div>
+          </div><!-- end #grid-->
+
+          <div class="column-section" style="border: none;" id="submit-query">
+            <div class="section-controls">
+              	<button id="submit-button">Submit</button>
+                <button id="clear-button">Clear</button>
+                <button id="show-query-button">Show Query</button><br />
+                <input type="checkbox" value="Submit Asynchronously" name="async" id="asbox" />
+                Submit asynchronously?
+            </div>
+          </div><!-- end #submit-query -->
+          
+        </div><!--/span-->
+        
+         <!-- Drilldown Modal -->
+          <div id="drilldown_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
+                <h3 id="myModalLabel">Explore Tweets</h3>
+            </div>
+            <div class="modal-body" id="drilldown_modal_body"></div>
+            <div class="modal-footer">
+                <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
+            </div>
+          </div>
+        
+        <div class="span4 well" id="review-well" style="display:none;">
+            <div class="btn-group" style="margin-bottom: 10px;" id="group-tweetbooks">
+                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
+                    Tweetbooks
+                    <span class="caret"></span>
+                </a>
+                <ul class="dropdown-menu" id="review-tweetbook-dropdown">
+                    <li><a href="#" class="holdmenu">
+                        <input type="text" id="new-tweetbook-entry" placeholder="Name a new tweetbook">
+                        <button type="button" class="btn" id="new-tweetbook-button">Add</button>
+                    </a></li>
+                    <li class="divider"></li>
+                    <div id="review-tweetbook-titles">
+                    </div>
+                </ul>
+            </div><br/>
+            
+            <div class="btn-group" id="group-background-query" style="margin-bottom: 10px;">
+                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
+                    Background Queries
+                    <span class="caret"></span>
+                </a>
+                <ul class="dropdown-menu" id="review-handles-dropdown">
+                </ul>
+            </div>
+            
+            <div id="query-preview-window" style="overflow: auto; width: 100%; background: white; border: 2px solid black;">
+            </div>
+        </div>
+        
+        <!-- Map -->
+        <div class="span8 well" >
+          <div id="map_canvas" style="width: 100%; height: 100%;"></div>
+        </div><!--/span-->
+        <div id="map_canvas_legend">
+        </div>
+      
+      </div><!--/row-->
+      <div class="row">
+      
+         <div id="dialog">
+            <h4>You must submit a query first.</h4>
+        </div></div>
+    </div><!-- container -->
+    <hr>
+    
+  </body>
+</html>
diff --git a/asterix-examples/src/main/resources/cherry/img/asterixlogo.png b/asterix-examples/src/main/resources/cherry/img/asterixlogo.png
new file mode 100755
index 0000000..d15e388
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/img/asterixlogo.png
Binary files differ
diff --git a/asterix-examples/src/main/resources/cherry/img/glyphicons-halflings-white.png b/asterix-examples/src/main/resources/cherry/img/glyphicons-halflings-white.png
new file mode 100755
index 0000000..3bf6484
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/img/glyphicons-halflings-white.png
Binary files differ
diff --git a/asterix-examples/src/main/resources/cherry/img/glyphicons-halflings.png b/asterix-examples/src/main/resources/cherry/img/glyphicons-halflings.png
new file mode 100755
index 0000000..a996999
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/img/glyphicons-halflings.png
Binary files differ
diff --git a/asterix-examples/src/main/resources/cherry/img/markers.png b/asterix-examples/src/main/resources/cherry/img/markers.png
new file mode 100755
index 0000000..b983f9f
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/img/markers.png
Binary files differ
diff --git a/asterix-examples/src/main/resources/cherry/img/mobile.png b/asterix-examples/src/main/resources/cherry/img/mobile.png
new file mode 100755
index 0000000..4d59e09
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/img/mobile.png
Binary files differ
diff --git a/asterix-examples/src/main/resources/cherry/img/mobile2.png b/asterix-examples/src/main/resources/cherry/img/mobile2.png
new file mode 100755
index 0000000..4d59e09
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/img/mobile2.png
Binary files differ
diff --git a/asterix-examples/src/main/resources/cherry/img/mobile_green.png b/asterix-examples/src/main/resources/cherry/img/mobile_green.png
new file mode 100755
index 0000000..31e367a
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/img/mobile_green.png
Binary files differ
diff --git a/asterix-examples/src/main/resources/cherry/img/mobile_green2.png b/asterix-examples/src/main/resources/cherry/img/mobile_green2.png
new file mode 100755
index 0000000..31e367a
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/img/mobile_green2.png
Binary files differ
diff --git a/asterix-examples/src/main/resources/cherry/js/asterix-api-core.js b/asterix-examples/src/main/resources/cherry/js/asterix-api-core.js
new file mode 100755
index 0000000..9553997
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/js/asterix-api-core.js
@@ -0,0 +1,462 @@
+/** 
+* Asterix Core API
+* @returns  {AsterixCoreAPI}    AsterixCoreAPI
+*/
+function AsterixCoreAPI() {
+    this.parameters = {
+        "statements"    : [],
+        "mode"          : "synchronous"
+    };
+    this.ui_callback_on_success = function() {};
+    this.ui_callback_on_success_async = function() {};
+    this.on_error = function() {};
+    this.extra = {};
+    return this;
+}
+
+/** Parameter Management **/
+
+/**
+* Sets the dataverse of this Asterix API call
+* @param    {String}            dataverse
+* @returns  {AsterixCoreAPI}    AsterixCoreAPI 
+*/
+AsterixCoreAPI.prototype.dataverse = function (dataverse) {
+    this.dataverse = dataverse;
+    return this;
+}
+
+/**
+* Set the on-success callback of the api call
+* @param    {Function}          on_success
+* @param    {Boolean}           is_synchronous
+* @returns  {AsterixCoreAPI}    AsterixCoreAPI 
+*/
+AsterixCoreAPI.prototype.success = function(on_success, is_synchronous) {
+    if (is_synchronous) {
+        this.ui_callback_on_success = on_success;
+    } else {
+        this.ui_callback_on_success_async = on_success;
+    }
+    
+    return this;
+}
+
+/**
+* Set the on-error callback of the api call
+* @param    {Function}          on_error
+* @returns  {AsterixCoreAPI}    AsterixCoreAPI 
+*/
+AsterixCoreAPI.prototype.error = function(on_error) {
+    this.on_error = on_error;
+    return this;
+}
+
+/**
+* Sets a parameter key, value
+* @param    {String}            param_key
+* @param    {Object}            param_value
+* @returns  {AsterixCoreAPI}    AsterixCoreAPI  
+*/
+AsterixCoreAPI.prototype.parameter = function (param_key, param_value) {
+    this.parameters[param_key] = param_value;
+    return this;
+}
+
+/**
+* Sets query statements
+* @param    {Array}             statements
+* @returns  {AsterixCoreAPI}    this API object
+*/
+AsterixCoreAPI.prototype.statements = function (statements) {
+    this.parameters["statements"] = statements;
+    return this;
+}
+
+/**
+* Pushes a single query statement
+* @param    {String}            statement containing one line of a query
+* @returns  {AsterixCoreAPI}    this API object
+*/
+AsterixCoreAPI.prototype.add_statement = function (statement) {
+    this.parameters["statements"].push(statement);
+    return this;
+}
+
+/**
+* Sets synchronization mode
+* @param    {String}            sync, either "synchronous" or "asynchronous"
+* @returns  {AsterixCoreAPI}    this API object
+*/
+AsterixCoreAPI.prototype.mode = function(sync) {
+    this.parameters["mode"] = sync;
+    return this;
+}
+
+/**
+* Extra data to run on success
+* @param    {String}            extra_key
+* @param    {Object}            extra_value
+* @returns  {AsterixCoreAPI}    this API object
+*/
+AsterixCoreAPI.prototype.add_extra = function(extra_key, extra_value) {
+    this.extra[extra_key] = extra_value;
+    return this;
+}
+
+/**
+* Create a dataset of a given type with a given key (optional)
+* @param    {Object}            param: keys "dataset", "type", "primary_key", 
+* @returns  {AsterixCoreAPI}    this API object
+*/
+AsterixCoreAPI.prototype.create_dataset = function(param) {
+    // Parse create object
+    var create_statement = 'create dataset ' + param["dataset"] + '(' + param["type"] + ')';
+    if (param.hasOwnProperty("primary_key")) {
+        create_statement += ' primary key ' + param["primary_key"] + ';';
+    }
+    
+    // Add to statements
+    this.parameters["statements"].push(create_statement);
+    
+    return this;
+}
+
+/**
+* Drop a dataset of a given name
+* @param    {String}            dataset
+* @returns  {AsterixCoreAPI}    this API object
+*/
+AsterixCoreAPI.prototype.drop_dataset = function(dataset) {
+    var drop_statement = 'drop dataset ' + dataset + ';';
+    this.parameters["statements"].push(drop_statement);
+    return this;
+}
+
+/**
+* Reference a query given a query object
+* @param    {Object}            async_handle, an opaque handle from a prior asynchronous query
+* @returns  {AsterixCoreAPI}    this API object 
+*/
+AsterixCoreAPI.prototype.handle = function(async_handle) {
+    this.query_handle = async_handle;
+    return this;
+}
+
+/**
+* @param    {Object}            for : {"var" in "dataset"}
+* @returns  {AsterixCoreAPI}    this API object
+*/
+AsterixCoreAPI.prototype.aql_for = function(for_object) {
+    var for_statement = "for $"; 
+    for (var key in for_object) {
+        for_statement += key + " in dataset " + for_object[key];
+    }
+    
+    this.parameters["statements"].push(for_statement);
+    return this;
+}
+
+/**
+* @param    {Object}            let : {"key" => "values"}
+* @returns  {AsterixCoreAPI}    this API object
+*
+* TODO This one needs work - hacky
+*/
+AsterixCoreAPI.prototype.aql_let = function(let_object) {
+    var let_statement = "";
+    
+    for (var var_name in let_object) {
+        let_statement = 'let $' + var_name + ' := ' + let_object[var_name];
+        this.parameters["statements"].push(let_statement);
+    }
+
+    return this;
+}
+
+/**
+* @param    {Array}             where_object : [statements]
+* @returns  {AsterixCoreAPI}    this API object
+*
+* TODO Fix me
+*/
+AsterixCoreAPI.prototype.aql_where = function(where_object) {
+    this.parameters["statements"].push("where " + where_object.join(" and "));
+    return this;    
+}
+
+/**
+* @param    {Object}            groupby, a map { "groupby" , "with" }
+* @returns  {AsterixCoreAPI}    this API object
+*/
+AsterixCoreAPI.prototype.aql_groupby = function(groupby_object) {
+    var groupby_statement = "group by " + groupby_object["groupby"];
+    groupby_statement += " with " + groupby_object["with"];
+    
+    this.parameters["statements"].push(groupby_statement);
+    
+    return this;
+}
+
+/**
+* Prepares a return statement of keys and value variables
+* @param    {Object}            return { "keys" => "values" }
+* @returns  {AsterixCoreAPI}    this API object
+*/
+AsterixCoreAPI.prototype.aql_return = function(return_object) {
+    var components = [];
+    for (var key in return_object) {
+        components.push('"' + key + '" : ' + return_object[key]);
+    }
+    
+    var return_statement = 'return { ' + components.join(', ') + ' }'; 
+    this.parameters["statements"].push(return_statement);
+    
+    return this;
+}
+
+/** API Calls: Query API **/
+
+/**
+* Query
+*
+* @rest-parameter   {String, REQUIRED}  query, query string to pass to ASTERIX
+* @rest-parameter   {String}            mode, whether a call is "synchronous" or "asynchronous"
+* @rest-result      {Object}
+*                       {
+*                           @result     <result as a string, if mode = synchronous>
+*                           @error-code [<code>, <message>] if an error occurs
+*                           @handle:    <opaqure result handle, if mode = asynchronous>
+*                       }              
+* @endpoint         {Asterix REST API}  /query
+*/
+AsterixCoreAPI.prototype.api_core_query = function () {
+    
+    var api = this;
+    var use_dataverse = "use dataverse " + api.dataverse + ";\n";
+    var callbacks = {
+        "sync" : api.ui_callback_on_success,
+        "async" : api.ui_callback_on_success_async
+    };
+    var json = {
+        "endpoint" : "http://localhost:19101/query",
+        "query" : use_dataverse + api.parameters["statements"].join("\n"),
+        "mode" : api.parameters["mode"]
+    };
+
+    api.api_helper_proxy_handler(json, callbacks, api.extra);
+}
+
+/**
+* Query Status
+*
+* @rest-parameter   {Object, REQUIRED}  handle, opaque result handle from previous asynchronous query call
+* @rest-result      {Object}
+*                       {
+*                           @status: ("RUNNING" | "SUCCESS" | "ERROR" )
+*                       }
+* @endpoint         {Asterix REST API}  /query/status
+*/
+AsterixCoreAPI.prototype.api_core_query_status = function () {
+
+    var api = this;
+    
+    var use_dataverse = "use dataverse " + api.dataverse + ";\n";
+    
+    var callbacks = {
+        "sync" : this.ui_callback_on_success
+    };
+    
+    var json = {
+        "endpoint"  : "http://localhost:19101/query/status",
+        "handle"    : api.query_handle
+    };
+    
+    api.api_helper_proxy_handler(json, callbacks, api.extra);
+}
+
+/**
+* Query Result
+*
+* @rest-parameter   {Object, REQUIRED}  handle, opaque result handle from previous asynchronous query call
+* @rest-parameter   {String}            mode, "synchronous" by default, "asynchronous" if not
+* @rest-result      {Object}
+*                       {
+*                           @result     <result as a string, if mode = synchronous or asynchrous result available
+*                                           {} if mode is asynchronous and results not available >
+*                           @error-code [<code>, <message>] if an error occurs
+*                       }
+* @endpoint         {Asterix REST API}  /query/result
+*/
+AsterixCoreAPI.prototype.api_core_query_result = function () {
+    
+    var api = this;
+    
+    var use_dataverse = "use dataverse " + api.dataverse + ";\n";
+    
+    var callbacks = {
+        "sync" : this.ui_callback_on_success
+    };
+    
+    var json = {
+        "endpoint" : "http://localhost:19101/query/result",
+        "handle" : api.query_handle      
+    };
+    
+    api.api_helper_proxy_handler(json, callbacks, api.extra);
+}
+
+/** API Calls - Update API **/
+
+/**
+* Update
+*
+* @rest-parameter 
+*/
+AsterixCoreAPI.prototype.api_core_update = function () {
+
+    var api = this;
+    
+    var dataverse_statement = 'use dataverse ' + this.dataverse + '; ';
+    
+    var json = {
+        "endpoint" : "http://localhost:19101/update",
+        "statements" : dataverse_statement + this.parameters["statements"].join(" ")
+    };
+    
+   $.ajax({
+        type : 'POST',
+        url: "ajaxFacadeCherry.php",
+        data: json,
+        dataType: "json",
+        success: function(data) {
+
+            // Update API special case
+            if (data == "") {
+                api.ui_callback_on_success(api.extra);
+                
+            } else {
+                var response = $.parseJSON(data[0]);
+                
+                if (response && response["error-code"]) {
+                
+                    api.api_helper_default_on_error(response["error-code"][0], response["error-code"][1]);
+                
+                } else if (response && response["results"]) {
+                
+                    alert("Response: " + response["results"]);
+                
+                } else if (!response) {
+                
+                    api.api_helper_default_on_error(4, "Update API Call Error");
+                
+                }
+            }
+        }
+    
+    });
+}
+
+/** API Calls - DDL API **/
+    
+/**
+* DDL
+*
+* @rest-parameter   {Object, REQUIRED}  DDL
+* @rest-result      {Object}
+*                       {
+*                           @result:    <array of results, one per DDL statement in input>
+*                       }
+* @endpoint         {Asterix REST API}  /ddl
+*/
+AsterixCoreAPI.prototype.api_core_ddl = function () {
+    var api = this;
+    
+    var dataverse_statement = 'use dataverse ' + this.dataverse + '; ';
+    
+    var json = {
+        "endpoint" : "http://localhost:19101/ddl",
+        "ddl" : dataverse_statement + this.parameters["statements"].join(" ")
+    };
+    
+    var callback = {
+        "sync" : api.ui_callback_on_success
+    };
+    
+    api.api_helper_proxy_handler(json, callback, api.extra);
+}
+
+/** API Utilities **/
+
+/**
+* API Helper - Proxy Handler [TEMPORARY]
+*
+* @param    {Object}    json, the JSON object containing the parameters and endpoint for this API call
+* @param    {Objct}     callback, the on-success callbacks for this handler
+*               {
+*                   "sync" : default callback
+*                   "async" : non-default callback
+*               }
+* @param    {Object}    extra, any extra stuff passed from UI [TEMPORARY]
+*/
+AsterixCoreAPI.prototype.api_helper_proxy_handler = function(json, callback, extra) {
+    
+    /*var callbacks = {
+        "sync" : api.ui_callback_on_success,
+        "async" : api.ui_callback_on_success_async
+    };
+    var json = {
+        "endpoint" : "http://localhost:19101/query",
+        "query" : use_dataverse + api.parameters["statements"].join("\n"),
+        "mode" : api.parameters["mode"]
+    };*/
+    var as = new AsterixSDK();
+    api = this;
+
+    var branch = function(response) {
+        
+        if (response && response["error-code"]) {
+            
+            api.api_helper_default_on_error( response["error-code"][0], response["error-code"][1] );     
+            
+        } else if (response && response["results"]) {
+            var fn_callback = callback["sync"];
+            fn_callback(response, extra);
+            
+        } else if (response["handle"]) {
+            
+            var fn_callback = callback["async"];
+            fn_callback(response, extra);
+            
+        } else if (response["status"]) {
+                
+            var fn_callback = callback["sync"];
+            fn_callback(response, extra);
+        }
+    };
+
+    var c = {
+        "onSend" : function() {
+            return {
+                "endpoint" : json["endpoint"],
+                "apiData" : {
+                    "query" : json["query"],
+                    "mode" : json["mode"]
+                },
+                "callback" : branch
+            };
+        }
+    };
+    as.send(c);
+}
+
+/**
+* API Helper - Error Handler
+* Currently does an alert, but a more graceful notification would be better.
+* 
+* @param    {Number}    error_code, ( 1 | 2 | 99 ) denoting type of error
+* @param    {String}    error_message, an informative message about the error
+*/
+AsterixCoreAPI.prototype.api_helper_default_on_error = function (error_code, error_message) {
+    alert("ERROR " + error_code + ": " + error_message);       
+}
diff --git a/asterix-examples/src/main/resources/cherry/js/bootstrap-dropdown.js b/asterix-examples/src/main/resources/cherry/js/bootstrap-dropdown.js
new file mode 100755
index 0000000..8c98968
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/js/bootstrap-dropdown.js
@@ -0,0 +1,846 @@
+  
+
+
+<!DOCTYPE html>
+<html>
+  <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# githubog: http://ogp.me/ns/fb/githubog#">
+    <meta charset='utf-8'>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+        <title>bootstrap/docs/assets/js/bootstrap-dropdown.js at master · twitter/bootstrap</title>
+    <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub" />
+    <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub" />
+    <link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-114.png" />
+    <link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114.png" />
+    <link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-144.png" />
+    <link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144.png" />
+    <link rel="logo" type="image/svg" href="http://github-media-downloads.s3.amazonaws.com/github-logo.svg" />
+    <meta name="msapplication-TileImage" content="/windows-tile.png">
+    <meta name="msapplication-TileColor" content="#ffffff">
+
+    
+    
+    <link rel="icon" type="image/x-icon" href="/favicon.ico" />
+
+    <meta content="authenticity_token" name="csrf-param" />
+<meta content="FKZO7VCs2vemON7HGB4bRXA36101T7eVYLWJXyJ8FeY=" name="csrf-token" />
+
+    <link href="https://a248.e.akamai.net/assets.github.com/assets/github-c1b7909016a1df6d546eebce65d605438c51f5c7.css" media="all" rel="stylesheet" type="text/css" />
+    <link href="https://a248.e.akamai.net/assets.github.com/assets/github2-a70d440e2e461f87b4e7a06e02fbe906a55b49b5.css" media="all" rel="stylesheet" type="text/css" />
+    
+
+
+      <script src="https://a248.e.akamai.net/assets.github.com/assets/frameworks-d76b58e749b52bc47a4c46620bf2c320fabe5248.js" type="text/javascript"></script>
+      <script src="https://a248.e.akamai.net/assets.github.com/assets/github-bc24a03e43b13c54969f05228849f804fda1b806.js" type="text/javascript"></script>
+      
+      <meta http-equiv="x-pjax-version" content="66b88c7db22db852b164ad07a8656f79">
+
+        <link data-pjax-transient rel='permalink' href='/twitter/bootstrap/blob/eb24718add4dd36fe92fdbdb79e6ff4ce5919300/docs/assets/js/bootstrap-dropdown.js'>
+    <meta property="og:title" content="bootstrap"/>
+    <meta property="og:type" content="githubog:gitrepository"/>
+    <meta property="og:url" content="https://github.com/twitter/bootstrap"/>
+    <meta property="og:image" content="https://secure.gravatar.com/avatar/2f4a8254d032a8ec5e4c48d461e54fcc?s=420&amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png"/>
+    <meta property="og:site_name" content="GitHub"/>
+    <meta property="og:description" content="bootstrap - Sleek, intuitive, and powerful front-end framework for faster and easier web development."/>
+    <meta property="twitter:card" content="summary"/>
+    <meta property="twitter:site" content="@GitHub">
+    <meta property="twitter:title" content="twitter/bootstrap"/>
+
+    <meta name="description" content="bootstrap - Sleek, intuitive, and powerful front-end framework for faster and easier web development." />
+
+  <link href="https://github.com/twitter/bootstrap/commits/master.atom" rel="alternate" title="Recent Commits to bootstrap:master" type="application/atom+xml" />
+
+  </head>
+
+
+  <body class="logged_in page-blob linux vis-public env-production  ">
+    <div id="wrapper">
+
+      
+
+      
+
+      
+
+      
+
+
+        <div class="header header-logged-in true">
+          <div class="container clearfix">
+
+            <a class="header-logo-blacktocat" href="https://github.com/">
+  <span class="mega-icon mega-icon-blacktocat"></span>
+</a>
+
+            <div class="divider-vertical"></div>
+
+            
+  <a href="/notifications" class="notification-indicator tooltipped downwards" title="You have unread notifications">
+    <span class="mail-status unread"></span>
+  </a>
+  <div class="divider-vertical"></div>
+
+
+              <div class="command-bar js-command-bar  ">
+      <form accept-charset="UTF-8" action="/search" class="command-bar-form" id="top_search_form" method="get">
+  <a href="/search/advanced" class="advanced-search-icon tooltipped downwards command-bar-search" id="advanced_search" title="Advanced search"><span class="mini-icon mini-icon-advanced-search "></span></a>
+
+  <input type="text" name="q" id="js-command-bar-field" placeholder="Search or type a command" tabindex="1" data-username="bravelittlescientist" autocapitalize="off">
+
+  <span class="mini-icon help tooltipped downwards" title="Show command bar help">
+    <span class="mini-icon mini-icon-help"></span>
+  </span>
+
+  <input type="hidden" name="ref" value="commandbar">
+
+  <div class="divider-vertical"></div>
+</form>
+  <ul class="top-nav">
+      <li class="explore"><a href="https://github.com/explore">Explore</a></li>
+      <li><a href="https://gist.github.com">Gist</a></li>
+      <li><a href="/blog">Blog</a></li>
+    <li><a href="http://help.github.com">Help</a></li>
+  </ul>
+</div>
+
+
+            
+
+  
+    <ul id="user-links">
+      <li>
+        <a href="https://github.com/bravelittlescientist" class="name">
+          <img height="20" src="https://secure.gravatar.com/avatar/a4ced9dea455748842169cd53b6a3943?s=140&amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" width="20" /> bravelittlescientist
+        </a>
+      </li>
+      <li>
+        <a href="/new" id="new_repo" class="tooltipped downwards" title="Create a new repo">
+          <span class="mini-icon mini-icon-create"></span>
+        </a>
+      </li>
+      <li>
+        <a href="/settings/profile" id="account_settings"
+          class="tooltipped downwards"
+          title="Account settings ">
+          <span class="mini-icon mini-icon-account-settings"></span>
+        </a>
+      </li>
+      <li>
+        <a href="/logout" data-method="post" id="logout" class="tooltipped downwards" title="Sign out">
+          <span class="mini-icon mini-icon-logout"></span>
+        </a>
+      </li>
+    </ul>
+
+
+
+            
+          </div>
+        </div>
+
+
+      
+
+      
+
+
+            <div class="site hfeed" itemscope itemtype="http://schema.org/WebPage">
+      <div class="hentry">
+        
+        <div class="pagehead repohead instapaper_ignore readability-menu ">
+          <div class="container">
+            <div class="title-actions-bar">
+              
+
+
+<ul class="pagehead-actions">
+
+
+    <li class="subscription">
+      <form accept-charset="UTF-8" action="/notifications/subscribe" data-autosubmit="true" data-remote="true" method="post"><div style="margin:0;padding:0;display:inline"><input name="authenticity_token" type="hidden" value="FKZO7VCs2vemON7HGB4bRXA36101T7eVYLWJXyJ8FeY=" /></div>  <input id="repository_id" name="repository_id" type="hidden" value="2126244" />
+
+    <div class="select-menu js-menu-container js-select-menu">
+      <span class="minibutton select-menu-button js-menu-target">
+        <span class="js-select-button">
+          <span class="mini-icon mini-icon-watching"></span>
+          Watch
+        </span>
+      </span>
+
+      <div class="select-menu-modal-holder js-menu-content">
+        <div class="select-menu-modal">
+          <div class="select-menu-header">
+            <span class="select-menu-title">Notification status</span>
+            <span class="mini-icon mini-icon-remove-close js-menu-close"></span>
+          </div> <!-- /.select-menu-header -->
+
+          <div class="select-menu-list js-navigation-container">
+
+            <div class="select-menu-item js-navigation-item js-navigation-target selected">
+              <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+              <div class="select-menu-item-text">
+                <input checked="checked" id="do_included" name="do" type="radio" value="included" />
+                <h4>Not watching</h4>
+                <span class="description">You only receive notifications for discussions in which you participate or are @mentioned.</span>
+                <span class="js-select-button-text hidden-select-button-text">
+                  <span class="mini-icon mini-icon-watching"></span>
+                  Watch
+                </span>
+              </div>
+            </div> <!-- /.select-menu-item -->
+
+            <div class="select-menu-item js-navigation-item js-navigation-target ">
+              <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+              <div class="select-menu-item-text">
+                <input id="do_subscribed" name="do" type="radio" value="subscribed" />
+                <h4>Watching</h4>
+                <span class="description">You receive notifications for all discussions in this repository.</span>
+                <span class="js-select-button-text hidden-select-button-text">
+                  <span class="mini-icon mini-icon-unwatch"></span>
+                  Unwatch
+                </span>
+              </div>
+            </div> <!-- /.select-menu-item -->
+
+            <div class="select-menu-item js-navigation-item js-navigation-target ">
+              <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+              <div class="select-menu-item-text">
+                <input id="do_ignore" name="do" type="radio" value="ignore" />
+                <h4>Ignoring</h4>
+                <span class="description">You do not receive any notifications for discussions in this repository.</span>
+                <span class="js-select-button-text hidden-select-button-text">
+                  <span class="mini-icon mini-icon-mute"></span>
+                  Stop ignoring
+                </span>
+              </div>
+            </div> <!-- /.select-menu-item -->
+
+          </div> <!-- /.select-menu-list -->
+
+        </div> <!-- /.select-menu-modal -->
+      </div> <!-- /.select-menu-modal-holder -->
+    </div> <!-- /.select-menu -->
+
+</form>
+    </li>
+
+    <li class="js-toggler-container js-social-container starring-container ">
+      <a href="/twitter/bootstrap/unstar" class="minibutton js-toggler-target star-button starred upwards" title="Unstar this repo" data-remote="true" data-method="post" rel="nofollow">
+        <span class="mini-icon mini-icon-remove-star"></span>
+        <span class="text">Unstar</span>
+      </a>
+      <a href="/twitter/bootstrap/star" class="minibutton js-toggler-target star-button unstarred upwards" title="Star this repo" data-remote="true" data-method="post" rel="nofollow">
+        <span class="mini-icon mini-icon-star"></span>
+        <span class="text">Star</span>
+      </a>
+      <a class="social-count js-social-count" href="/twitter/bootstrap/stargazers">46,640</a>
+    </li>
+
+        <li>
+          <a href="/twitter/bootstrap/fork_select" class="minibutton js-toggler-target fork-button lighter upwards" title="Fork this repo" rel="facebox nofollow">
+            <span class="mini-icon mini-icon-branch-create"></span>
+            <span class="text">Fork</span>
+          </a>
+          <a href="/twitter/bootstrap/network" class="social-count">13,468</a>
+        </li>
+
+
+</ul>
+
+              <h1 itemscope itemtype="http://data-vocabulary.org/Breadcrumb" class="entry-title public">
+                <span class="repo-label"><span>public</span></span>
+                <span class="mega-icon mega-icon-public-repo"></span>
+                <span class="author vcard">
+                  <a href="/twitter" class="url fn" itemprop="url" rel="author">
+                  <span itemprop="title">twitter</span>
+                  </a></span> /
+                <strong><a href="/twitter/bootstrap" class="js-current-repository">bootstrap</a></strong>
+              </h1>
+            </div>
+
+            
+  <ul class="tabs">
+    <li><a href="/twitter/bootstrap" class="selected" highlight="repo_source repo_downloads repo_commits repo_tags repo_branches">Code</a></li>
+    <li><a href="/twitter/bootstrap/network" highlight="repo_network">Network</a></li>
+    <li><a href="/twitter/bootstrap/pulls" highlight="repo_pulls">Pull Requests <span class='counter'>63</span></a></li>
+
+      <li><a href="/twitter/bootstrap/issues" highlight="repo_issues">Issues <span class='counter'>150</span></a></li>
+
+      <li><a href="/twitter/bootstrap/wiki" highlight="repo_wiki">Wiki</a></li>
+
+
+    <li><a href="/twitter/bootstrap/graphs" highlight="repo_graphs repo_contributors">Graphs</a></li>
+
+
+  </ul>
+  
+<div class="tabnav">
+
+  <span class="tabnav-right">
+    <ul class="tabnav-tabs">
+          <li><a href="/twitter/bootstrap/tags" class="tabnav-tab" highlight="repo_tags">Tags <span class="counter ">18</span></a></li>
+    </ul>
+    
+  </span>
+
+  <div class="tabnav-widget scope">
+
+
+    <div class="select-menu js-menu-container js-select-menu js-branch-menu">
+      <a class="minibutton select-menu-button js-menu-target" data-hotkey="w" data-ref="master">
+        <span class="mini-icon mini-icon-branch"></span>
+        <i>branch:</i>
+        <span class="js-select-button">master</span>
+      </a>
+
+      <div class="select-menu-modal-holder js-menu-content js-navigation-container">
+
+        <div class="select-menu-modal">
+          <div class="select-menu-header">
+            <span class="select-menu-title">Switch branches/tags</span>
+            <span class="mini-icon mini-icon-remove-close js-menu-close"></span>
+          </div> <!-- /.select-menu-header -->
+
+          <div class="select-menu-filters">
+            <div class="select-menu-text-filter">
+              <input type="text" id="commitish-filter-field" class="js-filterable-field js-navigation-enable" placeholder="Filter branches/tags">
+            </div>
+            <div class="select-menu-tabs">
+              <ul>
+                <li class="select-menu-tab">
+                  <a href="#" data-tab-filter="branches" class="js-select-menu-tab">Branches</a>
+                </li>
+                <li class="select-menu-tab">
+                  <a href="#" data-tab-filter="tags" class="js-select-menu-tab">Tags</a>
+                </li>
+              </ul>
+            </div><!-- /.select-menu-tabs -->
+          </div><!-- /.select-menu-filters -->
+
+          <div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket css-truncate" data-tab-filter="branches">
+
+            <div data-filterable-for="commitish-filter-field" data-filterable-type="substring">
+
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/3.0.0-wip/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="3.0.0-wip" rel="nofollow" title="3.0.0-wip">3.0.0-wip</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/bootjack/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="bootjack" rel="nofollow" title="bootjack">bootjack</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/bs3_makefile_separated_done/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="bs3_makefile_separated_done" rel="nofollow" title="bs3_makefile_separated_done">bs3_makefile_separated_done</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/gh-pages/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="gh-pages" rel="nofollow" title="gh-pages">gh-pages</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target selected">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/master/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="master" rel="nofollow" title="master">master</a>
+                </div> <!-- /.select-menu-item -->
+            </div>
+
+              <div class="select-menu-no-results">Nothing to show</div>
+          </div> <!-- /.select-menu-list -->
+
+
+          <div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket css-truncate" data-tab-filter="tags">
+            <div data-filterable-for="commitish-filter-field" data-filterable-type="substring">
+
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.3.1/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.3.1" rel="nofollow" title="v2.3.1">v2.3.1</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.3.0/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.3.0" rel="nofollow" title="v2.3.0">v2.3.0</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.2.2/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.2.2" rel="nofollow" title="v2.2.2">v2.2.2</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.2.1/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.2.1" rel="nofollow" title="v2.2.1">v2.2.1</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.2.0/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.2.0" rel="nofollow" title="v2.2.0">v2.2.0</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.1.1/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.1.1" rel="nofollow" title="v2.1.1">v2.1.1</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.1.0/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.1.0" rel="nofollow" title="v2.1.0">v2.1.0</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.0.4/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.0.4" rel="nofollow" title="v2.0.4">v2.0.4</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.0.3/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.0.3" rel="nofollow" title="v2.0.3">v2.0.3</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.0.2/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.0.2" rel="nofollow" title="v2.0.2">v2.0.2</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.0.1/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.0.1" rel="nofollow" title="v2.0.1">v2.0.1</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v2.0.0/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v2.0.0" rel="nofollow" title="v2.0.0">v2.0.0</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v1.4.0/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v1.4.0" rel="nofollow" title="v1.4.0">v1.4.0</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v1.3.0/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v1.3.0" rel="nofollow" title="v1.3.0">v1.3.0</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v1.2.0/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v1.2.0" rel="nofollow" title="v1.2.0">v1.2.0</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v1.1.1/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v1.1.1" rel="nofollow" title="v1.1.1">v1.1.1</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v1.1.0/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v1.1.0" rel="nofollow" title="v1.1.0">v1.1.0</a>
+                </div> <!-- /.select-menu-item -->
+                <div class="select-menu-item js-navigation-item js-navigation-target ">
+                  <span class="select-menu-item-icon mini-icon mini-icon-confirm"></span>
+                  <a href="/twitter/bootstrap/blob/v1.0.0/docs/assets/js/bootstrap-dropdown.js" class="js-navigation-open select-menu-item-text js-select-button-text css-truncate-target" data-name="v1.0.0" rel="nofollow" title="v1.0.0">v1.0.0</a>
+                </div> <!-- /.select-menu-item -->
+            </div>
+
+            <div class="select-menu-no-results">Nothing to show</div>
+
+          </div> <!-- /.select-menu-list -->
+
+        </div> <!-- /.select-menu-modal -->
+      </div> <!-- /.select-menu-modal-holder -->
+    </div> <!-- /.select-menu -->
+
+  </div> <!-- /.scope -->
+
+  <ul class="tabnav-tabs">
+    <li><a href="/twitter/bootstrap" class="selected tabnav-tab" highlight="repo_source">Files</a></li>
+    <li><a href="/twitter/bootstrap/commits/master" class="tabnav-tab" highlight="repo_commits">Commits</a></li>
+    <li><a href="/twitter/bootstrap/branches" class="tabnav-tab" highlight="repo_branches" rel="nofollow">Branches <span class="counter ">5</span></a></li>
+  </ul>
+
+</div>
+
+  
+  
+  
+
+
+            
+          </div>
+        </div><!-- /.repohead -->
+
+        <div id="js-repo-pjax-container" class="container context-loader-container" data-pjax-container>
+          
+
+
+<!-- blob contrib key: blob_contributors:v21:f057f0d70e047da6e902871fa10ec7a8 -->
+<!-- blob contrib frag key: views10/v8/blob_contributors:v21:f057f0d70e047da6e902871fa10ec7a8 -->
+
+
+<div id="slider">
+    <div class="frame-meta">
+
+      <p title="This is a placeholder element" class="js-history-link-replace hidden"></p>
+
+        <div class="breadcrumb">
+          <span class='bold'><span itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb"><a href="/twitter/bootstrap" class="js-slide-to" data-branch="master" data-direction="back" itemscope="url"><span itemprop="title">bootstrap</span></a></span></span><span class="separator"> / </span><span itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb"><a href="/twitter/bootstrap/tree/master/docs" class="js-slide-to" data-branch="master" data-direction="back" itemscope="url"><span itemprop="title">docs</span></a></span><span class="separator"> / </span><span itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb"><a href="/twitter/bootstrap/tree/master/docs/assets" class="js-slide-to" data-branch="master" data-direction="back" itemscope="url"><span itemprop="title">assets</span></a></span><span class="separator"> / </span><span itemscope="" itemtype="http://data-vocabulary.org/Breadcrumb"><a href="/twitter/bootstrap/tree/master/docs/assets/js" class="js-slide-to" data-branch="master" data-direction="back" itemscope="url"><span itemprop="title">js</span></a></span><span class="separator"> / </span><strong class="final-path">bootstrap-dropdown.js</strong> <span class="js-zeroclipboard zeroclipboard-button" data-clipboard-text="docs/assets/js/bootstrap-dropdown.js" data-copied-hint="copied!" title="copy to clipboard"><span class="mini-icon mini-icon-clipboard"></span></span>
+        </div>
+
+      <a href="/twitter/bootstrap/find/master" class="js-slide-to" data-hotkey="t" style="display:none">Show File Finder</a>
+
+
+        
+  <div class="commit file-history-tease">
+    <img class="main-avatar" height="24" src="https://secure.gravatar.com/avatar/a98244cbdacaf1c0b55499466002f7a8?s=140&amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" width="24" />
+    <span class="author"><a href="/fat" rel="author">fat</a></span>
+    <time class="js-relative-date" datetime="2013-02-28T20:55:14-08:00" title="2013-02-28 20:55:14">February 28, 2013</time>
+    <div class="commit-title">
+        <a href="/twitter/bootstrap/commit/3469339068a5676b225af7a39dffcad41e391934" class="message">2.3.1</a>
+    </div>
+
+    <div class="participation">
+      <p class="quickstat"><a href="#blob_contributors_box" rel="facebox"><strong>3</strong> contributors</a></p>
+          <a class="avatar tooltipped downwards" title="fat" href="/twitter/bootstrap/commits/6b2a010357e184e670a2f4768e37d4886e8a6597/docs/assets/js/bootstrap-dropdown.js?author=fat"><img height="20" src="https://secure.gravatar.com/avatar/a98244cbdacaf1c0b55499466002f7a8?s=140&amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" width="20" /></a>
+    <a class="avatar tooltipped downwards" title="mdo" href="/twitter/bootstrap/commits/6b2a010357e184e670a2f4768e37d4886e8a6597/docs/assets/js/bootstrap-dropdown.js?author=mdo"><img height="20" src="https://secure.gravatar.com/avatar/bc4ab438f7a4ce1c406aadc688427f2c?s=140&amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" width="20" /></a>
+    <a class="avatar tooltipped downwards" title="erlendfh" href="/twitter/bootstrap/commits/6b2a010357e184e670a2f4768e37d4886e8a6597/docs/assets/js/bootstrap-dropdown.js?author=erlendfh"><img height="20" src="https://secure.gravatar.com/avatar/cf4621433dfa81bba4712eed74acbebb?s=140&amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" width="20" /></a>
+
+
+    </div>
+    <div id="blob_contributors_box" style="display:none">
+      <h2>Users on GitHub who have contributed to this file</h2>
+      <ul class="facebox-user-list">
+        <li>
+          <img height="24" src="https://secure.gravatar.com/avatar/a98244cbdacaf1c0b55499466002f7a8?s=140&amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" width="24" />
+          <a href="/fat">fat</a>
+        </li>
+        <li>
+          <img height="24" src="https://secure.gravatar.com/avatar/bc4ab438f7a4ce1c406aadc688427f2c?s=140&amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" width="24" />
+          <a href="/mdo">mdo</a>
+        </li>
+        <li>
+          <img height="24" src="https://secure.gravatar.com/avatar/cf4621433dfa81bba4712eed74acbebb?s=140&amp;d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png" width="24" />
+          <a href="/erlendfh">erlendfh</a>
+        </li>
+      </ul>
+    </div>
+  </div>
+
+
+    </div><!-- ./.frame-meta -->
+
+    <div class="frames">
+      <div class="frame" data-permalink-url="/twitter/bootstrap/blob/eb24718add4dd36fe92fdbdb79e6ff4ce5919300/docs/assets/js/bootstrap-dropdown.js" data-title="bootstrap/docs/assets/js/bootstrap-dropdown.js at master · twitter/bootstrap · GitHub" data-type="blob">
+
+        <div id="files" class="bubble">
+          <div class="file">
+            <div class="meta">
+              <div class="info">
+                <span class="icon"><b class="mini-icon mini-icon-text-file"></b></span>
+                <span class="mode" title="File Mode">file</span>
+                  <span>166 lines (117 sloc)</span>
+                <span>4.203 kb</span>
+              </div>
+              <div class="actions">
+                <div class="button-group">
+                        <a class="minibutton tooltipped leftwards"
+                           title="Clicking this button will automatically fork this project so you can edit the file"
+                           href="/twitter/bootstrap/edit/master/docs/assets/js/bootstrap-dropdown.js"
+                           data-method="post" rel="nofollow">Edit</a>
+                  <a href="/twitter/bootstrap/raw/master/docs/assets/js/bootstrap-dropdown.js" class="button minibutton " id="raw-url">Raw</a>
+                    <a href="/twitter/bootstrap/blame/master/docs/assets/js/bootstrap-dropdown.js" class="button minibutton ">Blame</a>
+                  <a href="/twitter/bootstrap/commits/master/docs/assets/js/bootstrap-dropdown.js" class="button minibutton " rel="nofollow">History</a>
+                </div><!-- /.button-group -->
+              </div><!-- /.actions -->
+
+            </div>
+                <div class="data type-javascript js-blob-data">
+      <table cellpadding="0" cellspacing="0" class="lines">
+        <tr>
+          <td>
+            <pre class="line_numbers"><span id="L1" rel="#L1">1</span>
+<span id="L2" rel="#L2">2</span>
+<span id="L3" rel="#L3">3</span>
+<span id="L4" rel="#L4">4</span>
+<span id="L5" rel="#L5">5</span>
+<span id="L6" rel="#L6">6</span>
+<span id="L7" rel="#L7">7</span>
+<span id="L8" rel="#L8">8</span>
+<span id="L9" rel="#L9">9</span>
+<span id="L10" rel="#L10">10</span>
+<span id="L11" rel="#L11">11</span>
+<span id="L12" rel="#L12">12</span>
+<span id="L13" rel="#L13">13</span>
+<span id="L14" rel="#L14">14</span>
+<span id="L15" rel="#L15">15</span>
+<span id="L16" rel="#L16">16</span>
+<span id="L17" rel="#L17">17</span>
+<span id="L18" rel="#L18">18</span>
+<span id="L19" rel="#L19">19</span>
+<span id="L20" rel="#L20">20</span>
+<span id="L21" rel="#L21">21</span>
+<span id="L22" rel="#L22">22</span>
+<span id="L23" rel="#L23">23</span>
+<span id="L24" rel="#L24">24</span>
+<span id="L25" rel="#L25">25</span>
+<span id="L26" rel="#L26">26</span>
+<span id="L27" rel="#L27">27</span>
+<span id="L28" rel="#L28">28</span>
+<span id="L29" rel="#L29">29</span>
+<span id="L30" rel="#L30">30</span>
+<span id="L31" rel="#L31">31</span>
+<span id="L32" rel="#L32">32</span>
+<span id="L33" rel="#L33">33</span>
+<span id="L34" rel="#L34">34</span>
+<span id="L35" rel="#L35">35</span>
+<span id="L36" rel="#L36">36</span>
+<span id="L37" rel="#L37">37</span>
+<span id="L38" rel="#L38">38</span>
+<span id="L39" rel="#L39">39</span>
+<span id="L40" rel="#L40">40</span>
+<span id="L41" rel="#L41">41</span>
+<span id="L42" rel="#L42">42</span>
+<span id="L43" rel="#L43">43</span>
+<span id="L44" rel="#L44">44</span>
+<span id="L45" rel="#L45">45</span>
+<span id="L46" rel="#L46">46</span>
+<span id="L47" rel="#L47">47</span>
+<span id="L48" rel="#L48">48</span>
+<span id="L49" rel="#L49">49</span>
+<span id="L50" rel="#L50">50</span>
+<span id="L51" rel="#L51">51</span>
+<span id="L52" rel="#L52">52</span>
+<span id="L53" rel="#L53">53</span>
+<span id="L54" rel="#L54">54</span>
+<span id="L55" rel="#L55">55</span>
+<span id="L56" rel="#L56">56</span>
+<span id="L57" rel="#L57">57</span>
+<span id="L58" rel="#L58">58</span>
+<span id="L59" rel="#L59">59</span>
+<span id="L60" rel="#L60">60</span>
+<span id="L61" rel="#L61">61</span>
+<span id="L62" rel="#L62">62</span>
+<span id="L63" rel="#L63">63</span>
+<span id="L64" rel="#L64">64</span>
+<span id="L65" rel="#L65">65</span>
+<span id="L66" rel="#L66">66</span>
+<span id="L67" rel="#L67">67</span>
+<span id="L68" rel="#L68">68</span>
+<span id="L69" rel="#L69">69</span>
+<span id="L70" rel="#L70">70</span>
+<span id="L71" rel="#L71">71</span>
+<span id="L72" rel="#L72">72</span>
+<span id="L73" rel="#L73">73</span>
+<span id="L74" rel="#L74">74</span>
+<span id="L75" rel="#L75">75</span>
+<span id="L76" rel="#L76">76</span>
+<span id="L77" rel="#L77">77</span>
+<span id="L78" rel="#L78">78</span>
+<span id="L79" rel="#L79">79</span>
+<span id="L80" rel="#L80">80</span>
+<span id="L81" rel="#L81">81</span>
+<span id="L82" rel="#L82">82</span>
+<span id="L83" rel="#L83">83</span>
+<span id="L84" rel="#L84">84</span>
+<span id="L85" rel="#L85">85</span>
+<span id="L86" rel="#L86">86</span>
+<span id="L87" rel="#L87">87</span>
+<span id="L88" rel="#L88">88</span>
+<span id="L89" rel="#L89">89</span>
+<span id="L90" rel="#L90">90</span>
+<span id="L91" rel="#L91">91</span>
+<span id="L92" rel="#L92">92</span>
+<span id="L93" rel="#L93">93</span>
+<span id="L94" rel="#L94">94</span>
+<span id="L95" rel="#L95">95</span>
+<span id="L96" rel="#L96">96</span>
+<span id="L97" rel="#L97">97</span>
+<span id="L98" rel="#L98">98</span>
+<span id="L99" rel="#L99">99</span>
+<span id="L100" rel="#L100">100</span>
+<span id="L101" rel="#L101">101</span>
+<span id="L102" rel="#L102">102</span>
+<span id="L103" rel="#L103">103</span>
+<span id="L104" rel="#L104">104</span>
+<span id="L105" rel="#L105">105</span>
+<span id="L106" rel="#L106">106</span>
+<span id="L107" rel="#L107">107</span>
+<span id="L108" rel="#L108">108</span>
+<span id="L109" rel="#L109">109</span>
+<span id="L110" rel="#L110">110</span>
+<span id="L111" rel="#L111">111</span>
+<span id="L112" rel="#L112">112</span>
+<span id="L113" rel="#L113">113</span>
+<span id="L114" rel="#L114">114</span>
+<span id="L115" rel="#L115">115</span>
+<span id="L116" rel="#L116">116</span>
+<span id="L117" rel="#L117">117</span>
+<span id="L118" rel="#L118">118</span>
+<span id="L119" rel="#L119">119</span>
+<span id="L120" rel="#L120">120</span>
+<span id="L121" rel="#L121">121</span>
+<span id="L122" rel="#L122">122</span>
+<span id="L123" rel="#L123">123</span>
+<span id="L124" rel="#L124">124</span>
+<span id="L125" rel="#L125">125</span>
+<span id="L126" rel="#L126">126</span>
+<span id="L127" rel="#L127">127</span>
+<span id="L128" rel="#L128">128</span>
+<span id="L129" rel="#L129">129</span>
+<span id="L130" rel="#L130">130</span>
+<span id="L131" rel="#L131">131</span>
+<span id="L132" rel="#L132">132</span>
+<span id="L133" rel="#L133">133</span>
+<span id="L134" rel="#L134">134</span>
+<span id="L135" rel="#L135">135</span>
+<span id="L136" rel="#L136">136</span>
+<span id="L137" rel="#L137">137</span>
+<span id="L138" rel="#L138">138</span>
+<span id="L139" rel="#L139">139</span>
+<span id="L140" rel="#L140">140</span>
+<span id="L141" rel="#L141">141</span>
+<span id="L142" rel="#L142">142</span>
+<span id="L143" rel="#L143">143</span>
+<span id="L144" rel="#L144">144</span>
+<span id="L145" rel="#L145">145</span>
+<span id="L146" rel="#L146">146</span>
+<span id="L147" rel="#L147">147</span>
+<span id="L148" rel="#L148">148</span>
+<span id="L149" rel="#L149">149</span>
+<span id="L150" rel="#L150">150</span>
+<span id="L151" rel="#L151">151</span>
+<span id="L152" rel="#L152">152</span>
+<span id="L153" rel="#L153">153</span>
+<span id="L154" rel="#L154">154</span>
+<span id="L155" rel="#L155">155</span>
+<span id="L156" rel="#L156">156</span>
+<span id="L157" rel="#L157">157</span>
+<span id="L158" rel="#L158">158</span>
+<span id="L159" rel="#L159">159</span>
+<span id="L160" rel="#L160">160</span>
+<span id="L161" rel="#L161">161</span>
+<span id="L162" rel="#L162">162</span>
+<span id="L163" rel="#L163">163</span>
+<span id="L164" rel="#L164">164</span>
+<span id="L165" rel="#L165">165</span>
+</pre>
+          </td>
+          <td width="100%">
+                  <div class="highlight"><pre><div class='line' id='LC1'><span class="cm">/* ============================================================</span></div><div class='line' id='LC2'><span class="cm"> * bootstrap-dropdown.js v2.3.1</span></div><div class='line' id='LC3'><span class="cm"> * http://twitter.github.com/bootstrap/javascript.html#dropdowns</span></div><div class='line' id='LC4'><span class="cm"> * ============================================================</span></div><div class='line' id='LC5'><span class="cm"> * Copyright 2012 Twitter, Inc.</span></div><div class='line' id='LC6'><span class="cm"> *</span></div><div class='line' id='LC7'><span class="cm"> * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></div><div class='line' id='LC8'><span class="cm"> * you may not use this file except in compliance with the License.</span></div><div class='line' id='LC9'><span class="cm"> * You may obtain a copy of the License at</span></div><div class='line' id='LC10'><span class="cm"> *</span></div><div class='line' id='LC11'><span class="cm"> * http://www.apache.org/licenses/LICENSE-2.0</span></div><div class='line' id='LC12'><span class="cm"> *</span></div><div class='line' id='LC13'><span class="cm"> * Unless required by applicable law or agreed to in writing, software</span></div><div class='line' id='LC14'><span class="cm"> * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span></div><div class='line' id='LC15'><span class="cm"> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div class='line' id='LC16'><span class="cm"> * See the License for the specific language governing permissions and</span></div><div class='line' id='LC17'><span class="cm"> * limitations under the License.</span></div><div class='line' id='LC18'><span class="cm"> * ============================================================ */</span></div><div class='line' id='LC19'><br/></div><div class='line' id='LC20'><br/></div><div class='line' id='LC21'><span class="o">!</span><span class="kd">function</span> <span class="p">(</span><span class="nx">$</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC22'><br/></div><div class='line' id='LC23'>&nbsp;&nbsp;<span class="s2">&quot;use strict&quot;</span><span class="p">;</span> <span class="c1">// jshint ;_;</span></div><div class='line' id='LC24'><br/></div><div class='line' id='LC25'><br/></div><div class='line' id='LC26'>&nbsp;<span class="cm">/* DROPDOWN CLASS DEFINITION</span></div><div class='line' id='LC27'><span class="cm">  * ========================= */</span></div><div class='line' id='LC28'><br/></div><div class='line' id='LC29'>&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">toggle</span> <span class="o">=</span> <span class="s1">&#39;[data-toggle=dropdown]&#39;</span></div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">,</span> <span class="nx">Dropdown</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">element</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC31'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">$el</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">element</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;click.dropdown.data-api&#39;</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">toggle</span><span class="p">)</span></div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$</span><span class="p">(</span><span class="s1">&#39;html&#39;</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;click.dropdown.data-api&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$el</span><span class="p">.</span><span class="nx">parent</span><span class="p">().</span><span class="nx">removeClass</span><span class="p">(</span><span class="s1">&#39;open&#39;</span><span class="p">)</span></div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">})</span></div><div class='line' id='LC35'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC36'><br/></div><div class='line' id='LC37'>&nbsp;&nbsp;<span class="nx">Dropdown</span><span class="p">.</span><span class="nx">prototype</span> <span class="o">=</span> <span class="p">{</span></div><div class='line' id='LC38'><br/></div><div class='line' id='LC39'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">constructor</span><span class="o">:</span> <span class="nx">Dropdown</span></div><div class='line' id='LC40'><br/></div><div class='line' id='LC41'>&nbsp;&nbsp;<span class="p">,</span> <span class="nx">toggle</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC42'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">$this</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">)</span></div><div class='line' id='LC43'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">,</span> <span class="nx">$parent</span></div><div class='line' id='LC44'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">,</span> <span class="nx">isActive</span></div><div class='line' id='LC45'><br/></div><div class='line' id='LC46'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="nx">$this</span><span class="p">.</span><span class="nx">is</span><span class="p">(</span><span class="s1">&#39;.disabled, :disabled&#39;</span><span class="p">))</span> <span class="k">return</span></div><div class='line' id='LC47'><br/></div><div class='line' id='LC48'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$parent</span> <span class="o">=</span> <span class="nx">getParent</span><span class="p">(</span><span class="nx">$this</span><span class="p">)</span></div><div class='line' id='LC49'><br/></div><div class='line' id='LC50'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">isActive</span> <span class="o">=</span> <span class="nx">$parent</span><span class="p">.</span><span class="nx">hasClass</span><span class="p">(</span><span class="s1">&#39;open&#39;</span><span class="p">)</span></div><div class='line' id='LC51'><br/></div><div class='line' id='LC52'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">clearMenus</span><span class="p">()</span></div><div class='line' id='LC53'><br/></div><div class='line' id='LC54'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isActive</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC55'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$parent</span><span class="p">.</span><span class="nx">toggleClass</span><span class="p">(</span><span class="s1">&#39;open&#39;</span><span class="p">)</span></div><div class='line' id='LC56'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC57'><br/></div><div class='line' id='LC58'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$this</span><span class="p">.</span><span class="nx">focus</span><span class="p">()</span></div><div class='line' id='LC59'><br/></div><div class='line' id='LC60'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="kc">false</span></div><div class='line' id='LC61'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC62'><br/></div><div class='line' id='LC63'>&nbsp;&nbsp;<span class="p">,</span> <span class="nx">keydown</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC64'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">$this</span></div><div class='line' id='LC65'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">,</span> <span class="nx">$items</span></div><div class='line' id='LC66'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">,</span> <span class="nx">$active</span></div><div class='line' id='LC67'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">,</span> <span class="nx">$parent</span></div><div class='line' id='LC68'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">,</span> <span class="nx">isActive</span></div><div class='line' id='LC69'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">,</span> <span class="nx">index</span></div><div class='line' id='LC70'><br/></div><div class='line' id='LC71'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="sr">/(38|40|27)/</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span><span class="p">))</span> <span class="k">return</span></div><div class='line' id='LC72'><br/></div><div class='line' id='LC73'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$this</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">)</span></div><div class='line' id='LC74'><br/></div><div class='line' id='LC75'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">()</span></div><div class='line' id='LC76'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">e</span><span class="p">.</span><span class="nx">stopPropagation</span><span class="p">()</span></div><div class='line' id='LC77'><br/></div><div class='line' id='LC78'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="nx">$this</span><span class="p">.</span><span class="nx">is</span><span class="p">(</span><span class="s1">&#39;.disabled, :disabled&#39;</span><span class="p">))</span> <span class="k">return</span></div><div class='line' id='LC79'><br/></div><div class='line' id='LC80'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$parent</span> <span class="o">=</span> <span class="nx">getParent</span><span class="p">(</span><span class="nx">$this</span><span class="p">)</span></div><div class='line' id='LC81'><br/></div><div class='line' id='LC82'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">isActive</span> <span class="o">=</span> <span class="nx">$parent</span><span class="p">.</span><span class="nx">hasClass</span><span class="p">(</span><span class="s1">&#39;open&#39;</span><span class="p">)</span></div><div class='line' id='LC83'><br/></div><div class='line' id='LC84'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isActive</span> <span class="o">||</span> <span class="p">(</span><span class="nx">isActive</span> <span class="o">&amp;&amp;</span> <span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">==</span> <span class="mi">27</span><span class="p">))</span> <span class="p">{</span></div><div class='line' id='LC85'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">which</span> <span class="o">==</span> <span class="mi">27</span><span class="p">)</span> <span class="nx">$parent</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="nx">toggle</span><span class="p">).</span><span class="nx">focus</span><span class="p">()</span></div><div class='line' id='LC86'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="nx">$this</span><span class="p">.</span><span class="nx">click</span><span class="p">()</span></div><div class='line' id='LC87'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC88'><br/></div><div class='line' id='LC89'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$items</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;[role=menu] li:not(.divider):visible a&#39;</span><span class="p">,</span> <span class="nx">$parent</span><span class="p">)</span></div><div class='line' id='LC90'><br/></div><div class='line' id='LC91'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">$items</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="k">return</span></div><div class='line' id='LC92'><br/></div><div class='line' id='LC93'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">index</span> <span class="o">=</span> <span class="nx">$items</span><span class="p">.</span><span class="nx">index</span><span class="p">(</span><span class="nx">$items</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="s1">&#39;:focus&#39;</span><span class="p">))</span></div><div class='line' id='LC94'><br/></div><div class='line' id='LC95'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">==</span> <span class="mi">38</span> <span class="o">&amp;&amp;</span> <span class="nx">index</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="nx">index</span><span class="o">--</span>                                        <span class="c1">// up</span></div><div class='line' id='LC96'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">==</span> <span class="mi">40</span> <span class="o">&amp;&amp;</span> <span class="nx">index</span> <span class="o">&lt;</span> <span class="nx">$items</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="nx">index</span><span class="o">++</span>                        <span class="c1">// down</span></div><div class='line' id='LC97'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="o">!~</span><span class="nx">index</span><span class="p">)</span> <span class="nx">index</span> <span class="o">=</span> <span class="mi">0</span></div><div class='line' id='LC98'><br/></div><div class='line' id='LC99'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$items</span></div><div class='line' id='LC100'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">.</span><span class="nx">eq</span><span class="p">(</span><span class="nx">index</span><span class="p">)</span></div><div class='line' id='LC101'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">.</span><span class="nx">focus</span><span class="p">()</span></div><div class='line' id='LC102'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC103'><br/></div><div class='line' id='LC104'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC105'><br/></div><div class='line' id='LC106'>&nbsp;&nbsp;<span class="kd">function</span> <span class="nx">clearMenus</span><span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC107'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$</span><span class="p">(</span><span class="nx">toggle</span><span class="p">).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC108'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">getParent</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">)).</span><span class="nx">removeClass</span><span class="p">(</span><span class="s1">&#39;open&#39;</span><span class="p">)</span></div><div class='line' id='LC109'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">})</span></div><div class='line' id='LC110'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC111'><br/></div><div class='line' id='LC112'>&nbsp;&nbsp;<span class="kd">function</span> <span class="nx">getParent</span><span class="p">(</span><span class="nx">$this</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC113'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">selector</span> <span class="o">=</span> <span class="nx">$this</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;data-target&#39;</span><span class="p">)</span></div><div class='line' id='LC114'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">,</span> <span class="nx">$parent</span></div><div class='line' id='LC115'><br/></div><div class='line' id='LC116'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">selector</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC117'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">selector</span> <span class="o">=</span> <span class="nx">$this</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;href&#39;</span><span class="p">)</span></div><div class='line' id='LC118'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">selector</span> <span class="o">=</span> <span class="nx">selector</span> <span class="o">&amp;&amp;</span> <span class="sr">/#/</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">selector</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="nx">selector</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/.*(?=#[^\s]*$)/</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span> <span class="c1">//strip for ie7</span></div><div class='line' id='LC119'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC120'><br/></div><div class='line' id='LC121'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$parent</span> <span class="o">=</span> <span class="nx">selector</span> <span class="o">&amp;&amp;</span> <span class="nx">$</span><span class="p">(</span><span class="nx">selector</span><span class="p">)</span></div><div class='line' id='LC122'><br/></div><div class='line' id='LC123'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">$parent</span> <span class="o">||</span> <span class="o">!</span><span class="nx">$parent</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="nx">$parent</span> <span class="o">=</span> <span class="nx">$this</span><span class="p">.</span><span class="nx">parent</span><span class="p">()</span></div><div class='line' id='LC124'><br/></div><div class='line' id='LC125'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="nx">$parent</span></div><div class='line' id='LC126'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC127'><br/></div><div class='line' id='LC128'><br/></div><div class='line' id='LC129'>&nbsp;&nbsp;<span class="cm">/* DROPDOWN PLUGIN DEFINITION</span></div><div class='line' id='LC130'><span class="cm">   * ========================== */</span></div><div class='line' id='LC131'><br/></div><div class='line' id='LC132'>&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">old</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">fn</span><span class="p">.</span><span class="nx">dropdown</span></div><div class='line' id='LC133'><br/></div><div class='line' id='LC134'>&nbsp;&nbsp;<span class="nx">$</span><span class="p">.</span><span class="nx">fn</span><span class="p">.</span><span class="nx">dropdown</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">option</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC135'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC136'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">$this</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">)</span></div><div class='line' id='LC137'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">,</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">$this</span><span class="p">.</span><span class="nx">data</span><span class="p">(</span><span class="s1">&#39;dropdown&#39;</span><span class="p">)</span></div><div class='line' id='LC138'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">data</span><span class="p">)</span> <span class="nx">$this</span><span class="p">.</span><span class="nx">data</span><span class="p">(</span><span class="s1">&#39;dropdown&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nx">data</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Dropdown</span><span class="p">(</span><span class="k">this</span><span class="p">)))</span></div><div class='line' id='LC139'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">option</span> <span class="o">==</span> <span class="s1">&#39;string&#39;</span><span class="p">)</span> <span class="nx">data</span><span class="p">[</span><span class="nx">option</span><span class="p">].</span><span class="nx">call</span><span class="p">(</span><span class="nx">$this</span><span class="p">)</span></div><div class='line' id='LC140'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">})</span></div><div class='line' id='LC141'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC142'><br/></div><div class='line' id='LC143'>&nbsp;&nbsp;<span class="nx">$</span><span class="p">.</span><span class="nx">fn</span><span class="p">.</span><span class="nx">dropdown</span><span class="p">.</span><span class="nx">Constructor</span> <span class="o">=</span> <span class="nx">Dropdown</span></div><div class='line' id='LC144'><br/></div><div class='line' id='LC145'><br/></div><div class='line' id='LC146'>&nbsp;<span class="cm">/* DROPDOWN NO CONFLICT</span></div><div class='line' id='LC147'><span class="cm">  * ==================== */</span></div><div class='line' id='LC148'><br/></div><div class='line' id='LC149'>&nbsp;&nbsp;<span class="nx">$</span><span class="p">.</span><span class="nx">fn</span><span class="p">.</span><span class="nx">dropdown</span><span class="p">.</span><span class="nx">noConflict</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC150'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">$</span><span class="p">.</span><span class="nx">fn</span><span class="p">.</span><span class="nx">dropdown</span> <span class="o">=</span> <span class="nx">old</span></div><div class='line' id='LC151'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="k">this</span></div><div class='line' id='LC152'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC153'><br/></div><div class='line' id='LC154'><br/></div><div class='line' id='LC155'>&nbsp;&nbsp;<span class="cm">/* APPLY TO STANDARD DROPDOWN ELEMENTS</span></div><div class='line' id='LC156'><span class="cm">   * =================================== */</span></div><div class='line' id='LC157'><br/></div><div class='line' id='LC158'>&nbsp;&nbsp;<span class="nx">$</span><span class="p">(</span><span class="nb">document</span><span class="p">)</span></div><div class='line' id='LC159'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;click.dropdown.data-api&#39;</span><span class="p">,</span> <span class="nx">clearMenus</span><span class="p">)</span></div><div class='line' id='LC160'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;click.dropdown.data-api&#39;</span><span class="p">,</span> <span class="s1">&#39;.dropdown form&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span> <span class="nx">e</span><span class="p">.</span><span class="nx">stopPropagation</span><span class="p">()</span> <span class="p">})</span></div><div class='line' id='LC161'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;click.dropdown-menu&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span> <span class="nx">e</span><span class="p">.</span><span class="nx">stopPropagation</span><span class="p">()</span> <span class="p">})</span></div><div class='line' id='LC162'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;click.dropdown.data-api&#39;</span>  <span class="p">,</span> <span class="nx">toggle</span><span class="p">,</span> <span class="nx">Dropdown</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">toggle</span><span class="p">)</span></div><div class='line' id='LC163'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;keydown.dropdown.data-api&#39;</span><span class="p">,</span> <span class="nx">toggle</span> <span class="o">+</span> <span class="s1">&#39;, [role=menu]&#39;</span> <span class="p">,</span> <span class="nx">Dropdown</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">keydown</span><span class="p">)</span></div><div class='line' id='LC164'><br/></div><div class='line' id='LC165'><span class="p">}(</span><span class="nb">window</span><span class="p">.</span><span class="nx">jQuery</span><span class="p">);</span></div></pre></div>
+          </td>
+        </tr>
+      </table>
+  </div>
+
+          </div>
+        </div>
+
+        <a href="#jump-to-line" rel="facebox" data-hotkey="l" class="js-jump-to-line" style="display:none">Jump to Line</a>
+        <div id="jump-to-line" style="display:none">
+          <h2>Jump to Line</h2>
+          <form accept-charset="UTF-8" class="js-jump-to-line-form">
+            <input class="textfield js-jump-to-line-field" type="text">
+            <div class="full-button">
+              <button type="submit" class="button">Go</button>
+            </div>
+          </form>
+        </div>
+
+      </div>
+    </div>
+</div>
+
+<div id="js-frame-loading-template" class="frame frame-loading large-loading-area" style="display:none;">
+  <img class="js-frame-loading-spinner" src="https://a248.e.akamai.net/assets.github.com/images/spinners/octocat-spinner-128.gif?1347543529" height="64" width="64">
+</div>
+
+
+        </div>
+      </div>
+      <div class="context-overlay"></div>
+    </div>
+
+      <div id="footer-push"></div><!-- hack for sticky footer -->
+    </div><!-- end of wrapper - hack for sticky footer -->
+
+      <!-- footer -->
+      <div id="footer">
+  <div class="container clearfix">
+
+      <dl class="footer_nav">
+        <dt>GitHub</dt>
+        <dd><a href="https://github.com/about">About us</a></dd>
+        <dd><a href="https://github.com/blog">Blog</a></dd>
+        <dd><a href="https://github.com/contact">Contact &amp; support</a></dd>
+        <dd><a href="http://enterprise.github.com/">GitHub Enterprise</a></dd>
+        <dd><a href="http://status.github.com/">Site status</a></dd>
+      </dl>
+
+      <dl class="footer_nav">
+        <dt>Applications</dt>
+        <dd><a href="http://mac.github.com/">GitHub for Mac</a></dd>
+        <dd><a href="http://windows.github.com/">GitHub for Windows</a></dd>
+        <dd><a href="http://eclipse.github.com/">GitHub for Eclipse</a></dd>
+        <dd><a href="http://mobile.github.com/">GitHub mobile apps</a></dd>
+      </dl>
+
+      <dl class="footer_nav">
+        <dt>Services</dt>
+        <dd><a href="http://get.gaug.es/">Gauges: Web analytics</a></dd>
+        <dd><a href="http://speakerdeck.com">Speaker Deck: Presentations</a></dd>
+        <dd><a href="https://gist.github.com">Gist: Code snippets</a></dd>
+        <dd><a href="http://jobs.github.com/">Job board</a></dd>
+      </dl>
+
+      <dl class="footer_nav">
+        <dt>Documentation</dt>
+        <dd><a href="http://help.github.com/">GitHub Help</a></dd>
+        <dd><a href="http://developer.github.com/">Developer API</a></dd>
+        <dd><a href="http://github.github.com/github-flavored-markdown/">GitHub Flavored Markdown</a></dd>
+        <dd><a href="http://pages.github.com/">GitHub Pages</a></dd>
+      </dl>
+
+      <dl class="footer_nav">
+        <dt>More</dt>
+        <dd><a href="http://training.github.com/">Training</a></dd>
+        <dd><a href="https://github.com/edu">Students &amp; teachers</a></dd>
+        <dd><a href="http://shop.github.com">The Shop</a></dd>
+        <dd><a href="/plans">Plans &amp; pricing</a></dd>
+        <dd><a href="http://octodex.github.com/">The Octodex</a></dd>
+      </dl>
+
+      <hr class="footer-divider">
+
+
+    <p class="right">&copy; 2013 <span title="0.10638s from fe13.rs.github.com">GitHub</span>, Inc. All rights reserved.</p>
+    <a class="left" href="https://github.com/">
+      <span class="mega-icon mega-icon-invertocat"></span>
+    </a>
+    <ul id="legal">
+        <li><a href="https://github.com/site/terms">Terms of Service</a></li>
+        <li><a href="https://github.com/site/privacy">Privacy</a></li>
+        <li><a href="https://github.com/security">Security</a></li>
+    </ul>
+
+  </div><!-- /.container -->
+
+</div><!-- /.#footer -->
+
+
+    <div class="fullscreen-overlay js-fullscreen-overlay" id="fullscreen_overlay">
+  <div class="fullscreen-container js-fullscreen-container">
+    <div class="textarea-wrap">
+      <textarea name="fullscreen-contents" id="fullscreen-contents" class="js-fullscreen-contents" placeholder="" data-suggester="fullscreen_suggester"></textarea>
+          <div class="suggester-container">
+              <div class="suggester fullscreen-suggester js-navigation-container" id="fullscreen_suggester"
+                 data-url="/twitter/bootstrap/suggestions/commit">
+              </div>
+          </div>
+    </div>
+  </div>
+  <div class="fullscreen-sidebar">
+    <a href="#" class="exit-fullscreen js-exit-fullscreen tooltipped leftwards" title="Exit Zen Mode">
+      <span class="mega-icon mega-icon-normalscreen"></span>
+    </a>
+    <a href="#" class="theme-switcher js-theme-switcher tooltipped leftwards"
+      title="Switch themes">
+      <span class="mini-icon mini-icon-brightness"></span>
+    </a>
+  </div>
+</div>
+
+
+
+    <div id="ajax-error-message" class="flash flash-error">
+      <span class="mini-icon mini-icon-exclamation"></span>
+      Something went wrong with that request. Please try again.
+      <a href="#" class="mini-icon mini-icon-remove-close ajax-error-dismiss"></a>
+    </div>
+
+    
+    
+    <span id='server_response_time' data-time='0.10696' data-host='fe13'></span>
+    
+  </body>
+</html>
+
diff --git a/asterix-examples/src/main/resources/cherry/js/bootstrap.js b/asterix-examples/src/main/resources/cherry/js/bootstrap.js
new file mode 100755
index 0000000..c298ee4
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/js/bootstrap.js
@@ -0,0 +1,2276 @@
+/* ===================================================
+ * bootstrap-transition.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#transitions
+ * ===================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+  /* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
+   * ======================================================= */
+
+  $(function () {
+
+    $.support.transition = (function () {
+
+      var transitionEnd = (function () {
+
+        var el = document.createElement('bootstrap')
+          , transEndEventNames = {
+               'WebkitTransition' : 'webkitTransitionEnd'
+            ,  'MozTransition'    : 'transitionend'
+            ,  'OTransition'      : 'oTransitionEnd otransitionend'
+            ,  'transition'       : 'transitionend'
+            }
+          , name
+
+        for (name in transEndEventNames){
+          if (el.style[name] !== undefined) {
+            return transEndEventNames[name]
+          }
+        }
+
+      }())
+
+      return transitionEnd && {
+        end: transitionEnd
+      }
+
+    })()
+
+  })
+
+}(window.jQuery);/* ==========================================================
+ * bootstrap-alert.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#alerts
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* ALERT CLASS DEFINITION
+  * ====================== */
+
+  var dismiss = '[data-dismiss="alert"]'
+    , Alert = function (el) {
+        $(el).on('click', dismiss, this.close)
+      }
+
+  Alert.prototype.close = function (e) {
+    var $this = $(this)
+      , selector = $this.attr('data-target')
+      , $parent
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+    }
+
+    $parent = $(selector)
+
+    e && e.preventDefault()
+
+    $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
+
+    $parent.trigger(e = $.Event('close'))
+
+    if (e.isDefaultPrevented()) return
+
+    $parent.removeClass('in')
+
+    function removeElement() {
+      $parent
+        .trigger('closed')
+        .remove()
+    }
+
+    $.support.transition && $parent.hasClass('fade') ?
+      $parent.on($.support.transition.end, removeElement) :
+      removeElement()
+  }
+
+
+ /* ALERT PLUGIN DEFINITION
+  * ======================= */
+
+  var old = $.fn.alert
+
+  $.fn.alert = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('alert')
+      if (!data) $this.data('alert', (data = new Alert(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  $.fn.alert.Constructor = Alert
+
+
+ /* ALERT NO CONFLICT
+  * ================= */
+
+  $.fn.alert.noConflict = function () {
+    $.fn.alert = old
+    return this
+  }
+
+
+ /* ALERT DATA-API
+  * ============== */
+
+  $(document).on('click.alert.data-api', dismiss, Alert.prototype.close)
+
+}(window.jQuery);/* ============================================================
+ * bootstrap-button.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#buttons
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ============================================================ */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* BUTTON PUBLIC CLASS DEFINITION
+  * ============================== */
+
+  var Button = function (element, options) {
+    this.$element = $(element)
+    this.options = $.extend({}, $.fn.button.defaults, options)
+  }
+
+  Button.prototype.setState = function (state) {
+    var d = 'disabled'
+      , $el = this.$element
+      , data = $el.data()
+      , val = $el.is('input') ? 'val' : 'html'
+
+    state = state + 'Text'
+    data.resetText || $el.data('resetText', $el[val]())
+
+    $el[val](data[state] || this.options[state])
+
+    // push to event loop to allow forms to submit
+    setTimeout(function () {
+      state == 'loadingText' ?
+        $el.addClass(d).attr(d, d) :
+        $el.removeClass(d).removeAttr(d)
+    }, 0)
+  }
+
+  Button.prototype.toggle = function () {
+    var $parent = this.$element.closest('[data-toggle="buttons-radio"]')
+
+    $parent && $parent
+      .find('.active')
+      .removeClass('active')
+
+    this.$element.toggleClass('active')
+  }
+
+
+ /* BUTTON PLUGIN DEFINITION
+  * ======================== */
+
+  var old = $.fn.button
+
+  $.fn.button = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('button')
+        , options = typeof option == 'object' && option
+      if (!data) $this.data('button', (data = new Button(this, options)))
+      if (option == 'toggle') data.toggle()
+      else if (option) data.setState(option)
+    })
+  }
+
+  $.fn.button.defaults = {
+    loadingText: 'loading...'
+  }
+
+  $.fn.button.Constructor = Button
+
+
+ /* BUTTON NO CONFLICT
+  * ================== */
+
+  $.fn.button.noConflict = function () {
+    $.fn.button = old
+    return this
+  }
+
+
+ /* BUTTON DATA-API
+  * =============== */
+
+  $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) {
+    var $btn = $(e.target)
+    if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+    $btn.button('toggle')
+  })
+
+}(window.jQuery);/* ==========================================================
+ * bootstrap-carousel.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#carousel
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* CAROUSEL CLASS DEFINITION
+  * ========================= */
+
+  var Carousel = function (element, options) {
+    this.$element = $(element)
+    this.$indicators = this.$element.find('.carousel-indicators')
+    this.options = options
+    this.options.pause == 'hover' && this.$element
+      .on('mouseenter', $.proxy(this.pause, this))
+      .on('mouseleave', $.proxy(this.cycle, this))
+  }
+
+  Carousel.prototype = {
+
+    cycle: function (e) {
+      if (!e) this.paused = false
+      if (this.interval) clearInterval(this.interval);
+      this.options.interval
+        && !this.paused
+        && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+      return this
+    }
+
+  , getActiveIndex: function () {
+      this.$active = this.$element.find('.item.active')
+      this.$items = this.$active.parent().children()
+      return this.$items.index(this.$active)
+    }
+
+  , to: function (pos) {
+      var activeIndex = this.getActiveIndex()
+        , that = this
+
+      if (pos > (this.$items.length - 1) || pos < 0) return
+
+      if (this.sliding) {
+        return this.$element.one('slid', function () {
+          that.to(pos)
+        })
+      }
+
+      if (activeIndex == pos) {
+        return this.pause().cycle()
+      }
+
+      return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
+    }
+
+  , pause: function (e) {
+      if (!e) this.paused = true
+      if (this.$element.find('.next, .prev').length && $.support.transition.end) {
+        this.$element.trigger($.support.transition.end)
+        this.cycle(true)
+      }
+      clearInterval(this.interval)
+      this.interval = null
+      return this
+    }
+
+  , next: function () {
+      if (this.sliding) return
+      return this.slide('next')
+    }
+
+  , prev: function () {
+      if (this.sliding) return
+      return this.slide('prev')
+    }
+
+  , slide: function (type, next) {
+      var $active = this.$element.find('.item.active')
+        , $next = next || $active[type]()
+        , isCycling = this.interval
+        , direction = type == 'next' ? 'left' : 'right'
+        , fallback  = type == 'next' ? 'first' : 'last'
+        , that = this
+        , e
+
+      this.sliding = true
+
+      isCycling && this.pause()
+
+      $next = $next.length ? $next : this.$element.find('.item')[fallback]()
+
+      e = $.Event('slide', {
+        relatedTarget: $next[0]
+      , direction: direction
+      })
+
+      if ($next.hasClass('active')) return
+
+      if (this.$indicators.length) {
+        this.$indicators.find('.active').removeClass('active')
+        this.$element.one('slid', function () {
+          var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
+          $nextIndicator && $nextIndicator.addClass('active')
+        })
+      }
+
+      if ($.support.transition && this.$element.hasClass('slide')) {
+        this.$element.trigger(e)
+        if (e.isDefaultPrevented()) return
+        $next.addClass(type)
+        $next[0].offsetWidth // force reflow
+        $active.addClass(direction)
+        $next.addClass(direction)
+        this.$element.one($.support.transition.end, function () {
+          $next.removeClass([type, direction].join(' ')).addClass('active')
+          $active.removeClass(['active', direction].join(' '))
+          that.sliding = false
+          setTimeout(function () { that.$element.trigger('slid') }, 0)
+        })
+      } else {
+        this.$element.trigger(e)
+        if (e.isDefaultPrevented()) return
+        $active.removeClass('active')
+        $next.addClass('active')
+        this.sliding = false
+        this.$element.trigger('slid')
+      }
+
+      isCycling && this.cycle()
+
+      return this
+    }
+
+  }
+
+
+ /* CAROUSEL PLUGIN DEFINITION
+  * ========================== */
+
+  var old = $.fn.carousel
+
+  $.fn.carousel = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('carousel')
+        , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
+        , action = typeof option == 'string' ? option : options.slide
+      if (!data) $this.data('carousel', (data = new Carousel(this, options)))
+      if (typeof option == 'number') data.to(option)
+      else if (action) data[action]()
+      else if (options.interval) data.pause().cycle()
+    })
+  }
+
+  $.fn.carousel.defaults = {
+    interval: 5000
+  , pause: 'hover'
+  }
+
+  $.fn.carousel.Constructor = Carousel
+
+
+ /* CAROUSEL NO CONFLICT
+  * ==================== */
+
+  $.fn.carousel.noConflict = function () {
+    $.fn.carousel = old
+    return this
+  }
+
+ /* CAROUSEL DATA-API
+  * ================= */
+
+  $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
+    var $this = $(this), href
+      , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+      , options = $.extend({}, $target.data(), $this.data())
+      , slideIndex
+
+    $target.carousel(options)
+
+    if (slideIndex = $this.attr('data-slide-to')) {
+      $target.data('carousel').pause().to(slideIndex).cycle()
+    }
+
+    e.preventDefault()
+  })
+
+}(window.jQuery);/* =============================================================
+ * bootstrap-collapse.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#collapse
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ============================================================ */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* COLLAPSE PUBLIC CLASS DEFINITION
+  * ================================ */
+
+  var Collapse = function (element, options) {
+    this.$element = $(element)
+    this.options = $.extend({}, $.fn.collapse.defaults, options)
+
+    if (this.options.parent) {
+      this.$parent = $(this.options.parent)
+    }
+
+    this.options.toggle && this.toggle()
+  }
+
+  Collapse.prototype = {
+
+    constructor: Collapse
+
+  , dimension: function () {
+      var hasWidth = this.$element.hasClass('width')
+      return hasWidth ? 'width' : 'height'
+    }
+
+  , show: function () {
+      var dimension
+        , scroll
+        , actives
+        , hasData
+
+      if (this.transitioning || this.$element.hasClass('in')) return
+
+      dimension = this.dimension()
+      scroll = $.camelCase(['scroll', dimension].join('-'))
+      actives = this.$parent && this.$parent.find('> .accordion-group > .in')
+
+      if (actives && actives.length) {
+        hasData = actives.data('collapse')
+        if (hasData && hasData.transitioning) return
+        actives.collapse('hide')
+        hasData || actives.data('collapse', null)
+      }
+
+      this.$element[dimension](0)
+      this.transition('addClass', $.Event('show'), 'shown')
+      $.support.transition && this.$element[dimension](this.$element[0][scroll])
+    }
+
+  , hide: function () {
+      var dimension
+      if (this.transitioning || !this.$element.hasClass('in')) return
+      dimension = this.dimension()
+      this.reset(this.$element[dimension]())
+      this.transition('removeClass', $.Event('hide'), 'hidden')
+      this.$element[dimension](0)
+    }
+
+  , reset: function (size) {
+      var dimension = this.dimension()
+
+      this.$element
+        .removeClass('collapse')
+        [dimension](size || 'auto')
+        [0].offsetWidth
+
+      this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')
+
+      return this
+    }
+
+  , transition: function (method, startEvent, completeEvent) {
+      var that = this
+        , complete = function () {
+            if (startEvent.type == 'show') that.reset()
+            that.transitioning = 0
+            that.$element.trigger(completeEvent)
+          }
+
+      this.$element.trigger(startEvent)
+
+      if (startEvent.isDefaultPrevented()) return
+
+      this.transitioning = 1
+
+      this.$element[method]('in')
+
+      $.support.transition && this.$element.hasClass('collapse') ?
+        this.$element.one($.support.transition.end, complete) :
+        complete()
+    }
+
+  , toggle: function () {
+      this[this.$element.hasClass('in') ? 'hide' : 'show']()
+    }
+
+  }
+
+
+ /* COLLAPSE PLUGIN DEFINITION
+  * ========================== */
+
+  var old = $.fn.collapse
+
+  $.fn.collapse = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('collapse')
+        , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option)
+      if (!data) $this.data('collapse', (data = new Collapse(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.collapse.defaults = {
+    toggle: true
+  }
+
+  $.fn.collapse.Constructor = Collapse
+
+
+ /* COLLAPSE NO CONFLICT
+  * ==================== */
+
+  $.fn.collapse.noConflict = function () {
+    $.fn.collapse = old
+    return this
+  }
+
+
+ /* COLLAPSE DATA-API
+  * ================= */
+
+  $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) {
+    var $this = $(this), href
+      , target = $this.attr('data-target')
+        || e.preventDefault()
+        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
+      , option = $(target).data('collapse') ? 'toggle' : $this.data()
+    $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
+    $(target).collapse(option)
+  })
+
+}(window.jQuery);/* ============================================================
+ * bootstrap-dropdown.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#dropdowns
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ============================================================ */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* DROPDOWN CLASS DEFINITION
+  * ========================= */
+
+  var toggle = '[data-toggle=dropdown]'
+    , Dropdown = function (element) {
+        var $el = $(element).on('click.dropdown.data-api', this.toggle)
+        $('html').on('click.dropdown.data-api', function () {
+          $el.parent().removeClass('open')
+        })
+      }
+
+  Dropdown.prototype = {
+
+    constructor: Dropdown
+
+  , toggle: function (e) {
+      var $this = $(this)
+        , $parent
+        , isActive
+
+      if ($this.is('.disabled, :disabled')) return
+
+      $parent = getParent($this)
+
+      isActive = $parent.hasClass('open')
+
+      clearMenus()
+
+      if (!isActive) {
+        $parent.toggleClass('open')
+      }
+
+      $this.focus()
+
+      return false
+    }
+
+  , keydown: function (e) {
+      var $this
+        , $items
+        , $active
+        , $parent
+        , isActive
+        , index
+
+      if (!/(38|40|27)/.test(e.keyCode)) return
+
+      $this = $(this)
+
+      e.preventDefault()
+      e.stopPropagation()
+
+      if ($this.is('.disabled, :disabled')) return
+
+      $parent = getParent($this)
+
+      isActive = $parent.hasClass('open')
+
+      if (!isActive || (isActive && e.keyCode == 27)) {
+        if (e.which == 27) $parent.find(toggle).focus()
+        return $this.click()
+      }
+
+      $items = $('[role=menu] li:not(.divider):visible a', $parent)
+
+      if (!$items.length) return
+
+      index = $items.index($items.filter(':focus'))
+
+      if (e.keyCode == 38 && index > 0) index--                                        // up
+      if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
+      if (!~index) index = 0
+
+      $items
+        .eq(index)
+        .focus()
+    }
+
+  }
+
+  function clearMenus() {
+    $(toggle).each(function () {
+      getParent($(this)).removeClass('open')
+    })
+  }
+
+  function getParent($this) {
+    var selector = $this.attr('data-target')
+      , $parent
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+    }
+
+    $parent = selector && $(selector)
+
+    if (!$parent || !$parent.length) $parent = $this.parent()
+
+    return $parent
+  }
+
+
+  /* DROPDOWN PLUGIN DEFINITION
+   * ========================== */
+
+  var old = $.fn.dropdown
+
+  $.fn.dropdown = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('dropdown')
+      if (!data) $this.data('dropdown', (data = new Dropdown(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  $.fn.dropdown.Constructor = Dropdown
+
+
+ /* DROPDOWN NO CONFLICT
+  * ==================== */
+
+  $.fn.dropdown.noConflict = function () {
+    $.fn.dropdown = old
+    return this
+  }
+
+
+  /* APPLY TO STANDARD DROPDOWN ELEMENTS
+   * =================================== */
+
+  $(document)
+    .on('click.dropdown.data-api', clearMenus)
+    .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+    .on('click.dropdown-menu', function (e) { e.stopPropagation() })
+    .on('click.dropdown.data-api'  , toggle, Dropdown.prototype.toggle)
+    .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
+
+}(window.jQuery);
+/* =========================================================
+ * bootstrap-modal.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#modals
+ * =========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================= */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* MODAL CLASS DEFINITION
+  * ====================== */
+
+  var Modal = function (element, options) {
+    this.options = options
+    this.$element = $(element)
+      .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
+    this.options.remote && this.$element.find('.modal-body').load(this.options.remote)
+  }
+
+  Modal.prototype = {
+
+      constructor: Modal
+
+    , toggle: function () {
+        return this[!this.isShown ? 'show' : 'hide']()
+      }
+
+    , show: function () {
+        var that = this
+          , e = $.Event('show')
+
+        this.$element.trigger(e)
+
+        if (this.isShown || e.isDefaultPrevented()) return
+
+        this.isShown = true
+
+        this.escape()
+
+        this.backdrop(function () {
+          var transition = $.support.transition && that.$element.hasClass('fade')
+
+          if (!that.$element.parent().length) {
+            that.$element.appendTo(document.body) //don't move modals dom position
+          }
+
+          that.$element.show()
+
+          if (transition) {
+            that.$element[0].offsetWidth // force reflow
+          }
+
+          that.$element
+            .addClass('in')
+            .attr('aria-hidden', false)
+
+          that.enforceFocus()
+
+          transition ?
+            that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) :
+            that.$element.focus().trigger('shown')
+
+        })
+      }
+
+    , hide: function (e) {
+        e && e.preventDefault()
+
+        var that = this
+
+        e = $.Event('hide')
+
+        this.$element.trigger(e)
+
+        if (!this.isShown || e.isDefaultPrevented()) return
+
+        this.isShown = false
+
+        this.escape()
+
+        $(document).off('focusin.modal')
+
+        this.$element
+          .removeClass('in')
+          .attr('aria-hidden', true)
+
+        $.support.transition && this.$element.hasClass('fade') ?
+          this.hideWithTransition() :
+          this.hideModal()
+      }
+
+    , enforceFocus: function () {
+        var that = this
+        $(document).on('focusin.modal', function (e) {
+          if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
+            that.$element.focus()
+          }
+        })
+      }
+
+    , escape: function () {
+        var that = this
+        if (this.isShown && this.options.keyboard) {
+          this.$element.on('keyup.dismiss.modal', function ( e ) {
+            e.which == 27 && that.hide()
+          })
+        } else if (!this.isShown) {
+          this.$element.off('keyup.dismiss.modal')
+        }
+      }
+
+    , hideWithTransition: function () {
+        var that = this
+          , timeout = setTimeout(function () {
+              that.$element.off($.support.transition.end)
+              that.hideModal()
+            }, 500)
+
+        this.$element.one($.support.transition.end, function () {
+          clearTimeout(timeout)
+          that.hideModal()
+        })
+      }
+
+    , hideModal: function () {
+        var that = this
+        this.$element.hide()
+        this.backdrop(function () {
+          that.removeBackdrop()
+          that.$element.trigger('hidden')
+        })
+      }
+
+    , removeBackdrop: function () {
+        this.$backdrop && this.$backdrop.remove()
+        this.$backdrop = null
+      }
+
+    , backdrop: function (callback) {
+        var that = this
+          , animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+        if (this.isShown && this.options.backdrop) {
+          var doAnimate = $.support.transition && animate
+
+          this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+            .appendTo(document.body)
+
+          this.$backdrop.click(
+            this.options.backdrop == 'static' ?
+              $.proxy(this.$element[0].focus, this.$element[0])
+            : $.proxy(this.hide, this)
+          )
+
+          if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+          this.$backdrop.addClass('in')
+
+          if (!callback) return
+
+          doAnimate ?
+            this.$backdrop.one($.support.transition.end, callback) :
+            callback()
+
+        } else if (!this.isShown && this.$backdrop) {
+          this.$backdrop.removeClass('in')
+
+          $.support.transition && this.$element.hasClass('fade')?
+            this.$backdrop.one($.support.transition.end, callback) :
+            callback()
+
+        } else if (callback) {
+          callback()
+        }
+      }
+  }
+
+
+ /* MODAL PLUGIN DEFINITION
+  * ======================= */
+
+  var old = $.fn.modal
+
+  $.fn.modal = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('modal')
+        , options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
+      if (!data) $this.data('modal', (data = new Modal(this, options)))
+      if (typeof option == 'string') data[option]()
+      else if (options.show) data.show()
+    })
+  }
+
+  $.fn.modal.defaults = {
+      backdrop: true
+    , keyboard: true
+    , show: true
+  }
+
+  $.fn.modal.Constructor = Modal
+
+
+ /* MODAL NO CONFLICT
+  * ================= */
+
+  $.fn.modal.noConflict = function () {
+    $.fn.modal = old
+    return this
+  }
+
+
+ /* MODAL DATA-API
+  * ============== */
+
+  $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) {
+    var $this = $(this)
+      , href = $this.attr('href')
+      , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
+      , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data())
+
+    e.preventDefault()
+
+    $target
+      .modal(option)
+      .one('hide', function () {
+        $this.focus()
+      })
+  })
+
+}(window.jQuery);
+/* ===========================================================
+ * bootstrap-tooltip.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#tooltips
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ===========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* TOOLTIP PUBLIC CLASS DEFINITION
+  * =============================== */
+
+  var Tooltip = function (element, options) {
+    this.init('tooltip', element, options)
+  }
+
+  Tooltip.prototype = {
+
+    constructor: Tooltip
+
+  , init: function (type, element, options) {
+      var eventIn
+        , eventOut
+        , triggers
+        , trigger
+        , i
+
+      this.type = type
+      this.$element = $(element)
+      this.options = this.getOptions(options)
+      this.enabled = true
+
+      triggers = this.options.trigger.split(' ')
+
+      for (i = triggers.length; i--;) {
+        trigger = triggers[i]
+        if (trigger == 'click') {
+          this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+        } else if (trigger != 'manual') {
+          eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
+          eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
+          this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+          this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+        }
+      }
+
+      this.options.selector ?
+        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+        this.fixTitle()
+    }
+
+  , getOptions: function (options) {
+      options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
+
+      if (options.delay && typeof options.delay == 'number') {
+        options.delay = {
+          show: options.delay
+        , hide: options.delay
+        }
+      }
+
+      return options
+    }
+
+  , enter: function (e) {
+      var defaults = $.fn[this.type].defaults
+        , options = {}
+        , self
+
+      this._options && $.each(this._options, function (key, value) {
+        if (defaults[key] != value) options[key] = value
+      }, this)
+
+      self = $(e.currentTarget)[this.type](options).data(this.type)
+
+      if (!self.options.delay || !self.options.delay.show) return self.show()
+
+      clearTimeout(this.timeout)
+      self.hoverState = 'in'
+      this.timeout = setTimeout(function() {
+        if (self.hoverState == 'in') self.show()
+      }, self.options.delay.show)
+    }
+
+  , leave: function (e) {
+      var self = $(e.currentTarget)[this.type](this._options).data(this.type)
+
+      if (this.timeout) clearTimeout(this.timeout)
+      if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+      self.hoverState = 'out'
+      this.timeout = setTimeout(function() {
+        if (self.hoverState == 'out') self.hide()
+      }, self.options.delay.hide)
+    }
+
+  , show: function () {
+      var $tip
+        , pos
+        , actualWidth
+        , actualHeight
+        , placement
+        , tp
+        , e = $.Event('show')
+
+      if (this.hasContent() && this.enabled) {
+        this.$element.trigger(e)
+        if (e.isDefaultPrevented()) return
+        $tip = this.tip()
+        this.setContent()
+
+        if (this.options.animation) {
+          $tip.addClass('fade')
+        }
+
+        placement = typeof this.options.placement == 'function' ?
+          this.options.placement.call(this, $tip[0], this.$element[0]) :
+          this.options.placement
+
+        $tip
+          .detach()
+          .css({ top: 0, left: 0, display: 'block' })
+
+        this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+        pos = this.getPosition()
+
+        actualWidth = $tip[0].offsetWidth
+        actualHeight = $tip[0].offsetHeight
+
+        switch (placement) {
+          case 'bottom':
+            tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
+            break
+          case 'top':
+            tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
+            break
+          case 'left':
+            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
+            break
+          case 'right':
+            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
+            break
+        }
+
+        this.applyPlacement(tp, placement)
+        this.$element.trigger('shown')
+      }
+    }
+
+  , applyPlacement: function(offset, placement){
+      var $tip = this.tip()
+        , width = $tip[0].offsetWidth
+        , height = $tip[0].offsetHeight
+        , actualWidth
+        , actualHeight
+        , delta
+        , replace
+
+      $tip
+        .offset(offset)
+        .addClass(placement)
+        .addClass('in')
+
+      actualWidth = $tip[0].offsetWidth
+      actualHeight = $tip[0].offsetHeight
+
+      if (placement == 'top' && actualHeight != height) {
+        offset.top = offset.top + height - actualHeight
+        replace = true
+      }
+
+      if (placement == 'bottom' || placement == 'top') {
+        delta = 0
+
+        if (offset.left < 0){
+          delta = offset.left * -2
+          offset.left = 0
+          $tip.offset(offset)
+          actualWidth = $tip[0].offsetWidth
+          actualHeight = $tip[0].offsetHeight
+        }
+
+        this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+      } else {
+        this.replaceArrow(actualHeight - height, actualHeight, 'top')
+      }
+
+      if (replace) $tip.offset(offset)
+    }
+
+  , replaceArrow: function(delta, dimension, position){
+      this
+        .arrow()
+        .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
+    }
+
+  , setContent: function () {
+      var $tip = this.tip()
+        , title = this.getTitle()
+
+      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+      $tip.removeClass('fade in top bottom left right')
+    }
+
+  , hide: function () {
+      var that = this
+        , $tip = this.tip()
+        , e = $.Event('hide')
+
+      this.$element.trigger(e)
+      if (e.isDefaultPrevented()) return
+
+      $tip.removeClass('in')
+
+      function removeWithAnimation() {
+        var timeout = setTimeout(function () {
+          $tip.off($.support.transition.end).detach()
+        }, 500)
+
+        $tip.one($.support.transition.end, function () {
+          clearTimeout(timeout)
+          $tip.detach()
+        })
+      }
+
+      $.support.transition && this.$tip.hasClass('fade') ?
+        removeWithAnimation() :
+        $tip.detach()
+
+      this.$element.trigger('hidden')
+
+      return this
+    }
+
+  , fixTitle: function () {
+      var $e = this.$element
+      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+        $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+      }
+    }
+
+  , hasContent: function () {
+      return this.getTitle()
+    }
+
+  , getPosition: function () {
+      var el = this.$element[0]
+      return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+        width: el.offsetWidth
+      , height: el.offsetHeight
+      }, this.$element.offset())
+    }
+
+  , getTitle: function () {
+      var title
+        , $e = this.$element
+        , o = this.options
+
+      title = $e.attr('data-original-title')
+        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
+
+      return title
+    }
+
+  , tip: function () {
+      return this.$tip = this.$tip || $(this.options.template)
+    }
+
+  , arrow: function(){
+      return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
+    }
+
+  , validate: function () {
+      if (!this.$element[0].parentNode) {
+        this.hide()
+        this.$element = null
+        this.options = null
+      }
+    }
+
+  , enable: function () {
+      this.enabled = true
+    }
+
+  , disable: function () {
+      this.enabled = false
+    }
+
+  , toggleEnabled: function () {
+      this.enabled = !this.enabled
+    }
+
+  , toggle: function (e) {
+      var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
+      self.tip().hasClass('in') ? self.hide() : self.show()
+    }
+
+  , destroy: function () {
+      this.hide().$element.off('.' + this.type).removeData(this.type)
+    }
+
+  }
+
+
+ /* TOOLTIP PLUGIN DEFINITION
+  * ========================= */
+
+  var old = $.fn.tooltip
+
+  $.fn.tooltip = function ( option ) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('tooltip')
+        , options = typeof option == 'object' && option
+      if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.tooltip.Constructor = Tooltip
+
+  $.fn.tooltip.defaults = {
+    animation: true
+  , placement: 'top'
+  , selector: false
+  , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
+  , trigger: 'hover focus'
+  , title: ''
+  , delay: 0
+  , html: false
+  , container: false
+  }
+
+
+ /* TOOLTIP NO CONFLICT
+  * =================== */
+
+  $.fn.tooltip.noConflict = function () {
+    $.fn.tooltip = old
+    return this
+  }
+
+}(window.jQuery);
+/* ===========================================================
+ * bootstrap-popover.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#popovers
+ * ===========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * =========================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* POPOVER PUBLIC CLASS DEFINITION
+  * =============================== */
+
+  var Popover = function (element, options) {
+    this.init('popover', element, options)
+  }
+
+
+  /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
+     ========================================== */
+
+  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
+
+    constructor: Popover
+
+  , setContent: function () {
+      var $tip = this.tip()
+        , title = this.getTitle()
+        , content = this.getContent()
+
+      $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+      $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
+
+      $tip.removeClass('fade top bottom left right in')
+    }
+
+  , hasContent: function () {
+      return this.getTitle() || this.getContent()
+    }
+
+  , getContent: function () {
+      var content
+        , $e = this.$element
+        , o = this.options
+
+      content = (typeof o.content == 'function' ? o.content.call($e[0]) :  o.content)
+        || $e.attr('data-content')
+
+      return content
+    }
+
+  , tip: function () {
+      if (!this.$tip) {
+        this.$tip = $(this.options.template)
+      }
+      return this.$tip
+    }
+
+  , destroy: function () {
+      this.hide().$element.off('.' + this.type).removeData(this.type)
+    }
+
+  })
+
+
+ /* POPOVER PLUGIN DEFINITION
+  * ======================= */
+
+  var old = $.fn.popover
+
+  $.fn.popover = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('popover')
+        , options = typeof option == 'object' && option
+      if (!data) $this.data('popover', (data = new Popover(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.popover.Constructor = Popover
+
+  $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
+    placement: 'right'
+  , trigger: 'click'
+  , content: ''
+  , template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+  })
+
+
+ /* POPOVER NO CONFLICT
+  * =================== */
+
+  $.fn.popover.noConflict = function () {
+    $.fn.popover = old
+    return this
+  }
+
+}(window.jQuery);
+/* =============================================================
+ * bootstrap-scrollspy.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#scrollspy
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ============================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* SCROLLSPY CLASS DEFINITION
+  * ========================== */
+
+  function ScrollSpy(element, options) {
+    var process = $.proxy(this.process, this)
+      , $element = $(element).is('body') ? $(window) : $(element)
+      , href
+    this.options = $.extend({}, $.fn.scrollspy.defaults, options)
+    this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
+    this.selector = (this.options.target
+      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+      || '') + ' .nav li > a'
+    this.$body = $('body')
+    this.refresh()
+    this.process()
+  }
+
+  ScrollSpy.prototype = {
+
+      constructor: ScrollSpy
+
+    , refresh: function () {
+        var self = this
+          , $targets
+
+        this.offsets = $([])
+        this.targets = $([])
+
+        $targets = this.$body
+          .find(this.selector)
+          .map(function () {
+            var $el = $(this)
+              , href = $el.data('target') || $el.attr('href')
+              , $href = /^#\w/.test(href) && $(href)
+            return ( $href
+              && $href.length
+              && [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null
+          })
+          .sort(function (a, b) { return a[0] - b[0] })
+          .each(function () {
+            self.offsets.push(this[0])
+            self.targets.push(this[1])
+          })
+      }
+
+    , process: function () {
+        var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
+          , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
+          , maxScroll = scrollHeight - this.$scrollElement.height()
+          , offsets = this.offsets
+          , targets = this.targets
+          , activeTarget = this.activeTarget
+          , i
+
+        if (scrollTop >= maxScroll) {
+          return activeTarget != (i = targets.last()[0])
+            && this.activate ( i )
+        }
+
+        for (i = offsets.length; i--;) {
+          activeTarget != targets[i]
+            && scrollTop >= offsets[i]
+            && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
+            && this.activate( targets[i] )
+        }
+      }
+
+    , activate: function (target) {
+        var active
+          , selector
+
+        this.activeTarget = target
+
+        $(this.selector)
+          .parent('.active')
+          .removeClass('active')
+
+        selector = this.selector
+          + '[data-target="' + target + '"],'
+          + this.selector + '[href="' + target + '"]'
+
+        active = $(selector)
+          .parent('li')
+          .addClass('active')
+
+        if (active.parent('.dropdown-menu').length)  {
+          active = active.closest('li.dropdown').addClass('active')
+        }
+
+        active.trigger('activate')
+      }
+
+  }
+
+
+ /* SCROLLSPY PLUGIN DEFINITION
+  * =========================== */
+
+  var old = $.fn.scrollspy
+
+  $.fn.scrollspy = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('scrollspy')
+        , options = typeof option == 'object' && option
+      if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.scrollspy.Constructor = ScrollSpy
+
+  $.fn.scrollspy.defaults = {
+    offset: 10
+  }
+
+
+ /* SCROLLSPY NO CONFLICT
+  * ===================== */
+
+  $.fn.scrollspy.noConflict = function () {
+    $.fn.scrollspy = old
+    return this
+  }
+
+
+ /* SCROLLSPY DATA-API
+  * ================== */
+
+  $(window).on('load', function () {
+    $('[data-spy="scroll"]').each(function () {
+      var $spy = $(this)
+      $spy.scrollspy($spy.data())
+    })
+  })
+
+}(window.jQuery);/* ========================================================
+ * bootstrap-tab.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#tabs
+ * ========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ======================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* TAB CLASS DEFINITION
+  * ==================== */
+
+  var Tab = function (element) {
+    this.element = $(element)
+  }
+
+  Tab.prototype = {
+
+    constructor: Tab
+
+  , show: function () {
+      var $this = this.element
+        , $ul = $this.closest('ul:not(.dropdown-menu)')
+        , selector = $this.attr('data-target')
+        , previous
+        , $target
+        , e
+
+      if (!selector) {
+        selector = $this.attr('href')
+        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+      }
+
+      if ( $this.parent('li').hasClass('active') ) return
+
+      previous = $ul.find('.active:last a')[0]
+
+      e = $.Event('show', {
+        relatedTarget: previous
+      })
+
+      $this.trigger(e)
+
+      if (e.isDefaultPrevented()) return
+
+      $target = $(selector)
+
+      this.activate($this.parent('li'), $ul)
+      this.activate($target, $target.parent(), function () {
+        $this.trigger({
+          type: 'shown'
+        , relatedTarget: previous
+        })
+      })
+    }
+
+  , activate: function ( element, container, callback) {
+      var $active = container.find('> .active')
+        , transition = callback
+            && $.support.transition
+            && $active.hasClass('fade')
+
+      function next() {
+        $active
+          .removeClass('active')
+          .find('> .dropdown-menu > .active')
+          .removeClass('active')
+
+        element.addClass('active')
+
+        if (transition) {
+          element[0].offsetWidth // reflow for transition
+          element.addClass('in')
+        } else {
+          element.removeClass('fade')
+        }
+
+        if ( element.parent('.dropdown-menu') ) {
+          element.closest('li.dropdown').addClass('active')
+        }
+
+        callback && callback()
+      }
+
+      transition ?
+        $active.one($.support.transition.end, next) :
+        next()
+
+      $active.removeClass('in')
+    }
+  }
+
+
+ /* TAB PLUGIN DEFINITION
+  * ===================== */
+
+  var old = $.fn.tab
+
+  $.fn.tab = function ( option ) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('tab')
+      if (!data) $this.data('tab', (data = new Tab(this)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.tab.Constructor = Tab
+
+
+ /* TAB NO CONFLICT
+  * =============== */
+
+  $.fn.tab.noConflict = function () {
+    $.fn.tab = old
+    return this
+  }
+
+
+ /* TAB DATA-API
+  * ============ */
+
+  $(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+    e.preventDefault()
+    $(this).tab('show')
+  })
+
+}(window.jQuery);/* =============================================================
+ * bootstrap-typeahead.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#typeahead
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ============================================================ */
+
+
+!function($){
+
+  "use strict"; // jshint ;_;
+
+
+ /* TYPEAHEAD PUBLIC CLASS DEFINITION
+  * ================================= */
+
+  var Typeahead = function (element, options) {
+    this.$element = $(element)
+    this.options = $.extend({}, $.fn.typeahead.defaults, options)
+    this.matcher = this.options.matcher || this.matcher
+    this.sorter = this.options.sorter || this.sorter
+    this.highlighter = this.options.highlighter || this.highlighter
+    this.updater = this.options.updater || this.updater
+    this.source = this.options.source
+    this.$menu = $(this.options.menu)
+    this.shown = false
+    this.listen()
+  }
+
+  Typeahead.prototype = {
+
+    constructor: Typeahead
+
+  , select: function () {
+      var val = this.$menu.find('.active').attr('data-value')
+      this.$element
+        .val(this.updater(val))
+        .change()
+      return this.hide()
+    }
+
+  , updater: function (item) {
+      return item
+    }
+
+  , show: function () {
+      var pos = $.extend({}, this.$element.position(), {
+        height: this.$element[0].offsetHeight
+      })
+
+      this.$menu
+        .insertAfter(this.$element)
+        .css({
+          top: pos.top + pos.height
+        , left: pos.left
+        })
+        .show()
+
+      this.shown = true
+      return this
+    }
+
+  , hide: function () {
+      this.$menu.hide()
+      this.shown = false
+      return this
+    }
+
+  , lookup: function (event) {
+      var items
+
+      this.query = this.$element.val()
+
+      if (!this.query || this.query.length < this.options.minLength) {
+        return this.shown ? this.hide() : this
+      }
+
+      items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
+
+      return items ? this.process(items) : this
+    }
+
+  , process: function (items) {
+      var that = this
+
+      items = $.grep(items, function (item) {
+        return that.matcher(item)
+      })
+
+      items = this.sorter(items)
+
+      if (!items.length) {
+        return this.shown ? this.hide() : this
+      }
+
+      return this.render(items.slice(0, this.options.items)).show()
+    }
+
+  , matcher: function (item) {
+      return ~item.toLowerCase().indexOf(this.query.toLowerCase())
+    }
+
+  , sorter: function (items) {
+      var beginswith = []
+        , caseSensitive = []
+        , caseInsensitive = []
+        , item
+
+      while (item = items.shift()) {
+        if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
+        else if (~item.indexOf(this.query)) caseSensitive.push(item)
+        else caseInsensitive.push(item)
+      }
+
+      return beginswith.concat(caseSensitive, caseInsensitive)
+    }
+
+  , highlighter: function (item) {
+      var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
+      return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
+        return '<strong>' + match + '</strong>'
+      })
+    }
+
+  , render: function (items) {
+      var that = this
+
+      items = $(items).map(function (i, item) {
+        i = $(that.options.item).attr('data-value', item)
+        i.find('a').html(that.highlighter(item))
+        return i[0]
+      })
+
+      items.first().addClass('active')
+      this.$menu.html(items)
+      return this
+    }
+
+  , next: function (event) {
+      var active = this.$menu.find('.active').removeClass('active')
+        , next = active.next()
+
+      if (!next.length) {
+        next = $(this.$menu.find('li')[0])
+      }
+
+      next.addClass('active')
+    }
+
+  , prev: function (event) {
+      var active = this.$menu.find('.active').removeClass('active')
+        , prev = active.prev()
+
+      if (!prev.length) {
+        prev = this.$menu.find('li').last()
+      }
+
+      prev.addClass('active')
+    }
+
+  , listen: function () {
+      this.$element
+        .on('focus',    $.proxy(this.focus, this))
+        .on('blur',     $.proxy(this.blur, this))
+        .on('keypress', $.proxy(this.keypress, this))
+        .on('keyup',    $.proxy(this.keyup, this))
+
+      if (this.eventSupported('keydown')) {
+        this.$element.on('keydown', $.proxy(this.keydown, this))
+      }
+
+      this.$menu
+        .on('click', $.proxy(this.click, this))
+        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
+        .on('mouseleave', 'li', $.proxy(this.mouseleave, this))
+    }
+
+  , eventSupported: function(eventName) {
+      var isSupported = eventName in this.$element
+      if (!isSupported) {
+        this.$element.setAttribute(eventName, 'return;')
+        isSupported = typeof this.$element[eventName] === 'function'
+      }
+      return isSupported
+    }
+
+  , move: function (e) {
+      if (!this.shown) return
+
+      switch(e.keyCode) {
+        case 9: // tab
+        case 13: // enter
+        case 27: // escape
+          e.preventDefault()
+          break
+
+        case 38: // up arrow
+          e.preventDefault()
+          this.prev()
+          break
+
+        case 40: // down arrow
+          e.preventDefault()
+          this.next()
+          break
+      }
+
+      e.stopPropagation()
+    }
+
+  , keydown: function (e) {
+      this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27])
+      this.move(e)
+    }
+
+  , keypress: function (e) {
+      if (this.suppressKeyPressRepeat) return
+      this.move(e)
+    }
+
+  , keyup: function (e) {
+      switch(e.keyCode) {
+        case 40: // down arrow
+        case 38: // up arrow
+        case 16: // shift
+        case 17: // ctrl
+        case 18: // alt
+          break
+
+        case 9: // tab
+        case 13: // enter
+          if (!this.shown) return
+          this.select()
+          break
+
+        case 27: // escape
+          if (!this.shown) return
+          this.hide()
+          break
+
+        default:
+          this.lookup()
+      }
+
+      e.stopPropagation()
+      e.preventDefault()
+  }
+
+  , focus: function (e) {
+      this.focused = true
+    }
+
+  , blur: function (e) {
+      this.focused = false
+      if (!this.mousedover && this.shown) this.hide()
+    }
+
+  , click: function (e) {
+      e.stopPropagation()
+      e.preventDefault()
+      this.select()
+      this.$element.focus()
+    }
+
+  , mouseenter: function (e) {
+      this.mousedover = true
+      this.$menu.find('.active').removeClass('active')
+      $(e.currentTarget).addClass('active')
+    }
+
+  , mouseleave: function (e) {
+      this.mousedover = false
+      if (!this.focused && this.shown) this.hide()
+    }
+
+  }
+
+
+  /* TYPEAHEAD PLUGIN DEFINITION
+   * =========================== */
+
+  var old = $.fn.typeahead
+
+  $.fn.typeahead = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('typeahead')
+        , options = typeof option == 'object' && option
+      if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.typeahead.defaults = {
+    source: []
+  , items: 8
+  , menu: '<ul class="typeahead dropdown-menu"></ul>'
+  , item: '<li><a href="#"></a></li>'
+  , minLength: 1
+  }
+
+  $.fn.typeahead.Constructor = Typeahead
+
+
+ /* TYPEAHEAD NO CONFLICT
+  * =================== */
+
+  $.fn.typeahead.noConflict = function () {
+    $.fn.typeahead = old
+    return this
+  }
+
+
+ /* TYPEAHEAD DATA-API
+  * ================== */
+
+  $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
+    var $this = $(this)
+    if ($this.data('typeahead')) return
+    $this.typeahead($this.data())
+  })
+
+}(window.jQuery);
+/* ==========================================================
+ * bootstrap-affix.js v2.3.1
+ * http://twitter.github.com/bootstrap/javascript.html#affix
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* AFFIX CLASS DEFINITION
+  * ====================== */
+
+  var Affix = function (element, options) {
+    this.options = $.extend({}, $.fn.affix.defaults, options)
+    this.$window = $(window)
+      .on('scroll.affix.data-api', $.proxy(this.checkPosition, this))
+      .on('click.affix.data-api',  $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this))
+    this.$element = $(element)
+    this.checkPosition()
+  }
+
+  Affix.prototype.checkPosition = function () {
+    if (!this.$element.is(':visible')) return
+
+    var scrollHeight = $(document).height()
+      , scrollTop = this.$window.scrollTop()
+      , position = this.$element.offset()
+      , offset = this.options.offset
+      , offsetBottom = offset.bottom
+      , offsetTop = offset.top
+      , reset = 'affix affix-top affix-bottom'
+      , affix
+
+    if (typeof offset != 'object') offsetBottom = offsetTop = offset
+    if (typeof offsetTop == 'function') offsetTop = offset.top()
+    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
+
+    affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ?
+      false    : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ?
+      'bottom' : offsetTop != null && scrollTop <= offsetTop ?
+      'top'    : false
+
+    if (this.affixed === affix) return
+
+    this.affixed = affix
+    this.unpin = affix == 'bottom' ? position.top - scrollTop : null
+
+    this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : ''))
+  }
+
+
+ /* AFFIX PLUGIN DEFINITION
+  * ======================= */
+
+  var old = $.fn.affix
+
+  $.fn.affix = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('affix')
+        , options = typeof option == 'object' && option
+      if (!data) $this.data('affix', (data = new Affix(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.affix.Constructor = Affix
+
+  $.fn.affix.defaults = {
+    offset: 0
+  }
+
+
+ /* AFFIX NO CONFLICT
+  * ================= */
+
+  $.fn.affix.noConflict = function () {
+    $.fn.affix = old
+    return this
+  }
+
+
+ /* AFFIX DATA-API
+  * ============== */
+
+  $(window).on('load', function () {
+    $('[data-spy="affix"]').each(function () {
+      var $spy = $(this)
+        , data = $spy.data()
+
+      data.offset = data.offset || {}
+
+      data.offsetBottom && (data.offset.bottom = data.offsetBottom)
+      data.offsetTop && (data.offset.top = data.offsetTop)
+
+      $spy.affix(data)
+    })
+  })
+
+
+}(window.jQuery);
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/cherry/js/bootstrap.min.js b/asterix-examples/src/main/resources/cherry/js/bootstrap.min.js
new file mode 100755
index 0000000..95c5ac5
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/js/bootstrap.min.js
@@ -0,0 +1,6 @@
+/*!
+* Bootstrap.js by @fat & @mdo
+* Copyright 2012 Twitter, Inc.
+* http://www.apache.org/licenses/LICENSE-2.0.txt
+*/
+!function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||s.toggleClass("open"),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f<s.length-1&&f++,~f||(f=0),s.eq(f).focus()}};var s=e.fn.dropdown;e.fn.dropdown=function(t){return this.each(function(){var r=e(this),i=r.data("dropdown");i||r.data("dropdown",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.dropdown.Constructor=n,e.fn.dropdown.noConflict=function(){return e.fn.dropdown=s,this},e(document).on("click.dropdown.data-api",r).on("click.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("click.dropdown-menu",function(e){e.stopPropagation()}).on("click.dropdown.data-api",t,n.prototype.toggle).on("keydown.dropdown.data-api",t+", [role=menu]",n.prototype.keydown)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=n,this.$element=e(t).delegate('[data-dismiss="modal"]',"click.dismiss.modal",e.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};t.prototype={constructor:t,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var t=this,n=e.Event("show");this.$element.trigger(n);if(this.isShown||n.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var n=e.support.transition&&t.$element.hasClass("fade");t.$element.parent().length||t.$element.appendTo(document.body),t.$element.show(),n&&t.$element[0].offsetWidth,t.$element.addClass("in").attr("aria-hidden",!1),t.enforceFocus(),n?t.$element.one(e.support.transition.end,function(){t.$element.focus().trigger("shown")}):t.$element.focus().trigger("shown")})},hide:function(t){t&&t.preventDefault();var n=this;t=e.Event("hide"),this.$element.trigger(t);if(!this.isShown||t.isDefaultPrevented())return;this.isShown=!1,this.escape(),e(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),e.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var t=this;e(document).on("focusin.modal",function(e){t.$element[0]!==e.target&&!t.$element.has(e.target).length&&t.$element.focus()})},escape:function(){var e=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(t){t.which==27&&e.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var t=this,n=setTimeout(function(){t.$element.off(e.support.transition.end),t.hideModal()},500);this.$element.one(e.support.transition.end,function(){clearTimeout(n),t.hideModal()})},hideModal:function(){var e=this;this.$element.hide(),this.backdrop(function(){e.removeBackdrop(),e.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(t){var n=this,r=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var i=e.support.transition&&r;this.$backdrop=e('<div class="modal-backdrop '+r+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e.fn[this.type].defaults,r={},i;this._options&&e.each(this._options,function(e,t){n[e]!=t&&(r[e]=t)},this),i=e(t.currentTarget)[this.type](r).data(this.type);if(!i.options.delay||!i.options.delay.show)return i.show();clearTimeout(this.timeout),i.hoverState="in",this.timeout=setTimeout(function(){i.hoverState=="in"&&i.show()},i.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery);
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/cherry/js/cherry.js b/asterix-examples/src/main/resources/cherry/js/cherry.js
new file mode 100755
index 0000000..2044668
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/js/cherry.js
@@ -0,0 +1,950 @@
+$(function() {	
+	    
+    APIHandler = new AsterixSDK();
+
+    APIqueryTracker = {};
+    drilldown_data_map = {};
+    drilldown_data_map_vals = {};
+    asyncQueryManager = {};
+    
+    // Review Mode
+    review_mode_tweetbooks = [];
+    review_mode_handles = [];
+    
+    $('#drilldown_modal').modal({ show: false});
+    $('#explore-mode').click( onLaunchExploreMode );
+    $('#review-mode').click( onLaunchReviewMode );
+    
+    /** UI **/
+    map_cells = [];
+    map_tweet_markers = [];
+    param_placeholder = {};
+    
+    $("#clear-button").button().click(function () {
+        mapWidgetClearMap();
+        param_placeholder = {};
+        
+        map.setZoom(4);
+        map.setCenter(new google.maps.LatLng(38.89, -77.03));
+        
+        $('#query-preview-window').html('');
+        $("#metatweetzone").html('');
+    });
+    
+    $("#selection-button").button('toggle');
+ 
+    var dialog = $("#dialog").dialog({
+        width: "auto",
+        title: "AQL Query"
+    }).dialog("close");
+    $("#show-query-button")
+    	.button()
+    	.attr("disabled", true)
+    	.click(function (event) {
+        	$("#dialog").dialog("open");
+    	});
+    
+    // setup grid sliders
+    var updateSliderDisplay = function(event, ui) {
+        if (event.target.id == "grid-lat-slider") {
+            $("#gridlat").text(""+ui.value);
+        } else {
+          $("#gridlng").text(""+ui.value);
+        }
+    };
+    
+    sliderOptions = {
+        max: 20,
+        min: .1,
+        step: .1,
+        value: 2.0,
+        slidechange: updateSliderDisplay,
+        slide: updateSliderDisplay,
+        start: updateSliderDisplay,
+        stop: updateSliderDisplay
+    };
+
+    $("#gridlat").text(""+sliderOptions.value);
+    $("#gridlng").text(""+sliderOptions.value);
+    $(".grid-slider").slider(sliderOptions);
+    
+    // setup datepickers
+    var dateOptions = {
+        dateFormat: "yy-mm-dd",
+        defaultDate: "2012-01-02",
+        navigationAsDateFormat: true,
+        constrainInput: true
+    };
+    var start_dp = $("#start-date").datepicker(dateOptions);
+    start_dp.val(dateOptions.defaultDate);
+    dateOptions['defaultDate'] = "2012-12-31";
+    var end_dp= $("#end-date").datepicker(dateOptions);
+    end_dp.val(dateOptions.defaultDate);
+    
+    // This little bit of code manages period checks of the asynchronous query manager,
+    // which holds onto handles asynchornously received. We can set the handle update
+    // frequency using seconds, and it will let us know when it is ready.
+    var intervalID = setInterval( 
+        function() {
+    		asynchronousQueryIntervalUpdate();
+    	}, 
+    	asynchronousQueryGetInterval()
+    );
+    
+    // setup map
+    onOpenExploreMap();
+    var mapOptions = {
+        center: new google.maps.LatLng(38.89, 77.03),
+        zoom: 4,
+        mapTypeId: google.maps.MapTypeId.ROADMAP, // SATELLITE
+        streetViewControl: false,
+        draggable : false
+    };
+    map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
+    
+    // setup location autocomplete
+    var input = document.getElementById('location-text-box');
+    var autocomplete = new google.maps.places.Autocomplete(input);
+    autocomplete.bindTo('bounds', map);
+
+    google.maps.event.addListener(autocomplete, 'place_changed', function() {
+        var place = autocomplete.getPlace();
+        if (place.geometry.viewport) {
+            map.fitBounds(place.geometry.viewport);
+        } else {
+            map.setCenter(place.geometry.location);
+            map.setZoom(17);  // Why 17? Because it looks good.
+        }
+        var address = '';
+        if (place.address_components) {
+            address = [(place.address_components[0] && place.address_components[0].short_name || ''),
+              (place.address_components[1] && place.address_components[1].short_name || ''),
+              (place.address_components[2] && place.address_components[2].short_name || '') ].join(' ');
+        }
+    });
+    
+    // handle selection rectangle drawing
+    shouldDraw = false;
+    var startLatLng;
+    selectionRect = null;
+    var selectionRadio = $("#selection-button");
+    var firstClick = true;
+    
+    google.maps.event.addListener(map, 'mousedown', function (event) {
+        // only allow drawing if selection is selected
+        if (selectionRadio.hasClass("active")) {
+            startLatLng = event.latLng;
+            shouldDraw = true;
+        }
+    });
+    
+    //triggerUIUpdateOnNewTweetBook({"title" : "Party"});
+
+    google.maps.event.addListener(map, 'mousemove', drawRect);
+    function drawRect (event) {
+        if (shouldDraw) {
+            if (!selectionRect) {
+                var selectionRectOpts = {
+                    bounds: new google.maps.LatLngBounds(startLatLng, event.latLng),
+                    map: map,
+                    strokeWeight: 1,
+                    strokeColor: "2b3f8c",
+                    fillColor: "2b3f8c"
+                };
+                selectionRect = new google.maps.Rectangle(selectionRectOpts);
+                google.maps.event.addListener(selectionRect, 'mouseup', function () {
+                    shouldDraw = false;
+                    //submitQuery();
+                });
+            } else {
+                if (startLatLng.lng() < event.latLng.lng()) {
+                    selectionRect.setBounds(new google.maps.LatLngBounds(startLatLng, event.latLng));
+                } else {
+                    selectionRect.setBounds(new google.maps.LatLngBounds(event.latLng, startLatLng));
+                }
+            }
+        }
+    };
+    
+    // toggle location search style: by location or by map selection
+    $('#selection-button').on('click', function (e) {
+        $("#location-text-box").attr("disabled", "disabled");
+        if (selectionRect) {
+            selectionRect.setMap(map);
+        }
+    });
+    $('#location-button').on('click', function (e) {
+        $("#location-text-box").removeAttr("disabled");
+        if (selectionRect) {
+            selectionRect.setMap(null);
+        }
+    });
+    
+    $('.dropdown-menu a.holdmenu').click(function(e) {
+        e.stopPropagation();
+    });
+    
+    $('#new-tweetbook-button').on('click', function (e) {
+        onCreateNewTweetBook($('#new-tweetbook-entry').val());
+        
+        $('#new-tweetbook-entry').val($('#new-tweetbook-entry').attr('placeholder'));
+    });
+    
+    // handle ajax calls
+    $("#submit-button").button().click(function () {
+    	// Clear current map on trigger
+    	mapWidgetClearMap();
+    	
+    	// gather all of the data from the inputs
+        var kwterm = $("#keyword-textbox").val();
+        var startdp = $("#start-date").datepicker("getDate");
+        var enddp = $("#end-date").datepicker("getDate");
+        var startdt = $.datepicker.formatDate("yy-mm-dd", startdp)+"T00:00:00Z";
+        var enddt = $.datepicker.formatDate("yy-mm-dd", enddp)+"T23:59:59Z";
+
+        var formData = {
+            "keyword": kwterm,
+            "startdt": startdt,
+            "enddt": enddt,
+            "gridlat": $("#grid-lat-slider").slider("value"),
+            "gridlng": $("#grid-lng-slider").slider("value")
+        };
+
+    	// Get Map Bounds
+    	var bounds;
+        if ($('#selection-button').hasClass("active") && selectionRect) {
+            bounds = selectionRect.getBounds();
+        } else {
+            bounds = map.getBounds();
+        }
+    	
+    	formData["swLat"] = Math.abs(bounds.getSouthWest().lat());
+        formData["swLng"] = Math.abs(bounds.getSouthWest().lng());
+        formData["neLat"] = Math.abs(bounds.getNorthEast().lat());
+        formData["neLng"] = Math.abs(bounds.getNorthEast().lng());
+		var formBounds = {
+            "ne" : { "lat" : formData["neLat"], "lng" : formData["neLng"]}, 
+		    "sw" : { "lat" : formData["swLat"], "lng" : formData["swLng"]}
+        };
+
+		var build_cherry_mode = "synchronous";
+		if ($('#asbox').is(":checked")) {
+		    build_cherry_mode = "asynchronous";
+		}
+		
+		// You don't need to run a query to use the API!
+		// It can also be used to generate queries, which can
+		// then be passed into another API call or stored 
+		// for a different application purpose. 
+        var l = new LegacyExpression()
+            .dataverse("twitter")
+		    .bind(new ForClause("t", new AsterixClause().set("TweetMessages")))
+            .bind(new LetClause("keyword", new AsterixClause().set('"' + formData["keyword"] + '"')))
+            .bind(new LetClause("region", new AsterixSDK().rectangle(formBounds)))
+            .bind(new WhereClause("where " + [
+		        'spatial-intersect($t.sender-location, $region)',
+		        '$t.send-time > datetime("' + formData["startdt"] + '")',
+		        '$t.send-time < datetime("' + formData["enddt"] + '")',
+		        'contains($t.message-text, $keyword)'
+             ]).join(" "))
+            .bind(new GroupClause().set("group by $c := spatial-cell($t.sender-location, create-point(24.5,-125.5), " + formData["gridlat"].toFixed(1) + ", " + formData["gridlng"].toFixed(1) + ")"))
+		    .return({ "cell" : "$c", "count" : "count($t)" })
+            .success(cherryQuerySyncCallback, true)
+		    .success(cherryQueryAsyncCallback, false)
+            .extra({
+                "payload" : formData,
+                "query_string" : "use dataverse twitter;\n" //LEGACY + buildCherryQuery.parameters["statements"].join("\n")
+            })
+            .send("http://localhost:19101/query", 
+            {
+                "query" : "use dataverse twitter;\n" + buildCherryQuery.parameters["statements"].join("\n"),
+                "mode" : build_cherry_mode, 
+            });
+        
+		APIqueryTracker = {
+		    "query" : "use dataverse twitter;",// buildCherryQuery.parameters["statements"].join("\n"),
+		    "data" : formData
+		};
+		
+		$('#dialog').html(APIqueryTracker["query"]);//.replace("\n", '<br />'));
+
+        if (!$('#asbox').is(":checked")) {
+		    $('#show-query-button').attr("disabled", false);
+        } else {
+            $('#show-query-button').attr("disabled", true);
+        }
+    });
+    
+});
+
+/** Asynchronous Query Management - Handles & Such **/
+
+/**
+* Checks through each asynchronous query to see if they are ready yet
+*/
+function asynchronousQueryIntervalUpdate() {
+    for (var handle_key in asyncQueryManager) {
+        if (!asyncQueryManager[handle_key].hasOwnProperty("ready")) { 
+            asynchronousQueryGetAPIQueryStatus( asyncQueryManager[handle_key]["handle"], handle_key ); 
+        }
+    }
+}
+
+/**
+* Returns current time interval to check for asynchronous query readiness
+* @returns  {number}    milliseconds between asychronous query checks
+*/
+function asynchronousQueryGetInterval() {
+    var seconds = 10;
+    return seconds * 1000;
+}
+
+/**
+* Updates UI when an API Query's status is marked ready
+* @param    {Object}    res, a result object from the Asterix API
+* @param    {object}    extra_info, containing the asynchronous handle's id
+*/
+function asynchronousQueryAPIStatusReceived (res, extra_info) {
+    var handle_outcome = $.parseJSON(res[0]);
+    var handle_id = extra_info["handle_id"];
+    if (handle_outcome["status"] == "SUCCESS") {
+    
+        // We don't need to check if this one is ready again, it's not going anywhere...
+        // Unless the life cycle of handles has changed drastically
+        asyncQueryManager[handle_id]["ready"] = true;
+        
+        // Make this handle's result look retrievable
+        $('#handle_' + handle_id).addClass("label-success");
+    }    
+}
+
+/**
+* Retrieves status of an asynchronous query, using an opaque result handle from API
+* @param    {Object}    handle, an object previously returned from an async call
+* @param    {number}    handle_id, the integer ID parsed from the handle object
+*/
+function asynchronousQueryGetAPIQueryStatus (handle, handle_id) {
+    var apiQueryStatus = new AsterixCoreAPI()
+        .dataverse("twitter")
+        .handle(handle)
+        .success(asynchronousQueryAPIStatusReceived, true)
+        .add_extra("handle_id", handle_id)
+        .api_core_query_status();
+}
+
+/**
+* On-success callback after async API query
+* @param    {object}    res, a result object containing an opaque result handle to Asterix
+* @param    {object}    extra, a result object containing a query string and query parameters
+*/
+function cherryQueryAsyncCallback(res, extra) {
+    
+    // Parse handle, handle id and query from async call result
+    var handle = res[0];
+    var handle_query = extra["query_string"];
+    var handle_id = $.parseJSON(handle)["handle"].toString().split(',')[0];    
+    
+    // Add to stored map of existing handles
+    asyncQueryManager[handle_id] = {
+        "handle" : handle,
+        "query" : handle_query,
+        "data" : extra["payload"]
+    };
+    
+    $('#review-handles-dropdown').append('<a href="#" class="holdmenu"><span class="label" id="handle_' + handle_id + '">Handle ' + handle_id + '</span></a>');
+    
+    $('#handle_' + handle_id).hover(
+        function(){ 
+            $('#query-preview-window').html('');
+            $('#query-preview-window').html('<br/><br/>' + asyncQueryManager[handle_id]["query"]);
+        },
+        function() {
+            $('#query-preview-window').html('');
+        }
+    ); 
+    
+    $('#handle_' + handle_id).on('click', function (e) {
+        
+        // make sure query is ready to be run
+        if (asyncQueryManager[handle_id]["ready"]) {
+        
+            // Update API Query Tracker and view to reflect this query
+            $('#query-preview-window').html('<br/><br/>' + asyncQueryManager[handle_id]["query"]);
+            APIqueryTracker = {
+                "query" : asyncQueryManager[handle_id]["query"],
+                "data"  : asyncQueryManager[handle_id]["data"]
+            };
+            $('#dialog').html(APIqueryTracker["query"]);
+        
+            // Generate new Asterix Core API Query
+            var asyncResultQuery = new AsterixCoreAPI()
+                .dataverse("twitter")
+                .handle(asyncQueryManager[handle_id]["handle"])
+                .success(cherryQuerySyncCallback, true)
+                .add_extra("payload", asyncQueryManager[handle_id]["data"]) // Legacy
+		        .add_extra("query_string", asyncQueryManager[handle_id]["query"]) // Legacy
+		        .api_core_query_result(); 
+        }
+    });
+}
+
+
+/** Core Query Management and Drilldown
+
+/**
+* Utility Method for parsing a record of this form:
+* { "cell": rectangle("22.5,64.5 24.5,66.5"), "count": 5 }
+* returns a json object with keys: weight, latSW, lngSW, latNE, lngNE
+*/
+function getRecord(cell_count_record) {
+    var record_representation = {};
+    
+    var rectangle = cell_count_record.split('")')[0].split('("')[1];
+    record_representation["latSW"] = parseFloat(rectangle.split(" ")[0].split(',')[0]);
+    record_representation["lngSW"] = parseFloat(rectangle.split(" ")[0].split(',')[1]);
+    record_representation["latNE"] = parseFloat(rectangle.split(" ")[1].split(',')[0]);
+    record_representation["lngNE"] = parseFloat(rectangle.split(" ")[1].split(',')[1]);
+    record_representation["weight"] = parseInt(cell_count_record.split('count": ')[1].split(" ")[0]);
+    
+    return record_representation;
+}
+
+/**
+* A spatial data cleaning and mapping call
+* @param    {Object}    res, a result object from a cherry geospatial query
+* @param    {Object}    extra, extra data passed from the API call - legacy stuff
+*/
+function cherryQuerySyncCallback(res, extra) {
+    records = res["results"];
+
+    var coordinates = [];
+    var weights = [];
+                
+    for (var subrecord in records) {
+        for (var record in records[subrecord]) {
+            
+            var coordinate = getRecord(records[subrecord][record]);
+            weights.push(coordinate["weight"]);
+            coordinates.push(coordinate);
+        }
+    }
+    triggerUIUpdate(coordinates, extra["payload"], weights);
+}
+
+/**
+* Triggers a map update based on a set of spatial query result cells
+* @param    [Array]     mapPlotData, an array of coordinate and weight objects
+* @param    [Array]     params, an object containing original query parameters [LEGACY]
+* @param    [Array]     plotWeights, a list of weights of the spatial cells - e.g., number of tweets
+*/
+function triggerUIUpdate(mapPlotData, params, plotWeights) {
+    /** Clear anything currently on the map **/
+    mapWidgetClearMap();
+    param_placeholder = params;
+    
+    // Compute data point spread
+    var dataBreakpoints = mapWidgetLegendComputeNaturalBreaks(plotWeights);
+     
+    $.each(mapPlotData, function (m, val) {
+    
+        // Only map points in data range of top 4 natural breaks
+        if (mapPlotData[m].weight > dataBreakpoints[0]) {
+        
+            // Get color value of legend 
+            var mapColor = mapWidgetLegendGetHeatValue(mapPlotData[m].weight, dataBreakpoints);
+            var markerRadius = mapWidgetComputeCircleRadius(mapPlotData[m], dataBreakpoints);
+            var point_opacity = 1.0; // TODO
+           
+            var point_center = new google.maps.LatLng(
+                (mapPlotData[m].latSW + mapPlotData[m].latNE)/2.0, 
+                (mapPlotData[m].lngSW + mapPlotData[m].lngNE)/2.0);
+            
+            // Create and plot marker
+            var map_circle_options = {
+                center: point_center,
+                radius: markerRadius,
+                map: map,
+                fillOpacity: point_opacity,
+                fillColor: mapColor,
+                clickable: true
+            };
+            var map_circle = new google.maps.Circle(map_circle_options);
+            map_circle.val = mapPlotData[m];
+            
+            // Clicking on a circle drills down map to that value
+            google.maps.event.addListener(map_circle, 'click', function (event) {
+                onMapPointDrillDown(map_circle.val);     
+            });
+            
+            // Add this marker to global marker cells
+            map_cells.push(map_circle);
+        }    
+    });
+    
+    // Add a legend to the map
+    mapControlWidgetAddLegend(dataBreakpoints);
+}
+
+/**
+* prepares an Asterix API query to drill down in a rectangular spatial zone
+*
+* @params {object} marker_borders [LEGACY] a set of bounds for a region from a previous api result
+*/
+function onMapPointDrillDown(marker_borders) {
+    var zoneData = APIqueryTracker["data"]; // TODO: Change how this is managed
+    
+    var zswBounds = new google.maps.LatLng(marker_borders.latSW, marker_borders.lngNE);
+    var zneBounds = new google.maps.LatLng(marker_borders.latNE, marker_borders.lngSW); 
+    
+    var zoneBounds = new google.maps.LatLngBounds(zswBounds, zneBounds);
+    zoneData["swLat"] = zoneBounds.getSouthWest().lat();
+    zoneData["swLng"] = -1*zoneBounds.getSouthWest().lng();
+    zoneData["neLat"] = zoneBounds.getNorthEast().lat();
+    zoneData["neLng"] = -1*zoneBounds.getNorthEast().lng();
+    
+    mapWidgetClearMap();
+    
+    var customBounds = new google.maps.LatLngBounds();
+    var zoomSWBounds = new google.maps.LatLng(zoneData["swLat"], -1*zoneData["swLng"]);
+    var zoomNEBounds = new google.maps.LatLng(zoneData["neLat"], -1*zoneData["neLng"]); 
+    customBounds.extend(zoomSWBounds);
+    customBounds.extend(zoomNEBounds);
+    map.fitBounds(customBounds);
+    
+    var drilldown_string = ["use dataverse " + "twitter" + ";",
+        "for $t in dataset('" + "TweetMessages" + "')",
+        "let $keyword := \"" +zoneData["keyword"] + "\"",
+        "let $region := polygon(\"", 
+           zoneData["neLat"] + "," + zoneData["swLng"] + " ",
+           zoneData["swLat"] + "," + zoneData["swLng"] + " ",
+           zoneData["swLat"] + "," + zoneData["neLng"] + " ",
+           zoneData["neLat"] + "," + zoneData["neLng"] + "\")",
+           "where spatial-intersect($t.sender-location, $region) and",
+           "$t.send-time > datetime(\"" + zoneData["startdt"] + "\") and $t.send-time < datetime(\"" + zoneData["enddt"] + "\") and",
+           "contains($t.message-text, $keyword)",
+           "return { \"tweetId\": $t.tweetid, \"tweetText\": $t.message-text, \"tweetLoc\": $t.sender-location}"];
+    
+    var zQ = new AsterixCoreAPI()
+        .dataverse("twitter")
+        .statements(drilldown_string)
+        .add_extra("payload", zoneData) // Legacy
+        .mode("synchronous")
+        .success(onTweetbookQuerySuccessPlot, true)
+        .add_extra("query_string", drilldown_string.join(" "))
+        .add_extra("marker_path", "../img/mobile2.png")
+        .add_extra("on_click_marker", onClickTweetbookMapMarker)
+        .add_extra("on_clean_result", onCleanTweetbookDrilldown)
+        .api_core_query();
+}
+
+function triggerUIUpdateOnDropTweetBook(extra_info) {
+    // TODO Remove menu entry
+    // review-tweetbook-titles.html('')
+    // Append each in review_mode_tweetbooks if not same as extra_info["title"]
+    // $('#review-tweetbook-titles').append('<li><a href="#">' + extra_info["title"] + '</a></li>');
+}
+
+function onDrillDownAtLocation(tO) {
+
+    $('#drilldown_modal_body').append('<div id="drilltweetobj' + tO["tweetEntryId"] + '"></div>');
+    
+    $('#drilltweetobj' + tO["tweetEntryId"]).append('<p>' + tO["tweetText"] + '</p>');
+    
+    $('#drilltweetobj' + tO["tweetEntryId"]).append('<input class="textbox" type="text" id="metacomment' + tO["tweetEntryId"] + '">');
+    
+    if (tO.hasOwnProperty("tweetbookComment")) {
+        $('#metacomment' + tO["tweetEntryId"]).val(tO["tweetbookComment"]);
+    }
+    
+    $('#drilltweetobj' + tO["tweetEntryId"]).append('<button title="' + tO["tweetEntryId"] + '" id="meta' + tO["tweetEntryId"] + '">Add Comment to...</button>');
+    
+    $('#drilltweetobj' + tO["tweetEntryId"]).append('<input class="textbox" type="text" id="tweetbooktarget' + tO["tweetEntryId"] + '">');
+
+    $('#meta' + tO["tweetEntryId"])
+        .button()
+        .click( function () {
+       
+            var valid = $('#meta' + tO["tweetEntryId"]).attr('title');
+            var valcomment = $("#metacomment" + valid).val();
+            var valtext = drilldown_data_map_vals[valid.toString()]["tweetText"];
+            var tweetbookname = $("#tweetbooktarget" + valid).val();
+            
+            //Try to add the tweetbook, if it does not already exist
+            onCreateNewTweetBook(tweetbookname);
+            
+            var apiCall = new AsterixCoreAPI()
+                .dataverse("twitter")
+                .statements([
+                    'delete $l from dataset ' + tweetbookname + ' where $l.id = "' + valid + '";',
+                    'insert into dataset ' + tweetbookname + '({ "id" : "' + valid + '", "metacomment" : "' + valcomment + '"});'  
+                ])
+                .api_core_update();
+        });
+    
+}
+
+function onCreateNewTweetBook(tweetbook_title) {
+    
+    var newTweetbookAPICall = new AsterixCoreAPI()
+        .dataverse("twitter")
+        .create_dataset({ 
+            "dataset"       : tweetbook_title,
+            "type"          : "MetaTweet",
+            "primary_key"   : "id"
+        })
+        .add_extra("title", tweetbook_title)
+        .success(triggerUIUpdateOnNewTweetBook, true)
+        .api_core_update(); 
+        // Possible bug...ERROR 1: Invalid statement: Non-DDL statement DATASET_DECL to the DDL API.
+      
+    /*var removeTest = new AsterixCoreAPI()
+        .dataverse("twitter")
+        .drop_dataset("blah")
+        .api_core_update(); */
+}
+
+function onDropTweetBook(tweetbook_title) {
+    var removeTest = new AsterixCoreAPI()
+        .dataverse("twitter")
+        .drop_dataset(tweetbook_title)
+        .success(triggerUIUpdateOnDropTweetBook, true)
+        .api_core_update(); 
+}
+
+function onTweetbookQuerySuccessPlot (res, extra) {
+    var response = $.parseJSON(res[0]);
+    var records = response["results"];
+    var coordinates = [];
+    map_tweet_markers = [];  
+    map_tweet_overlays = [];
+    drilldown_data_map = {};
+    drilldown_data_map_vals = {};
+    
+    var micon = extra["marker_path"];
+    var marker_click_function = extra["on_click_marker"];
+    var clean_result_function = extra["on_clean_result"];
+    
+    coordinates = clean_result_function(records);
+
+    for (var dm in coordinates) {
+        var keyLat = coordinates[dm].tweetLat.toString();
+        var keyLng = coordinates[dm].tweetLng.toString();
+        if (!drilldown_data_map.hasOwnProperty(keyLat)) {
+            drilldown_data_map[keyLat] = {}; 
+        }
+        if (!drilldown_data_map[keyLat].hasOwnProperty(keyLng)) {
+            drilldown_data_map[keyLat][keyLng] = []; 
+        }
+        drilldown_data_map[keyLat][keyLng].push(coordinates[dm]);
+        drilldown_data_map_vals[coordinates[dm].tweetEntryId.toString()] = coordinates[dm];  
+    }
+    
+    $.each(drilldown_data_map, function(drillKeyLat, valuesAtLat) {
+        $.each(drilldown_data_map[drillKeyLat], function (drillKeyLng, valueAtLng) {
+            
+            // Get subset of drilldown position on map
+            var cposition =  new google.maps.LatLng(parseFloat(drillKeyLat), parseFloat(drillKeyLng));
+            
+            // Create a marker using the snazzy phone icon
+            var map_tweet_m = new google.maps.Marker({
+                position: cposition,
+                map: map,
+                icon: micon,
+                clickable: true,
+            });
+            
+            // Open Tweet exploration window on click
+            google.maps.event.addListener(map_tweet_m, 'click', function (event) {
+                marker_click_function(drilldown_data_map[drillKeyLat][drillKeyLng]);
+            });
+            
+            // Add marker to index of tweets
+            map_tweet_markers.push(map_tweet_m); 
+            
+        });
+    });
+}
+
+function triggerUIUpdateOnNewTweetBook(extra_info) {
+    // Add tweetbook to log
+    if (parseInt($.inArray(extra_info["title"], review_mode_tweetbooks)) == -1) {
+        review_mode_tweetbooks.push(extra_info["title"]);
+        
+        // Add menu entry
+        $('#review-tweetbook-titles').append('<li><a href="#"><span id="tbook_' + extra_info["title"] + '">' + extra_info["title"] + '</span></a></li>');
+    
+        // Add on-click behavior
+        $("#tbook_" + extra_info["title"]).on('click', function(e) {
+            var plotTweetbookQuery = new AsterixCoreAPI()
+                .dataverse("twitter")
+                .success(onTweetbookQuerySuccessPlot, true)
+                .aql_for({"mt": extra_info["title"]})
+                .aql_where(["int64($mt.id)%1500 = 0"])
+                .aql_return({ "id" : "$mt.id", "location" : "$mt.loc", "comment" : "$mt.metacomment", "tweet" : "$mt.tweet" }) 
+                .add_extra("tweetbook_title", extra_info["title"])
+                .add_extra("marker_path", "../img/mobile_green2.png")
+                .add_extra("on_click_marker", onClickTweetbookMapMarker)
+                .add_extra("on_clean_result", onCleanPlotTweetbook)
+                .api_core_query();
+                
+        });
+    }
+}
+
+function onCleanPlotTweetbook(records) {
+    var toPlot = [];
+    for (var subrecords = 0; subrecords < records.length; subrecords++) {
+        for (var record in records[subrecords]) {
+            var tweetbook_element = {
+                "tweetEntryId" : parseInt(records[subrecords][record].split(",")[0].split(":")[1].split('"')[1]),
+                "tweetLat"     : parseFloat(records[subrecords][record].split("location\": point(\"")[1].split(",")[0]),
+                "tweetLng"     : -1*parseFloat(records[subrecords][record].split("location\": point(\"")[1].split(",")[1].split("\"")[0]),
+                "tweetText"    : records[subrecords][record].split("tweet\": \"")[1].split("\"")[0],
+                "tweetbookComment" : records[subrecords][record].split("comment\": \"")[1].split("\", \"tweet\":")[0]
+            };
+            toPlot.push(tweetbook_element);
+        }
+    }
+    return toPlot;
+}
+
+function onCleanTweetbookDrilldown (rec) {
+    var drilldown_cleaned = [];
+    for (var subresult = 0; subresult < rec.length; subresult++) {
+        for (var entry in rec[subresult]) {
+            
+            var drill_element = {
+                "tweetEntryId" : parseInt(rec[subresult][entry].split(",")[0].split(":")[1].split('"')[1]),
+                "tweetText" : rec[subresult][entry].split("tweetText\": \"")[1].split("\", \"tweetLoc\":")[0],
+                "tweetLat" : parseFloat(rec[subresult][entry].split("tweetLoc\": point(\"")[1].split(",")[0]),
+                "tweetLng" : -1*parseFloat(rec[subresult][entry].split("tweetLoc\": point(\"")[1].split(",")[1].split("\"")[0])
+            };
+            drilldown_cleaned.push(drill_element);
+            
+        } 
+    }
+    return drilldown_cleaned;
+}
+
+function onClickTweetbookMapMarker(tweet_arr) {
+    $('#drilldown_modal_body').html('');
+
+    // Clear existing display
+    $.each(tweet_arr, function (t, valueT) {
+        var tweet_obj = tweet_arr[t];
+        onDrillDownAtLocation(tweet_obj);
+    });
+    
+    $('#drilldown_modal').modal('show');
+}
+
+/** Toggling Review and Explore Modes **/
+
+/**
+* Explore mode: Initial map creation and screen alignment
+*/
+function onOpenExploreMap () {
+    var explore_column_height = $('#explore-well').height();   
+    $('#map_canvas').height(explore_column_height + "px");
+    $('#review-well').height(explore_column_height + "px");
+    $('#review-well').css('max-height', explore_column_height + "px");
+    var pad = $('#review-well').innerHeight() - $('#review-well').height();
+    var prev_window_target = $('#review-well').height() - 20 - $('#group-tweetbooks').innerHeight() - $('#group-background-query').innerHeight() - 2*pad;
+    $('#query-preview-window').height(prev_window_target +'px');
+}
+
+/**
+* Launching explore mode: clear windows/variables, show correct sidebar
+*/
+function onLaunchExploreMode() {
+    $('#review-active').removeClass('active');
+    $('#review-well').hide();
+    
+    $('#explore-active').addClass('active');    
+    $('#explore-well').show();
+    
+    $("#clear-button").trigger("click");
+}
+
+/**
+* Launching review mode: clear windows/variables, show correct sidebar
+*/
+function onLaunchReviewMode() {
+    $('#explore-active').removeClass('active');
+    $('#explore-well').hide();
+    $('#review-active').addClass('active');
+    $('#review-well').show();
+    
+    $("#clear-button").trigger("click");
+}
+
+/** Map Widget Utility Methods **/
+
+/**
+* Plots a legend onto the map, with values in progress bars
+* @param    {number Array}  breakpoints, an array of numbers representing natural breakpoints
+*/
+function mapControlWidgetAddLegend(breakpoints) {
+   
+    // Retriever colors, lightest to darkest
+    var colors = mapWidgetGetColorPalette();
+    
+    // Initial div structure
+    $("#map_canvas_legend").html('<div id="legend-holder"><div id="legend-progress-bar" class="progress"></div><span id="legend-label"></span></div>');
+
+    // Add color scale to legend
+    $('#legend-progress-bar').css("width", "200px").html('');
+    
+    // Add a progress bar for each color
+    for (var color in colors) {
+        
+        // Bar values
+        var upperBound = breakpoints[parseInt(color) + 1];
+        
+        // Create Progress Bar
+        $('<div/>')
+            .attr("class", "bar")
+            .attr("id", "pbar" + color)
+            .css("width" , '25.0%')
+            .html("< " + upperBound)
+            .appendTo('#legend-progress-bar');
+        
+        $('#pbar' + color).css({
+            "background-image" : 'none',
+            "background-color" : colors[parseInt(color)]
+        });
+        
+        // Attach a message showing minimum bounds     
+        $('#legend-label').html('Regions with at least ' + breakpoints[0] + ' tweets');
+        $('#legend-label').css({
+            "color" : "black"
+        });
+    }
+    
+    // Add legend to map
+    map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(document.getElementById('legend-holder'));
+    $('#map_canvas_legend').show(); 
+}
+
+/**
+* Clears map elements - legend, plotted items, overlays
+*/
+function mapWidgetClearMap() {
+
+    if (selectionRect) {
+        selectionRect.setMap(null);
+        selectionRect = null;
+    }
+    for (c in map_cells) {
+        map_cells[c].setMap(null);
+    }
+    map_cells = [];
+    for (m in map_tweet_markers) {
+        map_tweet_markers[m].setMap(null);
+    }
+    map_tweet_markers = [];
+    
+    // Remove legend from map
+    map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].clear();
+}
+
+/**
+* Uses jenks algorithm in geostats library to find natural breaks in numeric data
+* @param    {number Array} weights of points to plot
+* @returns  {number Array} array of natural breakpoints, of which the top 4 subsets will be plotted
+*/ 
+function mapWidgetLegendComputeNaturalBreaks(weights) {
+    var plotDataWeights = new geostats(weights.sort());
+    return plotDataWeights.getJenks(6).slice(2, 7);
+}
+
+/**
+* Computes values for map legend given a value and an array of jenks breakpoints
+* @param    {number}        weight of point to plot on map
+* @param    {number Array}  breakpoints, an array of 5 points corresponding to bounds of 4 natural ranges
+* @returns  {String}        an RGB value corresponding to a subset of data
+*/
+function mapWidgetLegendGetHeatValue(weight, breakpoints) {
+
+    // Determine into which range the weight falls
+    var weightColor = 0;
+    if (weight >= breakpoints[3]) {
+        weightColor = 3;
+    } else if (weight >= breakpoints[2]) {
+        weightColor = 2;
+    } else if (weight >= breakpoints[1]) {
+        weightColor = 1;
+    }
+
+    // Get default map color palette
+    var colorValues = mapWidgetGetColorPalette();
+    return colorValues[weightColor];
+}
+
+/**
+* Returns an array containing a 4-color palette, lightest to darkest
+* External palette source: http://www.colourlovers.com/palette/2763366/s_i_l_e_n_c_e_r
+* @returns  {Array}    [colors]
+*/
+function mapWidgetGetColorPalette() {
+    return [ 
+        "rgb(115,189,158)", 
+        "rgb(74,142,145)", 
+        "rgb(19,93,96)", 
+        "rgb(7,51,46)"
+    ];  
+}
+
+/**
+* Computes radius for a given data point from a spatial cell
+* @param    {Object}    keys => ["latSW" "lngSW" "latNE" "lngNE" "weight"]
+* @returns  {number}    radius between 2 points in metres
+*/
+function mapWidgetComputeCircleRadius(spatialCell, breakpoints) {
+    
+    var weight = spatialCell.weight;
+    // Compute weight color
+    var weightColor = 0.25;
+    if (weight >= breakpoints[3]) {
+        weightColor = 1.0;
+    } else if (weight >= breakpoints[2]) {
+        weightColor = 0.75;
+    } else if (weight >= breakpoints[1]) {
+        weightColor = 0.5;
+    }
+
+    // Define Boundary Points
+    var point_center = new google.maps.LatLng((spatialCell.latSW + spatialCell.latNE)/2.0, (spatialCell.lngSW + spatialCell.lngNE)/2.0);
+    var point_left = new google.maps.LatLng((spatialCell.latSW + spatialCell.latNE)/2.0, spatialCell.lngSW);
+    var point_top = new google.maps.LatLng(spatialCell.latNE, (spatialCell.lngSW + spatialCell.lngNE)/2.0);
+    
+    // TODO not actually a weight color :)
+    return weightColor * 1000 * Math.min(distanceBetweenPoints_(point_center, point_left), distanceBetweenPoints_(point_center, point_top));
+}
+
+/** External Utility Methods **/
+
+/**
+ * Calculates the distance between two latlng locations in km.
+ * @see http://www.movable-type.co.uk/scripts/latlong.html
+ *
+ * @param {google.maps.LatLng} p1 The first lat lng point.
+ * @param {google.maps.LatLng} p2 The second lat lng point.
+ * @return {number} The distance between the two points in km.
+ * @private
+*/
+function distanceBetweenPoints_(p1, p2) {
+  if (!p1 || !p2) {
+    return 0;
+  }
+
+  var R = 6371; // Radius of the Earth in km
+  var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;
+  var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;
+  var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
+    Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) *
+    Math.sin(dLon / 2) * Math.sin(dLon / 2);
+  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+  var d = R * c;
+  return d;
+};
diff --git a/asterix-examples/src/main/resources/cherry/js/geostats.js b/asterix-examples/src/main/resources/cherry/js/geostats.js
new file mode 100755
index 0000000..adc8e1d
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/js/geostats.js
@@ -0,0 +1,679 @@
+/**
+* geostats() is a tiny and standalone javascript library for classification 
+* Project page - https://github.com/simogeo/geostats
+* Copyright (c) 2011 Simon Georget, http://valums.com
+* Licensed under the MIT license
+*/
+
+var _t = function(str) {
+	return str;
+};
+
+var inArray = function(needle, haystack) {
+    for(var i = 0; i < haystack.length; i++) {
+        if(haystack[i] == needle) return true;
+    }
+    return false;
+};
+
+var geostats = function(a) {
+
+	this.separator = ' - ';
+	this.legendSeparator = this.separator;
+	this.method  = '';
+	this.roundlength 	= 2; // Number of decimals, round values
+	this.is_uniqueValues = false;
+	
+	this.bounds  = Array();
+	this.ranges  = Array();
+	this.colors  = Array();
+	this.counter = Array();
+	
+	// statistics information
+	this.stat_sorted	= null;
+	this.stat_mean 		= null;
+	this.stat_median 	= null;
+	this.stat_sum 		= null;
+	this.stat_max 		= null;
+	this.stat_min 		= null;
+	this.stat_pop 		= null;
+	this.stat_variance	= null;
+	this.stat_stddev	= null;
+	this.stat_cov		= null;
+
+	
+	if(typeof a !== 'undefined' && a.length > 0) {
+		this.serie = a;
+	} else {
+		this.serie = Array();
+	};
+	
+	/**
+	 * Set a new serie
+	 */
+	this.setSerie = function(a) {
+	
+		this.serie = Array() // init empty array to prevent bug when calling classification after another with less items (sample getQuantile(6) and getQuantile(4))
+		this.serie = a;
+		
+	};
+	
+	/**
+	 * Set colors
+	 */
+	this.setColors = function(colors) {
+		
+		this.colors = colors;
+		
+	};
+	
+	/**
+	 * Get feature count
+	 * With bounds array(0, 0.75, 1.5, 2.25, 3); 
+	 * should populate this.counter with 5 keys
+	 * and increment counters for each key
+	 */
+	this.doCount = function() {
+		
+		if (this._nodata())
+			return;
+		
+
+		var tmp = this.sorted();
+		// console.log(tmp.join(', '));
+
+		
+		// we init counter with 0 value
+		for(i = 0; i < this.bounds.length; i++) {
+			this.counter[i]= 0;
+		}
+		
+		for(j=0; j < tmp.length; j++) {
+			
+			// get current class for value to increment the counter
+			var cclass = this.getClass(tmp[j]);
+			this.counter[cclass]++;
+
+		}
+
+	};
+	
+	/**
+	 * Transform a bounds array to a range array the following array : array(0,
+	 * 0.75, 1.5, 2.25, 3); becomes : array('0-0.75', '0.75-1.5', '1.5-2.25',
+	 * '2.25-3');
+	 */
+	this.setRanges = function() {
+	
+		this.ranges = Array(); // init empty array to prevent bug when calling classification after another with less items (sample getQuantile(6) and getQuantile(4))
+		
+		for (i = 0; i < (this.bounds.length - 1); i++) {
+			this.ranges[i] = this.bounds[i] + this.separator + this.bounds[i + 1];
+		}
+	};
+
+	/** return min value */
+	this.min = function() {
+		
+		if (this._nodata())
+			return;
+		
+		if (this.stat_min  == null) {
+			
+			this.stat_min = this.serie[0];
+			for (i = 0; i < this.pop(); i++) {
+				if (this.serie[i] < this.stat_min) {
+					this.stat_min = this.serie[i];
+				}
+			}
+			
+		}
+		
+		return this.stat_min;
+	};
+
+	/** return max value */
+	this.max = function() {
+		
+		if (this._nodata())
+			return;
+		
+		if (this.stat_max  == null) {
+			
+			this.stat_max = this.serie[0];
+			for (i = 0; i < this.pop(); i++) {
+				if (this.serie[i] > this.stat_max) {
+					this.stat_max = this.serie[i];
+				}
+			}
+			
+		}
+		
+		return this.stat_max;
+	};
+
+	/** return sum value */
+	this.sum = function() {
+		
+		if (this._nodata())
+			return;
+		
+		if (this.stat_sum  == null) {
+			
+			this.stat_sum = 0;
+			for (i = 0; i < this.pop(); i++) {
+				this.stat_sum += this.serie[i];
+			}
+			
+		}
+		
+		return this.stat_sum;
+	};
+
+	/** return population number */
+	this.pop = function() {
+		
+		if (this._nodata())
+			return;
+		
+		if (this.stat_pop  == null) {
+			
+			this.stat_pop = this.serie.length;
+			
+		}
+		
+		return this.stat_pop;
+	};
+
+	/** return mean value */
+	this.mean = function() {
+		
+		if (this._nodata())
+			return;
+		
+		if (this.stat_mean  == null) {
+			
+			this.stat_mean = this.sum() / this.pop();
+			
+		}
+		
+		return this.stat_mean;
+	};
+
+	/** return median value */
+	this.median = function() {
+		
+		if (this._nodata())
+			return;
+		
+		if (this.stat_median  == null) {
+			
+			this.stat_median = 0;
+			var tmp = this.sorted();
+	
+			if (tmp.length % 2) {
+				this.stat_median = tmp[(Math.ceil(tmp.length / 2) - 1)];
+			} else {
+				this.stat_median = (tmp[(tmp.length / 2) - 1] + tmp[(tmp.length / 2)]) / 2;
+			}
+			
+		}
+		
+		return this.stat_median;
+	};
+
+	/** return variance value */
+	this.variance = function() {
+		
+		round = (typeof round === "undefined") ? true : false;
+		
+		if (this._nodata())
+			return;
+		
+		if (this.stat_variance  == null) {
+
+			var tmp = 0;
+			for (var i = 0; i < this.pop(); i++) {
+				tmp += Math.pow( (this.serie[i] - this.mean()), 2 );
+			}
+
+			this.stat_variance =  tmp /	this.pop();
+			
+			if(round == true) {
+				this.stat_variance = Math.round(this.stat_variance * Math.pow(10,this.roundlength) )/ Math.pow(10,this.roundlength);
+			}
+			
+		}
+		
+		return this.stat_variance;
+	};
+	
+	/** return standard deviation value */
+	this.stddev = function(round) {
+		
+		round = (typeof round === "undefined") ? true : false;
+		
+		if (this._nodata())
+			return;
+		
+		if (this.stat_stddev  == null) {
+			
+			this.stat_stddev = Math.sqrt(this.variance());
+			
+			if(round == true) {
+				this.stat_stddev = Math.round(this.stat_stddev * Math.pow(10,this.roundlength) )/ Math.pow(10,this.roundlength);
+			}
+			
+		}
+		
+		return this.stat_stddev;
+	};
+	
+	/** coefficient of variation - measure of dispersion */
+	this.cov = function(round) {
+		
+		round = (typeof round === "undefined") ? true : false;
+		
+		if (this._nodata())
+			return;
+		
+		if (this.stat_cov  == null) {
+			
+			this.stat_cov = this.stddev() / this.mean();
+			
+			if(round == true) {
+				this.stat_cov = Math.round(this.stat_cov * Math.pow(10,this.roundlength) )/ Math.pow(10,this.roundlength);
+			}
+			
+		}
+		
+		return this.stat_cov;
+	};
+	
+	/** data test */
+	this._nodata = function() {
+		if (this.serie.length == 0) {
+			
+			alert("Error. You should first enter a serie!");
+			return 1;
+		} else
+			return 0;
+		
+	};
+
+	/** return sorted values (as array) */
+	this.sorted = function() {
+		
+		if (this.stat_sorted  == null) {
+			
+			if(this.is_uniqueValues == false) {
+				this.stat_sorted = this.serie.sort(function(a, b) {
+					return a - b;
+				});
+			} else {
+				this.stat_sorted = this.serie.sort(function(a,b){
+					var nameA=a.toLowerCase(), nameB=b.toLowerCase()
+				    if(nameA < nameB) return -1;
+				    if(nameA > nameB) return 1;
+				    return 0;
+				})
+			}
+		}
+		
+		return this.stat_sorted;
+		
+	};
+
+	/** return all info */
+	this.info = function() {
+		
+		if (this._nodata())
+			return;
+		
+		var content = '';
+		content += _t('Population') + ' : ' + this.pop() + ' - [' + _t('Min')
+				+ ' : ' + this.min() + ' | ' + _t('Max') + ' : ' + this.max()
+				+ ']' + "\n";
+		content += _t('Mean') + ' : ' + this.mean() + ' - ' + _t('Median')	+ ' : ' + this.median() + "\n";
+		content += _t('Variance') + ' : ' + this.variance() + ' - ' + _t('Standard deviation')	+ ' : ' + this.stddev()  
+				+ ' - ' + _t('Coefficient of variation')	+ ' : ' + this.cov() + "\n";
+
+		return content;
+	};
+
+	/**
+	 * Equal intervals discretization Return an array with bounds : ie array(0,
+	 * 0.75, 1.5, 2.25, 3);
+	 */
+	this.getEqInterval = function(nbClass) {
+
+		if (this._nodata())
+			return;
+
+		this.method = _t('eq. intervals') + ' (' + nbClass + ' ' + _t('classes')
+				+ ')';
+
+		var a = Array();
+		var val = this.min();
+		var interval = (this.max() - this.min()) / nbClass;
+
+		for (i = 0; i <= nbClass; i++) {
+			a[i] = val;
+			val += interval;
+		}
+
+		this.bounds = a;
+		this.setRanges();
+		
+		return a;
+	};
+	
+
+	/**
+	 * Quantile discretization Return an array with bounds : ie array(0, 0.75,
+	 * 1.5, 2.25, 3);
+	 */
+	this.getQuantile = function(nbClass) {
+
+		if (this._nodata())
+			return;
+
+		this.method = _t('quantile') + ' (' + nbClass + ' ' + _t('classes') + ')';
+
+		var a = Array();
+		var tmp = this.sorted();
+
+		var classSize = Math.round(this.pop() / nbClass);
+		var step = classSize;
+		var i = 0;
+
+		// we set first value
+		a[0] = tmp[0];
+
+		for (i = 1; i < nbClass; i++) {
+			a[i] = tmp[step];
+			step += classSize;
+		}
+		// we set last value
+		a.push(tmp[tmp.length - 1]);
+		
+		this.bounds = a;
+		this.setRanges();
+		
+		return a;
+
+	};
+	
+	/**
+	 * Credits : Doug Curl (javascript) and Daniel J Lewis (python implementation)
+	 * http://www.arcgis.com/home/item.html?id=0b633ff2f40d412995b8be377211c47b
+	 * http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
+	 */
+	this.getJenks = function(nbClass) {
+	
+		if (this._nodata())
+			return;
+		
+		this.method = _t('Jenks') + ' (' + nbClass + ' ' + _t('classes') + ')';
+		
+		dataList = this.sorted();
+
+		// now iterate through the datalist:
+		// determine mat1 and mat2
+		// really not sure how these 2 different arrays are set - the code for
+		// each seems the same!
+		// but the effect are 2 different arrays: mat1 and mat2
+		var mat1 = []
+		for ( var x = 0, xl = dataList.length + 1; x < xl; x++) {
+			var temp = []
+			for ( var j = 0, jl = nbClass + 1; j < jl; j++) {
+				temp.push(0)
+			}
+			mat1.push(temp)
+		}
+
+		var mat2 = []
+		for ( var i = 0, il = dataList.length + 1; i < il; i++) {
+			var temp2 = []
+			for ( var c = 0, cl = nbClass + 1; c < cl; c++) {
+				temp2.push(0)
+			}
+			mat2.push(temp2)
+		}
+
+		// absolutely no idea what this does - best I can tell, it sets the 1st
+		// group in the
+		// mat1 and mat2 arrays to 1 and 0 respectively
+		for ( var y = 1, yl = nbClass + 1; y < yl; y++) {
+			mat1[0][y] = 1
+			mat2[0][y] = 0
+			for ( var t = 1, tl = dataList.length + 1; t < tl; t++) {
+				mat2[t][y] = Infinity
+			}
+			var v = 0.0
+		}
+
+		// and this part - I'm a little clueless on - but it works
+		// pretty sure it iterates across the entire dataset and compares each
+		// value to
+		// one another to and adjust the indices until you meet the rules:
+		// minimum deviation
+		// within a class and maximum separation between classes
+		for ( var l = 2, ll = dataList.length + 1; l < ll; l++) {
+			var s1 = 0.0
+			var s2 = 0.0
+			var w = 0.0
+			for ( var m = 1, ml = l + 1; m < ml; m++) {
+				var i3 = l - m + 1
+				var val = parseFloat(dataList[i3 - 1])
+				s2 += val * val
+				s1 += val
+				w += 1
+				v = s2 - (s1 * s1) / w
+				var i4 = i3 - 1
+				if (i4 != 0) {
+					for ( var p = 2, pl = nbClass + 1; p < pl; p++) {
+						if (mat2[l][p] >= (v + mat2[i4][p - 1])) {
+							mat1[l][p] = i3
+							mat2[l][p] = v + mat2[i4][p - 1]
+						}
+					}
+				}
+			}
+			mat1[l][1] = 1
+			mat2[l][1] = v
+		}
+
+		var k = dataList.length
+		var kclass = []
+
+		// fill the kclass (classification) array with zeros:
+		for (i = 0, il = nbClass + 1; i < il; i++) {
+			kclass.push(0)
+		}
+
+		// this is the last number in the array:
+		kclass[nbClass] = parseFloat(dataList[dataList.length - 1])
+		// this is the first number - can set to zero, but want to set to lowest
+		// to use for legend:
+		kclass[0] = parseFloat(dataList[0])
+		var countNum = nbClass
+		while (countNum >= 2) {
+			var id = parseInt((mat1[k][countNum]) - 2)
+			kclass[countNum - 1] = dataList[id]
+			k = parseInt((mat1[k][countNum] - 1))
+			// spits out the rank and value of the break values:
+			// console.log("id="+id,"rank = " + String(mat1[k][countNum]),"val =
+			// " + String(dataList[id]))
+			// count down:
+			countNum -= 1
+		}
+		// check to see if the 0 and 1 in the array are the same - if so, set 0
+		// to 0:
+		if (kclass[0] == kclass[1]) {
+			kclass[0] = 0
+		}
+		
+		this.bounds = kclass;
+		this.setRanges();
+
+		return kclass; //array of breaks
+	}
+	
+	
+	/**
+	 * Quantile discretization Return an array with bounds : ie array(0, 0.75,
+	 * 1.5, 2.25, 3);
+	 */
+	this.getUniqueValues = function() {
+
+		if (this._nodata())
+			return;
+
+		this.method = _t('unique values');
+		this.is_uniqueValues = true;
+		
+		var tmp = this.sorted(); // display in alphabetical order
+
+		var a = Array();
+
+		for (i = 0; i < this.pop(); i++) {
+			if(!inArray (tmp[i], a))
+				a.push(tmp[i]);
+		}
+		
+		this.bounds = a;
+		
+		return a;
+
+	};
+	
+	
+	/**
+	 * Return the class of a given value.
+	 * For example value : 6
+	 * and bounds array = (0, 4, 8, 12);
+	 * Return 2
+	 */
+	this.getClass = function(value) {
+
+		for(i = 0; i < this.bounds.length; i++) {
+			
+			
+			if(this.is_uniqueValues == true) {
+				if(value == this.bounds[i])
+					return i;
+			} else {
+				if(value <= this.bounds[i + 1]) {
+					return i;
+				}
+			}
+		}
+		
+		return _t("Unable to get value's class.");
+		
+	};
+
+	/**
+	 * Return the ranges array : array('0-0.75', '0.75-1.5', '1.5-2.25',
+	 * '2.25-3');
+	 */
+	this.getRanges = function() {
+		
+		return this.ranges;
+		
+	};
+
+	/**
+	 * Returns the number/index of this.ranges that value falls into
+	 */
+	this.getRangeNum = function(value) {
+		var bounds, i;
+
+		for (i = 0; i < this.ranges.length; i++) {
+			bounds = this.ranges[i].split(/ - /);
+			if (value <= parseFloat(bounds[1])) {
+				return i;
+			}
+		}
+	}
+	
+	/**
+	 * Return an html legend
+	 * 
+	 */
+	this.getHtmlLegend = function(colors, legend, counter, callback) {
+		
+		var cnt= '';
+		
+		if(colors != null) {
+			ccolors = colors;
+		}
+		else {
+			ccolors = this.colors;
+		}
+		
+		if(legend != null) {
+			lg = legend;
+		}
+		else {
+			lg =  'Legend';
+		}
+		
+		if(counter != null) {
+			this.doCount();
+			getcounter = true;
+		}
+		else {
+			getcounter = false;
+		}
+		
+		if(callback != null) {
+			fn = callback;
+		}
+		else {
+			fn = function(o) {return o;};
+		}
+		
+		
+		if(ccolors.length < this.ranges.length) {
+			alert(_t('The number of colors should fit the number of ranges. Exit!'));
+			return;
+		}
+		
+		var content  = '<div class="geostats-legend"><div class="geostats-legend-title">' + _t(lg) + '</div>';
+		
+		if(this.is_uniqueValues == false) {
+			for (i = 0; i < (this.ranges.length); i++) {
+				if(getcounter===true) {
+					cnt = ' <span class="geostats-legend-counter">(' + this.counter[i] + ')</span>';
+				}
+	
+				// check if it has separator or not
+				if(this.ranges[i].indexOf(this.separator) != -1) {
+					var tmp = this.ranges[i].split(this.separator);
+					var el = fn(tmp[0]) + this.legendSeparator + fn(tmp[1]);
+				} else {
+					var el = fn(this.ranges[i]);
+				}
+				content += '<div><div class="geostats-legend-block" style="background-color:' + ccolors[i] + '"></div> ' + el + cnt + '</div>';
+			}
+		} else {
+			// only if classification is done on unique values
+			for (i = 0; i < (this.bounds.length); i++) {
+				if(getcounter===true) {
+					cnt = ' <span class="geostats-legend-counter">(' + this.counter[i] + ')</span>';
+				}
+				var el = fn(this.bounds[i]);
+				content += '<div><div class="geostats-legend-block" style="background-color:' + ccolors[i] + '"></div> ' + el + cnt + '</div>';
+			}
+		}
+    content += '</div>';
+		return content;
+	};
+
+	this.getSortedlist = function() {
+		return this.sorted().join(', ');
+	};
+
+};
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/cherry/js/jquery.dataTables.min.js b/asterix-examples/src/main/resources/cherry/js/jquery.dataTables.min.js
new file mode 100755
index 0000000..02694a4
--- /dev/null
+++ b/asterix-examples/src/main/resources/cherry/js/jquery.dataTables.min.js
@@ -0,0 +1,155 @@
+/*
+ * File:        jquery.dataTables.min.js
+ * Version:     1.9.4
+ * Author:      Allan Jardine (www.sprymedia.co.uk)
+ * Info:        www.datatables.net
+ * 
+ * Copyright 2008-2012 Allan Jardine, all rights reserved.
+ *
+ * This source file is free software, under either the GPL v2 license or a
+ * BSD style license, available at:
+ *   http://datatables.net/license_gpl2
+ *   http://datatables.net/license_bsd
+ * 
+ * This source file 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 license files for details.
+ */
+(function(X,l,n){var L=function(h){var j=function(e){function o(a,b){var c=j.defaults.columns,d=a.aoColumns.length,c=h.extend({},j.models.oColumn,c,{sSortingClass:a.oClasses.sSortable,sSortingClassJUI:a.oClasses.sSortJUI,nTh:b?b:l.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.oDefaults:d});a.aoColumns.push(c);if(a.aoPreSearchCols[d]===n||null===a.aoPreSearchCols[d])a.aoPreSearchCols[d]=h.extend({},j.models.oSearch);else if(c=a.aoPreSearchCols[d],
+c.bRegex===n&&(c.bRegex=!0),c.bSmart===n&&(c.bSmart=!0),c.bCaseInsensitive===n)c.bCaseInsensitive=!0;m(a,d,null)}function m(a,b,c){var d=a.aoColumns[b];c!==n&&null!==c&&(c.mDataProp&&!c.mData&&(c.mData=c.mDataProp),c.sType!==n&&(d.sType=c.sType,d._bAutoType=!1),h.extend(d,c),p(d,c,"sWidth","sWidthOrig"),c.iDataSort!==n&&(d.aDataSort=[c.iDataSort]),p(d,c,"aDataSort"));var i=d.mRender?Q(d.mRender):null,f=Q(d.mData);d.fnGetData=function(a,b){var c=f(a,b);return d.mRender&&b&&""!==b?i(c,b,a):c};d.fnSetData=
+L(d.mData);a.oFeatures.bSort||(d.bSortable=!1);!d.bSortable||-1==h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortableNone,d.sSortingClassJUI=""):-1==h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortable,d.sSortingClassJUI=a.oClasses.sSortJUI):-1!=h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortableAsc,d.sSortingClassJUI=a.oClasses.sSortJUIAscAllowed):-1==
+h.inArray("asc",d.asSorting)&&-1!=h.inArray("desc",d.asSorting)&&(d.sSortingClass=a.oClasses.sSortableDesc,d.sSortingClassJUI=a.oClasses.sSortJUIDescAllowed)}function k(a){if(!1===a.oFeatures.bAutoWidth)return!1;da(a);for(var b=0,c=a.aoColumns.length;b<c;b++)a.aoColumns[b].nTh.style.width=a.aoColumns[b].sWidth}function G(a,b){var c=r(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function R(a,b){var c=r(a,"bVisible"),c=h.inArray(b,c);return-1!==c?c:null}function t(a){return r(a,"bVisible").length}
+function r(a,b){var c=[];h.map(a.aoColumns,function(a,i){a[b]&&c.push(i)});return c}function B(a){for(var b=j.ext.aTypes,c=b.length,d=0;d<c;d++){var i=b[d](a);if(null!==i)return i}return"string"}function u(a,b){for(var c=b.split(","),d=[],i=0,f=a.aoColumns.length;i<f;i++)for(var g=0;g<f;g++)if(a.aoColumns[i].sName==c[g]){d.push(g);break}return d}function M(a){for(var b="",c=0,d=a.aoColumns.length;c<d;c++)b+=a.aoColumns[c].sName+",";return b.length==d?"":b.slice(0,-1)}function ta(a,b,c,d){var i,f,
+g,e,w;if(b)for(i=b.length-1;0<=i;i--){var j=b[i].aTargets;h.isArray(j)||D(a,1,"aTargets must be an array of targets, not a "+typeof j);f=0;for(g=j.length;f<g;f++)if("number"===typeof j[f]&&0<=j[f]){for(;a.aoColumns.length<=j[f];)o(a);d(j[f],b[i])}else if("number"===typeof j[f]&&0>j[f])d(a.aoColumns.length+j[f],b[i]);else if("string"===typeof j[f]){e=0;for(w=a.aoColumns.length;e<w;e++)("_all"==j[f]||h(a.aoColumns[e].nTh).hasClass(j[f]))&&d(e,b[i])}}if(c){i=0;for(a=c.length;i<a;i++)d(i,c[i])}}function H(a,
+b){var c;c=h.isArray(b)?b.slice():h.extend(!0,{},b);var d=a.aoData.length,i=h.extend(!0,{},j.models.oRow);i._aData=c;a.aoData.push(i);for(var f,i=0,g=a.aoColumns.length;i<g;i++)c=a.aoColumns[i],"function"===typeof c.fnRender&&c.bUseRendered&&null!==c.mData?F(a,d,i,S(a,d,i)):F(a,d,i,v(a,d,i)),c._bAutoType&&"string"!=c.sType&&(f=v(a,d,i,"type"),null!==f&&""!==f&&(f=B(f),null===c.sType?c.sType=f:c.sType!=f&&"html"!=c.sType&&(c.sType="string")));a.aiDisplayMaster.push(d);a.oFeatures.bDeferRender||ea(a,
+d);return d}function ua(a){var b,c,d,i,f,g,e;if(a.bDeferLoading||null===a.sAjaxSource)for(b=a.nTBody.firstChild;b;){if("TR"==b.nodeName.toUpperCase()){c=a.aoData.length;b._DT_RowIndex=c;a.aoData.push(h.extend(!0,{},j.models.oRow,{nTr:b}));a.aiDisplayMaster.push(c);f=b.firstChild;for(d=0;f;){g=f.nodeName.toUpperCase();if("TD"==g||"TH"==g)F(a,c,d,h.trim(f.innerHTML)),d++;f=f.nextSibling}}b=b.nextSibling}i=T(a);d=[];b=0;for(c=i.length;b<c;b++)for(f=i[b].firstChild;f;)g=f.nodeName.toUpperCase(),("TD"==
+g||"TH"==g)&&d.push(f),f=f.nextSibling;c=0;for(i=a.aoColumns.length;c<i;c++){e=a.aoColumns[c];null===e.sTitle&&(e.sTitle=e.nTh.innerHTML);var w=e._bAutoType,o="function"===typeof e.fnRender,k=null!==e.sClass,n=e.bVisible,m,p;if(w||o||k||!n){g=0;for(b=a.aoData.length;g<b;g++)f=a.aoData[g],m=d[g*i+c],w&&"string"!=e.sType&&(p=v(a,g,c,"type"),""!==p&&(p=B(p),null===e.sType?e.sType=p:e.sType!=p&&"html"!=e.sType&&(e.sType="string"))),e.mRender?m.innerHTML=v(a,g,c,"display"):e.mData!==c&&(m.innerHTML=v(a,
+g,c,"display")),o&&(p=S(a,g,c),m.innerHTML=p,e.bUseRendered&&F(a,g,c,p)),k&&(m.className+=" "+e.sClass),n?f._anHidden[c]=null:(f._anHidden[c]=m,m.parentNode.removeChild(m)),e.fnCreatedCell&&e.fnCreatedCell.call(a.oInstance,m,v(a,g,c,"display"),f._aData,g,c)}}if(0!==a.aoRowCreatedCallback.length){b=0;for(c=a.aoData.length;b<c;b++)f=a.aoData[b],A(a,"aoRowCreatedCallback",null,[f.nTr,f._aData,b])}}function I(a,b){return b._DT_RowIndex!==n?b._DT_RowIndex:null}function fa(a,b,c){for(var b=J(a,b),d=0,a=
+a.aoColumns.length;d<a;d++)if(b[d]===c)return d;return-1}function Y(a,b,c,d){for(var i=[],f=0,g=d.length;f<g;f++)i.push(v(a,b,d[f],c));return i}function v(a,b,c,d){var i=a.aoColumns[c];if((c=i.fnGetData(a.aoData[b]._aData,d))===n)return a.iDrawError!=a.iDraw&&null===i.sDefaultContent&&(D(a,0,"Requested unknown parameter "+("function"==typeof i.mData?"{mData function}":"'"+i.mData+"'")+" from the data source for row "+b),a.iDrawError=a.iDraw),i.sDefaultContent;if(null===c&&null!==i.sDefaultContent)c=
+i.sDefaultContent;else if("function"===typeof c)return c();return"display"==d&&null===c?"":c}function F(a,b,c,d){a.aoColumns[c].fnSetData(a.aoData[b]._aData,d)}function Q(a){if(null===a)return function(){return null};if("function"===typeof a)return function(b,d,i){return a(b,d,i)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("["))){var b=function(a,d,i){var f=i.split("."),g;if(""!==i){var e=0;for(g=f.length;e<g;e++){if(i=f[e].match(U)){f[e]=f[e].replace(U,"");""!==f[e]&&(a=a[f[e]]);
+g=[];f.splice(0,e+1);for(var f=f.join("."),e=0,h=a.length;e<h;e++)g.push(b(a[e],d,f));a=i[0].substring(1,i[0].length-1);a=""===a?g:g.join(a);break}if(null===a||a[f[e]]===n)return n;a=a[f[e]]}}return a};return function(c,d){return b(c,d,a)}}return function(b){return b[a]}}function L(a){if(null===a)return function(){};if("function"===typeof a)return function(b,d){a(b,"set",d)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("["))){var b=function(a,d,i){var i=i.split("."),f,g,e=0;for(g=
+i.length-1;e<g;e++){if(f=i[e].match(U)){i[e]=i[e].replace(U,"");a[i[e]]=[];f=i.slice();f.splice(0,e+1);g=f.join(".");for(var h=0,j=d.length;h<j;h++)f={},b(f,d[h],g),a[i[e]].push(f);return}if(null===a[i[e]]||a[i[e]]===n)a[i[e]]={};a=a[i[e]]}a[i[i.length-1].replace(U,"")]=d};return function(c,d){return b(c,d,a)}}return function(b,d){b[a]=d}}function Z(a){for(var b=[],c=a.aoData.length,d=0;d<c;d++)b.push(a.aoData[d]._aData);return b}function ga(a){a.aoData.splice(0,a.aoData.length);a.aiDisplayMaster.splice(0,
+a.aiDisplayMaster.length);a.aiDisplay.splice(0,a.aiDisplay.length);y(a)}function ha(a,b){for(var c=-1,d=0,i=a.length;d<i;d++)a[d]==b?c=d:a[d]>b&&a[d]--; -1!=c&&a.splice(c,1)}function S(a,b,c){var d=a.aoColumns[c];return d.fnRender({iDataRow:b,iDataColumn:c,oSettings:a,aData:a.aoData[b]._aData,mDataProp:d.mData},v(a,b,c,"display"))}function ea(a,b){var c=a.aoData[b],d;if(null===c.nTr){c.nTr=l.createElement("tr");c.nTr._DT_RowIndex=b;c._aData.DT_RowId&&(c.nTr.id=c._aData.DT_RowId);c._aData.DT_RowClass&&
+(c.nTr.className=c._aData.DT_RowClass);for(var i=0,f=a.aoColumns.length;i<f;i++){var g=a.aoColumns[i];d=l.createElement(g.sCellType);d.innerHTML="function"===typeof g.fnRender&&(!g.bUseRendered||null===g.mData)?S(a,b,i):v(a,b,i,"display");null!==g.sClass&&(d.className=g.sClass);g.bVisible?(c.nTr.appendChild(d),c._anHidden[i]=null):c._anHidden[i]=d;g.fnCreatedCell&&g.fnCreatedCell.call(a.oInstance,d,v(a,b,i,"display"),c._aData,b,i)}A(a,"aoRowCreatedCallback",null,[c.nTr,c._aData,b])}}function va(a){var b,
+c,d;if(0!==h("th, td",a.nTHead).length){b=0;for(d=a.aoColumns.length;b<d;b++)if(c=a.aoColumns[b].nTh,c.setAttribute("role","columnheader"),a.aoColumns[b].bSortable&&(c.setAttribute("tabindex",a.iTabIndex),c.setAttribute("aria-controls",a.sTableId)),null!==a.aoColumns[b].sClass&&h(c).addClass(a.aoColumns[b].sClass),a.aoColumns[b].sTitle!=c.innerHTML)c.innerHTML=a.aoColumns[b].sTitle}else{var i=l.createElement("tr");b=0;for(d=a.aoColumns.length;b<d;b++)c=a.aoColumns[b].nTh,c.innerHTML=a.aoColumns[b].sTitle,
+c.setAttribute("tabindex","0"),null!==a.aoColumns[b].sClass&&h(c).addClass(a.aoColumns[b].sClass),i.appendChild(c);h(a.nTHead).html("")[0].appendChild(i);V(a.aoHeader,a.nTHead)}h(a.nTHead).children("tr").attr("role","row");if(a.bJUI){b=0;for(d=a.aoColumns.length;b<d;b++){c=a.aoColumns[b].nTh;i=l.createElement("div");i.className=a.oClasses.sSortJUIWrapper;h(c).contents().appendTo(i);var f=l.createElement("span");f.className=a.oClasses.sSortIcon;i.appendChild(f);c.appendChild(i)}}if(a.oFeatures.bSort)for(b=
+0;b<a.aoColumns.length;b++)!1!==a.aoColumns[b].bSortable?ia(a,a.aoColumns[b].nTh,b):h(a.aoColumns[b].nTh).addClass(a.oClasses.sSortableNone);""!==a.oClasses.sFooterTH&&h(a.nTFoot).children("tr").children("th").addClass(a.oClasses.sFooterTH);if(null!==a.nTFoot){c=N(a,null,a.aoFooter);b=0;for(d=a.aoColumns.length;b<d;b++)c[b]&&(a.aoColumns[b].nTf=c[b],a.aoColumns[b].sClass&&h(c[b]).addClass(a.aoColumns[b].sClass))}}function W(a,b,c){var d,i,f,g=[],e=[],h=a.aoColumns.length,j;c===n&&(c=!1);d=0;for(i=
+b.length;d<i;d++){g[d]=b[d].slice();g[d].nTr=b[d].nTr;for(f=h-1;0<=f;f--)!a.aoColumns[f].bVisible&&!c&&g[d].splice(f,1);e.push([])}d=0;for(i=g.length;d<i;d++){if(a=g[d].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=g[d].length;f<b;f++)if(j=h=1,e[d][f]===n){a.appendChild(g[d][f].cell);for(e[d][f]=1;g[d+h]!==n&&g[d][f].cell==g[d+h][f].cell;)e[d+h][f]=1,h++;for(;g[d][f+j]!==n&&g[d][f].cell==g[d][f+j].cell;){for(c=0;c<h;c++)e[d+c][f+j]=1;j++}g[d][f].cell.rowSpan=h;g[d][f].cell.colSpan=j}}}function x(a){var b=
+A(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==h.inArray(!1,b))E(a,!1);else{var c,d,b=[],i=0,f=a.asStripeClasses.length;c=a.aoOpenRows.length;a.bDrawing=!0;a.iInitDisplayStart!==n&&-1!=a.iInitDisplayStart&&(a._iDisplayStart=a.oFeatures.bServerSide?a.iInitDisplayStart:a.iInitDisplayStart>=a.fnRecordsDisplay()?0:a.iInitDisplayStart,a.iInitDisplayStart=-1,y(a));if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++;else if(a.oFeatures.bServerSide){if(!a.bDestroying&&!wa(a))return}else a.iDraw++;if(0!==a.aiDisplay.length){var g=
+a._iDisplayStart;d=a._iDisplayEnd;a.oFeatures.bServerSide&&(g=0,d=a.aoData.length);for(;g<d;g++){var e=a.aoData[a.aiDisplay[g]];null===e.nTr&&ea(a,a.aiDisplay[g]);var j=e.nTr;if(0!==f){var o=a.asStripeClasses[i%f];e._sRowStripe!=o&&(h(j).removeClass(e._sRowStripe).addClass(o),e._sRowStripe=o)}A(a,"aoRowCallback",null,[j,a.aoData[a.aiDisplay[g]]._aData,i,g]);b.push(j);i++;if(0!==c)for(e=0;e<c;e++)if(j==a.aoOpenRows[e].nParent){b.push(a.aoOpenRows[e].nTr);break}}}else b[0]=l.createElement("tr"),a.asStripeClasses[0]&&
+(b[0].className=a.asStripeClasses[0]),c=a.oLanguage,f=c.sZeroRecords,1==a.iDraw&&null!==a.sAjaxSource&&!a.oFeatures.bServerSide?f=c.sLoadingRecords:c.sEmptyTable&&0===a.fnRecordsTotal()&&(f=c.sEmptyTable),c=l.createElement("td"),c.setAttribute("valign","top"),c.colSpan=t(a),c.className=a.oClasses.sRowEmpty,c.innerHTML=ja(a,f),b[i].appendChild(c);A(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Z(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay]);A(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],
+Z(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay]);i=l.createDocumentFragment();c=l.createDocumentFragment();if(a.nTBody){f=a.nTBody.parentNode;c.appendChild(a.nTBody);if(!a.oScroll.bInfinite||!a._bInitComplete||a.bSorted||a.bFiltered)for(;c=a.nTBody.firstChild;)a.nTBody.removeChild(c);c=0;for(d=b.length;c<d;c++)i.appendChild(b[c]);a.nTBody.appendChild(i);null!==f&&f.appendChild(a.nTBody)}A(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1;a.oFeatures.bServerSide&&(E(a,!1),
+a._bInitComplete||$(a))}}function aa(a){a.oFeatures.bSort?O(a,a.oPreviousSearch):a.oFeatures.bFilter?K(a,a.oPreviousSearch):(y(a),x(a))}function xa(a){var b=h("<div></div>")[0];a.nTable.parentNode.insertBefore(b,a.nTable);a.nTableWrapper=h('<div id="'+a.sTableId+'_wrapper" class="'+a.oClasses.sWrapper+'" role="grid"></div>')[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var c=a.nTableWrapper,d=a.sDom.split(""),i,f,g,e,w,o,k,m=0;m<d.length;m++){f=0;g=d[m];if("<"==g){e=h("<div></div>")[0];w=d[m+
+1];if("'"==w||'"'==w){o="";for(k=2;d[m+k]!=w;)o+=d[m+k],k++;"H"==o?o=a.oClasses.sJUIHeader:"F"==o&&(o=a.oClasses.sJUIFooter);-1!=o.indexOf(".")?(w=o.split("."),e.id=w[0].substr(1,w[0].length-1),e.className=w[1]):"#"==o.charAt(0)?e.id=o.substr(1,o.length-1):e.className=o;m+=k}c.appendChild(e);c=e}else if(">"==g)c=c.parentNode;else if("l"==g&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange)i=ya(a),f=1;else if("f"==g&&a.oFeatures.bFilter)i=za(a),f=1;else if("r"==g&&a.oFeatures.bProcessing)i=Aa(a),f=
+1;else if("t"==g)i=Ba(a),f=1;else if("i"==g&&a.oFeatures.bInfo)i=Ca(a),f=1;else if("p"==g&&a.oFeatures.bPaginate)i=Da(a),f=1;else if(0!==j.ext.aoFeatures.length){e=j.ext.aoFeatures;k=0;for(w=e.length;k<w;k++)if(g==e[k].cFeature){(i=e[k].fnInit(a))&&(f=1);break}}1==f&&null!==i&&("object"!==typeof a.aanFeatures[g]&&(a.aanFeatures[g]=[]),a.aanFeatures[g].push(i),c.appendChild(i))}b.parentNode.replaceChild(a.nTableWrapper,b)}function V(a,b){var c=h(b).children("tr"),d,i,f,g,e,j,o,k,m,p;a.splice(0,a.length);
+f=0;for(j=c.length;f<j;f++)a.push([]);f=0;for(j=c.length;f<j;f++){d=c[f];for(i=d.firstChild;i;){if("TD"==i.nodeName.toUpperCase()||"TH"==i.nodeName.toUpperCase()){k=1*i.getAttribute("colspan");m=1*i.getAttribute("rowspan");k=!k||0===k||1===k?1:k;m=!m||0===m||1===m?1:m;g=0;for(e=a[f];e[g];)g++;o=g;p=1===k?!0:!1;for(e=0;e<k;e++)for(g=0;g<m;g++)a[f+g][o+e]={cell:i,unique:p},a[f+g].nTr=d}i=i.nextSibling}}}function N(a,b,c){var d=[];c||(c=a.aoHeader,b&&(c=[],V(c,b)));for(var b=0,i=c.length;b<i;b++)for(var f=
+0,g=c[b].length;f<g;f++)if(c[b][f].unique&&(!d[f]||!a.bSortCellsTop))d[f]=c[b][f].cell;return d}function wa(a){if(a.bAjaxDataGet){a.iDraw++;E(a,!0);var b=Ea(a);ka(a,b);a.fnServerData.call(a.oInstance,a.sAjaxSource,b,function(b){Fa(a,b)},a);return!1}return!0}function Ea(a){var b=a.aoColumns.length,c=[],d,i,f,g;c.push({name:"sEcho",value:a.iDraw});c.push({name:"iColumns",value:b});c.push({name:"sColumns",value:M(a)});c.push({name:"iDisplayStart",value:a._iDisplayStart});c.push({name:"iDisplayLength",
+value:!1!==a.oFeatures.bPaginate?a._iDisplayLength:-1});for(f=0;f<b;f++)d=a.aoColumns[f].mData,c.push({name:"mDataProp_"+f,value:"function"===typeof d?"function":d});if(!1!==a.oFeatures.bFilter){c.push({name:"sSearch",value:a.oPreviousSearch.sSearch});c.push({name:"bRegex",value:a.oPreviousSearch.bRegex});for(f=0;f<b;f++)c.push({name:"sSearch_"+f,value:a.aoPreSearchCols[f].sSearch}),c.push({name:"bRegex_"+f,value:a.aoPreSearchCols[f].bRegex}),c.push({name:"bSearchable_"+f,value:a.aoColumns[f].bSearchable})}if(!1!==
+a.oFeatures.bSort){var e=0;d=null!==a.aaSortingFixed?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(f=0;f<d.length;f++){i=a.aoColumns[d[f][0]].aDataSort;for(g=0;g<i.length;g++)c.push({name:"iSortCol_"+e,value:i[g]}),c.push({name:"sSortDir_"+e,value:d[f][1]}),e++}c.push({name:"iSortingCols",value:e});for(f=0;f<b;f++)c.push({name:"bSortable_"+f,value:a.aoColumns[f].bSortable})}return c}function ka(a,b){A(a,"aoServerParams","serverParams",[b])}function Fa(a,b){if(b.sEcho!==n){if(1*b.sEcho<
+a.iDraw)return;a.iDraw=1*b.sEcho}(!a.oScroll.bInfinite||a.oScroll.bInfinite&&(a.bSorted||a.bFiltered))&&ga(a);a._iRecordsTotal=parseInt(b.iTotalRecords,10);a._iRecordsDisplay=parseInt(b.iTotalDisplayRecords,10);var c=M(a),c=b.sColumns!==n&&""!==c&&b.sColumns!=c,d;c&&(d=u(a,b.sColumns));for(var i=Q(a.sAjaxDataProp)(b),f=0,g=i.length;f<g;f++)if(c){for(var e=[],h=0,j=a.aoColumns.length;h<j;h++)e.push(i[f][d[h]]);H(a,e)}else H(a,i[f]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;x(a);a.bAjaxDataGet=
+!0;E(a,!1)}function za(a){var b=a.oPreviousSearch,c=a.oLanguage.sSearch,c=-1!==c.indexOf("_INPUT_")?c.replace("_INPUT_",'<input type="text" />'):""===c?'<input type="text" />':c+' <input type="text" />',d=l.createElement("div");d.className=a.oClasses.sFilter;d.innerHTML="<label>"+c+"</label>";a.aanFeatures.f||(d.id=a.sTableId+"_filter");c=h('input[type="text"]',d);d._DT_Input=c[0];c.val(b.sSearch.replace('"',"&quot;"));c.bind("keyup.DT",function(){for(var c=a.aanFeatures.f,d=this.value===""?"":this.value,
+g=0,e=c.length;g<e;g++)c[g]!=h(this).parents("div.dataTables_filter")[0]&&h(c[g]._DT_Input).val(d);d!=b.sSearch&&K(a,{sSearch:d,bRegex:b.bRegex,bSmart:b.bSmart,bCaseInsensitive:b.bCaseInsensitive})});c.attr("aria-controls",a.sTableId).bind("keypress.DT",function(a){if(a.keyCode==13)return false});return d}function K(a,b,c){var d=a.oPreviousSearch,i=a.aoPreSearchCols,f=function(a){d.sSearch=a.sSearch;d.bRegex=a.bRegex;d.bSmart=a.bSmart;d.bCaseInsensitive=a.bCaseInsensitive};if(a.oFeatures.bServerSide)f(b);
+else{Ga(a,b.sSearch,c,b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<a.aoPreSearchCols.length;b++)Ha(a,i[b].sSearch,b,i[b].bRegex,i[b].bSmart,i[b].bCaseInsensitive);Ia(a)}a.bFiltered=!0;h(a.oInstance).trigger("filter",a);a._iDisplayStart=0;y(a);x(a);la(a,0)}function Ia(a){for(var b=j.ext.afnFiltering,c=r(a,"bSearchable"),d=0,i=b.length;d<i;d++)for(var f=0,g=0,e=a.aiDisplay.length;g<e;g++){var h=a.aiDisplay[g-f];b[d](a,Y(a,h,"filter",c),h)||(a.aiDisplay.splice(g-f,1),f++)}}function Ha(a,b,c,
+d,i,f){if(""!==b)for(var g=0,b=ma(b,d,i,f),d=a.aiDisplay.length-1;0<=d;d--)i=Ja(v(a,a.aiDisplay[d],c,"filter"),a.aoColumns[c].sType),b.test(i)||(a.aiDisplay.splice(d,1),g++)}function Ga(a,b,c,d,i,f){d=ma(b,d,i,f);i=a.oPreviousSearch;c||(c=0);0!==j.ext.afnFiltering.length&&(c=1);if(0>=b.length)a.aiDisplay.splice(0,a.aiDisplay.length),a.aiDisplay=a.aiDisplayMaster.slice();else if(a.aiDisplay.length==a.aiDisplayMaster.length||i.sSearch.length>b.length||1==c||0!==b.indexOf(i.sSearch)){a.aiDisplay.splice(0,
+a.aiDisplay.length);la(a,1);for(b=0;b<a.aiDisplayMaster.length;b++)d.test(a.asDataSearch[b])&&a.aiDisplay.push(a.aiDisplayMaster[b])}else for(b=c=0;b<a.asDataSearch.length;b++)d.test(a.asDataSearch[b])||(a.aiDisplay.splice(b-c,1),c++)}function la(a,b){if(!a.oFeatures.bServerSide){a.asDataSearch=[];for(var c=r(a,"bSearchable"),d=1===b?a.aiDisplayMaster:a.aiDisplay,i=0,f=d.length;i<f;i++)a.asDataSearch[i]=na(a,Y(a,d[i],"filter",c))}}function na(a,b){var c=b.join("  ");-1!==c.indexOf("&")&&(c=h("<div>").html(c).text());
+return c.replace(/[\n\r]/g," ")}function ma(a,b,c,d){if(c)return a=b?a.split(" "):oa(a).split(" "),a="^(?=.*?"+a.join(")(?=.*?")+").*$",RegExp(a,d?"i":"");a=b?a:oa(a);return RegExp(a,d?"i":"")}function Ja(a,b){return"function"===typeof j.ext.ofnSearch[b]?j.ext.ofnSearch[b](a):null===a?"":"html"==b?a.replace(/[\r\n]/g," ").replace(/<.*?>/g,""):"string"===typeof a?a.replace(/[\r\n]/g," "):a}function oa(a){return a.replace(RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),
+"\\$1")}function Ca(a){var b=l.createElement("div");b.className=a.oClasses.sInfo;a.aanFeatures.i||(a.aoDrawCallback.push({fn:Ka,sName:"information"}),b.id=a.sTableId+"_info");a.nTable.setAttribute("aria-describedby",a.sTableId+"_info");return b}function Ka(a){if(a.oFeatures.bInfo&&0!==a.aanFeatures.i.length){var b=a.oLanguage,c=a._iDisplayStart+1,d=a.fnDisplayEnd(),i=a.fnRecordsTotal(),f=a.fnRecordsDisplay(),g;g=0===f?b.sInfoEmpty:b.sInfo;f!=i&&(g+=" "+b.sInfoFiltered);g+=b.sInfoPostFix;g=ja(a,g);
+null!==b.fnInfoCallback&&(g=b.fnInfoCallback.call(a.oInstance,a,c,d,i,f,g));a=a.aanFeatures.i;b=0;for(c=a.length;b<c;b++)h(a[b]).html(g)}}function ja(a,b){var c=a.fnFormatNumber(a._iDisplayStart+1),d=a.fnDisplayEnd(),d=a.fnFormatNumber(d),i=a.fnRecordsDisplay(),i=a.fnFormatNumber(i),f=a.fnRecordsTotal(),f=a.fnFormatNumber(f);a.oScroll.bInfinite&&(c=a.fnFormatNumber(1));return b.replace(/_START_/g,c).replace(/_END_/g,d).replace(/_TOTAL_/g,i).replace(/_MAX_/g,f)}function ba(a){var b,c,d=a.iInitDisplayStart;
+if(!1===a.bInitialised)setTimeout(function(){ba(a)},200);else{xa(a);va(a);W(a,a.aoHeader);a.nTFoot&&W(a,a.aoFooter);E(a,!0);a.oFeatures.bAutoWidth&&da(a);b=0;for(c=a.aoColumns.length;b<c;b++)null!==a.aoColumns[b].sWidth&&(a.aoColumns[b].nTh.style.width=q(a.aoColumns[b].sWidth));a.oFeatures.bSort?O(a):a.oFeatures.bFilter?K(a,a.oPreviousSearch):(a.aiDisplay=a.aiDisplayMaster.slice(),y(a),x(a));null!==a.sAjaxSource&&!a.oFeatures.bServerSide?(c=[],ka(a,c),a.fnServerData.call(a.oInstance,a.sAjaxSource,
+c,function(c){var f=a.sAjaxDataProp!==""?Q(a.sAjaxDataProp)(c):c;for(b=0;b<f.length;b++)H(a,f[b]);a.iInitDisplayStart=d;if(a.oFeatures.bSort)O(a);else{a.aiDisplay=a.aiDisplayMaster.slice();y(a);x(a)}E(a,false);$(a,c)},a)):a.oFeatures.bServerSide||(E(a,!1),$(a))}}function $(a,b){a._bInitComplete=!0;A(a,"aoInitComplete","init",[a,b])}function pa(a){var b=j.defaults.oLanguage;!a.sEmptyTable&&(a.sZeroRecords&&"No data available in table"===b.sEmptyTable)&&p(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&
+(a.sZeroRecords&&"Loading..."===b.sLoadingRecords)&&p(a,a,"sZeroRecords","sLoadingRecords")}function ya(a){if(a.oScroll.bInfinite)return null;var b='<select size="1" '+('name="'+a.sTableId+'_length"')+">",c,d,i=a.aLengthMenu;if(2==i.length&&"object"===typeof i[0]&&"object"===typeof i[1]){c=0;for(d=i[0].length;c<d;c++)b+='<option value="'+i[0][c]+'">'+i[1][c]+"</option>"}else{c=0;for(d=i.length;c<d;c++)b+='<option value="'+i[c]+'">'+i[c]+"</option>"}b+="</select>";i=l.createElement("div");a.aanFeatures.l||
+(i.id=a.sTableId+"_length");i.className=a.oClasses.sLength;i.innerHTML="<label>"+a.oLanguage.sLengthMenu.replace("_MENU_",b)+"</label>";h('select option[value="'+a._iDisplayLength+'"]',i).attr("selected",!0);h("select",i).bind("change.DT",function(){var b=h(this).val(),i=a.aanFeatures.l;c=0;for(d=i.length;c<d;c++)i[c]!=this.parentNode&&h("select",i[c]).val(b);a._iDisplayLength=parseInt(b,10);y(a);if(a.fnDisplayEnd()==a.fnRecordsDisplay()){a._iDisplayStart=a.fnDisplayEnd()-a._iDisplayLength;if(a._iDisplayStart<
+0)a._iDisplayStart=0}if(a._iDisplayLength==-1)a._iDisplayStart=0;x(a)});h("select",i).attr("aria-controls",a.sTableId);return i}function y(a){a._iDisplayEnd=!1===a.oFeatures.bPaginate?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength>a.aiDisplay.length||-1==a._iDisplayLength?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Da(a){if(a.oScroll.bInfinite)return null;var b=l.createElement("div");b.className=a.oClasses.sPaging+a.sPaginationType;j.ext.oPagination[a.sPaginationType].fnInit(a,
+b,function(a){y(a);x(a)});a.aanFeatures.p||a.aoDrawCallback.push({fn:function(a){j.ext.oPagination[a.sPaginationType].fnUpdate(a,function(a){y(a);x(a)})},sName:"pagination"});return b}function qa(a,b){var c=a._iDisplayStart;if("number"===typeof b)a._iDisplayStart=b*a._iDisplayLength,a._iDisplayStart>a.fnRecordsDisplay()&&(a._iDisplayStart=0);else if("first"==b)a._iDisplayStart=0;else if("previous"==b)a._iDisplayStart=0<=a._iDisplayLength?a._iDisplayStart-a._iDisplayLength:0,0>a._iDisplayStart&&(a._iDisplayStart=
+0);else if("next"==b)0<=a._iDisplayLength?a._iDisplayStart+a._iDisplayLength<a.fnRecordsDisplay()&&(a._iDisplayStart+=a._iDisplayLength):a._iDisplayStart=0;else if("last"==b)if(0<=a._iDisplayLength){var d=parseInt((a.fnRecordsDisplay()-1)/a._iDisplayLength,10)+1;a._iDisplayStart=(d-1)*a._iDisplayLength}else a._iDisplayStart=0;else D(a,0,"Unknown paging action: "+b);h(a.oInstance).trigger("page",a);return c!=a._iDisplayStart}function Aa(a){var b=l.createElement("div");a.aanFeatures.r||(b.id=a.sTableId+
+"_processing");b.innerHTML=a.oLanguage.sProcessing;b.className=a.oClasses.sProcessing;a.nTable.parentNode.insertBefore(b,a.nTable);return b}function E(a,b){if(a.oFeatures.bProcessing)for(var c=a.aanFeatures.r,d=0,i=c.length;d<i;d++)c[d].style.visibility=b?"visible":"hidden";h(a.oInstance).trigger("processing",[a,b])}function Ba(a){if(""===a.oScroll.sX&&""===a.oScroll.sY)return a.nTable;var b=l.createElement("div"),c=l.createElement("div"),d=l.createElement("div"),i=l.createElement("div"),f=l.createElement("div"),
+g=l.createElement("div"),e=a.nTable.cloneNode(!1),j=a.nTable.cloneNode(!1),o=a.nTable.getElementsByTagName("thead")[0],k=0===a.nTable.getElementsByTagName("tfoot").length?null:a.nTable.getElementsByTagName("tfoot")[0],m=a.oClasses;c.appendChild(d);f.appendChild(g);i.appendChild(a.nTable);b.appendChild(c);b.appendChild(i);d.appendChild(e);e.appendChild(o);null!==k&&(b.appendChild(f),g.appendChild(j),j.appendChild(k));b.className=m.sScrollWrapper;c.className=m.sScrollHead;d.className=m.sScrollHeadInner;
+i.className=m.sScrollBody;f.className=m.sScrollFoot;g.className=m.sScrollFootInner;a.oScroll.bAutoCss&&(c.style.overflow="hidden",c.style.position="relative",f.style.overflow="hidden",i.style.overflow="auto");c.style.border="0";c.style.width="100%";f.style.border="0";d.style.width=""!==a.oScroll.sXInner?a.oScroll.sXInner:"100%";e.removeAttribute("id");e.style.marginLeft="0";a.nTable.style.marginLeft="0";null!==k&&(j.removeAttribute("id"),j.style.marginLeft="0");d=h(a.nTable).children("caption");0<
+d.length&&(d=d[0],"top"===d._captionSide?e.appendChild(d):"bottom"===d._captionSide&&k&&j.appendChild(d));""!==a.oScroll.sX&&(c.style.width=q(a.oScroll.sX),i.style.width=q(a.oScroll.sX),null!==k&&(f.style.width=q(a.oScroll.sX)),h(i).scroll(function(){c.scrollLeft=this.scrollLeft;if(k!==null)f.scrollLeft=this.scrollLeft}));""!==a.oScroll.sY&&(i.style.height=q(a.oScroll.sY));a.aoDrawCallback.push({fn:La,sName:"scrolling"});a.oScroll.bInfinite&&h(i).scroll(function(){if(!a.bDrawing&&h(this).scrollTop()!==
+0&&h(this).scrollTop()+h(this).height()>h(a.nTable).height()-a.oScroll.iLoadGap&&a.fnDisplayEnd()<a.fnRecordsDisplay()){qa(a,"next");y(a);x(a)}});a.nScrollHead=c;a.nScrollFoot=f;return b}function La(a){var b=a.nScrollHead.getElementsByTagName("div")[0],c=b.getElementsByTagName("table")[0],d=a.nTable.parentNode,i,f,g,e,j,o,k,m,p=[],n=[],l=null!==a.nTFoot?a.nScrollFoot.getElementsByTagName("div")[0]:null,R=null!==a.nTFoot?l.getElementsByTagName("table")[0]:null,r=a.oBrowser.bScrollOversize,s=function(a){k=
+a.style;k.paddingTop="0";k.paddingBottom="0";k.borderTopWidth="0";k.borderBottomWidth="0";k.height=0};h(a.nTable).children("thead, tfoot").remove();i=h(a.nTHead).clone()[0];a.nTable.insertBefore(i,a.nTable.childNodes[0]);g=a.nTHead.getElementsByTagName("tr");e=i.getElementsByTagName("tr");null!==a.nTFoot&&(j=h(a.nTFoot).clone()[0],a.nTable.insertBefore(j,a.nTable.childNodes[1]),o=a.nTFoot.getElementsByTagName("tr"),j=j.getElementsByTagName("tr"));""===a.oScroll.sX&&(d.style.width="100%",b.parentNode.style.width=
+"100%");var t=N(a,i);i=0;for(f=t.length;i<f;i++)m=G(a,i),t[i].style.width=a.aoColumns[m].sWidth;null!==a.nTFoot&&C(function(a){a.style.width=""},j);a.oScroll.bCollapse&&""!==a.oScroll.sY&&(d.style.height=d.offsetHeight+a.nTHead.offsetHeight+"px");i=h(a.nTable).outerWidth();if(""===a.oScroll.sX){if(a.nTable.style.width="100%",r&&(h("tbody",d).height()>d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(h(a.nTable).outerWidth()-a.oScroll.iBarWidth)}else""!==a.oScroll.sXInner?a.nTable.style.width=
+q(a.oScroll.sXInner):i==h(d).width()&&h(d).height()<h(a.nTable).height()?(a.nTable.style.width=q(i-a.oScroll.iBarWidth),h(a.nTable).outerWidth()>i-a.oScroll.iBarWidth&&(a.nTable.style.width=q(i))):a.nTable.style.width=q(i);i=h(a.nTable).outerWidth();C(s,e);C(function(a){p.push(q(h(a).width()))},e);C(function(a,b){a.style.width=p[b]},g);h(e).height(0);null!==a.nTFoot&&(C(s,j),C(function(a){n.push(q(h(a).width()))},j),C(function(a,b){a.style.width=n[b]},o),h(j).height(0));C(function(a,b){a.innerHTML=
+"";a.style.width=p[b]},e);null!==a.nTFoot&&C(function(a,b){a.innerHTML="";a.style.width=n[b]},j);if(h(a.nTable).outerWidth()<i){g=d.scrollHeight>d.offsetHeight||"scroll"==h(d).css("overflow-y")?i+a.oScroll.iBarWidth:i;if(r&&(d.scrollHeight>d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(g-a.oScroll.iBarWidth);d.style.width=q(g);a.nScrollHead.style.width=q(g);null!==a.nTFoot&&(a.nScrollFoot.style.width=q(g));""===a.oScroll.sX?D(a,1,"The table cannot fit into the current element which will cause column misalignment. The table has been drawn at its minimum possible width."):
+""!==a.oScroll.sXInner&&D(a,1,"The table cannot fit into the current element which will cause column misalignment. Increase the sScrollXInner value or remove it to allow automatic calculation")}else d.style.width=q("100%"),a.nScrollHead.style.width=q("100%"),null!==a.nTFoot&&(a.nScrollFoot.style.width=q("100%"));""===a.oScroll.sY&&r&&(d.style.height=q(a.nTable.offsetHeight+a.oScroll.iBarWidth));""!==a.oScroll.sY&&a.oScroll.bCollapse&&(d.style.height=q(a.oScroll.sY),r=""!==a.oScroll.sX&&a.nTable.offsetWidth>
+d.offsetWidth?a.oScroll.iBarWidth:0,a.nTable.offsetHeight<d.offsetHeight&&(d.style.height=q(a.nTable.offsetHeight+r)));r=h(a.nTable).outerWidth();c.style.width=q(r);b.style.width=q(r);c=h(a.nTable).height()>d.clientHeight||"scroll"==h(d).css("overflow-y");b.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px";null!==a.nTFoot&&(R.style.width=q(r),l.style.width=q(r),l.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px");h(d).scroll();if(a.bSorted||a.bFiltered)d.scrollTop=0}function C(a,b,c){for(var d=
+0,i=0,f=b.length,g,e;i<f;){g=b[i].firstChild;for(e=c?c[i].firstChild:null;g;)1===g.nodeType&&(c?a(g,e,d):a(g,d),d++),g=g.nextSibling,e=c?e.nextSibling:null;i++}}function Ma(a,b){if(!a||null===a||""===a)return 0;b||(b=l.body);var c,d=l.createElement("div");d.style.width=q(a);b.appendChild(d);c=d.offsetWidth;b.removeChild(d);return c}function da(a){var b=0,c,d=0,i=a.aoColumns.length,f,e,j=h("th",a.nTHead),o=a.nTable.getAttribute("width");e=a.nTable.parentNode;for(f=0;f<i;f++)a.aoColumns[f].bVisible&&
+(d++,null!==a.aoColumns[f].sWidth&&(c=Ma(a.aoColumns[f].sWidthOrig,e),null!==c&&(a.aoColumns[f].sWidth=q(c)),b++));if(i==j.length&&0===b&&d==i&&""===a.oScroll.sX&&""===a.oScroll.sY)for(f=0;f<a.aoColumns.length;f++)c=h(j[f]).width(),null!==c&&(a.aoColumns[f].sWidth=q(c));else{b=a.nTable.cloneNode(!1);f=a.nTHead.cloneNode(!0);d=l.createElement("tbody");c=l.createElement("tr");b.removeAttribute("id");b.appendChild(f);null!==a.nTFoot&&(b.appendChild(a.nTFoot.cloneNode(!0)),C(function(a){a.style.width=
+""},b.getElementsByTagName("tr")));b.appendChild(d);d.appendChild(c);d=h("thead th",b);0===d.length&&(d=h("tbody tr:eq(0)>td",b));j=N(a,f);for(f=d=0;f<i;f++){var k=a.aoColumns[f];k.bVisible&&null!==k.sWidthOrig&&""!==k.sWidthOrig?j[f-d].style.width=q(k.sWidthOrig):k.bVisible?j[f-d].style.width="":d++}for(f=0;f<i;f++)a.aoColumns[f].bVisible&&(d=Na(a,f),null!==d&&(d=d.cloneNode(!0),""!==a.aoColumns[f].sContentPadding&&(d.innerHTML+=a.aoColumns[f].sContentPadding),c.appendChild(d)));e.appendChild(b);
+""!==a.oScroll.sX&&""!==a.oScroll.sXInner?b.style.width=q(a.oScroll.sXInner):""!==a.oScroll.sX?(b.style.width="",h(b).width()<e.offsetWidth&&(b.style.width=q(e.offsetWidth))):""!==a.oScroll.sY?b.style.width=q(e.offsetWidth):o&&(b.style.width=q(o));b.style.visibility="hidden";Oa(a,b);i=h("tbody tr:eq(0)",b).children();0===i.length&&(i=N(a,h("thead",b)[0]));if(""!==a.oScroll.sX){for(f=d=e=0;f<a.aoColumns.length;f++)a.aoColumns[f].bVisible&&(e=null===a.aoColumns[f].sWidthOrig?e+h(i[d]).outerWidth():
+e+(parseInt(a.aoColumns[f].sWidth.replace("px",""),10)+(h(i[d]).outerWidth()-h(i[d]).width())),d++);b.style.width=q(e);a.nTable.style.width=q(e)}for(f=d=0;f<a.aoColumns.length;f++)a.aoColumns[f].bVisible&&(e=h(i[d]).width(),null!==e&&0<e&&(a.aoColumns[f].sWidth=q(e)),d++);i=h(b).css("width");a.nTable.style.width=-1!==i.indexOf("%")?i:q(h(b).outerWidth());b.parentNode.removeChild(b)}o&&(a.nTable.style.width=q(o))}function Oa(a,b){""===a.oScroll.sX&&""!==a.oScroll.sY?(h(b).width(),b.style.width=q(h(b).outerWidth()-
+a.oScroll.iBarWidth)):""!==a.oScroll.sX&&(b.style.width=q(h(b).outerWidth()))}function Na(a,b){var c=Pa(a,b);if(0>c)return null;if(null===a.aoData[c].nTr){var d=l.createElement("td");d.innerHTML=v(a,c,b,"");return d}return J(a,c)[b]}function Pa(a,b){for(var c=-1,d=-1,i=0;i<a.aoData.length;i++){var e=v(a,i,b,"display")+"",e=e.replace(/<.*?>/g,"");e.length>c&&(c=e.length,d=i)}return d}function q(a){if(null===a)return"0px";if("number"==typeof a)return 0>a?"0px":a+"px";var b=a.charCodeAt(a.length-1);
+return 48>b||57<b?a:a+"px"}function Qa(){var a=l.createElement("p"),b=a.style;b.width="100%";b.height="200px";b.padding="0px";var c=l.createElement("div"),b=c.style;b.position="absolute";b.top="0px";b.left="0px";b.visibility="hidden";b.width="200px";b.height="150px";b.padding="0px";b.overflow="hidden";c.appendChild(a);l.body.appendChild(c);b=a.offsetWidth;c.style.overflow="scroll";a=a.offsetWidth;b==a&&(a=c.clientWidth);l.body.removeChild(c);return b-a}function O(a,b){var c,d,i,e,g,k,o=[],m=[],p=
+j.ext.oSort,l=a.aoData,q=a.aoColumns,G=a.oLanguage.oAria;if(!a.oFeatures.bServerSide&&(0!==a.aaSorting.length||null!==a.aaSortingFixed)){o=null!==a.aaSortingFixed?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(c=0;c<o.length;c++)if(d=o[c][0],i=R(a,d),e=a.aoColumns[d].sSortDataType,j.ext.afnSortData[e])if(g=j.ext.afnSortData[e].call(a.oInstance,a,d,i),g.length===l.length){i=0;for(e=l.length;i<e;i++)F(a,i,d,g[i])}else D(a,0,"Returned data sort array (col "+d+") is the wrong length");c=
+0;for(d=a.aiDisplayMaster.length;c<d;c++)m[a.aiDisplayMaster[c]]=c;var r=o.length,s;c=0;for(d=l.length;c<d;c++)for(i=0;i<r;i++){s=q[o[i][0]].aDataSort;g=0;for(k=s.length;g<k;g++)e=q[s[g]].sType,e=p[(e?e:"string")+"-pre"],l[c]._aSortData[s[g]]=e?e(v(a,c,s[g],"sort")):v(a,c,s[g],"sort")}a.aiDisplayMaster.sort(function(a,b){var c,d,e,i,f;for(c=0;c<r;c++){f=q[o[c][0]].aDataSort;d=0;for(e=f.length;d<e;d++)if(i=q[f[d]].sType,i=p[(i?i:"string")+"-"+o[c][1]](l[a]._aSortData[f[d]],l[b]._aSortData[f[d]]),0!==
+i)return i}return p["numeric-asc"](m[a],m[b])})}(b===n||b)&&!a.oFeatures.bDeferRender&&P(a);c=0;for(d=a.aoColumns.length;c<d;c++)e=q[c].sTitle.replace(/<.*?>/g,""),i=q[c].nTh,i.removeAttribute("aria-sort"),i.removeAttribute("aria-label"),q[c].bSortable?0<o.length&&o[0][0]==c?(i.setAttribute("aria-sort","asc"==o[0][1]?"ascending":"descending"),i.setAttribute("aria-label",e+("asc"==(q[c].asSorting[o[0][2]+1]?q[c].asSorting[o[0][2]+1]:q[c].asSorting[0])?G.sSortAscending:G.sSortDescending))):i.setAttribute("aria-label",
+e+("asc"==q[c].asSorting[0]?G.sSortAscending:G.sSortDescending)):i.setAttribute("aria-label",e);a.bSorted=!0;h(a.oInstance).trigger("sort",a);a.oFeatures.bFilter?K(a,a.oPreviousSearch,1):(a.aiDisplay=a.aiDisplayMaster.slice(),a._iDisplayStart=0,y(a),x(a))}function ia(a,b,c,d){Ra(b,{},function(b){if(!1!==a.aoColumns[c].bSortable){var e=function(){var d,e;if(b.shiftKey){for(var f=!1,h=0;h<a.aaSorting.length;h++)if(a.aaSorting[h][0]==c){f=!0;d=a.aaSorting[h][0];e=a.aaSorting[h][2]+1;a.aoColumns[d].asSorting[e]?
+(a.aaSorting[h][1]=a.aoColumns[d].asSorting[e],a.aaSorting[h][2]=e):a.aaSorting.splice(h,1);break}!1===f&&a.aaSorting.push([c,a.aoColumns[c].asSorting[0],0])}else 1==a.aaSorting.length&&a.aaSorting[0][0]==c?(d=a.aaSorting[0][0],e=a.aaSorting[0][2]+1,a.aoColumns[d].asSorting[e]||(e=0),a.aaSorting[0][1]=a.aoColumns[d].asSorting[e],a.aaSorting[0][2]=e):(a.aaSorting.splice(0,a.aaSorting.length),a.aaSorting.push([c,a.aoColumns[c].asSorting[0],0]));O(a)};a.oFeatures.bProcessing?(E(a,!0),setTimeout(function(){e();
+a.oFeatures.bServerSide||E(a,!1)},0)):e();"function"==typeof d&&d(a)}})}function P(a){var b,c,d,e,f,g=a.aoColumns.length,j=a.oClasses;for(b=0;b<g;b++)a.aoColumns[b].bSortable&&h(a.aoColumns[b].nTh).removeClass(j.sSortAsc+" "+j.sSortDesc+" "+a.aoColumns[b].sSortingClass);c=null!==a.aaSortingFixed?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(b=0;b<a.aoColumns.length;b++)if(a.aoColumns[b].bSortable){f=a.aoColumns[b].sSortingClass;e=-1;for(d=0;d<c.length;d++)if(c[d][0]==b){f="asc"==c[d][1]?
+j.sSortAsc:j.sSortDesc;e=d;break}h(a.aoColumns[b].nTh).addClass(f);a.bJUI&&(f=h("span."+j.sSortIcon,a.aoColumns[b].nTh),f.removeClass(j.sSortJUIAsc+" "+j.sSortJUIDesc+" "+j.sSortJUI+" "+j.sSortJUIAscAllowed+" "+j.sSortJUIDescAllowed),f.addClass(-1==e?a.aoColumns[b].sSortingClassJUI:"asc"==c[e][1]?j.sSortJUIAsc:j.sSortJUIDesc))}else h(a.aoColumns[b].nTh).addClass(a.aoColumns[b].sSortingClass);f=j.sSortColumn;if(a.oFeatures.bSort&&a.oFeatures.bSortClasses){a=J(a);e=[];for(b=0;b<g;b++)e.push("");b=0;
+for(d=1;b<c.length;b++)j=parseInt(c[b][0],10),e[j]=f+d,3>d&&d++;f=RegExp(f+"[123]");var o;b=0;for(c=a.length;b<c;b++)j=b%g,d=a[b].className,o=e[j],j=d.replace(f,o),j!=d?a[b].className=h.trim(j):0<o.length&&-1==d.indexOf(o)&&(a[b].className=d+" "+o)}}function ra(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b,c;b=a.oScroll.bInfinite;var d={iCreate:(new Date).getTime(),iStart:b?0:a._iDisplayStart,iEnd:b?a._iDisplayLength:a._iDisplayEnd,iLength:a._iDisplayLength,aaSorting:h.extend(!0,[],a.aaSorting),
+oSearch:h.extend(!0,{},a.oPreviousSearch),aoSearchCols:h.extend(!0,[],a.aoPreSearchCols),abVisCols:[]};b=0;for(c=a.aoColumns.length;b<c;b++)d.abVisCols.push(a.aoColumns[b].bVisible);A(a,"aoStateSaveParams","stateSaveParams",[a,d]);a.fnStateSave.call(a.oInstance,a,d)}}function Sa(a,b){if(a.oFeatures.bStateSave){var c=a.fnStateLoad.call(a.oInstance,a);if(c){var d=A(a,"aoStateLoadParams","stateLoadParams",[a,c]);if(-1===h.inArray(!1,d)){a.oLoadedState=h.extend(!0,{},c);a._iDisplayStart=c.iStart;a.iInitDisplayStart=
+c.iStart;a._iDisplayEnd=c.iEnd;a._iDisplayLength=c.iLength;a.aaSorting=c.aaSorting.slice();a.saved_aaSorting=c.aaSorting.slice();h.extend(a.oPreviousSearch,c.oSearch);h.extend(!0,a.aoPreSearchCols,c.aoSearchCols);b.saved_aoColumns=[];for(d=0;d<c.abVisCols.length;d++)b.saved_aoColumns[d]={},b.saved_aoColumns[d].bVisible=c.abVisCols[d];A(a,"aoStateLoaded","stateLoaded",[a,c])}}}}function s(a){for(var b=0;b<j.settings.length;b++)if(j.settings[b].nTable===a)return j.settings[b];return null}function T(a){for(var b=
+[],a=a.aoData,c=0,d=a.length;c<d;c++)null!==a[c].nTr&&b.push(a[c].nTr);return b}function J(a,b){var c=[],d,e,f,g,h,j;e=0;var o=a.aoData.length;b!==n&&(e=b,o=b+1);for(f=e;f<o;f++)if(j=a.aoData[f],null!==j.nTr){e=[];for(d=j.nTr.firstChild;d;)g=d.nodeName.toLowerCase(),("td"==g||"th"==g)&&e.push(d),d=d.nextSibling;g=d=0;for(h=a.aoColumns.length;g<h;g++)a.aoColumns[g].bVisible?c.push(e[g-d]):(c.push(j._anHidden[g]),d++)}return c}function D(a,b,c){a=null===a?"DataTables warning: "+c:"DataTables warning (table id = '"+
+a.sTableId+"'): "+c;if(0===b)if("alert"==j.ext.sErrMode)alert(a);else throw Error(a);else X.console&&console.log&&console.log(a)}function p(a,b,c,d){d===n&&(d=c);b[c]!==n&&(a[d]=b[c])}function Ta(a,b){var c,d;for(d in b)b.hasOwnProperty(d)&&(c=b[d],"object"===typeof e[d]&&null!==c&&!1===h.isArray(c)?h.extend(!0,a[d],c):a[d]=c);return a}function Ra(a,b,c){h(a).bind("click.DT",b,function(b){a.blur();c(b)}).bind("keypress.DT",b,function(a){13===a.which&&c(a)}).bind("selectstart.DT",function(){return!1})}
+function z(a,b,c,d){c&&a[b].push({fn:c,sName:d})}function A(a,b,c,d){for(var b=a[b],e=[],f=b.length-1;0<=f;f--)e.push(b[f].fn.apply(a.oInstance,d));null!==c&&h(a.oInstance).trigger(c,d);return e}function Ua(a){var b=h('<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden"><div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;"><div id="DT_BrowserTest" style="width:100%; height:10px;"></div></div></div>')[0];l.body.appendChild(b);a.oBrowser.bScrollOversize=
+100===h("#DT_BrowserTest",b)[0].offsetWidth?!0:!1;l.body.removeChild(b)}function Va(a){return function(){var b=[s(this[j.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return j.ext.oApi[a].apply(this,b)}}var U=/\[.*?\]$/,Wa=X.JSON?JSON.stringify:function(a){var b=typeof a;if("object"!==b||null===a)return"string"===b&&(a='"'+a+'"'),a+"";var c,d,e=[],f=h.isArray(a);for(c in a)d=a[c],b=typeof d,"string"===b?d='"'+d+'"':"object"===b&&null!==d&&(d=Wa(d)),e.push((f?"":'"'+c+'":')+d);return(f?
+"[":"{")+e+(f?"]":"}")};this.$=function(a,b){var c,d,e=[],f;d=s(this[j.ext.iApiIndex]);var g=d.aoData,o=d.aiDisplay,k=d.aiDisplayMaster;b||(b={});b=h.extend({},{filter:"none",order:"current",page:"all"},b);if("current"==b.page){c=d._iDisplayStart;for(d=d.fnDisplayEnd();c<d;c++)(f=g[o[c]].nTr)&&e.push(f)}else if("current"==b.order&&"none"==b.filter){c=0;for(d=k.length;c<d;c++)(f=g[k[c]].nTr)&&e.push(f)}else if("current"==b.order&&"applied"==b.filter){c=0;for(d=o.length;c<d;c++)(f=g[o[c]].nTr)&&e.push(f)}else if("original"==
+b.order&&"none"==b.filter){c=0;for(d=g.length;c<d;c++)(f=g[c].nTr)&&e.push(f)}else if("original"==b.order&&"applied"==b.filter){c=0;for(d=g.length;c<d;c++)f=g[c].nTr,-1!==h.inArray(c,o)&&f&&e.push(f)}else D(d,1,"Unknown selection options");e=h(e);c=e.filter(a);e=e.find(a);return h([].concat(h.makeArray(c),h.makeArray(e)))};this._=function(a,b){var c=[],d,e,f=this.$(a,b);d=0;for(e=f.length;d<e;d++)c.push(this.fnGetData(f[d]));return c};this.fnAddData=function(a,b){if(0===a.length)return[];var c=[],
+d,e=s(this[j.ext.iApiIndex]);if("object"===typeof a[0]&&null!==a[0])for(var f=0;f<a.length;f++){d=H(e,a[f]);if(-1==d)return c;c.push(d)}else{d=H(e,a);if(-1==d)return c;c.push(d)}e.aiDisplay=e.aiDisplayMaster.slice();(b===n||b)&&aa(e);return c};this.fnAdjustColumnSizing=function(a){var b=s(this[j.ext.iApiIndex]);k(b);a===n||a?this.fnDraw(!1):(""!==b.oScroll.sX||""!==b.oScroll.sY)&&this.oApi._fnScrollDraw(b)};this.fnClearTable=function(a){var b=s(this[j.ext.iApiIndex]);ga(b);(a===n||a)&&x(b)};this.fnClose=
+function(a){for(var b=s(this[j.ext.iApiIndex]),c=0;c<b.aoOpenRows.length;c++)if(b.aoOpenRows[c].nParent==a)return(a=b.aoOpenRows[c].nTr.parentNode)&&a.removeChild(b.aoOpenRows[c].nTr),b.aoOpenRows.splice(c,1),0;return 1};this.fnDeleteRow=function(a,b,c){var d=s(this[j.ext.iApiIndex]),e,f,a="object"===typeof a?I(d,a):a,g=d.aoData.splice(a,1);e=0;for(f=d.aoData.length;e<f;e++)null!==d.aoData[e].nTr&&(d.aoData[e].nTr._DT_RowIndex=e);e=h.inArray(a,d.aiDisplay);d.asDataSearch.splice(e,1);ha(d.aiDisplayMaster,
+a);ha(d.aiDisplay,a);"function"===typeof b&&b.call(this,d,g);d._iDisplayStart>=d.fnRecordsDisplay()&&(d._iDisplayStart-=d._iDisplayLength,0>d._iDisplayStart&&(d._iDisplayStart=0));if(c===n||c)y(d),x(d);return g};this.fnDestroy=function(a){var b=s(this[j.ext.iApiIndex]),c=b.nTableWrapper.parentNode,d=b.nTBody,i,f,a=a===n?!1:a;b.bDestroying=!0;A(b,"aoDestroyCallback","destroy",[b]);if(!a){i=0;for(f=b.aoColumns.length;i<f;i++)!1===b.aoColumns[i].bVisible&&this.fnSetColumnVis(i,!0)}h(b.nTableWrapper).find("*").andSelf().unbind(".DT");
+h("tbody>tr>td."+b.oClasses.sRowEmpty,b.nTable).parent().remove();b.nTable!=b.nTHead.parentNode&&(h(b.nTable).children("thead").remove(),b.nTable.appendChild(b.nTHead));b.nTFoot&&b.nTable!=b.nTFoot.parentNode&&(h(b.nTable).children("tfoot").remove(),b.nTable.appendChild(b.nTFoot));b.nTable.parentNode.removeChild(b.nTable);h(b.nTableWrapper).remove();b.aaSorting=[];b.aaSortingFixed=[];P(b);h(T(b)).removeClass(b.asStripeClasses.join(" "));h("th, td",b.nTHead).removeClass([b.oClasses.sSortable,b.oClasses.sSortableAsc,
+b.oClasses.sSortableDesc,b.oClasses.sSortableNone].join(" "));b.bJUI&&(h("th span."+b.oClasses.sSortIcon+", td span."+b.oClasses.sSortIcon,b.nTHead).remove(),h("th, td",b.nTHead).each(function(){var a=h("div."+b.oClasses.sSortJUIWrapper,this),c=a.contents();h(this).append(c);a.remove()}));!a&&b.nTableReinsertBefore?c.insertBefore(b.nTable,b.nTableReinsertBefore):a||c.appendChild(b.nTable);i=0;for(f=b.aoData.length;i<f;i++)null!==b.aoData[i].nTr&&d.appendChild(b.aoData[i].nTr);!0===b.oFeatures.bAutoWidth&&
+(b.nTable.style.width=q(b.sDestroyWidth));if(f=b.asDestroyStripes.length){a=h(d).children("tr");for(i=0;i<f;i++)a.filter(":nth-child("+f+"n + "+i+")").addClass(b.asDestroyStripes[i])}i=0;for(f=j.settings.length;i<f;i++)j.settings[i]==b&&j.settings.splice(i,1);e=b=null};this.fnDraw=function(a){var b=s(this[j.ext.iApiIndex]);!1===a?(y(b),x(b)):aa(b)};this.fnFilter=function(a,b,c,d,e,f){var g=s(this[j.ext.iApiIndex]);if(g.oFeatures.bFilter){if(c===n||null===c)c=!1;if(d===n||null===d)d=!0;if(e===n||null===
+e)e=!0;if(f===n||null===f)f=!0;if(b===n||null===b){if(K(g,{sSearch:a+"",bRegex:c,bSmart:d,bCaseInsensitive:f},1),e&&g.aanFeatures.f){b=g.aanFeatures.f;c=0;for(d=b.length;c<d;c++)try{b[c]._DT_Input!=l.activeElement&&h(b[c]._DT_Input).val(a)}catch(o){h(b[c]._DT_Input).val(a)}}}else h.extend(g.aoPreSearchCols[b],{sSearch:a+"",bRegex:c,bSmart:d,bCaseInsensitive:f}),K(g,g.oPreviousSearch,1)}};this.fnGetData=function(a,b){var c=s(this[j.ext.iApiIndex]);if(a!==n){var d=a;if("object"===typeof a){var e=a.nodeName.toLowerCase();
+"tr"===e?d=I(c,a):"td"===e&&(d=I(c,a.parentNode),b=fa(c,d,a))}return b!==n?v(c,d,b,""):c.aoData[d]!==n?c.aoData[d]._aData:null}return Z(c)};this.fnGetNodes=function(a){var b=s(this[j.ext.iApiIndex]);return a!==n?b.aoData[a]!==n?b.aoData[a].nTr:null:T(b)};this.fnGetPosition=function(a){var b=s(this[j.ext.iApiIndex]),c=a.nodeName.toUpperCase();return"TR"==c?I(b,a):"TD"==c||"TH"==c?(c=I(b,a.parentNode),a=fa(b,c,a),[c,R(b,a),a]):null};this.fnIsOpen=function(a){for(var b=s(this[j.ext.iApiIndex]),c=0;c<
+b.aoOpenRows.length;c++)if(b.aoOpenRows[c].nParent==a)return!0;return!1};this.fnOpen=function(a,b,c){var d=s(this[j.ext.iApiIndex]),e=T(d);if(-1!==h.inArray(a,e)){this.fnClose(a);var e=l.createElement("tr"),f=l.createElement("td");e.appendChild(f);f.className=c;f.colSpan=t(d);"string"===typeof b?f.innerHTML=b:h(f).html(b);b=h("tr",d.nTBody);-1!=h.inArray(a,b)&&h(e).insertAfter(a);d.aoOpenRows.push({nTr:e,nParent:a});return e}};this.fnPageChange=function(a,b){var c=s(this[j.ext.iApiIndex]);qa(c,a);
+y(c);(b===n||b)&&x(c)};this.fnSetColumnVis=function(a,b,c){var d=s(this[j.ext.iApiIndex]),e,f,g=d.aoColumns,h=d.aoData,o,m;if(g[a].bVisible!=b){if(b){for(e=f=0;e<a;e++)g[e].bVisible&&f++;m=f>=t(d);if(!m)for(e=a;e<g.length;e++)if(g[e].bVisible){o=e;break}e=0;for(f=h.length;e<f;e++)null!==h[e].nTr&&(m?h[e].nTr.appendChild(h[e]._anHidden[a]):h[e].nTr.insertBefore(h[e]._anHidden[a],J(d,e)[o]))}else{e=0;for(f=h.length;e<f;e++)null!==h[e].nTr&&(o=J(d,e)[a],h[e]._anHidden[a]=o,o.parentNode.removeChild(o))}g[a].bVisible=
+b;W(d,d.aoHeader);d.nTFoot&&W(d,d.aoFooter);e=0;for(f=d.aoOpenRows.length;e<f;e++)d.aoOpenRows[e].nTr.colSpan=t(d);if(c===n||c)k(d),x(d);ra(d)}};this.fnSettings=function(){return s(this[j.ext.iApiIndex])};this.fnSort=function(a){var b=s(this[j.ext.iApiIndex]);b.aaSorting=a;O(b)};this.fnSortListener=function(a,b,c){ia(s(this[j.ext.iApiIndex]),a,b,c)};this.fnUpdate=function(a,b,c,d,e){var f=s(this[j.ext.iApiIndex]),b="object"===typeof b?I(f,b):b;if(h.isArray(a)&&c===n){f.aoData[b]._aData=a.slice();
+for(c=0;c<f.aoColumns.length;c++)this.fnUpdate(v(f,b,c),b,c,!1,!1)}else if(h.isPlainObject(a)&&c===n){f.aoData[b]._aData=h.extend(!0,{},a);for(c=0;c<f.aoColumns.length;c++)this.fnUpdate(v(f,b,c),b,c,!1,!1)}else{F(f,b,c,a);var a=v(f,b,c,"display"),g=f.aoColumns[c];null!==g.fnRender&&(a=S(f,b,c),g.bUseRendered&&F(f,b,c,a));null!==f.aoData[b].nTr&&(J(f,b)[c].innerHTML=a)}c=h.inArray(b,f.aiDisplay);f.asDataSearch[c]=na(f,Y(f,b,"filter",r(f,"bSearchable")));(e===n||e)&&k(f);(d===n||d)&&aa(f);return 0};
+this.fnVersionCheck=j.ext.fnVersionCheck;this.oApi={_fnExternApiFunc:Va,_fnInitialise:ba,_fnInitComplete:$,_fnLanguageCompat:pa,_fnAddColumn:o,_fnColumnOptions:m,_fnAddData:H,_fnCreateTr:ea,_fnGatherData:ua,_fnBuildHead:va,_fnDrawHead:W,_fnDraw:x,_fnReDraw:aa,_fnAjaxUpdate:wa,_fnAjaxParameters:Ea,_fnAjaxUpdateDraw:Fa,_fnServerParams:ka,_fnAddOptionsHtml:xa,_fnFeatureHtmlTable:Ba,_fnScrollDraw:La,_fnAdjustColumnSizing:k,_fnFeatureHtmlFilter:za,_fnFilterComplete:K,_fnFilterCustom:Ia,_fnFilterColumn:Ha,
+_fnFilter:Ga,_fnBuildSearchArray:la,_fnBuildSearchRow:na,_fnFilterCreateSearch:ma,_fnDataToSearch:Ja,_fnSort:O,_fnSortAttachListener:ia,_fnSortingClasses:P,_fnFeatureHtmlPaginate:Da,_fnPageChange:qa,_fnFeatureHtmlInfo:Ca,_fnUpdateInfo:Ka,_fnFeatureHtmlLength:ya,_fnFeatureHtmlProcessing:Aa,_fnProcessingDisplay:E,_fnVisibleToColumnIndex:G,_fnColumnIndexToVisible:R,_fnNodeToDataIndex:I,_fnVisbleColumns:t,_fnCalculateEnd:y,_fnConvertToWidth:Ma,_fnCalculateColumnWidths:da,_fnScrollingWidthAdjust:Oa,_fnGetWidestNode:Na,
+_fnGetMaxLenString:Pa,_fnStringToCss:q,_fnDetectType:B,_fnSettingsFromNode:s,_fnGetDataMaster:Z,_fnGetTrNodes:T,_fnGetTdNodes:J,_fnEscapeRegex:oa,_fnDeleteIndex:ha,_fnReOrderIndex:u,_fnColumnOrdering:M,_fnLog:D,_fnClearTable:ga,_fnSaveState:ra,_fnLoadState:Sa,_fnCreateCookie:function(a,b,c,d,e){var f=new Date;f.setTime(f.getTime()+1E3*c);var c=X.location.pathname.split("/"),a=a+"_"+c.pop().replace(/[\/:]/g,"").toLowerCase(),g;null!==e?(g="function"===typeof h.parseJSON?h.parseJSON(b):eval("("+b+")"),
+b=e(a,g,f.toGMTString(),c.join("/")+"/")):b=a+"="+encodeURIComponent(b)+"; expires="+f.toGMTString()+"; path="+c.join("/")+"/";a=l.cookie.split(";");e=b.split(";")[0].length;f=[];if(4096<e+l.cookie.length+10){for(var j=0,o=a.length;j<o;j++)if(-1!=a[j].indexOf(d)){var k=a[j].split("=");try{(g=eval("("+decodeURIComponent(k[1])+")"))&&g.iCreate&&f.push({name:k[0],time:g.iCreate})}catch(m){}}for(f.sort(function(a,b){return b.time-a.time});4096<e+l.cookie.length+10;){if(0===f.length)return;d=f.pop();l.cookie=
+d.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+c.join("/")+"/"}}l.cookie=b},_fnReadCookie:function(a){for(var b=X.location.pathname.split("/"),a=a+"_"+b[b.length-1].replace(/[\/:]/g,"").toLowerCase()+"=",b=l.cookie.split(";"),c=0;c<b.length;c++){for(var d=b[c];" "==d.charAt(0);)d=d.substring(1,d.length);if(0===d.indexOf(a))return decodeURIComponent(d.substring(a.length,d.length))}return null},_fnDetectHeader:V,_fnGetUniqueThs:N,_fnScrollBarWidth:Qa,_fnApplyToChildren:C,_fnMap:p,_fnGetRowData:Y,
+_fnGetCellData:v,_fnSetCellData:F,_fnGetObjectDataFn:Q,_fnSetObjectDataFn:L,_fnApplyColumnDefs:ta,_fnBindAction:Ra,_fnExtend:Ta,_fnCallbackReg:z,_fnCallbackFire:A,_fnJsonString:Wa,_fnRender:S,_fnNodeToColumnIndex:fa,_fnInfoMacros:ja,_fnBrowserDetect:Ua,_fnGetColumns:r};h.extend(j.ext.oApi,this.oApi);for(var sa in j.ext.oApi)sa&&(this[sa]=Va(sa));var ca=this;this.each(function(){var a=0,b,c,d;c=this.getAttribute("id");var i=!1,f=!1;if("table"!=this.nodeName.toLowerCase())D(null,0,"Attempted to initialise DataTables on a node which is not a table: "+
+this.nodeName);else{a=0;for(b=j.settings.length;a<b;a++){if(j.settings[a].nTable==this){if(e===n||e.bRetrieve)return j.settings[a].oInstance;if(e.bDestroy){j.settings[a].oInstance.fnDestroy();break}else{D(j.settings[a],0,"Cannot reinitialise DataTable.\n\nTo retrieve the DataTables object for this table, pass no arguments or see the docs for bRetrieve and bDestroy");return}}if(j.settings[a].sTableId==this.id){j.settings.splice(a,1);break}}if(null===c||""===c)this.id=c="DataTables_Table_"+j.ext._oExternConfig.iNextUnique++;
+var g=h.extend(!0,{},j.models.oSettings,{nTable:this,oApi:ca.oApi,oInit:e,sDestroyWidth:h(this).width(),sInstance:c,sTableId:c});j.settings.push(g);g.oInstance=1===ca.length?ca:h(this).dataTable();e||(e={});e.oLanguage&&pa(e.oLanguage);e=Ta(h.extend(!0,{},j.defaults),e);p(g.oFeatures,e,"bPaginate");p(g.oFeatures,e,"bLengthChange");p(g.oFeatures,e,"bFilter");p(g.oFeatures,e,"bSort");p(g.oFeatures,e,"bInfo");p(g.oFeatures,e,"bProcessing");p(g.oFeatures,e,"bAutoWidth");p(g.oFeatures,e,"bSortClasses");
+p(g.oFeatures,e,"bServerSide");p(g.oFeatures,e,"bDeferRender");p(g.oScroll,e,"sScrollX","sX");p(g.oScroll,e,"sScrollXInner","sXInner");p(g.oScroll,e,"sScrollY","sY");p(g.oScroll,e,"bScrollCollapse","bCollapse");p(g.oScroll,e,"bScrollInfinite","bInfinite");p(g.oScroll,e,"iScrollLoadGap","iLoadGap");p(g.oScroll,e,"bScrollAutoCss","bAutoCss");p(g,e,"asStripeClasses");p(g,e,"asStripClasses","asStripeClasses");p(g,e,"fnServerData");p(g,e,"fnFormatNumber");p(g,e,"sServerMethod");p(g,e,"aaSorting");p(g,
+e,"aaSortingFixed");p(g,e,"aLengthMenu");p(g,e,"sPaginationType");p(g,e,"sAjaxSource");p(g,e,"sAjaxDataProp");p(g,e,"iCookieDuration");p(g,e,"sCookiePrefix");p(g,e,"sDom");p(g,e,"bSortCellsTop");p(g,e,"iTabIndex");p(g,e,"oSearch","oPreviousSearch");p(g,e,"aoSearchCols","aoPreSearchCols");p(g,e,"iDisplayLength","_iDisplayLength");p(g,e,"bJQueryUI","bJUI");p(g,e,"fnCookieCallback");p(g,e,"fnStateLoad");p(g,e,"fnStateSave");p(g.oLanguage,e,"fnInfoCallback");z(g,"aoDrawCallback",e.fnDrawCallback,"user");
+z(g,"aoServerParams",e.fnServerParams,"user");z(g,"aoStateSaveParams",e.fnStateSaveParams,"user");z(g,"aoStateLoadParams",e.fnStateLoadParams,"user");z(g,"aoStateLoaded",e.fnStateLoaded,"user");z(g,"aoRowCallback",e.fnRowCallback,"user");z(g,"aoRowCreatedCallback",e.fnCreatedRow,"user");z(g,"aoHeaderCallback",e.fnHeaderCallback,"user");z(g,"aoFooterCallback",e.fnFooterCallback,"user");z(g,"aoInitComplete",e.fnInitComplete,"user");z(g,"aoPreDrawCallback",e.fnPreDrawCallback,"user");g.oFeatures.bServerSide&&
+g.oFeatures.bSort&&g.oFeatures.bSortClasses?z(g,"aoDrawCallback",P,"server_side_sort_classes"):g.oFeatures.bDeferRender&&z(g,"aoDrawCallback",P,"defer_sort_classes");e.bJQueryUI?(h.extend(g.oClasses,j.ext.oJUIClasses),e.sDom===j.defaults.sDom&&"lfrtip"===j.defaults.sDom&&(g.sDom='<"H"lfr>t<"F"ip>')):h.extend(g.oClasses,j.ext.oStdClasses);h(this).addClass(g.oClasses.sTable);if(""!==g.oScroll.sX||""!==g.oScroll.sY)g.oScroll.iBarWidth=Qa();g.iInitDisplayStart===n&&(g.iInitDisplayStart=e.iDisplayStart,
+g._iDisplayStart=e.iDisplayStart);e.bStateSave&&(g.oFeatures.bStateSave=!0,Sa(g,e),z(g,"aoDrawCallback",ra,"state_save"));null!==e.iDeferLoading&&(g.bDeferLoading=!0,a=h.isArray(e.iDeferLoading),g._iRecordsDisplay=a?e.iDeferLoading[0]:e.iDeferLoading,g._iRecordsTotal=a?e.iDeferLoading[1]:e.iDeferLoading);null!==e.aaData&&(f=!0);""!==e.oLanguage.sUrl?(g.oLanguage.sUrl=e.oLanguage.sUrl,h.getJSON(g.oLanguage.sUrl,null,function(a){pa(a);h.extend(true,g.oLanguage,e.oLanguage,a);ba(g)}),i=!0):h.extend(!0,
+g.oLanguage,e.oLanguage);null===e.asStripeClasses&&(g.asStripeClasses=[g.oClasses.sStripeOdd,g.oClasses.sStripeEven]);b=g.asStripeClasses.length;g.asDestroyStripes=[];if(b){c=!1;d=h(this).children("tbody").children("tr:lt("+b+")");for(a=0;a<b;a++)d.hasClass(g.asStripeClasses[a])&&(c=!0,g.asDestroyStripes.push(g.asStripeClasses[a]));c&&d.removeClass(g.asStripeClasses.join(" "))}c=[];a=this.getElementsByTagName("thead");0!==a.length&&(V(g.aoHeader,a[0]),c=N(g));if(null===e.aoColumns){d=[];a=0;for(b=
+c.length;a<b;a++)d.push(null)}else d=e.aoColumns;a=0;for(b=d.length;a<b;a++)e.saved_aoColumns!==n&&e.saved_aoColumns.length==b&&(null===d[a]&&(d[a]={}),d[a].bVisible=e.saved_aoColumns[a].bVisible),o(g,c?c[a]:null);ta(g,e.aoColumnDefs,d,function(a,b){m(g,a,b)});a=0;for(b=g.aaSorting.length;a<b;a++){g.aaSorting[a][0]>=g.aoColumns.length&&(g.aaSorting[a][0]=0);var k=g.aoColumns[g.aaSorting[a][0]];g.aaSorting[a][2]===n&&(g.aaSorting[a][2]=0);e.aaSorting===n&&g.saved_aaSorting===n&&(g.aaSorting[a][1]=
+k.asSorting[0]);c=0;for(d=k.asSorting.length;c<d;c++)if(g.aaSorting[a][1]==k.asSorting[c]){g.aaSorting[a][2]=c;break}}P(g);Ua(g);a=h(this).children("caption").each(function(){this._captionSide=h(this).css("caption-side")});b=h(this).children("thead");0===b.length&&(b=[l.createElement("thead")],this.appendChild(b[0]));g.nTHead=b[0];b=h(this).children("tbody");0===b.length&&(b=[l.createElement("tbody")],this.appendChild(b[0]));g.nTBody=b[0];g.nTBody.setAttribute("role","alert");g.nTBody.setAttribute("aria-live",
+"polite");g.nTBody.setAttribute("aria-relevant","all");b=h(this).children("tfoot");if(0===b.length&&0<a.length&&(""!==g.oScroll.sX||""!==g.oScroll.sY))b=[l.createElement("tfoot")],this.appendChild(b[0]);0<b.length&&(g.nTFoot=b[0],V(g.aoFooter,g.nTFoot));if(f)for(a=0;a<e.aaData.length;a++)H(g,e.aaData[a]);else ua(g);g.aiDisplay=g.aiDisplayMaster.slice();g.bInitialised=!0;!1===i&&ba(g)}});ca=null;return this};j.fnVersionCheck=function(e){for(var h=function(e,h){for(;e.length<h;)e+="0";return e},m=j.ext.sVersion.split("."),
+e=e.split("."),k="",n="",l=0,t=e.length;l<t;l++)k+=h(m[l],3),n+=h(e[l],3);return parseInt(k,10)>=parseInt(n,10)};j.fnIsDataTable=function(e){for(var h=j.settings,m=0;m<h.length;m++)if(h[m].nTable===e||h[m].nScrollHead===e||h[m].nScrollFoot===e)return!0;return!1};j.fnTables=function(e){var o=[];jQuery.each(j.settings,function(j,k){(!e||!0===e&&h(k.nTable).is(":visible"))&&o.push(k.nTable)});return o};j.version="1.9.4";j.settings=[];j.models={};j.models.ext={afnFiltering:[],afnSortData:[],aoFeatures:[],
+aTypes:[],fnVersionCheck:j.fnVersionCheck,iApiIndex:0,ofnSearch:{},oApi:{},oStdClasses:{},oJUIClasses:{},oPagination:{},oSort:{},sVersion:j.version,sErrMode:"alert",_oExternConfig:{iNextUnique:0}};j.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};j.models.oRow={nTr:null,_aData:[],_aSortData:[],_anHidden:[],_sRowStripe:""};j.models.oColumn={aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bUseRendered:null,bVisible:null,_bAutoType:!0,fnCreatedCell:null,fnGetData:null,
+fnRender:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};j.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,
+bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollAutoCss:!0,bScrollCollapse:!1,bScrollInfinite:!1,bServerSide:!1,bSort:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCookieCallback:null,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(e){if(1E3>e)return e;for(var h=e+"",e=h.split(""),j="",h=h.length,k=0;k<h;k++)0===k%3&&0!==k&&(j=this.oLanguage.sInfoThousands+j),j=e[h-k-1]+j;return j},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,
+fnRowCallback:null,fnServerData:function(e,j,m,k){k.jqXHR=h.ajax({url:e,data:j,success:function(e){e.sError&&k.oApi._fnLog(k,0,e.sError);h(k.oInstance).trigger("xhr",[k,e]);m(e)},dataType:"json",cache:!1,type:k.sServerMethod,error:function(e,h){"parsererror"==h&&k.oApi._fnLog(k,0,"DataTables warning: JSON data from server could not be parsed. This is caused by a JSON formatting error.")}})},fnServerParams:null,fnStateLoad:function(e){var e=this.oApi._fnReadCookie(e.sCookiePrefix+e.sInstance),j;try{j=
+"function"===typeof h.parseJSON?h.parseJSON(e):eval("("+e+")")}catch(m){j=null}return j},fnStateLoadParams:null,fnStateLoaded:null,fnStateSave:function(e,h){this.oApi._fnCreateCookie(e.sCookiePrefix+e.sInstance,this.oApi._fnJsonString(h),e.iCookieDuration,e.sCookiePrefix,e.fnCookieCallback)},fnStateSaveParams:null,iCookieDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iScrollLoadGap:100,iTabIndex:0,oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},
+oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sInfoThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},j.models.oSearch),sAjaxDataProp:"aaData",
+sAjaxSource:null,sCookiePrefix:"SpryMedia_DataTables_",sDom:"lfrtip",sPaginationType:"two_button",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET"};j.defaults.columns={aDataSort:null,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bUseRendered:!0,bVisible:!0,fnCreatedCell:null,fnRender:null,iDataSort:-1,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};j.models.oSettings={oFeatures:{bAutoWidth:null,
+bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortClasses:null,bStateSave:null},oScroll:{bAutoCss:null,bCollapse:null,bInfinite:null,iBarWidth:0,iLoadGap:null,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1},aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aoColumns:[],aoHeader:[],aoFooter:[],asDataSearch:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:null,
+asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,sPaginationType:"two_button",iCookieDuration:0,sCookiePrefix:"",fnCookieCallback:null,aoStateSave:[],aoStateLoad:[],
+oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iDisplayEnd:10,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return this.oFeatures.bServerSide?parseInt(this._iRecordsTotal,10):this.aiDisplayMaster.length},
+fnRecordsDisplay:function(){return this.oFeatures.bServerSide?parseInt(this._iRecordsDisplay,10):this.aiDisplay.length},fnDisplayEnd:function(){return this.oFeatures.bServerSide?!1===this.oFeatures.bPaginate||-1==this._iDisplayLength?this._iDisplayStart+this.aiDisplay.length:Math.min(this._iDisplayStart+this._iDisplayLength,this._iRecordsDisplay):this._iDisplayEnd},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null};j.ext=h.extend(!0,{},j.models.ext);h.extend(j.ext.oStdClasses,
+{sTable:"dataTable",sPagePrevEnabled:"paginate_enabled_previous",sPagePrevDisabled:"paginate_disabled_previous",sPageNextEnabled:"paginate_enabled_next",sPageNextDisabled:"paginate_disabled_next",sPageJUINext:"",sPageJUIPrev:"",sPageButton:"paginate_button",sPageButtonActive:"paginate_active",sPageButtonStaticDisabled:"paginate_button paginate_button_disabled",sPageFirst:"first",sPagePrevious:"previous",sPageNext:"next",sPageLast:"last",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",
+sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",
+sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sFooterTH:"",sJUIHeader:"",sJUIFooter:""});h.extend(j.ext.oJUIClasses,j.ext.oStdClasses,{sPagePrevEnabled:"fg-button ui-button ui-state-default ui-corner-left",sPagePrevDisabled:"fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",sPageNextEnabled:"fg-button ui-button ui-state-default ui-corner-right",
+sPageNextDisabled:"fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",sPageJUINext:"ui-icon ui-icon-circle-arrow-e",sPageJUIPrev:"ui-icon ui-icon-circle-arrow-w",sPageButton:"fg-button ui-button ui-state-default",sPageButtonActive:"fg-button ui-button ui-state-default ui-state-disabled",sPageButtonStaticDisabled:"fg-button ui-button ui-state-default ui-state-disabled",sPageFirst:"first ui-corner-tl ui-corner-bl",sPageLast:"last ui-corner-tr ui-corner-br",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",
+sSortAsc:"ui-state-default",sSortDesc:"ui-state-default",sSortable:"ui-state-default",sSortableAsc:"ui-state-default",sSortableDesc:"ui-state-default",sSortableNone:"ui-state-default",sSortJUIAsc:"css_right ui-icon ui-icon-triangle-1-n",sSortJUIDesc:"css_right ui-icon ui-icon-triangle-1-s",sSortJUI:"css_right ui-icon ui-icon-carat-2-n-s",sSortJUIAscAllowed:"css_right ui-icon ui-icon-carat-1-n",sSortJUIDescAllowed:"css_right ui-icon ui-icon-carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",
+sScrollHead:"dataTables_scrollHead ui-state-default",sScrollFoot:"dataTables_scrollFoot ui-state-default",sFooterTH:"ui-state-default",sJUIHeader:"fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix",sJUIFooter:"fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"});h.extend(j.ext.oPagination,{two_button:{fnInit:function(e,j,m){var k=e.oLanguage.oPaginate,n=function(h){e.oApi._fnPageChange(e,h.data.action)&&m(e)},k=!e.bJUI?'<a class="'+
+e.oClasses.sPagePrevDisabled+'" tabindex="'+e.iTabIndex+'" role="button">'+k.sPrevious+'</a><a class="'+e.oClasses.sPageNextDisabled+'" tabindex="'+e.iTabIndex+'" role="button">'+k.sNext+"</a>":'<a class="'+e.oClasses.sPagePrevDisabled+'" tabindex="'+e.iTabIndex+'" role="button"><span class="'+e.oClasses.sPageJUIPrev+'"></span></a><a class="'+e.oClasses.sPageNextDisabled+'" tabindex="'+e.iTabIndex+'" role="button"><span class="'+e.oClasses.sPageJUINext+'"></span></a>';h(j).append(k);var l=h("a",j),
+k=l[0],l=l[1];e.oApi._fnBindAction(k,{action:"previous"},n);e.oApi._fnBindAction(l,{action:"next"},n);e.aanFeatures.p||(j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_previous",l.id=e.sTableId+"_next",k.setAttribute("aria-controls",e.sTableId),l.setAttribute("aria-controls",e.sTableId))},fnUpdate:function(e){if(e.aanFeatures.p)for(var h=e.oClasses,j=e.aanFeatures.p,k,l=0,n=j.length;l<n;l++)if(k=j[l].firstChild)k.className=0===e._iDisplayStart?h.sPagePrevDisabled:h.sPagePrevEnabled,k=k.nextSibling,
+k.className=e.fnDisplayEnd()==e.fnRecordsDisplay()?h.sPageNextDisabled:h.sPageNextEnabled}},iFullNumbersShowPages:5,full_numbers:{fnInit:function(e,j,m){var k=e.oLanguage.oPaginate,l=e.oClasses,n=function(h){e.oApi._fnPageChange(e,h.data.action)&&m(e)};h(j).append('<a  tabindex="'+e.iTabIndex+'" class="'+l.sPageButton+" "+l.sPageFirst+'">'+k.sFirst+'</a><a  tabindex="'+e.iTabIndex+'" class="'+l.sPageButton+" "+l.sPagePrevious+'">'+k.sPrevious+'</a><span></span><a tabindex="'+e.iTabIndex+'" class="'+
+l.sPageButton+" "+l.sPageNext+'">'+k.sNext+'</a><a tabindex="'+e.iTabIndex+'" class="'+l.sPageButton+" "+l.sPageLast+'">'+k.sLast+"</a>");var t=h("a",j),k=t[0],l=t[1],r=t[2],t=t[3];e.oApi._fnBindAction(k,{action:"first"},n);e.oApi._fnBindAction(l,{action:"previous"},n);e.oApi._fnBindAction(r,{action:"next"},n);e.oApi._fnBindAction(t,{action:"last"},n);e.aanFeatures.p||(j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_first",l.id=e.sTableId+"_previous",r.id=e.sTableId+"_next",t.id=e.sTableId+"_last")},
+fnUpdate:function(e,o){if(e.aanFeatures.p){var m=j.ext.oPagination.iFullNumbersShowPages,k=Math.floor(m/2),l=Math.ceil(e.fnRecordsDisplay()/e._iDisplayLength),n=Math.ceil(e._iDisplayStart/e._iDisplayLength)+1,t="",r,B=e.oClasses,u,M=e.aanFeatures.p,L=function(h){e.oApi._fnBindAction(this,{page:h+r-1},function(h){e.oApi._fnPageChange(e,h.data.page);o(e);h.preventDefault()})};-1===e._iDisplayLength?n=k=r=1:l<m?(r=1,k=l):n<=k?(r=1,k=m):n>=l-k?(r=l-m+1,k=l):(r=n-Math.ceil(m/2)+1,k=r+m-1);for(m=r;m<=k;m++)t+=
+n!==m?'<a tabindex="'+e.iTabIndex+'" class="'+B.sPageButton+'">'+e.fnFormatNumber(m)+"</a>":'<a tabindex="'+e.iTabIndex+'" class="'+B.sPageButtonActive+'">'+e.fnFormatNumber(m)+"</a>";m=0;for(k=M.length;m<k;m++)u=M[m],u.hasChildNodes()&&(h("span:eq(0)",u).html(t).children("a").each(L),u=u.getElementsByTagName("a"),u=[u[0],u[1],u[u.length-2],u[u.length-1]],h(u).removeClass(B.sPageButton+" "+B.sPageButtonActive+" "+B.sPageButtonStaticDisabled),h([u[0],u[1]]).addClass(1==n?B.sPageButtonStaticDisabled:
+B.sPageButton),h([u[2],u[3]]).addClass(0===l||n===l||-1===e._iDisplayLength?B.sPageButtonStaticDisabled:B.sPageButton))}}}});h.extend(j.ext.oSort,{"string-pre":function(e){"string"!=typeof e&&(e=null!==e&&e.toString?e.toString():"");return e.toLowerCase()},"string-asc":function(e,h){return e<h?-1:e>h?1:0},"string-desc":function(e,h){return e<h?1:e>h?-1:0},"html-pre":function(e){return e.replace(/<.*?>/g,"").toLowerCase()},"html-asc":function(e,h){return e<h?-1:e>h?1:0},"html-desc":function(e,h){return e<
+h?1:e>h?-1:0},"date-pre":function(e){e=Date.parse(e);if(isNaN(e)||""===e)e=Date.parse("01/01/1970 00:00:00");return e},"date-asc":function(e,h){return e-h},"date-desc":function(e,h){return h-e},"numeric-pre":function(e){return"-"==e||""===e?0:1*e},"numeric-asc":function(e,h){return e-h},"numeric-desc":function(e,h){return h-e}});h.extend(j.ext.aTypes,[function(e){if("number"===typeof e)return"numeric";if("string"!==typeof e)return null;var h,j=!1;h=e.charAt(0);if(-1=="0123456789-".indexOf(h))return null;
+for(var k=1;k<e.length;k++){h=e.charAt(k);if(-1=="0123456789.".indexOf(h))return null;if("."==h){if(j)return null;j=!0}}return"numeric"},function(e){var h=Date.parse(e);return null!==h&&!isNaN(h)||"string"===typeof e&&0===e.length?"date":null},function(e){return"string"===typeof e&&-1!=e.indexOf("<")&&-1!=e.indexOf(">")?"html":null}]);h.fn.DataTable=j;h.fn.dataTable=j;h.fn.dataTableSettings=j.settings;h.fn.dataTableExt=j.ext};"function"===typeof define&&define.amd?define(["jquery"],L):jQuery&&!jQuery.fn.dataTable&&
+L(jQuery)})(window,document);
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/MIT-license.txt b/asterix-examples/src/main/resources/core/js/easyXDM/MIT-license.txt
new file mode 100644
index 0000000..4320fb1
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/MIT-license.txt
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2009-2011 Øyvind Sean Kinsey, oyvind@kinsey.no
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/cors/index.html b/asterix-examples/src/main/resources/core/js/easyXDM/cors/index.html
new file mode 100644
index 0000000..9370e1d
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/cors/index.html
@@ -0,0 +1,214 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM cross-domain XHMLHttpRequest provider</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+            // This should be changed so that it points to the minified version before use in production.
+        </script>
+        <script type="text/javascript">
+            // Update to point to your copy
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript">
+        
+        /* 
+         * This is a CORS (Cross-Origin Resource Sharing) and AJAX enabled endpoint for easyXDM.
+         * The ACL code is adapted from pmxdr (http://github.com/eligrey/pmxdr/) by Eli Grey (http://eligrey.com/)
+         *
+         */
+        // From http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting
+        function isHostMethod(object, property){
+            var t = typeof object[property];
+            return t == 'function' ||
+            (!!(t == 'object' && object[property])) ||
+            t == 'unknown';
+        }
+        
+        /**
+         * Creates a cross-browser XMLHttpRequest object
+         * @return {XMLHttpRequest} A XMLHttpRequest object.
+         */
+        var getXhr = (function(){
+            if (isHostMethod(window, "XMLHttpRequest")) {
+                return function(){
+                    return new XMLHttpRequest();
+                };
+            }
+            else {
+                var item = (function(){
+                    var list = ["Microsoft", "Msxml2", "Msxml3"], i = list.length;
+                    while (i--) {
+                        try {
+                            item = list[i] + ".XMLHTTP";
+                            var obj = new ActiveXObject(item);
+                            return item;
+                        } 
+                        catch (e) {
+                        }
+                    }
+                }());
+                return function(){
+                    return new ActiveXObject(item);
+                };
+            }
+        }());
+        
+        // this file is by default set up to use Access Control - this means that it will use the headers set by the server to decide whether or not to allow the call to return
+        var useAccessControl = true;
+        // always trusted origins, can be exact strings or regular expressions
+        var alwaysTrustedOrigins = [(/\.?easyxdm\.net/), (/xdm1/)];
+        
+        // instantiate a new easyXDM object which will handle the request 
+        var remote = new easyXDM.Rpc({
+            local: "../name.html",
+            swf: "../easyxdm.swf"
+        }, {
+            local: {
+                // define the exposed method
+                request: function(config, success, error){
+                
+                    // apply default values if not set
+                    easyXDM.apply(config, {
+                        method: "POST",
+                        headers: {
+                            "Content-Type": "application/x-www-form-urlencoded",
+                            "X-Requested-With": "XMLHttpRequest"
+                        },
+                        success: Function.prototype,
+                        error: function(msg){
+                            throw new Error(msg);
+                        },
+                        data: {},
+                        timeout: 10 * 1000
+                    }, true);
+                    
+                    // set the CORS request header
+                    // only if there is no XHR2 features
+                    if (!window.XMLHttpRequest || !('withCredentials' in (new XMLHttpRequest))) {
+                        config.headers.Origin = remote.origin;
+                    }
+                    
+                    var isPOST = config.method == "POST";
+                    
+                    // convert the data into a format we can send to the server 
+                    var pairs = [];
+                    for (var key in config.data) {
+                        if (config.data.hasOwnProperty(key)) {
+                            pairs.push(encodeURIComponent(key) + "=" + encodeURIComponent(config.data[key]));
+                        }
+                    }
+                    var data = pairs.join("&");
+                    
+                    // create the XMLHttpRequest object
+                    var req = getXhr();
+                    var url = !isPOST && data
+                        ? config.url + (~config.url.indexOf('?') ? '&' : '?') + data
+                        : config.url;
+                    req.open(config.method, url, true);
+                    
+                    // apply the request headers
+                    for (var prop in config.headers) {
+                        if (config.headers.hasOwnProperty(prop) && config.headers[prop]) {
+                            req.setRequestHeader(prop, config.headers[prop]);
+                        }
+                    }
+                    
+                    // set a timeout
+                    var timeout;
+                    timeout = setTimeout(function(){
+                        // reset the handler
+                        req.onreadystatechange = Function.prototype;
+                        req.abort();
+                        req = null;
+                        error({
+                            message: "timeout after " + config.timeout + " second",
+                            status: 0,
+                            data: null,
+                            toString: function(){
+                                return this.message + " Status: " + this.status;
+                            }
+                        }, null);
+                    }, config.timeout);
+                    
+                    // check if this origin should always be trusted
+                    var alwaysTrusted = false, i = alwaysTrustedOrigins.length;
+                    while (i-- && !alwaysTrusted) {
+                        if (alwaysTrustedOrigins[i] instanceof RegExp) {
+                            alwaysTrusted = alwaysTrustedOrigins[i].test(remote.origin);
+                        }
+                        else if (typeof alwaysTrustedOrigins[i] == "string") {
+                            alwaysTrusted = (remote.origin === alwaysTrustedOrigins[i]);
+                        }
+                    }
+                    
+                    
+                    // define the onreadystate handler
+                    req.onreadystatechange = function(){
+                        if (req.readyState == 4) {
+                            clearTimeout(timeout);
+                            
+                            // parse the response headers
+                            var rawHeaders = req.getAllResponseHeaders(), headers = {}, headers_lowercase = {}, reHeader = /([\w-_]+):\s+(.*)$/gm, m;
+                            while ((m = reHeader.exec(rawHeaders))) {
+                                headers_lowercase[m[1].toLowerCase()] = headers[m[1]] = m[2];
+                            }
+                            
+                            if (req.status < 200 || req.status >= 300) {
+                                if (useAccessControl) {
+                                    error("INVALID_STATUS_CODE");
+                                }
+                                else {
+                                    error("INVALID_STATUS_CODE", {
+                                        status: req.status,
+                                        data: req.responseText
+                                    });
+                                }
+                            }
+                            else {
+                            
+                                var errorMessage;
+                                if (useAccessControl) {
+                                    // normalize the valuse access controls
+                                    var aclAllowedOrigin = (headers_lowercase["access-control-allow-origin"] || "").replace(/\s/g, "");
+                                    var aclAllowedMethods = (headers_lowercase["access-control-allow-methods"] || "").replace(/\s/g, "");
+                                    
+                                    // determine if origin is trusted
+                                    if (alwaysTrusted || aclAllowedOrigin == "*" || aclAllowedOrigin.indexOf(remote.origin) != -1) {
+                                        // determine if the request method was allowed
+                                        if (aclAllowedMethods && aclAllowedMethods != "*" && aclAllowedMethods.indexOf(config.method) == -1) {
+                                            errorMessage = "DISALLOWED_REQUEST_METHOD";
+                                        }
+                                    }
+                                    else {
+                                        errorMessage = "DISALLOWED_ORIGIN";
+                                    }
+                                    
+                                }
+                                
+                                if (errorMessage) {
+                                    error(errorMessage);
+                                }
+                                else {
+                                    success({
+                                        data: req.responseText,
+                                        status: req.status,
+                                        headers: headers
+                                    });
+                                }
+                            }
+                            // reset the handler
+                            req.onreadystatechange = Function.prototype;
+                            req = null;
+                        }
+                    };
+                    
+                    // issue the request
+                    req.send(isPOST ? data : "");
+                }
+            }
+        });
+        </script>
+    </head>
+    <body>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM-2.4.17.1.zip b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM-2.4.17.1.zip
new file mode 100644
index 0000000..c44301f
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM-2.4.17.1.zip
Binary files differ
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.Widgets.debug.js b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.Widgets.debug.js
new file mode 100644
index 0000000..7dcf4bd
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.Widgets.debug.js
@@ -0,0 +1,333 @@
+/**
+ * easyXDM
+ * http://easyxdm.net/
+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+/*jslint browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window */

+/**

+ * easyXDM

+ * http://easyxdm.net/

+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining a copy

+ * of this software and associated documentation files (the "Software"), to deal

+ * in the Software without restriction, including without limitation the rights

+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+ * copies of the Software, and to permit persons to whom the Software is

+ * furnished to do so, subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be included in

+ * all copies or substantial portions of the Software.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+ * THE SOFTWARE.

+ */

+/**

+ * @class easyXDM.WidgetManager

+ * A class for managing widgets.<br/>

+ * Handles initializing widgets, and does all of the message distribution.

+ <pre><code>

+ _widgetManager = new easyXDM.WidgetManager({

+ local: "../hash.html",

+ container: document.getElementById("defaultcontainer")

+ },function(){

+ _widgetManager.addWidget("http://provider.easyxdm.net/example/widget.html",{});

+ });

+ </code></pre>

+ * Widgets can by dynamically added using the addWidget method

+ <pre><code>

+ _widgetManager.addWidget("http://provider.easyxdm.net/example/widget.html",{

+ container document.getElementById("widgetcontainer")

+ });

+ </code></pre>

+ * @constructor

+ * @param {Object} config The WidgetManagers configuration

+ * @namespace easyXDM

+ */

+easyXDM.WidgetManager = function(config){

+    var WidgetManager = this, _hashUrl = config.local, _channelNr = 0;

+    var Events = {

+        WidgetInitialized: "widgetinitialized",

+        WidgetFailed: "widgetfailed"

+    };

+    var _widgets = {}, _subscribers = {};

+    var _widgetSettings = {

+        hosturl: location.href

+    };

+    easyXDM.apply(_widgetSettings, config.widgetSettings);

+    var _container = config.container || document.body;

+    

+    /**

+     * @private

+     * Raises the specified event

+     * @param {String} event The raised event

+     * @param {Object} arg

+     */

+    function _raiseEvent(event, arg){

+        if (config.listeners && config.listeners[event]) {

+            config.listeners[event](WidgetManager, arg);

+        }

+    }

+    

+    /**

+     * @private

+     * Adds the widghet to the list of subscribers for the given topic

+     * @param {String} url The widgets url

+     * @param {String} topic The topic to subscribe to

+     */

+    function _subscribe(url, topic){

+        if (!(topic in _subscribers)) {

+            _subscribers[topic] = [];

+        }

+        _subscribers[topic].push(url);

+    }

+    

+    /**

+     * @private

+     * Initialized the widget.<br/>

+     * This is called after the widget has notified that it is ready.

+     * @param {Object} widget The widget

+     * @param {String} url The widgets url

+     * @param {Object} widgetConfig The widgets configuration

+     */

+    function _initializeWidget(widget, url, widgetConfig){

+        widget.initialize(_widgetSettings, function(response){

+            if (response.isInitialized) {

+                _widgets[url] = widget;

+                var i = response.subscriptions.length;

+                while (i--) {

+                    _subscribe(url, response.subscriptions[i]);

+                }

+                _raiseEvent(Events.WidgetInitialized, {

+                    url: url

+                });

+            }

+            else {

+                widget.destroy();

+                _raiseEvent(Events.WidgetFailed, {

+                    url: url

+                });

+            }

+        });

+    }

+    

+    /**

+     * @private

+     * Publishes the data to the topics subscribers

+     * @param {String} url The senders url

+     * @param {String} topic The datas topic

+     * @param {Object} data The data to publish

+     */

+    function _publish(url, topic, data){

+        var subscribers = _subscribers[topic];

+        if (subscribers) {

+            var i = subscribers.length, widgetUrl;

+            while (i--) {

+                widgetUrl = subscribers[i];

+                if (widgetUrl !== url) {

+                    _widgets[widgetUrl].send(url, topic, data);

+                }

+            }

+        }

+    }

+    

+    /**

+     * @private

+     * Sets up a new widget

+     * @param {String} url The widgets url

+     * @param {Object} widgetConfig The widgets configuration

+     */

+    function _setUpWidget(url, widgetConfig){

+        var widget = new easyXDM.Rpc({

+            channel: "widget" + _channelNr++,

+            local: _hashUrl,

+            remote: url,

+            container: widgetConfig.container || _container,

+            swf: config.swf,

+            onReady: function(){

+                _initializeWidget(widget, url, widgetConfig);

+            }

+        }, {

+            local: {

+                subscribe: {

+                    isVoid: true,

+                    method: function(topic){

+                        _subscribe(url, topic);

+                    }

+                },

+                publish: {

+                    isVoid: true,

+                    method: function(topic, data){

+                        _publish(url, topic, data);

+                    }

+                }

+            },

+            remote: {

+                initialize: {},

+                send: {

+                    isVoid: true

+                }

+            }

+        });

+    }

+    

+    /**

+     * Adds a widget to the collection

+     * @param {String} url The url to load the widget from

+     * @param {Object} widgetConfig The widgets url

+     */

+    this.addWidget = function(url, widgetConfig){

+        if (url in _widgets) {

+            throw new Error("A widget with this url has already been initialized");

+        }

+        _setUpWidget(url, widgetConfig);

+    };

+    

+    /**

+     * Removes the widget

+     * @param {Object} url

+     */

+    this.removeWidget = function(url){

+        if (url in _widgets) {

+            for (var topic in _subscribers) {

+                if (_subscribers.hasOwnProperty(topic)) {

+                    var subscribers = _subscribers[topic], i = subscribers.length;

+                    while (i--) {

+                        if (subscribers[i] === url) {

+                            subscribers.splice(i, 1);

+                            break;

+                        }

+                    }

+                }

+            }

+            _widgets[url].destroy();

+            delete _widgets[url];

+        }

+    };

+    

+    /**

+     * Publish data to a topics subscribers

+     * @param {String} topic The topic to publish to

+     * @param {Object} data The data to publish

+     */

+    this.publish = function(topic, data){

+        _publish("", topic, data);

+    };

+    

+    /**

+     * Broadcasts data to all the widgets

+     * @param {Object} data The data to broadcast

+     */

+    this.broadcast = function(data){

+        for (var url in _widgets) {

+            if (_widgets.hasOwnPropert(url)) {

+                _widgets[url].send({

+                    url: "",

+                    topic: "broadcast",

+                    data: data

+                });

+            }

+        }

+    };

+};

+

+/**

+ * @class easyXDM.Widget

+ * The base framework for creating widgets

+ * @constructor

+ * @param {Object} config The widgets configuration

+ * @param {Function} onReady A method to run after the widget has been initialized.

+ * @namespace easyXDM

+ */

+easyXDM.Widget = function(config){

+    var _widget = this;

+    var _incomingMessageHandler;

+    var _widgetHost = new easyXDM.Rpc({

+        swf: config.swf

+    }, {

+        remote: {

+            subscribe: {

+                isVoid: true

+            },

+            publish: {

+                isVoid: true

+            }

+        },

+        local: {

+            initialize: {

+                method: function(settings){

+                    config.initialized(_widget, _widgetHost);

+                    return {

+                        isInitialized: true,

+                        subscriptions: config.subscriptions

+                    };

+                }

+            },

+            send: {

+                isVoid: true,

+                method: function(url, topic, data){

+                    _incomingMessageHandler(url, topic, data);

+                }

+            }

+        }

+    });

+    

+    /**

+     * @private

+     * Destroy the interface on unload

+     */

+    window.onunload = function(){

+        _widgetHost.destroy();

+    };

+    

+    /**

+     * Publish data to subscribers to a topic

+     * @param {String} topic The topic to publish to

+     * @param {Object} data The data to publish

+     */

+    this.publish = function(topic, data){

+        _widgetHost.publish(topic, data);

+    };

+    

+    /**

+     * Subscribe to a topic

+     * @param {String} topic The topic to subscribe to

+     */

+    this.subscribe = function(topic){

+        _widgetHost.subscribe(topic);

+    };

+    

+    /**

+     * Register the method that will handle incoming messages

+     * @param {Function} fn The handler

+     */

+    this.registerMessageHandler = function(fn){

+        _incomingMessageHandler = fn;

+    };

+    

+    config.initialize(this, _widgetHost);

+};

diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.Widgets.js b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.Widgets.js
new file mode 100644
index 0000000..7dcf4bd
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.Widgets.js
@@ -0,0 +1,333 @@
+/**
+ * easyXDM
+ * http://easyxdm.net/
+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+/*jslint browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window */

+/**

+ * easyXDM

+ * http://easyxdm.net/

+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining a copy

+ * of this software and associated documentation files (the "Software"), to deal

+ * in the Software without restriction, including without limitation the rights

+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+ * copies of the Software, and to permit persons to whom the Software is

+ * furnished to do so, subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be included in

+ * all copies or substantial portions of the Software.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+ * THE SOFTWARE.

+ */

+/**

+ * @class easyXDM.WidgetManager

+ * A class for managing widgets.<br/>

+ * Handles initializing widgets, and does all of the message distribution.

+ <pre><code>

+ _widgetManager = new easyXDM.WidgetManager({

+ local: "../hash.html",

+ container: document.getElementById("defaultcontainer")

+ },function(){

+ _widgetManager.addWidget("http://provider.easyxdm.net/example/widget.html",{});

+ });

+ </code></pre>

+ * Widgets can by dynamically added using the addWidget method

+ <pre><code>

+ _widgetManager.addWidget("http://provider.easyxdm.net/example/widget.html",{

+ container document.getElementById("widgetcontainer")

+ });

+ </code></pre>

+ * @constructor

+ * @param {Object} config The WidgetManagers configuration

+ * @namespace easyXDM

+ */

+easyXDM.WidgetManager = function(config){

+    var WidgetManager = this, _hashUrl = config.local, _channelNr = 0;

+    var Events = {

+        WidgetInitialized: "widgetinitialized",

+        WidgetFailed: "widgetfailed"

+    };

+    var _widgets = {}, _subscribers = {};

+    var _widgetSettings = {

+        hosturl: location.href

+    };

+    easyXDM.apply(_widgetSettings, config.widgetSettings);

+    var _container = config.container || document.body;

+    

+    /**

+     * @private

+     * Raises the specified event

+     * @param {String} event The raised event

+     * @param {Object} arg

+     */

+    function _raiseEvent(event, arg){

+        if (config.listeners && config.listeners[event]) {

+            config.listeners[event](WidgetManager, arg);

+        }

+    }

+    

+    /**

+     * @private

+     * Adds the widghet to the list of subscribers for the given topic

+     * @param {String} url The widgets url

+     * @param {String} topic The topic to subscribe to

+     */

+    function _subscribe(url, topic){

+        if (!(topic in _subscribers)) {

+            _subscribers[topic] = [];

+        }

+        _subscribers[topic].push(url);

+    }

+    

+    /**

+     * @private

+     * Initialized the widget.<br/>

+     * This is called after the widget has notified that it is ready.

+     * @param {Object} widget The widget

+     * @param {String} url The widgets url

+     * @param {Object} widgetConfig The widgets configuration

+     */

+    function _initializeWidget(widget, url, widgetConfig){

+        widget.initialize(_widgetSettings, function(response){

+            if (response.isInitialized) {

+                _widgets[url] = widget;

+                var i = response.subscriptions.length;

+                while (i--) {

+                    _subscribe(url, response.subscriptions[i]);

+                }

+                _raiseEvent(Events.WidgetInitialized, {

+                    url: url

+                });

+            }

+            else {

+                widget.destroy();

+                _raiseEvent(Events.WidgetFailed, {

+                    url: url

+                });

+            }

+        });

+    }

+    

+    /**

+     * @private

+     * Publishes the data to the topics subscribers

+     * @param {String} url The senders url

+     * @param {String} topic The datas topic

+     * @param {Object} data The data to publish

+     */

+    function _publish(url, topic, data){

+        var subscribers = _subscribers[topic];

+        if (subscribers) {

+            var i = subscribers.length, widgetUrl;

+            while (i--) {

+                widgetUrl = subscribers[i];

+                if (widgetUrl !== url) {

+                    _widgets[widgetUrl].send(url, topic, data);

+                }

+            }

+        }

+    }

+    

+    /**

+     * @private

+     * Sets up a new widget

+     * @param {String} url The widgets url

+     * @param {Object} widgetConfig The widgets configuration

+     */

+    function _setUpWidget(url, widgetConfig){

+        var widget = new easyXDM.Rpc({

+            channel: "widget" + _channelNr++,

+            local: _hashUrl,

+            remote: url,

+            container: widgetConfig.container || _container,

+            swf: config.swf,

+            onReady: function(){

+                _initializeWidget(widget, url, widgetConfig);

+            }

+        }, {

+            local: {

+                subscribe: {

+                    isVoid: true,

+                    method: function(topic){

+                        _subscribe(url, topic);

+                    }

+                },

+                publish: {

+                    isVoid: true,

+                    method: function(topic, data){

+                        _publish(url, topic, data);

+                    }

+                }

+            },

+            remote: {

+                initialize: {},

+                send: {

+                    isVoid: true

+                }

+            }

+        });

+    }

+    

+    /**

+     * Adds a widget to the collection

+     * @param {String} url The url to load the widget from

+     * @param {Object} widgetConfig The widgets url

+     */

+    this.addWidget = function(url, widgetConfig){

+        if (url in _widgets) {

+            throw new Error("A widget with this url has already been initialized");

+        }

+        _setUpWidget(url, widgetConfig);

+    };

+    

+    /**

+     * Removes the widget

+     * @param {Object} url

+     */

+    this.removeWidget = function(url){

+        if (url in _widgets) {

+            for (var topic in _subscribers) {

+                if (_subscribers.hasOwnProperty(topic)) {

+                    var subscribers = _subscribers[topic], i = subscribers.length;

+                    while (i--) {

+                        if (subscribers[i] === url) {

+                            subscribers.splice(i, 1);

+                            break;

+                        }

+                    }

+                }

+            }

+            _widgets[url].destroy();

+            delete _widgets[url];

+        }

+    };

+    

+    /**

+     * Publish data to a topics subscribers

+     * @param {String} topic The topic to publish to

+     * @param {Object} data The data to publish

+     */

+    this.publish = function(topic, data){

+        _publish("", topic, data);

+    };

+    

+    /**

+     * Broadcasts data to all the widgets

+     * @param {Object} data The data to broadcast

+     */

+    this.broadcast = function(data){

+        for (var url in _widgets) {

+            if (_widgets.hasOwnPropert(url)) {

+                _widgets[url].send({

+                    url: "",

+                    topic: "broadcast",

+                    data: data

+                });

+            }

+        }

+    };

+};

+

+/**

+ * @class easyXDM.Widget

+ * The base framework for creating widgets

+ * @constructor

+ * @param {Object} config The widgets configuration

+ * @param {Function} onReady A method to run after the widget has been initialized.

+ * @namespace easyXDM

+ */

+easyXDM.Widget = function(config){

+    var _widget = this;

+    var _incomingMessageHandler;

+    var _widgetHost = new easyXDM.Rpc({

+        swf: config.swf

+    }, {

+        remote: {

+            subscribe: {

+                isVoid: true

+            },

+            publish: {

+                isVoid: true

+            }

+        },

+        local: {

+            initialize: {

+                method: function(settings){

+                    config.initialized(_widget, _widgetHost);

+                    return {

+                        isInitialized: true,

+                        subscriptions: config.subscriptions

+                    };

+                }

+            },

+            send: {

+                isVoid: true,

+                method: function(url, topic, data){

+                    _incomingMessageHandler(url, topic, data);

+                }

+            }

+        }

+    });

+    

+    /**

+     * @private

+     * Destroy the interface on unload

+     */

+    window.onunload = function(){

+        _widgetHost.destroy();

+    };

+    

+    /**

+     * Publish data to subscribers to a topic

+     * @param {String} topic The topic to publish to

+     * @param {Object} data The data to publish

+     */

+    this.publish = function(topic, data){

+        _widgetHost.publish(topic, data);

+    };

+    

+    /**

+     * Subscribe to a topic

+     * @param {String} topic The topic to subscribe to

+     */

+    this.subscribe = function(topic){

+        _widgetHost.subscribe(topic);

+    };

+    

+    /**

+     * Register the method that will handle incoming messages

+     * @param {Function} fn The handler

+     */

+    this.registerMessageHandler = function(fn){

+        _incomingMessageHandler = fn;

+    };

+    

+    config.initialize(this, _widgetHost);

+};

diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.Widgets.min.js b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.Widgets.min.js
new file mode 100644
index 0000000..8ed55cd
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.Widgets.min.js
@@ -0,0 +1,24 @@
+/**
+ * easyXDM
+ * http://easyxdm.net/
+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+easyXDM.WidgetManager=function(e){var h=this,b=e.local,k=0;var n={WidgetInitialized:"widgetinitialized",WidgetFailed:"widgetfailed"};var j={},d={};var i={hosturl:location.href};easyXDM.apply(i,e.widgetSettings);var g=e.container||document.body;function f(p,o){if(e.listeners&&e.listeners[p]){e.listeners[p](h,o)}}function c(p,o){if(!(o in d)){d[o]=[]}d[o].push(p)}function m(p,o,q){p.initialize(i,function(r){if(r.isInitialized){j[o]=p;var s=r.subscriptions.length;while(s--){c(o,r.subscriptions[s])}f(n.WidgetInitialized,{url:o})}else{p.destroy();f(n.WidgetFailed,{url:o})}})}function a(p,o,r){var s=d[o];if(s){var q=s.length,t;while(q--){t=s[q];if(t!==p){j[t].send(p,o,r)}}}}function l(o,q){var p=new easyXDM.Rpc({channel:"widget"+k++,local:b,remote:o,container:q.container||g,swf:e.swf,onReady:function(){m(p,o,q)}},{local:{subscribe:{isVoid:true,method:function(r){c(o,r)}},publish:{isVoid:true,method:function(r,s){a(o,r,s)}}},remote:{initialize:{},send:{isVoid:true}}})}this.addWidget=function(o,p){if(o in j){throw new Error("A widget with this url has already been initialized")}l(o,p)};this.removeWidget=function(p){if(p in j){for(var o in d){if(d.hasOwnProperty(o)){var r=d[o],q=r.length;while(q--){if(r[q]===p){r.splice(q,1);break}}}}j[p].destroy();delete j[p]}};this.publish=function(o,p){a("",o,p)};this.broadcast=function(p){for(var o in j){if(j.hasOwnPropert(o)){j[o].send({url:"",topic:"broadcast",data:p})}}}};easyXDM.Widget=function(c){var a=this;var b;var d=new easyXDM.Rpc({swf:c.swf},{remote:{subscribe:{isVoid:true},publish:{isVoid:true}},local:{initialize:{method:function(e){c.initialized(a,d);return{isInitialized:true,subscriptions:c.subscriptions}}},send:{isVoid:true,method:function(f,e,g){b(f,e,g)}}}});window.onunload=function(){d.destroy()};this.publish=function(e,f){d.publish(e,f)};this.subscribe=function(e){d.subscribe(e)};this.registerMessageHandler=function(e){b=e};c.initialize(this,d)};
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.debug.js b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.debug.js
new file mode 100644
index 0000000..61b9738
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.debug.js
@@ -0,0 +1,2871 @@
+/**
+ * easyXDM
+ * http://easyxdm.net/
+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+(function (window, document, location, setTimeout, decodeURIComponent, encodeURIComponent) {

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global JSON, XMLHttpRequest, window, escape, unescape, ActiveXObject */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+var global = this;

+var channelId = Math.floor(Math.random() * 10000); // randomize the initial id in case of multiple closures loaded 

+var emptyFn = Function.prototype;

+var reURI = /^((http.?:)\/\/([^:\/\s]+)(:\d+)*)/; // returns groups for protocol (2), domain (3) and port (4) 

+var reParent = /[\-\w]+\/\.\.\//; // matches a foo/../ expression 

+var reDoubleSlash = /([^:])\/\//g; // matches // anywhere but in the protocol

+var namespace = ""; // stores namespace under which easyXDM object is stored on the page (empty if object is global)

+var easyXDM = {};

+var _easyXDM = window.easyXDM; // map over global easyXDM in case of overwrite

+var IFRAME_PREFIX = "easyXDM_";

+var HAS_NAME_PROPERTY_BUG;

+var useHash = false; // whether to use the hash over the query

+var flashVersion; // will be set if using flash

+var HAS_FLASH_THROTTLED_BUG;

+var _trace = emptyFn;

+

+

+// http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting

+function isHostMethod(object, property){

+    var t = typeof object[property];

+    return t == 'function' ||

+    (!!(t == 'object' && object[property])) ||

+    t == 'unknown';

+}

+

+function isHostObject(object, property){

+    return !!(typeof(object[property]) == 'object' && object[property]);

+}

+

+// end

+

+// http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/

+function isArray(o){

+    return Object.prototype.toString.call(o) === '[object Array]';

+}

+

+// end

+function hasFlash(){

+    var name = "Shockwave Flash", mimeType = "application/x-shockwave-flash";

+    

+    if (!undef(navigator.plugins) && typeof navigator.plugins[name] == "object") {

+        // adapted from the swfobject code

+        var description = navigator.plugins[name].description;

+        if (description && !undef(navigator.mimeTypes) && navigator.mimeTypes[mimeType] && navigator.mimeTypes[mimeType].enabledPlugin) {

+            flashVersion = description.match(/\d+/g);

+        }

+    }

+    if (!flashVersion) {

+        var flash;

+        try {

+            flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");

+            flashVersion = Array.prototype.slice.call(flash.GetVariable("$version").match(/(\d+),(\d+),(\d+),(\d+)/), 1);

+            flash = null;

+        } 

+        catch (notSupportedException) {

+        }

+    }

+    if (!flashVersion) {

+        return false;

+    }

+    var major = parseInt(flashVersion[0], 10), minor = parseInt(flashVersion[1], 10);

+    HAS_FLASH_THROTTLED_BUG = major > 9 && minor > 0;

+    return true;

+}

+

+/*

+ * Cross Browser implementation for adding and removing event listeners.

+ */

+var on, un;

+if (isHostMethod(window, "addEventListener")) {

+    on = function(target, type, listener){

+        _trace("adding listener " + type);

+        target.addEventListener(type, listener, false);

+    };

+    un = function(target, type, listener){

+        _trace("removing listener " + type);

+        target.removeEventListener(type, listener, false);

+    };

+}

+else if (isHostMethod(window, "attachEvent")) {

+    on = function(object, sEvent, fpNotify){

+        _trace("adding listener " + sEvent);

+        object.attachEvent("on" + sEvent, fpNotify);

+    };

+    un = function(object, sEvent, fpNotify){

+        _trace("removing listener " + sEvent);

+        object.detachEvent("on" + sEvent, fpNotify);

+    };

+}

+else {

+    throw new Error("Browser not supported");

+}

+

+/*

+ * Cross Browser implementation of DOMContentLoaded.

+ */

+var domIsReady = false, domReadyQueue = [], readyState;

+if ("readyState" in document) {

+    // If browser is WebKit-powered, check for both 'loaded' (legacy browsers) and

+    // 'interactive' (HTML5 specs, recent WebKit builds) states.

+    // https://bugs.webkit.org/show_bug.cgi?id=45119

+    readyState = document.readyState;

+    domIsReady = readyState == "complete" || (~ navigator.userAgent.indexOf('AppleWebKit/') && (readyState == "loaded" || readyState == "interactive"));

+}

+else {

+    // If readyState is not supported in the browser, then in order to be able to fire whenReady functions apropriately

+    // when added dynamically _after_ DOM load, we have to deduce wether the DOM is ready or not.

+    // We only need a body to add elements to, so the existence of document.body is enough for us.

+    domIsReady = !!document.body;

+}

+

+function dom_onReady(){

+    if (domIsReady) {

+        return;

+    }

+    domIsReady = true;

+    _trace("firing dom_onReady");

+    for (var i = 0; i < domReadyQueue.length; i++) {

+        domReadyQueue[i]();

+    }

+    domReadyQueue.length = 0;

+}

+

+

+if (!domIsReady) {

+    if (isHostMethod(window, "addEventListener")) {

+        on(document, "DOMContentLoaded", dom_onReady);

+    }

+    else {

+        on(document, "readystatechange", function(){

+            if (document.readyState == "complete") {

+                dom_onReady();

+            }

+        });

+        if (document.documentElement.doScroll && window === top) {

+            var doScrollCheck = function(){

+                if (domIsReady) {

+                    return;

+                }

+                // http://javascript.nwbox.com/IEContentLoaded/

+                try {

+                    document.documentElement.doScroll("left");

+                } 

+                catch (e) {

+                    setTimeout(doScrollCheck, 1);

+                    return;

+                }

+                dom_onReady();

+            };

+            doScrollCheck();

+        }

+    }

+    

+    // A fallback to window.onload, that will always work

+    on(window, "load", dom_onReady);

+}

+/**

+ * This will add a function to the queue of functions to be run once the DOM reaches a ready state.

+ * If functions are added after this event then they will be executed immediately.

+ * @param {function} fn The function to add

+ * @param {Object} scope An optional scope for the function to be called with.

+ */

+function whenReady(fn, scope){

+    if (domIsReady) {

+        fn.call(scope);

+        return;

+    }

+    domReadyQueue.push(function(){

+        fn.call(scope);

+    });

+}

+

+/**

+ * Returns an instance of easyXDM from the parent window with

+ * respect to the namespace.

+ *

+ * @return An instance of easyXDM (in the parent window)

+ */

+function getParentObject(){

+    var obj = parent;

+    if (namespace !== "") {

+        for (var i = 0, ii = namespace.split("."); i < ii.length; i++) {

+            if (!obj) {

+                throw new Error(ii.slice(0, i + 1).join('.') + ' is not an object');

+            }

+            obj = obj[ii[i]];

+        }

+    }

+    if (!obj || !obj.easyXDM) {

+        throw new Error('Could not find easyXDM in parent.' + namespace);

+    }

+    return obj.easyXDM;

+}

+

+/**

+ * Removes easyXDM variable from the global scope. It also returns control

+ * of the easyXDM variable to whatever code used it before.

+ *

+ * @param {String} ns A string representation of an object that will hold

+ *                    an instance of easyXDM.

+ * @return An instance of easyXDM

+ */

+function noConflict(ns){

+    if (typeof ns != "string" || !ns) {

+        throw new Error('namespace must be a non-empty string');

+    }

+    _trace("Settings namespace to '" + ns + "'");

+    

+    window.easyXDM = _easyXDM;

+    namespace = ns;

+    if (namespace) {

+        IFRAME_PREFIX = "easyXDM_" + namespace.replace(".", "_") + "_";

+    }

+    return easyXDM;

+}

+

+/*

+ * Methods for working with URLs

+ */

+/**

+ * Get the domain name from a url.

+ * @param {String} url The url to extract the domain from.

+ * @return The domain part of the url.

+ * @type {String}

+ */

+function getDomainName(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    return url.match(reURI)[3];

+}

+

+/**

+ * Get the port for a given URL, or "" if none

+ * @param {String} url The url to extract the port from.

+ * @return The port part of the url.

+ * @type {String}

+ */

+function getPort(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    return url.match(reURI)[4] || "";

+}

+

+/**

+ * Returns  a string containing the schema, domain and if present the port

+ * @param {String} url The url to extract the location from

+ * @return {String} The location part of the url

+ */

+function getLocation(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    if (/^file/.test(url)) {

+        throw new Error("The file:// protocol is not supported");

+    }

+    var m = url.toLowerCase().match(reURI);

+    var proto = m[2], domain = m[3], port = m[4] || "";

+    if ((proto == "http:" && port == ":80") || (proto == "https:" && port == ":443")) {

+        port = "";

+    }

+    return proto + "//" + domain + port;

+}

+

+/**

+ * Resolves a relative url into an absolute one.

+ * @param {String} url The path to resolve.

+ * @return {String} The resolved url.

+ */

+function resolveUrl(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    

+    // replace all // except the one in proto with /

+    url = url.replace(reDoubleSlash, "$1/");

+    

+    // If the url is a valid url we do nothing

+    if (!url.match(/^(http||https):\/\//)) {

+        // If this is a relative path

+        var path = (url.substring(0, 1) === "/") ? "" : location.pathname;

+        if (path.substring(path.length - 1) !== "/") {

+            path = path.substring(0, path.lastIndexOf("/") + 1);

+        }

+        

+        url = location.protocol + "//" + location.host + path + url;

+    }

+    

+    // reduce all 'xyz/../' to just '' 

+    while (reParent.test(url)) {

+        url = url.replace(reParent, "");

+    }

+    

+    _trace("resolved url '" + url + "'");

+    return url;

+}

+

+/**

+ * Appends the parameters to the given url.<br/>

+ * The base url can contain existing query parameters.

+ * @param {String} url The base url.

+ * @param {Object} parameters The parameters to add.

+ * @return {String} A new valid url with the parameters appended.

+ */

+function appendQueryParameters(url, parameters){

+    if (!parameters) {

+        throw new Error("parameters is undefined or null");

+    }

+    

+    var hash = "", indexOf = url.indexOf("#");

+    if (indexOf !== -1) {

+        hash = url.substring(indexOf);

+        url = url.substring(0, indexOf);

+    }

+    var q = [];

+    for (var key in parameters) {

+        if (parameters.hasOwnProperty(key)) {

+            q.push(key + "=" + encodeURIComponent(parameters[key]));

+        }

+    }

+    return url + (useHash ? "#" : (url.indexOf("?") == -1 ? "?" : "&")) + q.join("&") + hash;

+}

+

+

+// build the query object either from location.query, if it contains the xdm_e argument, or from location.hash

+var query = (function(input){

+    input = input.substring(1).split("&");

+    var data = {}, pair, i = input.length;

+    while (i--) {

+        pair = input[i].split("=");

+        data[pair[0]] = decodeURIComponent(pair[1]);

+    }

+    return data;

+}(/xdm_e=/.test(location.search) ? location.search : location.hash));

+

+/*

+ * Helper methods

+ */

+/**

+ * Helper for checking if a variable/property is undefined

+ * @param {Object} v The variable to test

+ * @return {Boolean} True if the passed variable is undefined

+ */

+function undef(v){

+    return typeof v === "undefined";

+}

+

+/**

+ * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.

+ * @return {JSON} A valid JSON conforming object, or null if not found.

+ */

+var getJSON = function(){

+    var cached = {};

+    var obj = {

+        a: [1, 2, 3]

+    }, json = "{\"a\":[1,2,3]}";

+    

+    if (typeof JSON != "undefined" && typeof JSON.stringify === "function" && JSON.stringify(obj).replace((/\s/g), "") === json) {

+        // this is a working JSON instance

+        return JSON;

+    }

+    if (Object.toJSON) {

+        if (Object.toJSON(obj).replace((/\s/g), "") === json) {

+            // this is a working stringify method

+            cached.stringify = Object.toJSON;

+        }

+    }

+    

+    if (typeof String.prototype.evalJSON === "function") {

+        obj = json.evalJSON();

+        if (obj.a && obj.a.length === 3 && obj.a[2] === 3) {

+            // this is a working parse method           

+            cached.parse = function(str){

+                return str.evalJSON();

+            };

+        }

+    }

+    

+    if (cached.stringify && cached.parse) {

+        // Only memoize the result if we have valid instance

+        getJSON = function(){

+            return cached;

+        };

+        return cached;

+    }

+    return null;

+};

+

+/**

+ * Applies properties from the source object to the target object.<br/>

+ * @param {Object} target The target of the properties.

+ * @param {Object} source The source of the properties.

+ * @param {Boolean} noOverwrite Set to True to only set non-existing properties.

+ */

+function apply(destination, source, noOverwrite){

+    var member;

+    for (var prop in source) {

+        if (source.hasOwnProperty(prop)) {

+            if (prop in destination) {

+                member = source[prop];

+                if (typeof member === "object") {

+                    apply(destination[prop], member, noOverwrite);

+                }

+                else if (!noOverwrite) {

+                    destination[prop] = source[prop];

+                }

+            }

+            else {

+                destination[prop] = source[prop];

+            }

+        }

+    }

+    return destination;

+}

+

+// This tests for the bug in IE where setting the [name] property using javascript causes the value to be redirected into [submitName].

+function testForNamePropertyBug(){

+    var form = document.body.appendChild(document.createElement("form")), input = form.appendChild(document.createElement("input"));

+    input.name = IFRAME_PREFIX + "TEST" + channelId; // append channelId in order to avoid caching issues

+    HAS_NAME_PROPERTY_BUG = input !== form.elements[input.name];

+    document.body.removeChild(form);

+    _trace("HAS_NAME_PROPERTY_BUG: " + HAS_NAME_PROPERTY_BUG);

+}

+

+/**

+ * Creates a frame and appends it to the DOM.

+ * @param config {object} This object can have the following properties

+ * <ul>

+ * <li> {object} prop The properties that should be set on the frame. This should include the 'src' property.</li>

+ * <li> {object} attr The attributes that should be set on the frame.</li>

+ * <li> {DOMElement} container Its parent element (Optional).</li>

+ * <li> {function} onLoad A method that should be called with the frames contentWindow as argument when the frame is fully loaded. (Optional)</li>

+ * </ul>

+ * @return The frames DOMElement

+ * @type DOMElement

+ */

+function createFrame(config){

+    _trace("creating frame: " + config.props.src);

+    if (undef(HAS_NAME_PROPERTY_BUG)) {

+        testForNamePropertyBug();

+    }

+    var frame;

+    // This is to work around the problems in IE6/7 with setting the name property. 

+    // Internally this is set as 'submitName' instead when using 'iframe.name = ...'

+    // This is not required by easyXDM itself, but is to facilitate other use cases 

+    if (HAS_NAME_PROPERTY_BUG) {

+        frame = document.createElement("<iframe name=\"" + config.props.name + "\"/>");

+    }

+    else {

+        frame = document.createElement("IFRAME");

+        frame.name = config.props.name;

+    }

+    

+    frame.id = frame.name = config.props.name;

+    delete config.props.name;

+    

+    if (typeof config.container == "string") {

+        config.container = document.getElementById(config.container);

+    }

+    

+    if (!config.container) {

+        // This needs to be hidden like this, simply setting display:none and the like will cause failures in some browsers.

+        apply(frame.style, {

+            position: "absolute",

+            top: "-2000px",

+            // Avoid potential horizontal scrollbar

+            left: "0px"

+        });

+        config.container = document.body;

+    }

+    

+    // HACK: IE cannot have the src attribute set when the frame is appended

+    //       into the container, so we set it to "javascript:false" as a

+    //       placeholder for now.  If we left the src undefined, it would

+    //       instead default to "about:blank", which causes SSL mixed-content

+    //       warnings in IE6 when on an SSL parent page.

+    var src = config.props.src;

+    config.props.src = "javascript:false";

+    

+    // transfer properties to the frame

+    apply(frame, config.props);

+    

+    frame.border = frame.frameBorder = 0;

+    frame.allowTransparency = true;

+    config.container.appendChild(frame);

+    

+    if (config.onLoad) {

+        on(frame, "load", config.onLoad);

+    }

+    

+    // set the frame URL to the proper value (we previously set it to

+    // "javascript:false" to work around the IE issue mentioned above)

+    if(config.usePost) {

+        var form = config.container.appendChild(document.createElement('form')), input;

+        form.target = frame.name;

+        form.action = src;

+        form.method = 'POST';

+        if (typeof(config.usePost) === 'object') {

+            for (var i in config.usePost) {

+                if (config.usePost.hasOwnProperty(i)) {

+                    if (HAS_NAME_PROPERTY_BUG) {

+                        input = document.createElement('<input name="' + i + '"/>');

+                    } else {

+                        input = document.createElement("INPUT");

+                        input.name = i;

+                    }

+                    input.value = config.usePost[i];

+                    form.appendChild(input);

+                }

+            }

+        }

+        form.submit();

+        form.parentNode.removeChild(form);

+    } else {

+        frame.src = src;

+    }

+    config.props.src = src;

+    

+    return frame;

+}

+

+/**

+ * Check whether a domain is allowed using an Access Control List.

+ * The ACL can contain * and ? as wildcards, or can be regular expressions.

+ * If regular expressions they need to begin with ^ and end with $.

+ * @param {Array/String} acl The list of allowed domains

+ * @param {String} domain The domain to test.

+ * @return {Boolean} True if the domain is allowed, false if not.

+ */

+function checkAcl(acl, domain){

+    // normalize into an array

+    if (typeof acl == "string") {

+        acl = [acl];

+    }

+    var re, i = acl.length;

+    while (i--) {

+        re = acl[i];

+        re = new RegExp(re.substr(0, 1) == "^" ? re : ("^" + re.replace(/(\*)/g, ".$1").replace(/\?/g, ".") + "$"));

+        if (re.test(domain)) {

+            return true;

+        }

+    }

+    return false;

+}

+

+/*

+ * Functions related to stacks

+ */

+/**

+ * Prepares an array of stack-elements suitable for the current configuration

+ * @param {Object} config The Transports configuration. See easyXDM.Socket for more.

+ * @return {Array} An array of stack-elements with the TransportElement at index 0.

+ */

+function prepareTransportStack(config){

+    var protocol = config.protocol, stackEls;

+    config.isHost = config.isHost || undef(query.xdm_p);

+    useHash = config.hash || false;

+    _trace("preparing transport stack");

+    

+    if (!config.props) {

+        config.props = {};

+    }

+    if (!config.isHost) {

+        _trace("using parameters from query");

+        config.channel = query.xdm_c.replace(/["'<>\\]/g, "");

+        config.secret = query.xdm_s;

+        config.remote = query.xdm_e.replace(/["'<>\\]/g, "");

+        ;

+        protocol = query.xdm_p;

+        if (config.acl && !checkAcl(config.acl, config.remote)) {

+            throw new Error("Access denied for " + config.remote);

+        }

+    }

+    else {

+        config.remote = resolveUrl(config.remote);

+        config.channel = config.channel || "default" + channelId++;

+        config.secret = Math.random().toString(16).substring(2);

+        if (undef(protocol)) {

+            if (getLocation(location.href) == getLocation(config.remote)) {

+                /*

+                 * Both documents has the same origin, lets use direct access.

+                 */

+                protocol = "4";

+            }

+            else if (isHostMethod(window, "postMessage") || isHostMethod(document, "postMessage")) {

+                /*

+                 * This is supported in IE8+, Firefox 3+, Opera 9+, Chrome 2+ and Safari 4+

+                 */

+                protocol = "1";

+            }

+            else if (config.swf && isHostMethod(window, "ActiveXObject") && hasFlash()) {

+                /*

+                 * The Flash transport superseedes the NixTransport as the NixTransport has been blocked by MS

+                 */

+                protocol = "6";

+            }

+            else if (navigator.product === "Gecko" && "frameElement" in window && navigator.userAgent.indexOf('WebKit') == -1) {

+                /*

+                 * This is supported in Gecko (Firefox 1+)

+                 */

+                protocol = "5";

+            }

+            else if (config.remoteHelper) {

+                /*

+                 * This is supported in all browsers that retains the value of window.name when

+                 * navigating from one domain to another, and where parent.frames[foo] can be used

+                 * to get access to a frame from the same domain

+                 */

+                protocol = "2";

+            }

+            else {

+                /*

+                 * This is supported in all browsers where [window].location is writable for all

+                 * The resize event will be used if resize is supported and the iframe is not put

+                 * into a container, else polling will be used.

+                 */

+                protocol = "0";

+            }

+            _trace("selecting protocol: " + protocol);

+        }

+        else {

+            _trace("using protocol: " + protocol);

+        }

+    }

+    config.protocol = protocol; // for conditional branching

+    switch (protocol) {

+        case "0":// 0 = HashTransport

+            apply(config, {

+                interval: 100,

+                delay: 2000,

+                useResize: true,

+                useParent: false,

+                usePolling: false

+            }, true);

+            if (config.isHost) {

+                if (!config.local) {

+                    _trace("looking for image to use as local");

+                    // If no local is set then we need to find an image hosted on the current domain

+                    var domain = location.protocol + "//" + location.host, images = document.body.getElementsByTagName("img"), image;

+                    var i = images.length;

+                    while (i--) {

+                        image = images[i];

+                        if (image.src.substring(0, domain.length) === domain) {

+                            config.local = image.src;

+                            break;

+                        }

+                    }

+                    if (!config.local) {

+                        _trace("no image found, defaulting to using the window");

+                        // If no local was set, and we are unable to find a suitable file, then we resort to using the current window 

+                        config.local = window;

+                    }

+                }

+                

+                var parameters = {

+                    xdm_c: config.channel,

+                    xdm_p: 0

+                };

+                

+                if (config.local === window) {

+                    // We are using the current window to listen to

+                    config.usePolling = true;

+                    config.useParent = true;

+                    config.local = location.protocol + "//" + location.host + location.pathname + location.search;

+                    parameters.xdm_e = config.local;

+                    parameters.xdm_pa = 1; // use parent

+                }

+                else {

+                    parameters.xdm_e = resolveUrl(config.local);

+                }

+                

+                if (config.container) {

+                    config.useResize = false;

+                    parameters.xdm_po = 1; // use polling

+                }

+                config.remote = appendQueryParameters(config.remote, parameters);

+            }

+            else {

+                apply(config, {

+                    channel: query.xdm_c,

+                    remote: query.xdm_e,

+                    useParent: !undef(query.xdm_pa),

+                    usePolling: !undef(query.xdm_po),

+                    useResize: config.useParent ? false : config.useResize

+                });

+            }

+            stackEls = [new easyXDM.stack.HashTransport(config), new easyXDM.stack.ReliableBehavior({}), new easyXDM.stack.QueueBehavior({

+                encode: true,

+                maxLength: 4000 - config.remote.length

+            }), new easyXDM.stack.VerifyBehavior({

+                initiate: config.isHost

+            })];

+            break;

+        case "1":

+            stackEls = [new easyXDM.stack.PostMessageTransport(config)];

+            break;

+        case "2":

+            config.remoteHelper = resolveUrl(config.remoteHelper);

+            stackEls = [new easyXDM.stack.NameTransport(config), new easyXDM.stack.QueueBehavior(), new easyXDM.stack.VerifyBehavior({

+                initiate: config.isHost

+            })];

+            break;

+        case "3":

+            stackEls = [new easyXDM.stack.NixTransport(config)];

+            break;

+        case "4":

+            stackEls = [new easyXDM.stack.SameOriginTransport(config)];

+            break;

+        case "5":

+            stackEls = [new easyXDM.stack.FrameElementTransport(config)];

+            break;

+        case "6":

+            if (!flashVersion) {

+                hasFlash();

+            }

+            stackEls = [new easyXDM.stack.FlashTransport(config)];

+            break;

+    }

+    // this behavior is responsible for buffering outgoing messages, and for performing lazy initialization

+    stackEls.push(new easyXDM.stack.QueueBehavior({

+        lazy: config.lazy,

+        remove: true

+    }));

+    return stackEls;

+}

+

+/**

+ * Chains all the separate stack elements into a single usable stack.<br/>

+ * If an element is missing a necessary method then it will have a pass-through method applied.

+ * @param {Array} stackElements An array of stack elements to be linked.

+ * @return {easyXDM.stack.StackElement} The last element in the chain.

+ */

+function chainStack(stackElements){

+    var stackEl, defaults = {

+        incoming: function(message, origin){

+            this.up.incoming(message, origin);

+        },

+        outgoing: function(message, recipient){

+            this.down.outgoing(message, recipient);

+        },

+        callback: function(success){

+            this.up.callback(success);

+        },

+        init: function(){

+            this.down.init();

+        },

+        destroy: function(){

+            this.down.destroy();

+        }

+    };

+    for (var i = 0, len = stackElements.length; i < len; i++) {

+        stackEl = stackElements[i];

+        apply(stackEl, defaults, true);

+        if (i !== 0) {

+            stackEl.down = stackElements[i - 1];

+        }

+        if (i !== len - 1) {

+            stackEl.up = stackElements[i + 1];

+        }

+    }

+    return stackEl;

+}

+

+/**

+ * This will remove a stackelement from its stack while leaving the stack functional.

+ * @param {Object} element The elment to remove from the stack.

+ */

+function removeFromStack(element){

+    element.up.down = element.down;

+    element.down.up = element.up;

+    element.up = element.down = null;

+}

+

+/*

+ * Export the main object and any other methods applicable

+ */

+/** 

+ * @class easyXDM

+ * A javascript library providing cross-browser, cross-domain messaging/RPC.

+ * @version 2.4.17.1

+ * @singleton

+ */

+apply(easyXDM, {

+    /**

+     * The version of the library

+     * @type {string}

+     */

+    version: "2.4.17.1",

+    /**

+     * This is a map containing all the query parameters passed to the document.

+     * All the values has been decoded using decodeURIComponent.

+     * @type {object}

+     */

+    query: query,

+    /**

+     * @private

+     */

+    stack: {},

+    /**

+     * Applies properties from the source object to the target object.<br/>

+     * @param {object} target The target of the properties.

+     * @param {object} source The source of the properties.

+     * @param {boolean} noOverwrite Set to True to only set non-existing properties.

+     */

+    apply: apply,

+    

+    /**

+     * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.

+     * @return {JSON} A valid JSON conforming object, or null if not found.

+     */

+    getJSONObject: getJSON,

+    /**

+     * This will add a function to the queue of functions to be run once the DOM reaches a ready state.

+     * If functions are added after this event then they will be executed immediately.

+     * @param {function} fn The function to add

+     * @param {object} scope An optional scope for the function to be called with.

+     */

+    whenReady: whenReady,

+    /**

+     * Removes easyXDM variable from the global scope. It also returns control

+     * of the easyXDM variable to whatever code used it before.

+     *

+     * @param {String} ns A string representation of an object that will hold

+     *                    an instance of easyXDM.

+     * @return An instance of easyXDM

+     */

+    noConflict: noConflict

+});

+

+// Expose helper functions so we can test them

+apply(easyXDM, {

+    checkAcl: checkAcl,

+    getDomainName: getDomainName,

+    getLocation: getLocation,

+    appendQueryParameters: appendQueryParameters

+});

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global console, _FirebugCommandLine,  easyXDM, window, escape, unescape, isHostObject, undef, _trace, domIsReady, emptyFn, namespace */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+var debug = {

+    _deferred: [],

+    flush: function(){

+        this.trace("... deferred messages ...");

+        for (var i = 0, len = this._deferred.length; i < len; i++) {

+            this.trace(this._deferred[i]);

+        }

+        this._deferred.length = 0;

+        this.trace("... end of deferred messages ...");

+    },

+    getTime: function(){

+        var d = new Date(), h = d.getHours() + "", m = d.getMinutes() + "", s = d.getSeconds() + "", ms = d.getMilliseconds() + "", zeros = "000";

+        if (h.length == 1) {

+            h = "0" + h;

+        }

+        if (m.length == 1) {

+            m = "0" + m;

+        }

+        if (s.length == 1) {

+            s = "0" + s;

+        }

+        ms = zeros.substring(ms.length) + ms;

+        return h + ":" + m + ":" + s + "." + ms;

+    },

+    /**

+     * Logs the message to console.log if available

+     * @param {String} msg The message to log

+     */

+    log: function(msg){

+        // Uses memoizing to cache the implementation

+        if (!isHostObject(window, "console") || undef(console.log)) {

+            /**

+             * Sets log to be an empty function since we have no output available

+             * @ignore

+             */

+            this.log = emptyFn;

+        }

+        else {

+            /**

+             * Sets log to be a wrapper around console.log

+             * @ignore

+             * @param {String} msg

+             */

+            this.log = function(msg){

+                console.log(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ": " + msg);

+            };

+        }

+        this.log(msg);

+    },

+    /**

+     * Will try to trace the given message either to a DOMElement with the id "log",

+     * or by using console.info.

+     * @param {String} msg The message to trace

+     */

+    trace: function(msg){

+        // Uses memoizing to cache the implementation

+        if (!domIsReady) {

+            if (this._deferred.length === 0) {

+                easyXDM.whenReady(debug.flush, debug);

+            }

+            this._deferred.push(msg);

+            this.log(msg);

+        }

+        else {

+            var el = document.getElementById("log");

+            // is there a log element present?

+            if (el) {

+                /**

+                 * Sets trace to be a function that outputs the messages to the DOMElement with id "log"

+                 * @ignore

+                 * @param {String} msg

+                 */

+                this.trace = function(msg){

+                    try {

+                        el.appendChild(document.createElement("div")).appendChild(document.createTextNode(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg));

+                        el.scrollTop = el.scrollHeight;

+                    } 

+                    catch (e) {

+                        //In case we are unloading

+                    }

+                };

+            }

+            else if (isHostObject(window, "console") && !undef(console.info)) {

+                /**

+                 * Sets trace to be a wrapper around console.info

+                 * @ignore

+                 * @param {String} msg

+                 */

+                this.trace = function(msg){

+                    console.info(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg);

+                };

+            }

+            else {

+                /**

+                 * Create log window

+                 * @ignore

+                 */

+                var domain = location.host, windowname = domain.replace(/[\-.:]/g, "") + "easyxdm_log", logWin;

+                try {

+                    logWin = window.open("", windowname, "width=800,height=200,status=0,navigation=0,scrollbars=1");

+                } 

+                catch (e) {

+                }

+                if (logWin) {

+                    var doc = logWin.document;

+                    el = doc.getElementById("log");

+                    if (!el) {

+                        doc.write("<html><head><title>easyXDM log " + domain + "</title></head>");

+                        doc.write("<body><div id=\"log\"></div></body></html>");

+                        doc.close();

+                        el = doc.getElementById("log");

+                    }

+                    this.trace = function(msg){

+                        try {

+                            el.appendChild(doc.createElement("div")).appendChild(doc.createTextNode(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg));

+                            el.scrollTop = el.scrollHeight;

+                        } 

+                        catch (e) {

+                            //In case we are unloading

+                        }

+                    };

+                    this.trace("---- new logger at " + location.href);

+                }

+                

+                if (!el) {

+                    // We are unable to use any logging

+                    this.trace = emptyFn;

+                }

+            }

+            this.trace(msg);

+        }

+    },

+    /**

+     * Creates a method usable for tracing.

+     * @param {String} name The name the messages should be marked with

+     * @return {Function} A function that accepts a single string as argument.

+     */

+    getTracer: function(name){

+        return function(msg){

+            debug.trace(name + ": " + msg);

+        };

+    }

+};

+debug.log("easyXDM present on '" + location.href);

+easyXDM.Debug = debug;

+_trace = debug.getTracer("{Private}");

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, isHostObject, isHostMethod, un, on, createFrame, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/** 

+ * @class easyXDM.DomHelper

+ * Contains methods for dealing with the DOM

+ * @singleton

+ */

+easyXDM.DomHelper = {

+    /**

+     * Provides a consistent interface for adding eventhandlers

+     * @param {Object} target The target to add the event to

+     * @param {String} type The name of the event

+     * @param {Function} listener The listener

+     */

+    on: on,

+    /**

+     * Provides a consistent interface for removing eventhandlers

+     * @param {Object} target The target to remove the event from

+     * @param {String} type The name of the event

+     * @param {Function} listener The listener

+     */

+    un: un,

+    /**

+     * Checks for the presence of the JSON object.

+     * If it is not present it will use the supplied path to load the JSON2 library.

+     * This should be called in the documents head right after the easyXDM script tag.

+     * http://json.org/json2.js

+     * @param {String} path A valid path to json2.js

+     */

+    requiresJSON: function(path){

+        if (!isHostObject(window, "JSON")) {

+            debug.log("loading external JSON");

+            // we need to encode the < in order to avoid an illegal token error

+            // when the script is inlined in a document.

+            document.write('<' + 'script type="text/javascript" src="' + path + '"><' + '/script>');

+        }

+        else {

+            debug.log("native JSON found");

+        }

+    }

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+(function(){

+    // The map containing the stored functions

+    var _map = {};

+    

+    /**

+     * @class easyXDM.Fn

+     * This contains methods related to function handling, such as storing callbacks.

+     * @singleton

+     * @namespace easyXDM

+     */

+    easyXDM.Fn = {

+        /**

+         * Stores a function using the given name for reference

+         * @param {String} name The name that the function should be referred by

+         * @param {Function} fn The function to store

+         * @namespace easyXDM.fn

+         */

+        set: function(name, fn){

+            this._trace("storing function " + name);

+            _map[name] = fn;

+        },

+        /**

+         * Retrieves the function referred to by the given name

+         * @param {String} name The name of the function to retrieve

+         * @param {Boolean} del If the function should be deleted after retrieval

+         * @return {Function} The stored function

+         * @namespace easyXDM.fn

+         */

+        get: function(name, del){

+            this._trace("retrieving function " + name);

+            var fn = _map[name];

+            if (!fn) {

+                this._trace(name + " not found");

+            }

+            

+            if (del) {

+                delete _map[name];

+            }

+            return fn;

+        }

+    };

+    

+    easyXDM.Fn._trace = debug.getTracer("easyXDM.Fn");

+}());

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, chainStack, prepareTransportStack, getLocation, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.Socket

+ * This class creates a transport channel between two domains that is usable for sending and receiving string-based messages.<br/>

+ * The channel is reliable, supports queueing, and ensures that the message originates from the expected domain.<br/>

+ * Internally different stacks will be used depending on the browsers features and the available parameters.

+ * <h2>How to set up</h2>

+ * Setting up the provider:

+ * <pre><code>

+ * var socket = new easyXDM.Socket({

+ * &nbsp; local: "name.html",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket

+ * &nbsp; &nbsp; socket.postMessage("foo-message");

+ * &nbsp; },

+ * &nbsp; onMessage: function(message, origin) {

+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * Setting up the consumer:

+ * <pre><code>

+ * var socket = new easyXDM.Socket({

+ * &nbsp; remote: "http:&#47;&#47;remotedomain/page.html",

+ * &nbsp; remoteHelper: "http:&#47;&#47;remotedomain/name.html",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket

+ * &nbsp; &nbsp; socket.postMessage("foo-message");

+ * &nbsp; },

+ * &nbsp; onMessage: function(message, origin) {

+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * If you are unable to upload the <code>name.html</code> file to the consumers domain then remove the <code>remoteHelper</code> property

+ * and easyXDM will fall back to using the HashTransport instead of the NameTransport when not able to use any of the primary transports.

+ * @namespace easyXDM

+ * @constructor

+ * @cfg {String/Window} local The url to the local name.html document, a local static file, or a reference to the local window.

+ * @cfg {Boolean} lazy (Consumer only) Set this to true if you want easyXDM to defer creating the transport until really needed. 

+ * @cfg {String} remote (Consumer only) The url to the providers document.

+ * @cfg {String} remoteHelper (Consumer only) The url to the remote name.html file. This is to support NameTransport as a fallback. Optional.

+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.  Optional, defaults to 2000.

+ * @cfg {Number} interval The interval used when polling for messages. Optional, defaults to 300.

+ * @cfg {String} channel (Consumer only) The name of the channel to use. Can be used to set consistent iframe names. Must be unique. Optional.

+ * @cfg {Function} onMessage The method that should handle incoming messages.<br/> This method should accept two arguments, the message as a string, and the origin as a string. Optional.

+ * @cfg {Function} onReady A method that should be called when the transport is ready. Optional.

+ * @cfg {DOMElement|String} container (Consumer only) The element, or the id of the element that the primary iframe should be inserted into. If not set then the iframe will be positioned off-screen. Optional.

+ * @cfg {Array/String} acl (Provider only) Here you can specify which '[protocol]://[domain]' patterns that should be allowed to act as the consumer towards this provider.<br/>

+ * This can contain the wildcards ? and *.  Examples are 'http://example.com', '*.foo.com' and '*dom?.com'. If you want to use reqular expressions then you pattern needs to start with ^ and end with $.

+ * If none of the patterns match an Error will be thrown.  

+ * @cfg {Object} props (Consumer only) Additional properties that should be applied to the iframe. This can also contain nested objects e.g: <code>{style:{width:"100px", height:"100px"}}</code>. 

+ * Properties such as 'name' and 'src' will be overrided. Optional.

+ */

+easyXDM.Socket = function(config){

+    var trace = debug.getTracer("easyXDM.Socket");

+    trace("constructor");

+    

+    // create the stack

+    var stack = chainStack(prepareTransportStack(config).concat([{

+        incoming: function(message, origin){

+            config.onMessage(message, origin);

+        },

+        callback: function(success){

+            if (config.onReady) {

+                config.onReady(success);

+            }

+        }

+    }])), recipient = getLocation(config.remote);

+    

+    // set the origin

+    this.origin = getLocation(config.remote);

+	

+    /**

+     * Initiates the destruction of the stack.

+     */

+    this.destroy = function(){

+        stack.destroy();

+    };

+    

+    /**

+     * Posts a message to the remote end of the channel

+     * @param {String} message The message to send

+     */

+    this.postMessage = function(message){

+        stack.outgoing(message, recipient);

+    };

+    

+    stack.init();

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef,, chainStack, prepareTransportStack, debug, getLocation */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/** 

+ * @class easyXDM.Rpc

+ * Creates a proxy object that can be used to call methods implemented on the remote end of the channel, and also to provide the implementation

+ * of methods to be called from the remote end.<br/>

+ * The instantiated object will have methods matching those specified in <code>config.remote</code>.<br/>

+ * This requires the JSON object present in the document, either natively, using json.org's json2 or as a wrapper around library spesific methods.

+ * <h2>How to set up</h2>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; &#47;&#47; this configuration is equal to that used by the Socket.

+ * &nbsp; remote: "http:&#47;&#47;remotedomain/...",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the proxy

+ * &nbsp; &nbsp; rpc.foo(...

+ * &nbsp; }

+ * },{

+ * &nbsp; local: {..},

+ * &nbsp; remote: {..}

+ * });

+ * </code></pre>

+ * 

+ * <h2>Exposing functions (procedures)</h2>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {

+ * &nbsp; &nbsp; nameOfMethod: {

+ * &nbsp; &nbsp; &nbsp; method: function(arg1, arg2, success, error){

+ * &nbsp; &nbsp; &nbsp; &nbsp; ...

+ * &nbsp; &nbsp; &nbsp; }

+ * &nbsp; &nbsp; },

+ * &nbsp; &nbsp; &#47;&#47; with shorthand notation 

+ * &nbsp; &nbsp; nameOfAnotherMethod:  function(arg1, arg2, success, error){

+ * &nbsp; &nbsp; }

+ * &nbsp; },

+ * &nbsp; remote: {...}

+ * });

+ * </code></pre>

+

+ * The function referenced by  [method] will receive the passed arguments followed by the callback functions <code>success</code> and <code>error</code>.<br/>

+ * To send a successfull result back you can use

+ *     <pre><code>

+ *     return foo;

+ *     </pre></code>

+ * or

+ *     <pre><code>

+ *     success(foo);

+ *     </pre></code>

+ *  To return an error you can use

+ *     <pre><code>

+ *     throw new Error("foo error");

+ *     </code></pre>

+ * or

+ *     <pre><code>

+ *     error("foo error");

+ *     </code></pre>

+ *

+ * <h2>Defining remotely exposed methods (procedures/notifications)</h2>

+ * The definition of the remote end is quite similar:

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {...},

+ * &nbsp; remote: {

+ * &nbsp; &nbsp; nameOfMethod: {}

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * To call a remote method use

+ * <pre><code>

+ * rpc.nameOfMethod("arg1", "arg2", function(value) {

+ * &nbsp; alert("success: " + value);

+ * }, function(message) {

+ * &nbsp; alert("error: " + message + );

+ * });

+ * </code></pre>

+ * Both the <code>success</code> and <code>errror</code> callbacks are optional.<br/>

+ * When called with no callback a JSON-RPC 2.0 notification will be executed.

+ * Be aware that you will not be notified of any errors with this method.

+ * <br/>

+ * <h2>Specifying a custom serializer</h2>

+ * If you do not want to use the JSON2 library for non-native JSON support, but instead capabilities provided by some other library

+ * then you can specify a custom serializer using <code>serializer: foo</code>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {...},

+ * &nbsp; remote: {...},

+ * &nbsp; serializer : {

+ * &nbsp; &nbsp; parse: function(string){ ... },

+ * &nbsp; &nbsp; stringify: function(object) {...}

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * If <code>serializer</code> is set then the class will not attempt to use the native implementation.

+ * @namespace easyXDM

+ * @constructor

+ * @param {Object} config The underlying transports configuration. See easyXDM.Socket for available parameters.

+ * @param {Object} jsonRpcConfig The description of the interface to implement.

+ */

+easyXDM.Rpc = function(config, jsonRpcConfig){

+    var trace = debug.getTracer("easyXDM.Rpc");

+    trace("constructor");

+    

+    // expand shorthand notation

+    if (jsonRpcConfig.local) {

+        for (var method in jsonRpcConfig.local) {

+            if (jsonRpcConfig.local.hasOwnProperty(method)) {

+                var member = jsonRpcConfig.local[method];

+                if (typeof member === "function") {

+                    jsonRpcConfig.local[method] = {

+                        method: member

+                    };

+                }

+            }

+        }

+    }

+	

+    // create the stack

+    var stack = chainStack(prepareTransportStack(config).concat([new easyXDM.stack.RpcBehavior(this, jsonRpcConfig), {

+        callback: function(success){

+            if (config.onReady) {

+                config.onReady(success);

+            }

+        }

+    }]));

+	

+    // set the origin 

+    this.origin = getLocation(config.remote);

+	

+    

+    /**

+     * Initiates the destruction of the stack.

+     */

+    this.destroy = function(){

+        stack.destroy();

+    };

+    

+    stack.init();

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, getParentObject, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.SameOriginTransport

+ * SameOriginTransport is a transport class that can be used when both domains have the same origin.<br/>

+ * This can be useful for testing and for when the main application supports both internal and external sources.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote document to communicate with.

+ */

+easyXDM.stack.SameOriginTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.SameOriginTransport");

+    trace("constructor");

+    var pub, frame, send, targetOrigin;

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            send(message);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            

+            if (config.isHost) {

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: location.protocol + "//" + location.host + location.pathname,

+                        xdm_c: config.channel,

+                        xdm_p: 4 // 4 = SameOriginTransport

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+                easyXDM.Fn.set(config.channel, function(sendFn){

+                    send = sendFn;

+                    setTimeout(function(){

+                        pub.up.callback(true);

+                    }, 0);

+                    return function(msg){

+                        pub.up.incoming(msg, targetOrigin);

+                    };

+                });

+            }

+            else {

+                send = getParentObject().Fn.get(config.channel, true)(function(msg){

+                    pub.up.incoming(msg, targetOrigin);

+                });

+                setTimeout(function(){

+                    pub.up.callback(true);

+                }, 0);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global global, easyXDM, window, getLocation, appendQueryParameters, createFrame, debug, apply, whenReady, IFRAME_PREFIX, namespace, resolveUrl, getDomainName, HAS_FLASH_THROTTLED_BUG, getPort, query*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.FlashTransport

+ * FlashTransport is a transport class that uses an SWF with LocalConnection to pass messages back and forth.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote domain to communicate with.

+ * @cfg {String} secret the pre-shared secret used to secure the communication.

+ * @cfg {String} swf The path to the swf file

+ * @cfg {Boolean} swfNoThrottle Set this to true if you want to take steps to avoid beeing throttled when hidden.

+ * @cfg {String || DOMElement} swfContainer Set this if you want to control where the swf is placed

+ */

+easyXDM.stack.FlashTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.FlashTransport");

+    trace("constructor");

+    if (!config.swf) {

+        throw new Error("Path to easyxdm.swf is missing");

+    }

+    var pub, // the public interface

+ frame, send, targetOrigin, swf, swfContainer;

+    

+    function onMessage(message, origin){

+        setTimeout(function(){

+            trace("received message");

+            pub.up.incoming(message, targetOrigin);

+        }, 0);

+    }

+    

+    /**

+     * This method adds the SWF to the DOM and prepares the initialization of the channel

+     */

+    function addSwf(domain){

+        trace("creating factory with SWF from " + domain);

+        // the differentiating query argument is needed in Flash9 to avoid a caching issue where LocalConnection would throw an error.

+        var url = config.swf + "?host=" + config.isHost;

+        var id = "easyXDM_swf_" + Math.floor(Math.random() * 10000);

+        

+        // prepare the init function that will fire once the swf is ready

+        easyXDM.Fn.set("flash_loaded" + domain.replace(/[\-.]/g, "_"), function(){

+            easyXDM.stack.FlashTransport[domain].swf = swf = swfContainer.firstChild;

+            var queue = easyXDM.stack.FlashTransport[domain].queue;

+            for (var i = 0; i < queue.length; i++) {

+                queue[i]();

+            }

+            queue.length = 0;

+        });

+        

+        if (config.swfContainer) {

+            swfContainer = (typeof config.swfContainer == "string") ? document.getElementById(config.swfContainer) : config.swfContainer;

+        }

+        else {

+            // create the container that will hold the swf

+            swfContainer = document.createElement('div');

+            

+            // http://bugs.adobe.com/jira/browse/FP-4796

+            // http://tech.groups.yahoo.com/group/flexcoders/message/162365

+            // https://groups.google.com/forum/#!topic/easyxdm/mJZJhWagoLc

+            apply(swfContainer.style, HAS_FLASH_THROTTLED_BUG && config.swfNoThrottle ? {

+                height: "20px",

+                width: "20px",

+                position: "fixed",

+                right: 0,

+                top: 0

+            } : {

+                height: "1px",

+                width: "1px",

+                position: "absolute",

+                overflow: "hidden",

+                right: 0,

+                top: 0

+            });

+            document.body.appendChild(swfContainer);

+        }

+        

+        // create the object/embed

+        var flashVars = "callback=flash_loaded" + domain.replace(/[\-.]/g, "_") + "&proto=" + global.location.protocol + "&domain=" + getDomainName(global.location.href) + "&port=" + getPort(global.location.href) + "&ns=" + namespace;

+        flashVars += "&log=true";

+        swfContainer.innerHTML = "<object height='20' width='20' type='application/x-shockwave-flash' id='" + id + "' data='" + url + "'>" +

+        "<param name='allowScriptAccess' value='always'></param>" +

+        "<param name='wmode' value='transparent'>" +

+        "<param name='movie' value='" +

+        url +

+        "'></param>" +

+        "<param name='flashvars' value='" +

+        flashVars +

+        "'></param>" +

+        "<embed type='application/x-shockwave-flash' FlashVars='" +

+        flashVars +

+        "' allowScriptAccess='always' wmode='transparent' src='" +

+        url +

+        "' height='1' width='1'></embed>" +

+        "</object>";

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            swf.postMessage(config.channel, message.toString());

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            try {

+                swf.destroyChannel(config.channel);

+            } 

+            catch (e) {

+            }

+            swf = null;

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            

+            targetOrigin = config.remote;

+            

+            // Prepare the code that will be run after the swf has been intialized

+            easyXDM.Fn.set("flash_" + config.channel + "_init", function(){

+                setTimeout(function(){

+                    trace("firing onReady");

+                    pub.up.callback(true);

+                });

+            });

+            

+            // set up the omMessage handler

+            easyXDM.Fn.set("flash_" + config.channel + "_onMessage", onMessage);

+            

+            config.swf = resolveUrl(config.swf); // reports have been made of requests gone rogue when using relative paths

+            var swfdomain = getDomainName(config.swf);

+            var fn = function(){

+                // set init to true in case the fn was called was invoked from a separate instance

+                easyXDM.stack.FlashTransport[swfdomain].init = true;

+                swf = easyXDM.stack.FlashTransport[swfdomain].swf;

+                // create the channel

+                swf.createChannel(config.channel, config.secret, getLocation(config.remote), config.isHost);

+                

+                if (config.isHost) {

+                    // if Flash is going to be throttled and we want to avoid this

+                    if (HAS_FLASH_THROTTLED_BUG && config.swfNoThrottle) {

+                        apply(config.props, {

+                            position: "fixed",

+                            right: 0,

+                            top: 0,

+                            height: "20px",

+                            width: "20px"

+                        });

+                    }

+                    // set up the iframe

+                    apply(config.props, {

+                        src: appendQueryParameters(config.remote, {

+                            xdm_e: getLocation(location.href),

+                            xdm_c: config.channel,

+                            xdm_p: 6, // 6 = FlashTransport

+                            xdm_s: config.secret

+                        }),

+                        name: IFRAME_PREFIX + config.channel + "_provider"

+                    });

+                    frame = createFrame(config);

+                }

+            };

+            

+            if (easyXDM.stack.FlashTransport[swfdomain] && easyXDM.stack.FlashTransport[swfdomain].init) {

+                // if the swf is in place and we are the consumer

+                fn();

+            }

+            else {

+                // if the swf does not yet exist

+                if (!easyXDM.stack.FlashTransport[swfdomain]) {

+                    // add the queue to hold the init fn's

+                    easyXDM.stack.FlashTransport[swfdomain] = {

+                        queue: [fn]

+                    };

+                    addSwf(swfdomain);

+                }

+                else {

+                    easyXDM.stack.FlashTransport[swfdomain].queue.push(fn);

+                }

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.PostMessageTransport

+ * PostMessageTransport is a transport class that uses HTML5 postMessage for communication.<br/>

+ * <a href="http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx</a><br/>

+ * <a href="https://developer.mozilla.org/en/DOM/window.postMessage">https://developer.mozilla.org/en/DOM/window.postMessage</a>

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote domain to communicate with.

+ */

+easyXDM.stack.PostMessageTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.PostMessageTransport");

+    trace("constructor");

+    var pub, // the public interface

+ frame, // the remote frame, if any

+ callerWindow, // the window that we will call with

+ targetOrigin; // the domain to communicate with

+    /**

+     * Resolves the origin from the event object

+     * @private

+     * @param {Object} event The messageevent

+     * @return {String} The scheme, host and port of the origin

+     */

+    function _getOrigin(event){

+        if (event.origin) {

+            // This is the HTML5 property

+            return getLocation(event.origin);

+        }

+        if (event.uri) {

+            // From earlier implementations 

+            return getLocation(event.uri);

+        }

+        if (event.domain) {

+            // This is the last option and will fail if the 

+            // origin is not using the same schema as we are

+            return location.protocol + "//" + event.domain;

+        }

+        throw "Unable to retrieve the origin of the event";

+    }

+    

+    /**

+     * This is the main implementation for the onMessage event.<br/>

+     * It checks the validity of the origin and passes the message on if appropriate.

+     * @private

+     * @param {Object} event The messageevent

+     */

+    function _window_onMessage(event){

+        var origin = _getOrigin(event);

+        trace("received message '" + event.data + "' from " + origin);

+        if (origin == targetOrigin && event.data.substring(0, config.channel.length + 1) == config.channel + " ") {

+            pub.up.incoming(event.data.substring(config.channel.length + 1), origin);

+        }

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            callerWindow.postMessage(config.channel + " " + message, domain || targetOrigin);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            un(window, "message", _window_onMessage);

+            if (frame) {

+                callerWindow = null;

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            if (config.isHost) {

+                // add the event handler for listening

+                var waitForReady = function(event){  

+                    if (event.data == config.channel + "-ready") {

+                        trace("firing onReady");

+                        // replace the eventlistener

+                        callerWindow = ("postMessage" in frame.contentWindow) ? frame.contentWindow : frame.contentWindow.document;

+                        un(window, "message", waitForReady);

+                        on(window, "message", _window_onMessage);

+                        setTimeout(function(){

+                            pub.up.callback(true);

+                        }, 0);

+                    }

+                };

+                on(window, "message", waitForReady);

+                

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: getLocation(location.href),

+                        xdm_c: config.channel,

+                        xdm_p: 1 // 1 = PostMessage

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+            }

+            else {

+                // add the event handler for listening

+                on(window, "message", _window_onMessage);

+                callerWindow = ("postMessage" in window.parent) ? window.parent : window.parent.document;

+                callerWindow.postMessage(config.channel + "-ready", targetOrigin);

+                

+                setTimeout(function(){

+                    pub.up.callback(true);

+                }, 0);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, apply, query, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.FrameElementTransport

+ * FrameElementTransport is a transport class that can be used with Gecko-browser as these allow passing variables using the frameElement property.<br/>

+ * Security is maintained as Gecho uses Lexical Authorization to determine under which scope a function is running.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote document to communicate with.

+ */

+easyXDM.stack.FrameElementTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.FrameElementTransport");

+    trace("constructor");

+    var pub, frame, send, targetOrigin;

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            send.call(this, message);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            

+            if (config.isHost) {

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: getLocation(location.href),

+                        xdm_c: config.channel,

+                        xdm_p: 5 // 5 = FrameElementTransport

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+                frame.fn = function(sendFn){

+                    delete frame.fn;

+                    send = sendFn;

+                    setTimeout(function(){

+                        pub.up.callback(true);

+                    }, 0);

+                    // remove the function so that it cannot be used to overwrite the send function later on

+                    return function(msg){

+                        pub.up.incoming(msg, targetOrigin);

+                    };

+                };

+            }

+            else {

+                // This is to mitigate origin-spoofing

+                if (document.referrer && getLocation(document.referrer) != query.xdm_e) {

+                    window.top.location = query.xdm_e;

+                }

+                send = window.frameElement.fn(function(msg){

+                    pub.up.incoming(msg, targetOrigin);

+                });

+                pub.up.callback(true);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, getLocation, appendQueryParameters, resolveUrl, createFrame, debug, un, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.NameTransport

+ * NameTransport uses the window.name property to relay data.

+ * The <code>local</code> parameter needs to be set on both the consumer and provider,<br/>

+ * and the <code>remoteHelper</code> parameter needs to be set on the consumer.

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remoteHelper The url to the remote instance of hash.html - this is only needed for the host.

+ * @namespace easyXDM.stack

+ */

+easyXDM.stack.NameTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.NameTransport");

+    trace("constructor");

+    if (config.isHost && undef(config.remoteHelper)) {

+        trace("missing remoteHelper");

+        throw new Error("missing remoteHelper");

+    }

+    

+    var pub; // the public interface

+    var isHost, callerWindow, remoteWindow, readyCount, callback, remoteOrigin, remoteUrl;

+    

+    function _sendMessage(message){

+        var url = config.remoteHelper + (isHost ? "#_3" : "#_2") + config.channel;

+        trace("sending message " + message);

+        trace("navigating to  '" + url + "'");

+        callerWindow.contentWindow.sendMessage(message, url);

+    }

+    

+    function _onReady(){

+        if (isHost) {

+            if (++readyCount === 2 || !isHost) {

+                pub.up.callback(true);

+            }

+        }

+        else {

+            _sendMessage("ready");

+            trace("calling onReady");

+            pub.up.callback(true);

+        }

+    }

+    

+    function _onMessage(message){

+        trace("received message " + message);

+        pub.up.incoming(message, remoteOrigin);

+    }

+    

+    function _onLoad(){

+        if (callback) {

+            setTimeout(function(){

+                callback(true);

+            }, 0);

+        }

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            callback = fn;

+            _sendMessage(message);

+        },

+        destroy: function(){

+            trace("destroy");

+            callerWindow.parentNode.removeChild(callerWindow);

+            callerWindow = null;

+            if (isHost) {

+                remoteWindow.parentNode.removeChild(remoteWindow);

+                remoteWindow = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            isHost = config.isHost;

+            readyCount = 0;

+            remoteOrigin = getLocation(config.remote);

+            config.local = resolveUrl(config.local);

+            

+            if (isHost) {

+                // Register the callback

+                easyXDM.Fn.set(config.channel, function(message){

+                    trace("received initial message " + message);

+                    if (isHost && message === "ready") {

+                        // Replace the handler

+                        easyXDM.Fn.set(config.channel, _onMessage);

+                        _onReady();

+                    }

+                });

+                

+                // Set up the frame that points to the remote instance

+                remoteUrl = appendQueryParameters(config.remote, {

+                    xdm_e: config.local,

+                    xdm_c: config.channel,

+                    xdm_p: 2

+                });

+                apply(config.props, {

+                    src: remoteUrl + '#' + config.channel,

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                remoteWindow = createFrame(config);

+            }

+            else {

+                config.remoteHelper = config.remote;

+                easyXDM.Fn.set(config.channel, _onMessage);

+            }

+            

+            // Set up the iframe that will be used for the transport

+            var onLoad = function(){

+                // Remove the handler

+                var w = callerWindow || this;

+                un(w, "load", onLoad);

+                easyXDM.Fn.set(config.channel + "_load", _onLoad);

+                (function test(){

+                    if (typeof w.contentWindow.sendMessage == "function") {

+                        _onReady();

+                    }

+                    else {

+                        setTimeout(test, 50);

+                    }

+                }());

+            };

+            

+            callerWindow = createFrame({

+                props: {

+                    src: config.local + "#_4" + config.channel

+                },

+                onLoad: onLoad

+            });

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.HashTransport

+ * HashTransport is a transport class that uses the IFrame URL Technique for communication.<br/>

+ * <a href="http://msdn.microsoft.com/en-us/library/bb735305.aspx">http://msdn.microsoft.com/en-us/library/bb735305.aspx</a><br/>

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String/Window} local The url to the local file used for proxying messages, or the local window.

+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.

+ * @cfg {Number} interval The interval used when polling for messages.

+ */

+easyXDM.stack.HashTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.HashTransport");

+    trace("constructor");

+    var pub;

+    var me = this, isHost, _timer, pollInterval, _lastMsg, _msgNr, _listenerWindow, _callerWindow;

+    var useParent, _remoteOrigin;

+    

+    function _sendMessage(message){

+        trace("sending message '" + (_msgNr + 1) + " " + message + "' to " + _remoteOrigin);

+        if (!_callerWindow) {

+            trace("no caller window");

+            return;

+        }

+        var url = config.remote + "#" + (_msgNr++) + "_" + message;

+        ((isHost || !useParent) ? _callerWindow.contentWindow : _callerWindow).location = url;

+    }

+    

+    function _handleHash(hash){

+        _lastMsg = hash;

+        trace("received message '" + _lastMsg + "' from " + _remoteOrigin);

+        pub.up.incoming(_lastMsg.substring(_lastMsg.indexOf("_") + 1), _remoteOrigin);

+    }

+    

+    /**

+     * Checks location.hash for a new message and relays this to the receiver.

+     * @private

+     */

+    function _pollHash(){

+        if (!_listenerWindow) {

+            return;

+        }

+        var href = _listenerWindow.location.href, hash = "", indexOf = href.indexOf("#");

+        if (indexOf != -1) {

+            hash = href.substring(indexOf);

+        }

+        if (hash && hash != _lastMsg) {

+            trace("poll: new message");

+            _handleHash(hash);

+        }

+    }

+    

+    function _attachListeners(){

+        trace("starting polling");

+        _timer = setInterval(_pollHash, pollInterval);

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain){

+            _sendMessage(message);

+        },

+        destroy: function(){

+            window.clearInterval(_timer);

+            if (isHost || !useParent) {

+                _callerWindow.parentNode.removeChild(_callerWindow);

+            }

+            _callerWindow = null;

+        },

+        onDOMReady: function(){

+            isHost = config.isHost;

+            pollInterval = config.interval;

+            _lastMsg = "#" + config.channel;

+            _msgNr = 0;

+            useParent = config.useParent;

+            _remoteOrigin = getLocation(config.remote);

+            if (isHost) {

+                apply(config.props, {

+                    src: config.remote,

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                if (useParent) {

+                    config.onLoad = function(){

+                        _listenerWindow = window;

+                        _attachListeners();

+                        pub.up.callback(true);

+                    };

+                }

+                else {

+                    var tries = 0, max = config.delay / 50;

+                    (function getRef(){

+                        if (++tries > max) {

+                            trace("unable to get reference to _listenerWindow, giving up");

+                            throw new Error("Unable to reference listenerwindow");

+                        }

+                        try {

+                            _listenerWindow = _callerWindow.contentWindow.frames[IFRAME_PREFIX + config.channel + "_consumer"];

+                        } 

+                        catch (ex) {

+                        }

+                        if (_listenerWindow) {

+                            _attachListeners();

+                            trace("got a reference to _listenerWindow");

+                            pub.up.callback(true);

+                        }

+                        else {

+                            setTimeout(getRef, 50);

+                        }

+                    }());

+                }

+                _callerWindow = createFrame(config);

+            }

+            else {

+                _listenerWindow = window;

+                _attachListeners();

+                if (useParent) {

+                    _callerWindow = parent;

+                    pub.up.callback(true);

+                }

+                else {

+                    apply(config, {

+                        props: {

+                            src: config.remote + "#" + config.channel + new Date(),

+                            name: IFRAME_PREFIX + config.channel + "_consumer"

+                        },

+                        onLoad: function(){

+                            pub.up.callback(true);

+                        }

+                    });

+                    _callerWindow = createFrame(config);

+                }

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.ReliableBehavior

+ * This is a behavior that tries to make the underlying transport reliable by using acknowledgements.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration.

+ */

+easyXDM.stack.ReliableBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.ReliableBehavior");

+    trace("constructor");

+    var pub, // the public interface

+ callback; // the callback to execute when we have a confirmed success/failure

+    var idOut = 0, idIn = 0, currentMessage = "";

+    

+    return (pub = {

+        incoming: function(message, origin){

+            trace("incoming: " + message);

+            var indexOf = message.indexOf("_"), ack = message.substring(0, indexOf).split(",");

+            message = message.substring(indexOf + 1);

+            

+            if (ack[0] == idOut) {

+                trace("message delivered");

+                currentMessage = "";

+                if (callback) {

+                    callback(true);

+                    callback = null;

+                }

+            }

+            if (message.length > 0) {

+                trace("sending ack, and passing on " + message);

+                pub.down.outgoing(ack[1] + "," + idOut + "_" + currentMessage, origin);

+                if (idIn != ack[1]) {

+                    idIn = ack[1];

+                    pub.up.incoming(message, origin);

+                }

+            }

+            

+        },

+        outgoing: function(message, origin, fn){

+            currentMessage = message;

+            callback = fn;

+            pub.down.outgoing(idIn + "," + (++idOut) + "_" + message, origin);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug, undef, removeFromStack*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.QueueBehavior

+ * This is a behavior that enables queueing of messages. <br/>

+ * It will buffer incoming messages and dispach these as fast as the underlying transport allows.

+ * This will also fragment/defragment messages so that the outgoing message is never bigger than the

+ * set length.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration. Optional.

+ * @cfg {Number} maxLength The maximum length of each outgoing message. Set this to enable fragmentation.

+ */

+easyXDM.stack.QueueBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.QueueBehavior");

+    trace("constructor");

+    var pub, queue = [], waiting = true, incoming = "", destroying, maxLength = 0, lazy = false, doFragment = false;

+    

+    function dispatch(){

+        if (config.remove && queue.length === 0) {

+            trace("removing myself from the stack");

+            removeFromStack(pub);

+            return;

+        }

+        if (waiting || queue.length === 0 || destroying) {

+            return;

+        }

+        trace("dispatching from queue");

+        waiting = true;

+        var message = queue.shift();

+        

+        pub.down.outgoing(message.data, message.origin, function(success){

+            waiting = false;

+            if (message.callback) {

+                setTimeout(function(){

+                    message.callback(success);

+                }, 0);

+            }

+            dispatch();

+        });

+    }

+    return (pub = {

+        init: function(){

+            if (undef(config)) {

+                config = {};

+            }

+            if (config.maxLength) {

+                maxLength = config.maxLength;

+                doFragment = true;

+            }

+            if (config.lazy) {

+                lazy = true;

+            }

+            else {

+                pub.down.init();

+            }

+        },

+        callback: function(success){

+            waiting = false;

+            var up = pub.up; // in case dispatch calls removeFromStack

+            dispatch();

+            up.callback(success);

+        },

+        incoming: function(message, origin){

+            if (doFragment) {

+                var indexOf = message.indexOf("_"), seq = parseInt(message.substring(0, indexOf), 10);

+                incoming += message.substring(indexOf + 1);

+                if (seq === 0) {

+                    trace("received the last fragment");

+                    if (config.encode) {

+                        incoming = decodeURIComponent(incoming);

+                    }

+                    pub.up.incoming(incoming, origin);

+                    incoming = "";

+                }

+                else {

+                    trace("waiting for more fragments, seq=" + message);

+                }

+            }

+            else {

+                pub.up.incoming(message, origin);

+            }

+        },

+        outgoing: function(message, origin, fn){

+            if (config.encode) {

+                message = encodeURIComponent(message);

+            }

+            var fragments = [], fragment;

+            if (doFragment) {

+                // fragment into chunks

+                while (message.length !== 0) {

+                    fragment = message.substring(0, maxLength);

+                    message = message.substring(fragment.length);

+                    fragments.push(fragment);

+                }

+                // enqueue the chunks

+                while ((fragment = fragments.shift())) {

+                    trace("enqueuing");

+                    queue.push({

+                        data: fragments.length + "_" + fragment,

+                        origin: origin,

+                        callback: fragments.length === 0 ? fn : null

+                    });

+                }

+            }

+            else {

+                queue.push({

+                    data: message,

+                    origin: origin,

+                    callback: fn

+                });

+            }

+            if (lazy) {

+                pub.down.init();

+            }

+            else {

+                dispatch();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            destroying = true;

+            pub.down.destroy();

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.VerifyBehavior

+ * This behavior will verify that communication with the remote end is possible, and will also sign all outgoing,

+ * and verify all incoming messages. This removes the risk of someone hijacking the iframe to send malicious messages.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration.

+ * @cfg {Boolean} initiate If the verification should be initiated from this end.

+ */

+easyXDM.stack.VerifyBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.VerifyBehavior");

+    trace("constructor");

+    if (undef(config.initiate)) {

+        throw new Error("settings.initiate is not set");

+    }

+    var pub, mySecret, theirSecret, verified = false;

+    

+    function startVerification(){

+        trace("requesting verification");

+        mySecret = Math.random().toString(16).substring(2);

+        pub.down.outgoing(mySecret);

+    }

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var indexOf = message.indexOf("_");

+            if (indexOf === -1) {

+                if (message === mySecret) {

+                    trace("verified, calling callback");

+                    pub.up.callback(true);

+                }

+                else if (!theirSecret) {

+                    trace("returning secret");

+                    theirSecret = message;

+                    if (!config.initiate) {

+                        startVerification();

+                    }

+                    pub.down.outgoing(message);

+                }

+            }

+            else {

+                if (message.substring(0, indexOf) === theirSecret) {

+                    pub.up.incoming(message.substring(indexOf + 1), origin);

+                }

+            }

+        },

+        outgoing: function(message, origin, fn){

+            pub.down.outgoing(mySecret + "_" + message, origin, fn);

+        },

+        callback: function(success){

+            if (config.initiate) {

+                startVerification();

+            }

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, getJSON, debug, emptyFn, isArray */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.RpcBehavior

+ * This uses JSON-RPC 2.0 to expose local methods and to invoke remote methods and have responses returned over the the string based transport stack.<br/>

+ * Exposed methods can return values synchronous, asyncronous, or bet set up to not return anything.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} proxy The object to apply the methods to.

+ * @param {Object} config The definition of the local and remote interface to implement.

+ * @cfg {Object} local The local interface to expose.

+ * @cfg {Object} remote The remote methods to expose through the proxy.

+ * @cfg {Object} serializer The serializer to use for serializing and deserializing the JSON. Should be compatible with the HTML5 JSON object. Optional, will default to JSON.

+ */

+easyXDM.stack.RpcBehavior = function(proxy, config){

+    var trace = debug.getTracer("easyXDM.stack.RpcBehavior");

+    var pub, serializer = config.serializer || getJSON();

+    var _callbackCounter = 0, _callbacks = {};

+    

+    /**

+     * Serializes and sends the message

+     * @private

+     * @param {Object} data The JSON-RPC message to be sent. The jsonrpc property will be added.

+     */

+    function _send(data){

+        data.jsonrpc = "2.0";

+        pub.down.outgoing(serializer.stringify(data));

+    }

+    

+    /**

+     * Creates a method that implements the given definition

+     * @private

+     * @param {Object} The method configuration

+     * @param {String} method The name of the method

+     * @return {Function} A stub capable of proxying the requested method call

+     */

+    function _createMethod(definition, method){

+        var slice = Array.prototype.slice;

+        

+        trace("creating method " + method);

+        return function(){

+            trace("executing method " + method);

+            var l = arguments.length, callback, message = {

+                method: method

+            };

+            

+            if (l > 0 && typeof arguments[l - 1] === "function") {

+                //with callback, procedure

+                if (l > 1 && typeof arguments[l - 2] === "function") {

+                    // two callbacks, success and error

+                    callback = {

+                        success: arguments[l - 2],

+                        error: arguments[l - 1]

+                    };

+                    message.params = slice.call(arguments, 0, l - 2);

+                }

+                else {

+                    // single callback, success

+                    callback = {

+                        success: arguments[l - 1]

+                    };

+                    message.params = slice.call(arguments, 0, l - 1);

+                }

+                _callbacks["" + (++_callbackCounter)] = callback;

+                message.id = _callbackCounter;

+            }

+            else {

+                // no callbacks, a notification

+                message.params = slice.call(arguments, 0);

+            }

+            if (definition.namedParams && message.params.length === 1) {

+                message.params = message.params[0];

+            }

+            // Send the method request

+            _send(message);

+        };

+    }

+    

+    /**

+     * Executes the exposed method

+     * @private

+     * @param {String} method The name of the method

+     * @param {Number} id The callback id to use

+     * @param {Function} method The exposed implementation

+     * @param {Array} params The parameters supplied by the remote end

+     */

+    function _executeMethod(method, id, fn, params){

+        if (!fn) {

+            trace("requested to execute non-existent procedure " + method);

+            if (id) {

+                _send({

+                    id: id,

+                    error: {

+                        code: -32601,

+                        message: "Procedure not found."

+                    }

+                });

+            }

+            return;

+        }

+        

+        trace("requested to execute procedure " + method);

+        var success, error;

+        if (id) {

+            success = function(result){

+                success = emptyFn;

+                _send({

+                    id: id,

+                    result: result

+                });

+            };

+            error = function(message, data){

+                error = emptyFn;

+                var msg = {

+                    id: id,

+                    error: {

+                        code: -32099,

+                        message: message

+                    }

+                };

+                if (data) {

+                    msg.error.data = data;

+                }

+                _send(msg);

+            };

+        }

+        else {

+            success = error = emptyFn;

+        }

+        // Call local method

+        if (!isArray(params)) {

+            params = [params];

+        }

+        try {

+            var result = fn.method.apply(fn.scope, params.concat([success, error]));

+            if (!undef(result)) {

+                success(result);

+            }

+        } 

+        catch (ex1) {

+            error(ex1.message);

+        }

+    }

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var data = serializer.parse(message);

+            if (data.method) {

+                trace("received request to execute method " + data.method + (data.id ? (" using callback id " + data.id) : ""));

+                // A method call from the remote end

+                if (config.handle) {

+                    config.handle(data, _send);

+                }

+                else {

+                    _executeMethod(data.method, data.id, config.local[data.method], data.params);

+                }

+            }

+            else {

+                trace("received return value destined to callback with id " + data.id);

+                // A method response from the other end

+                var callback = _callbacks[data.id];

+                if (data.error) {

+                    if (callback.error) {

+                        callback.error(data.error);

+                    }

+                    else {

+                        trace("unhandled error returned.");

+                    }

+                }

+                else if (callback.success) {

+                    callback.success(data.result);

+                }

+                delete _callbacks[data.id];

+            }

+        },

+        init: function(){

+            trace("init");

+            if (config.remote) {

+                trace("creating stubs");

+                // Implement the remote sides exposed methods

+                for (var method in config.remote) {

+                    if (config.remote.hasOwnProperty(method)) {

+                        proxy[method] = _createMethod(config.remote[method], method);

+                    }

+                }

+            }

+            pub.down.init();

+        },

+        destroy: function(){

+            trace("destroy");

+            for (var method in config.remote) {

+                if (config.remote.hasOwnProperty(method) && proxy.hasOwnProperty(method)) {

+                    delete proxy[method];

+                }

+            }

+            pub.down.destroy();

+        }

+    });

+};

+global.easyXDM = easyXDM;

+})(window, document, location, window.setTimeout, decodeURIComponent, encodeURIComponent);

diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.js b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.js
new file mode 100644
index 0000000..c0dabbd
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.js
@@ -0,0 +1,2576 @@
+/**
+ * easyXDM
+ * http://easyxdm.net/
+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+(function (window, document, location, setTimeout, decodeURIComponent, encodeURIComponent) {

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global JSON, XMLHttpRequest, window, escape, unescape, ActiveXObject */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+var global = this;

+var channelId = Math.floor(Math.random() * 10000); // randomize the initial id in case of multiple closures loaded 

+var emptyFn = Function.prototype;

+var reURI = /^((http.?:)\/\/([^:\/\s]+)(:\d+)*)/; // returns groups for protocol (2), domain (3) and port (4) 

+var reParent = /[\-\w]+\/\.\.\//; // matches a foo/../ expression 

+var reDoubleSlash = /([^:])\/\//g; // matches // anywhere but in the protocol

+var namespace = ""; // stores namespace under which easyXDM object is stored on the page (empty if object is global)

+var easyXDM = {};

+var _easyXDM = window.easyXDM; // map over global easyXDM in case of overwrite

+var IFRAME_PREFIX = "easyXDM_";

+var HAS_NAME_PROPERTY_BUG;

+var useHash = false; // whether to use the hash over the query

+var flashVersion; // will be set if using flash

+var HAS_FLASH_THROTTLED_BUG;

+

+

+// http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting

+function isHostMethod(object, property){

+    var t = typeof object[property];

+    return t == 'function' ||

+    (!!(t == 'object' && object[property])) ||

+    t == 'unknown';

+}

+

+function isHostObject(object, property){

+    return !!(typeof(object[property]) == 'object' && object[property]);

+}

+

+// end

+

+// http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/

+function isArray(o){

+    return Object.prototype.toString.call(o) === '[object Array]';

+}

+

+// end

+function hasFlash(){

+    var name = "Shockwave Flash", mimeType = "application/x-shockwave-flash";

+    

+    if (!undef(navigator.plugins) && typeof navigator.plugins[name] == "object") {

+        // adapted from the swfobject code

+        var description = navigator.plugins[name].description;

+        if (description && !undef(navigator.mimeTypes) && navigator.mimeTypes[mimeType] && navigator.mimeTypes[mimeType].enabledPlugin) {

+            flashVersion = description.match(/\d+/g);

+        }

+    }

+    if (!flashVersion) {

+        var flash;

+        try {

+            flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");

+            flashVersion = Array.prototype.slice.call(flash.GetVariable("$version").match(/(\d+),(\d+),(\d+),(\d+)/), 1);

+            flash = null;

+        } 

+        catch (notSupportedException) {

+        }

+    }

+    if (!flashVersion) {

+        return false;

+    }

+    var major = parseInt(flashVersion[0], 10), minor = parseInt(flashVersion[1], 10);

+    HAS_FLASH_THROTTLED_BUG = major > 9 && minor > 0;

+    return true;

+}

+

+/*

+ * Cross Browser implementation for adding and removing event listeners.

+ */

+var on, un;

+if (isHostMethod(window, "addEventListener")) {

+    on = function(target, type, listener){

+        target.addEventListener(type, listener, false);

+    };

+    un = function(target, type, listener){

+        target.removeEventListener(type, listener, false);

+    };

+}

+else if (isHostMethod(window, "attachEvent")) {

+    on = function(object, sEvent, fpNotify){

+        object.attachEvent("on" + sEvent, fpNotify);

+    };

+    un = function(object, sEvent, fpNotify){

+        object.detachEvent("on" + sEvent, fpNotify);

+    };

+}

+else {

+    throw new Error("Browser not supported");

+}

+

+/*

+ * Cross Browser implementation of DOMContentLoaded.

+ */

+var domIsReady = false, domReadyQueue = [], readyState;

+if ("readyState" in document) {

+    // If browser is WebKit-powered, check for both 'loaded' (legacy browsers) and

+    // 'interactive' (HTML5 specs, recent WebKit builds) states.

+    // https://bugs.webkit.org/show_bug.cgi?id=45119

+    readyState = document.readyState;

+    domIsReady = readyState == "complete" || (~ navigator.userAgent.indexOf('AppleWebKit/') && (readyState == "loaded" || readyState == "interactive"));

+}

+else {

+    // If readyState is not supported in the browser, then in order to be able to fire whenReady functions apropriately

+    // when added dynamically _after_ DOM load, we have to deduce wether the DOM is ready or not.

+    // We only need a body to add elements to, so the existence of document.body is enough for us.

+    domIsReady = !!document.body;

+}

+

+function dom_onReady(){

+    if (domIsReady) {

+        return;

+    }

+    domIsReady = true;

+    for (var i = 0; i < domReadyQueue.length; i++) {

+        domReadyQueue[i]();

+    }

+    domReadyQueue.length = 0;

+}

+

+

+if (!domIsReady) {

+    if (isHostMethod(window, "addEventListener")) {

+        on(document, "DOMContentLoaded", dom_onReady);

+    }

+    else {

+        on(document, "readystatechange", function(){

+            if (document.readyState == "complete") {

+                dom_onReady();

+            }

+        });

+        if (document.documentElement.doScroll && window === top) {

+            var doScrollCheck = function(){

+                if (domIsReady) {

+                    return;

+                }

+                // http://javascript.nwbox.com/IEContentLoaded/

+                try {

+                    document.documentElement.doScroll("left");

+                } 

+                catch (e) {

+                    setTimeout(doScrollCheck, 1);

+                    return;

+                }

+                dom_onReady();

+            };

+            doScrollCheck();

+        }

+    }

+    

+    // A fallback to window.onload, that will always work

+    on(window, "load", dom_onReady);

+}

+/**

+ * This will add a function to the queue of functions to be run once the DOM reaches a ready state.

+ * If functions are added after this event then they will be executed immediately.

+ * @param {function} fn The function to add

+ * @param {Object} scope An optional scope for the function to be called with.

+ */

+function whenReady(fn, scope){

+    if (domIsReady) {

+        fn.call(scope);

+        return;

+    }

+    domReadyQueue.push(function(){

+        fn.call(scope);

+    });

+}

+

+/**

+ * Returns an instance of easyXDM from the parent window with

+ * respect to the namespace.

+ *

+ * @return An instance of easyXDM (in the parent window)

+ */

+function getParentObject(){

+    var obj = parent;

+    if (namespace !== "") {

+        for (var i = 0, ii = namespace.split("."); i < ii.length; i++) {

+            obj = obj[ii[i]];

+        }

+    }

+    return obj.easyXDM;

+}

+

+/**

+ * Removes easyXDM variable from the global scope. It also returns control

+ * of the easyXDM variable to whatever code used it before.

+ *

+ * @param {String} ns A string representation of an object that will hold

+ *                    an instance of easyXDM.

+ * @return An instance of easyXDM

+ */

+function noConflict(ns){

+    

+    window.easyXDM = _easyXDM;

+    namespace = ns;

+    if (namespace) {

+        IFRAME_PREFIX = "easyXDM_" + namespace.replace(".", "_") + "_";

+    }

+    return easyXDM;

+}

+

+/*

+ * Methods for working with URLs

+ */

+/**

+ * Get the domain name from a url.

+ * @param {String} url The url to extract the domain from.

+ * @return The domain part of the url.

+ * @type {String}

+ */

+function getDomainName(url){

+    return url.match(reURI)[3];

+}

+

+/**

+ * Get the port for a given URL, or "" if none

+ * @param {String} url The url to extract the port from.

+ * @return The port part of the url.

+ * @type {String}

+ */

+function getPort(url){

+    return url.match(reURI)[4] || "";

+}

+

+/**

+ * Returns  a string containing the schema, domain and if present the port

+ * @param {String} url The url to extract the location from

+ * @return {String} The location part of the url

+ */

+function getLocation(url){

+    var m = url.toLowerCase().match(reURI);

+    var proto = m[2], domain = m[3], port = m[4] || "";

+    if ((proto == "http:" && port == ":80") || (proto == "https:" && port == ":443")) {

+        port = "";

+    }

+    return proto + "//" + domain + port;

+}

+

+/**

+ * Resolves a relative url into an absolute one.

+ * @param {String} url The path to resolve.

+ * @return {String} The resolved url.

+ */

+function resolveUrl(url){

+    

+    // replace all // except the one in proto with /

+    url = url.replace(reDoubleSlash, "$1/");

+    

+    // If the url is a valid url we do nothing

+    if (!url.match(/^(http||https):\/\//)) {

+        // If this is a relative path

+        var path = (url.substring(0, 1) === "/") ? "" : location.pathname;

+        if (path.substring(path.length - 1) !== "/") {

+            path = path.substring(0, path.lastIndexOf("/") + 1);

+        }

+        

+        url = location.protocol + "//" + location.host + path + url;

+    }

+    

+    // reduce all 'xyz/../' to just '' 

+    while (reParent.test(url)) {

+        url = url.replace(reParent, "");

+    }

+    

+    return url;

+}

+

+/**

+ * Appends the parameters to the given url.<br/>

+ * The base url can contain existing query parameters.

+ * @param {String} url The base url.

+ * @param {Object} parameters The parameters to add.

+ * @return {String} A new valid url with the parameters appended.

+ */

+function appendQueryParameters(url, parameters){

+    

+    var hash = "", indexOf = url.indexOf("#");

+    if (indexOf !== -1) {

+        hash = url.substring(indexOf);

+        url = url.substring(0, indexOf);

+    }

+    var q = [];

+    for (var key in parameters) {

+        if (parameters.hasOwnProperty(key)) {

+            q.push(key + "=" + encodeURIComponent(parameters[key]));

+        }

+    }

+    return url + (useHash ? "#" : (url.indexOf("?") == -1 ? "?" : "&")) + q.join("&") + hash;

+}

+

+

+// build the query object either from location.query, if it contains the xdm_e argument, or from location.hash

+var query = (function(input){

+    input = input.substring(1).split("&");

+    var data = {}, pair, i = input.length;

+    while (i--) {

+        pair = input[i].split("=");

+        data[pair[0]] = decodeURIComponent(pair[1]);

+    }

+    return data;

+}(/xdm_e=/.test(location.search) ? location.search : location.hash));

+

+/*

+ * Helper methods

+ */

+/**

+ * Helper for checking if a variable/property is undefined

+ * @param {Object} v The variable to test

+ * @return {Boolean} True if the passed variable is undefined

+ */

+function undef(v){

+    return typeof v === "undefined";

+}

+

+/**

+ * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.

+ * @return {JSON} A valid JSON conforming object, or null if not found.

+ */

+var getJSON = function(){

+    var cached = {};

+    var obj = {

+        a: [1, 2, 3]

+    }, json = "{\"a\":[1,2,3]}";

+    

+    if (typeof JSON != "undefined" && typeof JSON.stringify === "function" && JSON.stringify(obj).replace((/\s/g), "") === json) {

+        // this is a working JSON instance

+        return JSON;

+    }

+    if (Object.toJSON) {

+        if (Object.toJSON(obj).replace((/\s/g), "") === json) {

+            // this is a working stringify method

+            cached.stringify = Object.toJSON;

+        }

+    }

+    

+    if (typeof String.prototype.evalJSON === "function") {

+        obj = json.evalJSON();

+        if (obj.a && obj.a.length === 3 && obj.a[2] === 3) {

+            // this is a working parse method           

+            cached.parse = function(str){

+                return str.evalJSON();

+            };

+        }

+    }

+    

+    if (cached.stringify && cached.parse) {

+        // Only memoize the result if we have valid instance

+        getJSON = function(){

+            return cached;

+        };

+        return cached;

+    }

+    return null;

+};

+

+/**

+ * Applies properties from the source object to the target object.<br/>

+ * @param {Object} target The target of the properties.

+ * @param {Object} source The source of the properties.

+ * @param {Boolean} noOverwrite Set to True to only set non-existing properties.

+ */

+function apply(destination, source, noOverwrite){

+    var member;

+    for (var prop in source) {

+        if (source.hasOwnProperty(prop)) {

+            if (prop in destination) {

+                member = source[prop];

+                if (typeof member === "object") {

+                    apply(destination[prop], member, noOverwrite);

+                }

+                else if (!noOverwrite) {

+                    destination[prop] = source[prop];

+                }

+            }

+            else {

+                destination[prop] = source[prop];

+            }

+        }

+    }

+    return destination;

+}

+

+// This tests for the bug in IE where setting the [name] property using javascript causes the value to be redirected into [submitName].

+function testForNamePropertyBug(){

+    var form = document.body.appendChild(document.createElement("form")), input = form.appendChild(document.createElement("input"));

+    input.name = IFRAME_PREFIX + "TEST" + channelId; // append channelId in order to avoid caching issues

+    HAS_NAME_PROPERTY_BUG = input !== form.elements[input.name];

+    document.body.removeChild(form);

+}

+

+/**

+ * Creates a frame and appends it to the DOM.

+ * @param config {object} This object can have the following properties

+ * <ul>

+ * <li> {object} prop The properties that should be set on the frame. This should include the 'src' property.</li>

+ * <li> {object} attr The attributes that should be set on the frame.</li>

+ * <li> {DOMElement} container Its parent element (Optional).</li>

+ * <li> {function} onLoad A method that should be called with the frames contentWindow as argument when the frame is fully loaded. (Optional)</li>

+ * </ul>

+ * @return The frames DOMElement

+ * @type DOMElement

+ */

+function createFrame(config){

+    if (undef(HAS_NAME_PROPERTY_BUG)) {

+        testForNamePropertyBug();

+    }

+    var frame;

+    // This is to work around the problems in IE6/7 with setting the name property. 

+    // Internally this is set as 'submitName' instead when using 'iframe.name = ...'

+    // This is not required by easyXDM itself, but is to facilitate other use cases 

+    if (HAS_NAME_PROPERTY_BUG) {

+        frame = document.createElement("<iframe name=\"" + config.props.name + "\"/>");

+    }

+    else {

+        frame = document.createElement("IFRAME");

+        frame.name = config.props.name;

+    }

+    

+    frame.id = frame.name = config.props.name;

+    delete config.props.name;

+    

+    if (typeof config.container == "string") {

+        config.container = document.getElementById(config.container);

+    }

+    

+    if (!config.container) {

+        // This needs to be hidden like this, simply setting display:none and the like will cause failures in some browsers.

+        apply(frame.style, {

+            position: "absolute",

+            top: "-2000px",

+            // Avoid potential horizontal scrollbar

+            left: "0px"

+        });

+        config.container = document.body;

+    }

+    

+    // HACK: IE cannot have the src attribute set when the frame is appended

+    //       into the container, so we set it to "javascript:false" as a

+    //       placeholder for now.  If we left the src undefined, it would

+    //       instead default to "about:blank", which causes SSL mixed-content

+    //       warnings in IE6 when on an SSL parent page.

+    var src = config.props.src;

+    config.props.src = "javascript:false";

+    

+    // transfer properties to the frame

+    apply(frame, config.props);

+    

+    frame.border = frame.frameBorder = 0;

+    frame.allowTransparency = true;

+    config.container.appendChild(frame);

+    

+    if (config.onLoad) {

+        on(frame, "load", config.onLoad);

+    }

+    

+    // set the frame URL to the proper value (we previously set it to

+    // "javascript:false" to work around the IE issue mentioned above)

+    if(config.usePost) {

+        var form = config.container.appendChild(document.createElement('form')), input;

+        form.target = frame.name;

+        form.action = src;

+        form.method = 'POST';

+        if (typeof(config.usePost) === 'object') {

+            for (var i in config.usePost) {

+                if (config.usePost.hasOwnProperty(i)) {

+                    if (HAS_NAME_PROPERTY_BUG) {

+                        input = document.createElement('<input name="' + i + '"/>');

+                    } else {

+                        input = document.createElement("INPUT");

+                        input.name = i;

+                    }

+                    input.value = config.usePost[i];

+                    form.appendChild(input);

+                }

+            }

+        }

+        form.submit();

+        form.parentNode.removeChild(form);

+    } else {

+        frame.src = src;

+    }

+    config.props.src = src;

+    

+    return frame;

+}

+

+/**

+ * Check whether a domain is allowed using an Access Control List.

+ * The ACL can contain * and ? as wildcards, or can be regular expressions.

+ * If regular expressions they need to begin with ^ and end with $.

+ * @param {Array/String} acl The list of allowed domains

+ * @param {String} domain The domain to test.

+ * @return {Boolean} True if the domain is allowed, false if not.

+ */

+function checkAcl(acl, domain){

+    // normalize into an array

+    if (typeof acl == "string") {

+        acl = [acl];

+    }

+    var re, i = acl.length;

+    while (i--) {

+        re = acl[i];

+        re = new RegExp(re.substr(0, 1) == "^" ? re : ("^" + re.replace(/(\*)/g, ".$1").replace(/\?/g, ".") + "$"));

+        if (re.test(domain)) {

+            return true;

+        }

+    }

+    return false;

+}

+

+/*

+ * Functions related to stacks

+ */

+/**

+ * Prepares an array of stack-elements suitable for the current configuration

+ * @param {Object} config The Transports configuration. See easyXDM.Socket for more.

+ * @return {Array} An array of stack-elements with the TransportElement at index 0.

+ */

+function prepareTransportStack(config){

+    var protocol = config.protocol, stackEls;

+    config.isHost = config.isHost || undef(query.xdm_p);

+    useHash = config.hash || false;

+    

+    if (!config.props) {

+        config.props = {};

+    }

+    if (!config.isHost) {

+        config.channel = query.xdm_c.replace(/["'<>\\]/g, "");

+        config.secret = query.xdm_s;

+        config.remote = query.xdm_e.replace(/["'<>\\]/g, "");

+        ;

+        protocol = query.xdm_p;

+        if (config.acl && !checkAcl(config.acl, config.remote)) {

+            throw new Error("Access denied for " + config.remote);

+        }

+    }

+    else {

+        config.remote = resolveUrl(config.remote);

+        config.channel = config.channel || "default" + channelId++;

+        config.secret = Math.random().toString(16).substring(2);

+        if (undef(protocol)) {

+            if (getLocation(location.href) == getLocation(config.remote)) {

+                /*

+                 * Both documents has the same origin, lets use direct access.

+                 */

+                protocol = "4";

+            }

+            else if (isHostMethod(window, "postMessage") || isHostMethod(document, "postMessage")) {

+                /*

+                 * This is supported in IE8+, Firefox 3+, Opera 9+, Chrome 2+ and Safari 4+

+                 */

+                protocol = "1";

+            }

+            else if (config.swf && isHostMethod(window, "ActiveXObject") && hasFlash()) {

+                /*

+                 * The Flash transport superseedes the NixTransport as the NixTransport has been blocked by MS

+                 */

+                protocol = "6";

+            }

+            else if (navigator.product === "Gecko" && "frameElement" in window && navigator.userAgent.indexOf('WebKit') == -1) {

+                /*

+                 * This is supported in Gecko (Firefox 1+)

+                 */

+                protocol = "5";

+            }

+            else if (config.remoteHelper) {

+                /*

+                 * This is supported in all browsers that retains the value of window.name when

+                 * navigating from one domain to another, and where parent.frames[foo] can be used

+                 * to get access to a frame from the same domain

+                 */

+                protocol = "2";

+            }

+            else {

+                /*

+                 * This is supported in all browsers where [window].location is writable for all

+                 * The resize event will be used if resize is supported and the iframe is not put

+                 * into a container, else polling will be used.

+                 */

+                protocol = "0";

+            }

+        }

+    }

+    config.protocol = protocol; // for conditional branching

+    switch (protocol) {

+        case "0":// 0 = HashTransport

+            apply(config, {

+                interval: 100,

+                delay: 2000,

+                useResize: true,

+                useParent: false,

+                usePolling: false

+            }, true);

+            if (config.isHost) {

+                if (!config.local) {

+                    // If no local is set then we need to find an image hosted on the current domain

+                    var domain = location.protocol + "//" + location.host, images = document.body.getElementsByTagName("img"), image;

+                    var i = images.length;

+                    while (i--) {

+                        image = images[i];

+                        if (image.src.substring(0, domain.length) === domain) {

+                            config.local = image.src;

+                            break;

+                        }

+                    }

+                    if (!config.local) {

+                        // If no local was set, and we are unable to find a suitable file, then we resort to using the current window 

+                        config.local = window;

+                    }

+                }

+                

+                var parameters = {

+                    xdm_c: config.channel,

+                    xdm_p: 0

+                };

+                

+                if (config.local === window) {

+                    // We are using the current window to listen to

+                    config.usePolling = true;

+                    config.useParent = true;

+                    config.local = location.protocol + "//" + location.host + location.pathname + location.search;

+                    parameters.xdm_e = config.local;

+                    parameters.xdm_pa = 1; // use parent

+                }

+                else {

+                    parameters.xdm_e = resolveUrl(config.local);

+                }

+                

+                if (config.container) {

+                    config.useResize = false;

+                    parameters.xdm_po = 1; // use polling

+                }

+                config.remote = appendQueryParameters(config.remote, parameters);

+            }

+            else {

+                apply(config, {

+                    channel: query.xdm_c,

+                    remote: query.xdm_e,

+                    useParent: !undef(query.xdm_pa),

+                    usePolling: !undef(query.xdm_po),

+                    useResize: config.useParent ? false : config.useResize

+                });

+            }

+            stackEls = [new easyXDM.stack.HashTransport(config), new easyXDM.stack.ReliableBehavior({}), new easyXDM.stack.QueueBehavior({

+                encode: true,

+                maxLength: 4000 - config.remote.length

+            }), new easyXDM.stack.VerifyBehavior({

+                initiate: config.isHost

+            })];

+            break;

+        case "1":

+            stackEls = [new easyXDM.stack.PostMessageTransport(config)];

+            break;

+        case "2":

+            config.remoteHelper = resolveUrl(config.remoteHelper);

+            stackEls = [new easyXDM.stack.NameTransport(config), new easyXDM.stack.QueueBehavior(), new easyXDM.stack.VerifyBehavior({

+                initiate: config.isHost

+            })];

+            break;

+        case "3":

+            stackEls = [new easyXDM.stack.NixTransport(config)];

+            break;

+        case "4":

+            stackEls = [new easyXDM.stack.SameOriginTransport(config)];

+            break;

+        case "5":

+            stackEls = [new easyXDM.stack.FrameElementTransport(config)];

+            break;

+        case "6":

+            if (!flashVersion) {

+                hasFlash();

+            }

+            stackEls = [new easyXDM.stack.FlashTransport(config)];

+            break;

+    }

+    // this behavior is responsible for buffering outgoing messages, and for performing lazy initialization

+    stackEls.push(new easyXDM.stack.QueueBehavior({

+        lazy: config.lazy,

+        remove: true

+    }));

+    return stackEls;

+}

+

+/**

+ * Chains all the separate stack elements into a single usable stack.<br/>

+ * If an element is missing a necessary method then it will have a pass-through method applied.

+ * @param {Array} stackElements An array of stack elements to be linked.

+ * @return {easyXDM.stack.StackElement} The last element in the chain.

+ */

+function chainStack(stackElements){

+    var stackEl, defaults = {

+        incoming: function(message, origin){

+            this.up.incoming(message, origin);

+        },

+        outgoing: function(message, recipient){

+            this.down.outgoing(message, recipient);

+        },

+        callback: function(success){

+            this.up.callback(success);

+        },

+        init: function(){

+            this.down.init();

+        },

+        destroy: function(){

+            this.down.destroy();

+        }

+    };

+    for (var i = 0, len = stackElements.length; i < len; i++) {

+        stackEl = stackElements[i];

+        apply(stackEl, defaults, true);

+        if (i !== 0) {

+            stackEl.down = stackElements[i - 1];

+        }

+        if (i !== len - 1) {

+            stackEl.up = stackElements[i + 1];

+        }

+    }

+    return stackEl;

+}

+

+/**

+ * This will remove a stackelement from its stack while leaving the stack functional.

+ * @param {Object} element The elment to remove from the stack.

+ */

+function removeFromStack(element){

+    element.up.down = element.down;

+    element.down.up = element.up;

+    element.up = element.down = null;

+}

+

+/*

+ * Export the main object and any other methods applicable

+ */

+/** 

+ * @class easyXDM

+ * A javascript library providing cross-browser, cross-domain messaging/RPC.

+ * @version 2.4.17.1

+ * @singleton

+ */

+apply(easyXDM, {

+    /**

+     * The version of the library

+     * @type {string}

+     */

+    version: "2.4.17.1",

+    /**

+     * This is a map containing all the query parameters passed to the document.

+     * All the values has been decoded using decodeURIComponent.

+     * @type {object}

+     */

+    query: query,

+    /**

+     * @private

+     */

+    stack: {},

+    /**

+     * Applies properties from the source object to the target object.<br/>

+     * @param {object} target The target of the properties.

+     * @param {object} source The source of the properties.

+     * @param {boolean} noOverwrite Set to True to only set non-existing properties.

+     */

+    apply: apply,

+    

+    /**

+     * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.

+     * @return {JSON} A valid JSON conforming object, or null if not found.

+     */

+    getJSONObject: getJSON,

+    /**

+     * This will add a function to the queue of functions to be run once the DOM reaches a ready state.

+     * If functions are added after this event then they will be executed immediately.

+     * @param {function} fn The function to add

+     * @param {object} scope An optional scope for the function to be called with.

+     */

+    whenReady: whenReady,

+    /**

+     * Removes easyXDM variable from the global scope. It also returns control

+     * of the easyXDM variable to whatever code used it before.

+     *

+     * @param {String} ns A string representation of an object that will hold

+     *                    an instance of easyXDM.

+     * @return An instance of easyXDM

+     */

+    noConflict: noConflict

+});

+

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global console, _FirebugCommandLine,  easyXDM, window, escape, unescape, isHostObject, undef, _trace, domIsReady, emptyFn, namespace */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, isHostObject, isHostMethod, un, on, createFrame, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/** 

+ * @class easyXDM.DomHelper

+ * Contains methods for dealing with the DOM

+ * @singleton

+ */

+easyXDM.DomHelper = {

+    /**

+     * Provides a consistent interface for adding eventhandlers

+     * @param {Object} target The target to add the event to

+     * @param {String} type The name of the event

+     * @param {Function} listener The listener

+     */

+    on: on,

+    /**

+     * Provides a consistent interface for removing eventhandlers

+     * @param {Object} target The target to remove the event from

+     * @param {String} type The name of the event

+     * @param {Function} listener The listener

+     */

+    un: un,

+    /**

+     * Checks for the presence of the JSON object.

+     * If it is not present it will use the supplied path to load the JSON2 library.

+     * This should be called in the documents head right after the easyXDM script tag.

+     * http://json.org/json2.js

+     * @param {String} path A valid path to json2.js

+     */

+    requiresJSON: function(path){

+        if (!isHostObject(window, "JSON")) {

+            // we need to encode the < in order to avoid an illegal token error

+            // when the script is inlined in a document.

+            document.write('<' + 'script type="text/javascript" src="' + path + '"><' + '/script>');

+        }

+    }

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+(function(){

+    // The map containing the stored functions

+    var _map = {};

+    

+    /**

+     * @class easyXDM.Fn

+     * This contains methods related to function handling, such as storing callbacks.

+     * @singleton

+     * @namespace easyXDM

+     */

+    easyXDM.Fn = {

+        /**

+         * Stores a function using the given name for reference

+         * @param {String} name The name that the function should be referred by

+         * @param {Function} fn The function to store

+         * @namespace easyXDM.fn

+         */

+        set: function(name, fn){

+            _map[name] = fn;

+        },

+        /**

+         * Retrieves the function referred to by the given name

+         * @param {String} name The name of the function to retrieve

+         * @param {Boolean} del If the function should be deleted after retrieval

+         * @return {Function} The stored function

+         * @namespace easyXDM.fn

+         */

+        get: function(name, del){

+            var fn = _map[name];

+            

+            if (del) {

+                delete _map[name];

+            }

+            return fn;

+        }

+    };

+    

+}());

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, chainStack, prepareTransportStack, getLocation, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.Socket

+ * This class creates a transport channel between two domains that is usable for sending and receiving string-based messages.<br/>

+ * The channel is reliable, supports queueing, and ensures that the message originates from the expected domain.<br/>

+ * Internally different stacks will be used depending on the browsers features and the available parameters.

+ * <h2>How to set up</h2>

+ * Setting up the provider:

+ * <pre><code>

+ * var socket = new easyXDM.Socket({

+ * &nbsp; local: "name.html",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket

+ * &nbsp; &nbsp; socket.postMessage("foo-message");

+ * &nbsp; },

+ * &nbsp; onMessage: function(message, origin) {

+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * Setting up the consumer:

+ * <pre><code>

+ * var socket = new easyXDM.Socket({

+ * &nbsp; remote: "http:&#47;&#47;remotedomain/page.html",

+ * &nbsp; remoteHelper: "http:&#47;&#47;remotedomain/name.html",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket

+ * &nbsp; &nbsp; socket.postMessage("foo-message");

+ * &nbsp; },

+ * &nbsp; onMessage: function(message, origin) {

+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * If you are unable to upload the <code>name.html</code> file to the consumers domain then remove the <code>remoteHelper</code> property

+ * and easyXDM will fall back to using the HashTransport instead of the NameTransport when not able to use any of the primary transports.

+ * @namespace easyXDM

+ * @constructor

+ * @cfg {String/Window} local The url to the local name.html document, a local static file, or a reference to the local window.

+ * @cfg {Boolean} lazy (Consumer only) Set this to true if you want easyXDM to defer creating the transport until really needed. 

+ * @cfg {String} remote (Consumer only) The url to the providers document.

+ * @cfg {String} remoteHelper (Consumer only) The url to the remote name.html file. This is to support NameTransport as a fallback. Optional.

+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.  Optional, defaults to 2000.

+ * @cfg {Number} interval The interval used when polling for messages. Optional, defaults to 300.

+ * @cfg {String} channel (Consumer only) The name of the channel to use. Can be used to set consistent iframe names. Must be unique. Optional.

+ * @cfg {Function} onMessage The method that should handle incoming messages.<br/> This method should accept two arguments, the message as a string, and the origin as a string. Optional.

+ * @cfg {Function} onReady A method that should be called when the transport is ready. Optional.

+ * @cfg {DOMElement|String} container (Consumer only) The element, or the id of the element that the primary iframe should be inserted into. If not set then the iframe will be positioned off-screen. Optional.

+ * @cfg {Array/String} acl (Provider only) Here you can specify which '[protocol]://[domain]' patterns that should be allowed to act as the consumer towards this provider.<br/>

+ * This can contain the wildcards ? and *.  Examples are 'http://example.com', '*.foo.com' and '*dom?.com'. If you want to use reqular expressions then you pattern needs to start with ^ and end with $.

+ * If none of the patterns match an Error will be thrown.  

+ * @cfg {Object} props (Consumer only) Additional properties that should be applied to the iframe. This can also contain nested objects e.g: <code>{style:{width:"100px", height:"100px"}}</code>. 

+ * Properties such as 'name' and 'src' will be overrided. Optional.

+ */

+easyXDM.Socket = function(config){

+    

+    // create the stack

+    var stack = chainStack(prepareTransportStack(config).concat([{

+        incoming: function(message, origin){

+            config.onMessage(message, origin);

+        },

+        callback: function(success){

+            if (config.onReady) {

+                config.onReady(success);

+            }

+        }

+    }])), recipient = getLocation(config.remote);

+    

+    // set the origin

+    this.origin = getLocation(config.remote);

+	

+    /**

+     * Initiates the destruction of the stack.

+     */

+    this.destroy = function(){

+        stack.destroy();

+    };

+    

+    /**

+     * Posts a message to the remote end of the channel

+     * @param {String} message The message to send

+     */

+    this.postMessage = function(message){

+        stack.outgoing(message, recipient);

+    };

+    

+    stack.init();

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef,, chainStack, prepareTransportStack, debug, getLocation */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/** 

+ * @class easyXDM.Rpc

+ * Creates a proxy object that can be used to call methods implemented on the remote end of the channel, and also to provide the implementation

+ * of methods to be called from the remote end.<br/>

+ * The instantiated object will have methods matching those specified in <code>config.remote</code>.<br/>

+ * This requires the JSON object present in the document, either natively, using json.org's json2 or as a wrapper around library spesific methods.

+ * <h2>How to set up</h2>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; &#47;&#47; this configuration is equal to that used by the Socket.

+ * &nbsp; remote: "http:&#47;&#47;remotedomain/...",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the proxy

+ * &nbsp; &nbsp; rpc.foo(...

+ * &nbsp; }

+ * },{

+ * &nbsp; local: {..},

+ * &nbsp; remote: {..}

+ * });

+ * </code></pre>

+ * 

+ * <h2>Exposing functions (procedures)</h2>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {

+ * &nbsp; &nbsp; nameOfMethod: {

+ * &nbsp; &nbsp; &nbsp; method: function(arg1, arg2, success, error){

+ * &nbsp; &nbsp; &nbsp; &nbsp; ...

+ * &nbsp; &nbsp; &nbsp; }

+ * &nbsp; &nbsp; },

+ * &nbsp; &nbsp; &#47;&#47; with shorthand notation 

+ * &nbsp; &nbsp; nameOfAnotherMethod:  function(arg1, arg2, success, error){

+ * &nbsp; &nbsp; }

+ * &nbsp; },

+ * &nbsp; remote: {...}

+ * });

+ * </code></pre>

+

+ * The function referenced by  [method] will receive the passed arguments followed by the callback functions <code>success</code> and <code>error</code>.<br/>

+ * To send a successfull result back you can use

+ *     <pre><code>

+ *     return foo;

+ *     </pre></code>

+ * or

+ *     <pre><code>

+ *     success(foo);

+ *     </pre></code>

+ *  To return an error you can use

+ *     <pre><code>

+ *     throw new Error("foo error");

+ *     </code></pre>

+ * or

+ *     <pre><code>

+ *     error("foo error");

+ *     </code></pre>

+ *

+ * <h2>Defining remotely exposed methods (procedures/notifications)</h2>

+ * The definition of the remote end is quite similar:

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {...},

+ * &nbsp; remote: {

+ * &nbsp; &nbsp; nameOfMethod: {}

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * To call a remote method use

+ * <pre><code>

+ * rpc.nameOfMethod("arg1", "arg2", function(value) {

+ * &nbsp; alert("success: " + value);

+ * }, function(message) {

+ * &nbsp; alert("error: " + message + );

+ * });

+ * </code></pre>

+ * Both the <code>success</code> and <code>errror</code> callbacks are optional.<br/>

+ * When called with no callback a JSON-RPC 2.0 notification will be executed.

+ * Be aware that you will not be notified of any errors with this method.

+ * <br/>

+ * <h2>Specifying a custom serializer</h2>

+ * If you do not want to use the JSON2 library for non-native JSON support, but instead capabilities provided by some other library

+ * then you can specify a custom serializer using <code>serializer: foo</code>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {...},

+ * &nbsp; remote: {...},

+ * &nbsp; serializer : {

+ * &nbsp; &nbsp; parse: function(string){ ... },

+ * &nbsp; &nbsp; stringify: function(object) {...}

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * If <code>serializer</code> is set then the class will not attempt to use the native implementation.

+ * @namespace easyXDM

+ * @constructor

+ * @param {Object} config The underlying transports configuration. See easyXDM.Socket for available parameters.

+ * @param {Object} jsonRpcConfig The description of the interface to implement.

+ */

+easyXDM.Rpc = function(config, jsonRpcConfig){

+    

+    // expand shorthand notation

+    if (jsonRpcConfig.local) {

+        for (var method in jsonRpcConfig.local) {

+            if (jsonRpcConfig.local.hasOwnProperty(method)) {

+                var member = jsonRpcConfig.local[method];

+                if (typeof member === "function") {

+                    jsonRpcConfig.local[method] = {

+                        method: member

+                    };

+                }

+            }

+        }

+    }

+	

+    // create the stack

+    var stack = chainStack(prepareTransportStack(config).concat([new easyXDM.stack.RpcBehavior(this, jsonRpcConfig), {

+        callback: function(success){

+            if (config.onReady) {

+                config.onReady(success);

+            }

+        }

+    }]));

+	

+    // set the origin 

+    this.origin = getLocation(config.remote);

+	

+    

+    /**

+     * Initiates the destruction of the stack.

+     */

+    this.destroy = function(){

+        stack.destroy();

+    };

+    

+    stack.init();

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, getParentObject, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.SameOriginTransport

+ * SameOriginTransport is a transport class that can be used when both domains have the same origin.<br/>

+ * This can be useful for testing and for when the main application supports both internal and external sources.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote document to communicate with.

+ */

+easyXDM.stack.SameOriginTransport = function(config){

+    var pub, frame, send, targetOrigin;

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            send(message);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            targetOrigin = getLocation(config.remote);

+            

+            if (config.isHost) {

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: location.protocol + "//" + location.host + location.pathname,

+                        xdm_c: config.channel,

+                        xdm_p: 4 // 4 = SameOriginTransport

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+                easyXDM.Fn.set(config.channel, function(sendFn){

+                    send = sendFn;

+                    setTimeout(function(){

+                        pub.up.callback(true);

+                    }, 0);

+                    return function(msg){

+                        pub.up.incoming(msg, targetOrigin);

+                    };

+                });

+            }

+            else {

+                send = getParentObject().Fn.get(config.channel, true)(function(msg){

+                    pub.up.incoming(msg, targetOrigin);

+                });

+                setTimeout(function(){

+                    pub.up.callback(true);

+                }, 0);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global global, easyXDM, window, getLocation, appendQueryParameters, createFrame, debug, apply, whenReady, IFRAME_PREFIX, namespace, resolveUrl, getDomainName, HAS_FLASH_THROTTLED_BUG, getPort, query*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.FlashTransport

+ * FlashTransport is a transport class that uses an SWF with LocalConnection to pass messages back and forth.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote domain to communicate with.

+ * @cfg {String} secret the pre-shared secret used to secure the communication.

+ * @cfg {String} swf The path to the swf file

+ * @cfg {Boolean} swfNoThrottle Set this to true if you want to take steps to avoid beeing throttled when hidden.

+ * @cfg {String || DOMElement} swfContainer Set this if you want to control where the swf is placed

+ */

+easyXDM.stack.FlashTransport = function(config){

+    var pub, // the public interface

+ frame, send, targetOrigin, swf, swfContainer;

+    

+    function onMessage(message, origin){

+        setTimeout(function(){

+            pub.up.incoming(message, targetOrigin);

+        }, 0);

+    }

+    

+    /**

+     * This method adds the SWF to the DOM and prepares the initialization of the channel

+     */

+    function addSwf(domain){

+        // the differentiating query argument is needed in Flash9 to avoid a caching issue where LocalConnection would throw an error.

+        var url = config.swf + "?host=" + config.isHost;

+        var id = "easyXDM_swf_" + Math.floor(Math.random() * 10000);

+        

+        // prepare the init function that will fire once the swf is ready

+        easyXDM.Fn.set("flash_loaded" + domain.replace(/[\-.]/g, "_"), function(){

+            easyXDM.stack.FlashTransport[domain].swf = swf = swfContainer.firstChild;

+            var queue = easyXDM.stack.FlashTransport[domain].queue;

+            for (var i = 0; i < queue.length; i++) {

+                queue[i]();

+            }

+            queue.length = 0;

+        });

+        

+        if (config.swfContainer) {

+            swfContainer = (typeof config.swfContainer == "string") ? document.getElementById(config.swfContainer) : config.swfContainer;

+        }

+        else {

+            // create the container that will hold the swf

+            swfContainer = document.createElement('div');

+            

+            // http://bugs.adobe.com/jira/browse/FP-4796

+            // http://tech.groups.yahoo.com/group/flexcoders/message/162365

+            // https://groups.google.com/forum/#!topic/easyxdm/mJZJhWagoLc

+            apply(swfContainer.style, HAS_FLASH_THROTTLED_BUG && config.swfNoThrottle ? {

+                height: "20px",

+                width: "20px",

+                position: "fixed",

+                right: 0,

+                top: 0

+            } : {

+                height: "1px",

+                width: "1px",

+                position: "absolute",

+                overflow: "hidden",

+                right: 0,

+                top: 0

+            });

+            document.body.appendChild(swfContainer);

+        }

+        

+        // create the object/embed

+        var flashVars = "callback=flash_loaded" + domain.replace(/[\-.]/g, "_") + "&proto=" + global.location.protocol + "&domain=" + getDomainName(global.location.href) + "&port=" + getPort(global.location.href) + "&ns=" + namespace;

+        swfContainer.innerHTML = "<object height='20' width='20' type='application/x-shockwave-flash' id='" + id + "' data='" + url + "'>" +

+        "<param name='allowScriptAccess' value='always'></param>" +

+        "<param name='wmode' value='transparent'>" +

+        "<param name='movie' value='" +

+        url +

+        "'></param>" +

+        "<param name='flashvars' value='" +

+        flashVars +

+        "'></param>" +

+        "<embed type='application/x-shockwave-flash' FlashVars='" +

+        flashVars +

+        "' allowScriptAccess='always' wmode='transparent' src='" +

+        url +

+        "' height='1' width='1'></embed>" +

+        "</object>";

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            swf.postMessage(config.channel, message.toString());

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            try {

+                swf.destroyChannel(config.channel);

+            } 

+            catch (e) {

+            }

+            swf = null;

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            

+            targetOrigin = config.remote;

+            

+            // Prepare the code that will be run after the swf has been intialized

+            easyXDM.Fn.set("flash_" + config.channel + "_init", function(){

+                setTimeout(function(){

+                    pub.up.callback(true);

+                });

+            });

+            

+            // set up the omMessage handler

+            easyXDM.Fn.set("flash_" + config.channel + "_onMessage", onMessage);

+            

+            config.swf = resolveUrl(config.swf); // reports have been made of requests gone rogue when using relative paths

+            var swfdomain = getDomainName(config.swf);

+            var fn = function(){

+                // set init to true in case the fn was called was invoked from a separate instance

+                easyXDM.stack.FlashTransport[swfdomain].init = true;

+                swf = easyXDM.stack.FlashTransport[swfdomain].swf;

+                // create the channel

+                swf.createChannel(config.channel, config.secret, getLocation(config.remote), config.isHost);

+                

+                if (config.isHost) {

+                    // if Flash is going to be throttled and we want to avoid this

+                    if (HAS_FLASH_THROTTLED_BUG && config.swfNoThrottle) {

+                        apply(config.props, {

+                            position: "fixed",

+                            right: 0,

+                            top: 0,

+                            height: "20px",

+                            width: "20px"

+                        });

+                    }

+                    // set up the iframe

+                    apply(config.props, {

+                        src: appendQueryParameters(config.remote, {

+                            xdm_e: getLocation(location.href),

+                            xdm_c: config.channel,

+                            xdm_p: 6, // 6 = FlashTransport

+                            xdm_s: config.secret

+                        }),

+                        name: IFRAME_PREFIX + config.channel + "_provider"

+                    });

+                    frame = createFrame(config);

+                }

+            };

+            

+            if (easyXDM.stack.FlashTransport[swfdomain] && easyXDM.stack.FlashTransport[swfdomain].init) {

+                // if the swf is in place and we are the consumer

+                fn();

+            }

+            else {

+                // if the swf does not yet exist

+                if (!easyXDM.stack.FlashTransport[swfdomain]) {

+                    // add the queue to hold the init fn's

+                    easyXDM.stack.FlashTransport[swfdomain] = {

+                        queue: [fn]

+                    };

+                    addSwf(swfdomain);

+                }

+                else {

+                    easyXDM.stack.FlashTransport[swfdomain].queue.push(fn);

+                }

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.PostMessageTransport

+ * PostMessageTransport is a transport class that uses HTML5 postMessage for communication.<br/>

+ * <a href="http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx</a><br/>

+ * <a href="https://developer.mozilla.org/en/DOM/window.postMessage">https://developer.mozilla.org/en/DOM/window.postMessage</a>

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote domain to communicate with.

+ */

+easyXDM.stack.PostMessageTransport = function(config){

+    var pub, // the public interface

+ frame, // the remote frame, if any

+ callerWindow, // the window that we will call with

+ targetOrigin; // the domain to communicate with

+    /**

+     * Resolves the origin from the event object

+     * @private

+     * @param {Object} event The messageevent

+     * @return {String} The scheme, host and port of the origin

+     */

+    function _getOrigin(event){

+        if (event.origin) {

+            // This is the HTML5 property

+            return getLocation(event.origin);

+        }

+        if (event.uri) {

+            // From earlier implementations 

+            return getLocation(event.uri);

+        }

+        if (event.domain) {

+            // This is the last option and will fail if the 

+            // origin is not using the same schema as we are

+            return location.protocol + "//" + event.domain;

+        }

+        throw "Unable to retrieve the origin of the event";

+    }

+    

+    /**

+     * This is the main implementation for the onMessage event.<br/>

+     * It checks the validity of the origin and passes the message on if appropriate.

+     * @private

+     * @param {Object} event The messageevent

+     */

+    function _window_onMessage(event){

+        var origin = _getOrigin(event);

+        if (origin == targetOrigin && event.data.substring(0, config.channel.length + 1) == config.channel + " ") {

+            pub.up.incoming(event.data.substring(config.channel.length + 1), origin);

+        }

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            callerWindow.postMessage(config.channel + " " + message, domain || targetOrigin);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            un(window, "message", _window_onMessage);

+            if (frame) {

+                callerWindow = null;

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            targetOrigin = getLocation(config.remote);

+            if (config.isHost) {

+                // add the event handler for listening

+                var waitForReady = function(event){  

+                    if (event.data == config.channel + "-ready") {

+                        // replace the eventlistener

+                        callerWindow = ("postMessage" in frame.contentWindow) ? frame.contentWindow : frame.contentWindow.document;

+                        un(window, "message", waitForReady);

+                        on(window, "message", _window_onMessage);

+                        setTimeout(function(){

+                            pub.up.callback(true);

+                        }, 0);

+                    }

+                };

+                on(window, "message", waitForReady);

+                

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: getLocation(location.href),

+                        xdm_c: config.channel,

+                        xdm_p: 1 // 1 = PostMessage

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+            }

+            else {

+                // add the event handler for listening

+                on(window, "message", _window_onMessage);

+                callerWindow = ("postMessage" in window.parent) ? window.parent : window.parent.document;

+                callerWindow.postMessage(config.channel + "-ready", targetOrigin);

+                

+                setTimeout(function(){

+                    pub.up.callback(true);

+                }, 0);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, apply, query, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.FrameElementTransport

+ * FrameElementTransport is a transport class that can be used with Gecko-browser as these allow passing variables using the frameElement property.<br/>

+ * Security is maintained as Gecho uses Lexical Authorization to determine under which scope a function is running.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote document to communicate with.

+ */

+easyXDM.stack.FrameElementTransport = function(config){

+    var pub, frame, send, targetOrigin;

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            send.call(this, message);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            targetOrigin = getLocation(config.remote);

+            

+            if (config.isHost) {

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: getLocation(location.href),

+                        xdm_c: config.channel,

+                        xdm_p: 5 // 5 = FrameElementTransport

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+                frame.fn = function(sendFn){

+                    delete frame.fn;

+                    send = sendFn;

+                    setTimeout(function(){

+                        pub.up.callback(true);

+                    }, 0);

+                    // remove the function so that it cannot be used to overwrite the send function later on

+                    return function(msg){

+                        pub.up.incoming(msg, targetOrigin);

+                    };

+                };

+            }

+            else {

+                // This is to mitigate origin-spoofing

+                if (document.referrer && getLocation(document.referrer) != query.xdm_e) {

+                    window.top.location = query.xdm_e;

+                }

+                send = window.frameElement.fn(function(msg){

+                    pub.up.incoming(msg, targetOrigin);

+                });

+                pub.up.callback(true);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, getLocation, appendQueryParameters, resolveUrl, createFrame, debug, un, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.NameTransport

+ * NameTransport uses the window.name property to relay data.

+ * The <code>local</code> parameter needs to be set on both the consumer and provider,<br/>

+ * and the <code>remoteHelper</code> parameter needs to be set on the consumer.

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remoteHelper The url to the remote instance of hash.html - this is only needed for the host.

+ * @namespace easyXDM.stack

+ */

+easyXDM.stack.NameTransport = function(config){

+    

+    var pub; // the public interface

+    var isHost, callerWindow, remoteWindow, readyCount, callback, remoteOrigin, remoteUrl;

+    

+    function _sendMessage(message){

+        var url = config.remoteHelper + (isHost ? "#_3" : "#_2") + config.channel;

+        callerWindow.contentWindow.sendMessage(message, url);

+    }

+    

+    function _onReady(){

+        if (isHost) {

+            if (++readyCount === 2 || !isHost) {

+                pub.up.callback(true);

+            }

+        }

+        else {

+            _sendMessage("ready");

+            pub.up.callback(true);

+        }

+    }

+    

+    function _onMessage(message){

+        pub.up.incoming(message, remoteOrigin);

+    }

+    

+    function _onLoad(){

+        if (callback) {

+            setTimeout(function(){

+                callback(true);

+            }, 0);

+        }

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            callback = fn;

+            _sendMessage(message);

+        },

+        destroy: function(){

+            callerWindow.parentNode.removeChild(callerWindow);

+            callerWindow = null;

+            if (isHost) {

+                remoteWindow.parentNode.removeChild(remoteWindow);

+                remoteWindow = null;

+            }

+        },

+        onDOMReady: function(){

+            isHost = config.isHost;

+            readyCount = 0;

+            remoteOrigin = getLocation(config.remote);

+            config.local = resolveUrl(config.local);

+            

+            if (isHost) {

+                // Register the callback

+                easyXDM.Fn.set(config.channel, function(message){

+                    if (isHost && message === "ready") {

+                        // Replace the handler

+                        easyXDM.Fn.set(config.channel, _onMessage);

+                        _onReady();

+                    }

+                });

+                

+                // Set up the frame that points to the remote instance

+                remoteUrl = appendQueryParameters(config.remote, {

+                    xdm_e: config.local,

+                    xdm_c: config.channel,

+                    xdm_p: 2

+                });

+                apply(config.props, {

+                    src: remoteUrl + '#' + config.channel,

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                remoteWindow = createFrame(config);

+            }

+            else {

+                config.remoteHelper = config.remote;

+                easyXDM.Fn.set(config.channel, _onMessage);

+            }

+            

+            // Set up the iframe that will be used for the transport

+            var onLoad = function(){

+                // Remove the handler

+                var w = callerWindow || this;

+                un(w, "load", onLoad);

+                easyXDM.Fn.set(config.channel + "_load", _onLoad);

+                (function test(){

+                    if (typeof w.contentWindow.sendMessage == "function") {

+                        _onReady();

+                    }

+                    else {

+                        setTimeout(test, 50);

+                    }

+                }());

+            };

+            

+            callerWindow = createFrame({

+                props: {

+                    src: config.local + "#_4" + config.channel

+                },

+                onLoad: onLoad

+            });

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.HashTransport

+ * HashTransport is a transport class that uses the IFrame URL Technique for communication.<br/>

+ * <a href="http://msdn.microsoft.com/en-us/library/bb735305.aspx">http://msdn.microsoft.com/en-us/library/bb735305.aspx</a><br/>

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String/Window} local The url to the local file used for proxying messages, or the local window.

+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.

+ * @cfg {Number} interval The interval used when polling for messages.

+ */

+easyXDM.stack.HashTransport = function(config){

+    var pub;

+    var me = this, isHost, _timer, pollInterval, _lastMsg, _msgNr, _listenerWindow, _callerWindow;

+    var useParent, _remoteOrigin;

+    

+    function _sendMessage(message){

+        if (!_callerWindow) {

+            return;

+        }

+        var url = config.remote + "#" + (_msgNr++) + "_" + message;

+        ((isHost || !useParent) ? _callerWindow.contentWindow : _callerWindow).location = url;

+    }

+    

+    function _handleHash(hash){

+        _lastMsg = hash;

+        pub.up.incoming(_lastMsg.substring(_lastMsg.indexOf("_") + 1), _remoteOrigin);

+    }

+    

+    /**

+     * Checks location.hash for a new message and relays this to the receiver.

+     * @private

+     */

+    function _pollHash(){

+        if (!_listenerWindow) {

+            return;

+        }

+        var href = _listenerWindow.location.href, hash = "", indexOf = href.indexOf("#");

+        if (indexOf != -1) {

+            hash = href.substring(indexOf);

+        }

+        if (hash && hash != _lastMsg) {

+            _handleHash(hash);

+        }

+    }

+    

+    function _attachListeners(){

+        _timer = setInterval(_pollHash, pollInterval);

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain){

+            _sendMessage(message);

+        },

+        destroy: function(){

+            window.clearInterval(_timer);

+            if (isHost || !useParent) {

+                _callerWindow.parentNode.removeChild(_callerWindow);

+            }

+            _callerWindow = null;

+        },

+        onDOMReady: function(){

+            isHost = config.isHost;

+            pollInterval = config.interval;

+            _lastMsg = "#" + config.channel;

+            _msgNr = 0;

+            useParent = config.useParent;

+            _remoteOrigin = getLocation(config.remote);

+            if (isHost) {

+                apply(config.props, {

+                    src: config.remote,

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                if (useParent) {

+                    config.onLoad = function(){

+                        _listenerWindow = window;

+                        _attachListeners();

+                        pub.up.callback(true);

+                    };

+                }

+                else {

+                    var tries = 0, max = config.delay / 50;

+                    (function getRef(){

+                        if (++tries > max) {

+                            throw new Error("Unable to reference listenerwindow");

+                        }

+                        try {

+                            _listenerWindow = _callerWindow.contentWindow.frames[IFRAME_PREFIX + config.channel + "_consumer"];

+                        } 

+                        catch (ex) {

+                        }

+                        if (_listenerWindow) {

+                            _attachListeners();

+                            pub.up.callback(true);

+                        }

+                        else {

+                            setTimeout(getRef, 50);

+                        }

+                    }());

+                }

+                _callerWindow = createFrame(config);

+            }

+            else {

+                _listenerWindow = window;

+                _attachListeners();

+                if (useParent) {

+                    _callerWindow = parent;

+                    pub.up.callback(true);

+                }

+                else {

+                    apply(config, {

+                        props: {

+                            src: config.remote + "#" + config.channel + new Date(),

+                            name: IFRAME_PREFIX + config.channel + "_consumer"

+                        },

+                        onLoad: function(){

+                            pub.up.callback(true);

+                        }

+                    });

+                    _callerWindow = createFrame(config);

+                }

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.ReliableBehavior

+ * This is a behavior that tries to make the underlying transport reliable by using acknowledgements.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration.

+ */

+easyXDM.stack.ReliableBehavior = function(config){

+    var pub, // the public interface

+ callback; // the callback to execute when we have a confirmed success/failure

+    var idOut = 0, idIn = 0, currentMessage = "";

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var indexOf = message.indexOf("_"), ack = message.substring(0, indexOf).split(",");

+            message = message.substring(indexOf + 1);

+            

+            if (ack[0] == idOut) {

+                currentMessage = "";

+                if (callback) {

+                    callback(true);

+                    callback = null;

+                }

+            }

+            if (message.length > 0) {

+                pub.down.outgoing(ack[1] + "," + idOut + "_" + currentMessage, origin);

+                if (idIn != ack[1]) {

+                    idIn = ack[1];

+                    pub.up.incoming(message, origin);

+                }

+            }

+            

+        },

+        outgoing: function(message, origin, fn){

+            currentMessage = message;

+            callback = fn;

+            pub.down.outgoing(idIn + "," + (++idOut) + "_" + message, origin);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug, undef, removeFromStack*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.QueueBehavior

+ * This is a behavior that enables queueing of messages. <br/>

+ * It will buffer incoming messages and dispach these as fast as the underlying transport allows.

+ * This will also fragment/defragment messages so that the outgoing message is never bigger than the

+ * set length.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration. Optional.

+ * @cfg {Number} maxLength The maximum length of each outgoing message. Set this to enable fragmentation.

+ */

+easyXDM.stack.QueueBehavior = function(config){

+    var pub, queue = [], waiting = true, incoming = "", destroying, maxLength = 0, lazy = false, doFragment = false;

+    

+    function dispatch(){

+        if (config.remove && queue.length === 0) {

+            removeFromStack(pub);

+            return;

+        }

+        if (waiting || queue.length === 0 || destroying) {

+            return;

+        }

+        waiting = true;

+        var message = queue.shift();

+        

+        pub.down.outgoing(message.data, message.origin, function(success){

+            waiting = false;

+            if (message.callback) {

+                setTimeout(function(){

+                    message.callback(success);

+                }, 0);

+            }

+            dispatch();

+        });

+    }

+    return (pub = {

+        init: function(){

+            if (undef(config)) {

+                config = {};

+            }

+            if (config.maxLength) {

+                maxLength = config.maxLength;

+                doFragment = true;

+            }

+            if (config.lazy) {

+                lazy = true;

+            }

+            else {

+                pub.down.init();

+            }

+        },

+        callback: function(success){

+            waiting = false;

+            var up = pub.up; // in case dispatch calls removeFromStack

+            dispatch();

+            up.callback(success);

+        },

+        incoming: function(message, origin){

+            if (doFragment) {

+                var indexOf = message.indexOf("_"), seq = parseInt(message.substring(0, indexOf), 10);

+                incoming += message.substring(indexOf + 1);

+                if (seq === 0) {

+                    if (config.encode) {

+                        incoming = decodeURIComponent(incoming);

+                    }

+                    pub.up.incoming(incoming, origin);

+                    incoming = "";

+                }

+            }

+            else {

+                pub.up.incoming(message, origin);

+            }

+        },

+        outgoing: function(message, origin, fn){

+            if (config.encode) {

+                message = encodeURIComponent(message);

+            }

+            var fragments = [], fragment;

+            if (doFragment) {

+                // fragment into chunks

+                while (message.length !== 0) {

+                    fragment = message.substring(0, maxLength);

+                    message = message.substring(fragment.length);

+                    fragments.push(fragment);

+                }

+                // enqueue the chunks

+                while ((fragment = fragments.shift())) {

+                    queue.push({

+                        data: fragments.length + "_" + fragment,

+                        origin: origin,

+                        callback: fragments.length === 0 ? fn : null

+                    });

+                }

+            }

+            else {

+                queue.push({

+                    data: message,

+                    origin: origin,

+                    callback: fn

+                });

+            }

+            if (lazy) {

+                pub.down.init();

+            }

+            else {

+                dispatch();

+            }

+        },

+        destroy: function(){

+            destroying = true;

+            pub.down.destroy();

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.VerifyBehavior

+ * This behavior will verify that communication with the remote end is possible, and will also sign all outgoing,

+ * and verify all incoming messages. This removes the risk of someone hijacking the iframe to send malicious messages.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration.

+ * @cfg {Boolean} initiate If the verification should be initiated from this end.

+ */

+easyXDM.stack.VerifyBehavior = function(config){

+    var pub, mySecret, theirSecret, verified = false;

+    

+    function startVerification(){

+        mySecret = Math.random().toString(16).substring(2);

+        pub.down.outgoing(mySecret);

+    }

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var indexOf = message.indexOf("_");

+            if (indexOf === -1) {

+                if (message === mySecret) {

+                    pub.up.callback(true);

+                }

+                else if (!theirSecret) {

+                    theirSecret = message;

+                    if (!config.initiate) {

+                        startVerification();

+                    }

+                    pub.down.outgoing(message);

+                }

+            }

+            else {

+                if (message.substring(0, indexOf) === theirSecret) {

+                    pub.up.incoming(message.substring(indexOf + 1), origin);

+                }

+            }

+        },

+        outgoing: function(message, origin, fn){

+            pub.down.outgoing(mySecret + "_" + message, origin, fn);

+        },

+        callback: function(success){

+            if (config.initiate) {

+                startVerification();

+            }

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, getJSON, debug, emptyFn, isArray */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.RpcBehavior

+ * This uses JSON-RPC 2.0 to expose local methods and to invoke remote methods and have responses returned over the the string based transport stack.<br/>

+ * Exposed methods can return values synchronous, asyncronous, or bet set up to not return anything.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} proxy The object to apply the methods to.

+ * @param {Object} config The definition of the local and remote interface to implement.

+ * @cfg {Object} local The local interface to expose.

+ * @cfg {Object} remote The remote methods to expose through the proxy.

+ * @cfg {Object} serializer The serializer to use for serializing and deserializing the JSON. Should be compatible with the HTML5 JSON object. Optional, will default to JSON.

+ */

+easyXDM.stack.RpcBehavior = function(proxy, config){

+    var pub, serializer = config.serializer || getJSON();

+    var _callbackCounter = 0, _callbacks = {};

+    

+    /**

+     * Serializes and sends the message

+     * @private

+     * @param {Object} data The JSON-RPC message to be sent. The jsonrpc property will be added.

+     */

+    function _send(data){

+        data.jsonrpc = "2.0";

+        pub.down.outgoing(serializer.stringify(data));

+    }

+    

+    /**

+     * Creates a method that implements the given definition

+     * @private

+     * @param {Object} The method configuration

+     * @param {String} method The name of the method

+     * @return {Function} A stub capable of proxying the requested method call

+     */

+    function _createMethod(definition, method){

+        var slice = Array.prototype.slice;

+        

+        return function(){

+            var l = arguments.length, callback, message = {

+                method: method

+            };

+            

+            if (l > 0 && typeof arguments[l - 1] === "function") {

+                //with callback, procedure

+                if (l > 1 && typeof arguments[l - 2] === "function") {

+                    // two callbacks, success and error

+                    callback = {

+                        success: arguments[l - 2],

+                        error: arguments[l - 1]

+                    };

+                    message.params = slice.call(arguments, 0, l - 2);

+                }

+                else {

+                    // single callback, success

+                    callback = {

+                        success: arguments[l - 1]

+                    };

+                    message.params = slice.call(arguments, 0, l - 1);

+                }

+                _callbacks["" + (++_callbackCounter)] = callback;

+                message.id = _callbackCounter;

+            }

+            else {

+                // no callbacks, a notification

+                message.params = slice.call(arguments, 0);

+            }

+            if (definition.namedParams && message.params.length === 1) {

+                message.params = message.params[0];

+            }

+            // Send the method request

+            _send(message);

+        };

+    }

+    

+    /**

+     * Executes the exposed method

+     * @private

+     * @param {String} method The name of the method

+     * @param {Number} id The callback id to use

+     * @param {Function} method The exposed implementation

+     * @param {Array} params The parameters supplied by the remote end

+     */

+    function _executeMethod(method, id, fn, params){

+        if (!fn) {

+            if (id) {

+                _send({

+                    id: id,

+                    error: {

+                        code: -32601,

+                        message: "Procedure not found."

+                    }

+                });

+            }

+            return;

+        }

+        

+        var success, error;

+        if (id) {

+            success = function(result){

+                success = emptyFn;

+                _send({

+                    id: id,

+                    result: result

+                });

+            };

+            error = function(message, data){

+                error = emptyFn;

+                var msg = {

+                    id: id,

+                    error: {

+                        code: -32099,

+                        message: message

+                    }

+                };

+                if (data) {

+                    msg.error.data = data;

+                }

+                _send(msg);

+            };

+        }

+        else {

+            success = error = emptyFn;

+        }

+        // Call local method

+        if (!isArray(params)) {

+            params = [params];

+        }

+        try {

+            var result = fn.method.apply(fn.scope, params.concat([success, error]));

+            if (!undef(result)) {

+                success(result);

+            }

+        } 

+        catch (ex1) {

+            error(ex1.message);

+        }

+    }

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var data = serializer.parse(message);

+            if (data.method) {

+                // A method call from the remote end

+                if (config.handle) {

+                    config.handle(data, _send);

+                }

+                else {

+                    _executeMethod(data.method, data.id, config.local[data.method], data.params);

+                }

+            }

+            else {

+                // A method response from the other end

+                var callback = _callbacks[data.id];

+                if (data.error) {

+                    if (callback.error) {

+                        callback.error(data.error);

+                    }

+                }

+                else if (callback.success) {

+                    callback.success(data.result);

+                }

+                delete _callbacks[data.id];

+            }

+        },

+        init: function(){

+            if (config.remote) {

+                // Implement the remote sides exposed methods

+                for (var method in config.remote) {

+                    if (config.remote.hasOwnProperty(method)) {

+                        proxy[method] = _createMethod(config.remote[method], method);

+                    }

+                }

+            }

+            pub.down.init();

+        },

+        destroy: function(){

+            for (var method in config.remote) {

+                if (config.remote.hasOwnProperty(method) && proxy.hasOwnProperty(method)) {

+                    delete proxy[method];

+                }

+            }

+            pub.down.destroy();

+        }

+    });

+};

+global.easyXDM = easyXDM;

+})(window, document, location, window.setTimeout, decodeURIComponent, encodeURIComponent);

diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.min.js b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.min.js
new file mode 100644
index 0000000..8660795
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/easyXDM.min.js
@@ -0,0 +1,24 @@
+/**
+ * easyXDM
+ * http://easyxdm.net/
+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+(function(N,d,p,K,k,H){var b=this;var n=Math.floor(Math.random()*10000);var q=Function.prototype;var Q=/^((http.?:)\/\/([^:\/\s]+)(:\d+)*)/;var R=/[\-\w]+\/\.\.\//;var F=/([^:])\/\//g;var I="";var o={};var M=N.easyXDM;var U="easyXDM_";var E;var y=false;var i;var h;function C(X,Z){var Y=typeof X[Z];return Y=="function"||(!!(Y=="object"&&X[Z]))||Y=="unknown"}function u(X,Y){return !!(typeof(X[Y])=="object"&&X[Y])}function r(X){return Object.prototype.toString.call(X)==="[object Array]"}function c(){var Z="Shockwave Flash",ad="application/x-shockwave-flash";if(!t(navigator.plugins)&&typeof navigator.plugins[Z]=="object"){var ab=navigator.plugins[Z].description;if(ab&&!t(navigator.mimeTypes)&&navigator.mimeTypes[ad]&&navigator.mimeTypes[ad].enabledPlugin){i=ab.match(/\d+/g)}}if(!i){var Y;try{Y=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");i=Array.prototype.slice.call(Y.GetVariable("$version").match(/(\d+),(\d+),(\d+),(\d+)/),1);Y=null}catch(ac){}}if(!i){return false}var X=parseInt(i[0],10),aa=parseInt(i[1],10);h=X>9&&aa>0;return true}var v,x;if(C(N,"addEventListener")){v=function(Z,X,Y){Z.addEventListener(X,Y,false)};x=function(Z,X,Y){Z.removeEventListener(X,Y,false)}}else{if(C(N,"attachEvent")){v=function(X,Z,Y){X.attachEvent("on"+Z,Y)};x=function(X,Z,Y){X.detachEvent("on"+Z,Y)}}else{throw new Error("Browser not supported")}}var W=false,J=[],L;if("readyState" in d){L=d.readyState;W=L=="complete"||(~navigator.userAgent.indexOf("AppleWebKit/")&&(L=="loaded"||L=="interactive"))}else{W=!!d.body}function s(){if(W){return}W=true;for(var X=0;X<J.length;X++){J[X]()}J.length=0}if(!W){if(C(N,"addEventListener")){v(d,"DOMContentLoaded",s)}else{v(d,"readystatechange",function(){if(d.readyState=="complete"){s()}});if(d.documentElement.doScroll&&N===top){var g=function(){if(W){return}try{d.documentElement.doScroll("left")}catch(X){K(g,1);return}s()};g()}}v(N,"load",s)}function G(Y,X){if(W){Y.call(X);return}J.push(function(){Y.call(X)})}function m(){var Z=parent;if(I!==""){for(var X=0,Y=I.split(".");X<Y.length;X++){Z=Z[Y[X]]}}return Z.easyXDM}function e(X){N.easyXDM=M;I=X;if(I){U="easyXDM_"+I.replace(".","_")+"_"}return o}function z(X){return X.match(Q)[3]}function f(X){return X.match(Q)[4]||""}function j(Z){var X=Z.toLowerCase().match(Q);var aa=X[2],ab=X[3],Y=X[4]||"";if((aa=="http:"&&Y==":80")||(aa=="https:"&&Y==":443")){Y=""}return aa+"//"+ab+Y}function B(X){X=X.replace(F,"$1/");if(!X.match(/^(http||https):\/\//)){var Y=(X.substring(0,1)==="/")?"":p.pathname;if(Y.substring(Y.length-1)!=="/"){Y=Y.substring(0,Y.lastIndexOf("/")+1)}X=p.protocol+"//"+p.host+Y+X}while(R.test(X)){X=X.replace(R,"")}return X}function P(X,aa){var ac="",Z=X.indexOf("#");if(Z!==-1){ac=X.substring(Z);X=X.substring(0,Z)}var ab=[];for(var Y in aa){if(aa.hasOwnProperty(Y)){ab.push(Y+"="+H(aa[Y]))}}return X+(y?"#":(X.indexOf("?")==-1?"?":"&"))+ab.join("&")+ac}var S=(function(X){X=X.substring(1).split("&");var Z={},aa,Y=X.length;while(Y--){aa=X[Y].split("=");Z[aa[0]]=k(aa[1])}return Z}(/xdm_e=/.test(p.search)?p.search:p.hash));function t(X){return typeof X==="undefined"}var O=function(){var Y={};var Z={a:[1,2,3]},X='{"a":[1,2,3]}';if(typeof JSON!="undefined"&&typeof JSON.stringify==="function"&&JSON.stringify(Z).replace((/\s/g),"")===X){return JSON}if(Object.toJSON){if(Object.toJSON(Z).replace((/\s/g),"")===X){Y.stringify=Object.toJSON}}if(typeof String.prototype.evalJSON==="function"){Z=X.evalJSON();if(Z.a&&Z.a.length===3&&Z.a[2]===3){Y.parse=function(aa){return aa.evalJSON()}}}if(Y.stringify&&Y.parse){O=function(){return Y};return Y}return null};function T(X,Y,Z){var ab;for(var aa in Y){if(Y.hasOwnProperty(aa)){if(aa in X){ab=Y[aa];if(typeof ab==="object"){T(X[aa],ab,Z)}else{if(!Z){X[aa]=Y[aa]}}}else{X[aa]=Y[aa]}}}return X}function a(){var Y=d.body.appendChild(d.createElement("form")),X=Y.appendChild(d.createElement("input"));X.name=U+"TEST"+n;E=X!==Y.elements[X.name];d.body.removeChild(Y)}function A(Y){if(t(E)){a()}var ac;if(E){ac=d.createElement('<iframe name="'+Y.props.name+'"/>')}else{ac=d.createElement("IFRAME");ac.name=Y.props.name}ac.id=ac.name=Y.props.name;delete Y.props.name;if(typeof Y.container=="string"){Y.container=d.getElementById(Y.container)}if(!Y.container){T(ac.style,{position:"absolute",top:"-2000px",left:"0px"});Y.container=d.body}var ab=Y.props.src;Y.props.src="javascript:false";T(ac,Y.props);ac.border=ac.frameBorder=0;ac.allowTransparency=true;Y.container.appendChild(ac);if(Y.onLoad){v(ac,"load",Y.onLoad)}if(Y.usePost){var aa=Y.container.appendChild(d.createElement("form")),X;aa.target=ac.name;aa.action=ab;aa.method="POST";if(typeof(Y.usePost)==="object"){for(var Z in Y.usePost){if(Y.usePost.hasOwnProperty(Z)){if(E){X=d.createElement('<input name="'+Z+'"/>')}else{X=d.createElement("INPUT");X.name=Z}X.value=Y.usePost[Z];aa.appendChild(X)}}}aa.submit();aa.parentNode.removeChild(aa)}else{ac.src=ab}Y.props.src=ab;return ac}function V(aa,Z){if(typeof aa=="string"){aa=[aa]}var Y,X=aa.length;while(X--){Y=aa[X];Y=new RegExp(Y.substr(0,1)=="^"?Y:("^"+Y.replace(/(\*)/g,".$1").replace(/\?/g,".")+"$"));if(Y.test(Z)){return true}}return false}function l(Z){var ae=Z.protocol,Y;Z.isHost=Z.isHost||t(S.xdm_p);y=Z.hash||false;if(!Z.props){Z.props={}}if(!Z.isHost){Z.channel=S.xdm_c.replace(/["'<>\\]/g,"");Z.secret=S.xdm_s;Z.remote=S.xdm_e.replace(/["'<>\\]/g,"");ae=S.xdm_p;if(Z.acl&&!V(Z.acl,Z.remote)){throw new Error("Access denied for "+Z.remote)}}else{Z.remote=B(Z.remote);Z.channel=Z.channel||"default"+n++;Z.secret=Math.random().toString(16).substring(2);if(t(ae)){if(j(p.href)==j(Z.remote)){ae="4"}else{if(C(N,"postMessage")||C(d,"postMessage")){ae="1"}else{if(Z.swf&&C(N,"ActiveXObject")&&c()){ae="6"}else{if(navigator.product==="Gecko"&&"frameElement" in N&&navigator.userAgent.indexOf("WebKit")==-1){ae="5"}else{if(Z.remoteHelper){ae="2"}else{ae="0"}}}}}}}Z.protocol=ae;switch(ae){case"0":T(Z,{interval:100,delay:2000,useResize:true,useParent:false,usePolling:false},true);if(Z.isHost){if(!Z.local){var ac=p.protocol+"//"+p.host,X=d.body.getElementsByTagName("img"),ad;var aa=X.length;while(aa--){ad=X[aa];if(ad.src.substring(0,ac.length)===ac){Z.local=ad.src;break}}if(!Z.local){Z.local=N}}var ab={xdm_c:Z.channel,xdm_p:0};if(Z.local===N){Z.usePolling=true;Z.useParent=true;Z.local=p.protocol+"//"+p.host+p.pathname+p.search;ab.xdm_e=Z.local;ab.xdm_pa=1}else{ab.xdm_e=B(Z.local)}if(Z.container){Z.useResize=false;ab.xdm_po=1}Z.remote=P(Z.remote,ab)}else{T(Z,{channel:S.xdm_c,remote:S.xdm_e,useParent:!t(S.xdm_pa),usePolling:!t(S.xdm_po),useResize:Z.useParent?false:Z.useResize})}Y=[new o.stack.HashTransport(Z),new o.stack.ReliableBehavior({}),new o.stack.QueueBehavior({encode:true,maxLength:4000-Z.remote.length}),new o.stack.VerifyBehavior({initiate:Z.isHost})];break;case"1":Y=[new o.stack.PostMessageTransport(Z)];break;case"2":Z.remoteHelper=B(Z.remoteHelper);Y=[new o.stack.NameTransport(Z),new o.stack.QueueBehavior(),new o.stack.VerifyBehavior({initiate:Z.isHost})];break;case"3":Y=[new o.stack.NixTransport(Z)];break;case"4":Y=[new o.stack.SameOriginTransport(Z)];break;case"5":Y=[new o.stack.FrameElementTransport(Z)];break;case"6":if(!i){c()}Y=[new o.stack.FlashTransport(Z)];break}Y.push(new o.stack.QueueBehavior({lazy:Z.lazy,remove:true}));return Y}function D(aa){var ab,Z={incoming:function(ad,ac){this.up.incoming(ad,ac)},outgoing:function(ac,ad){this.down.outgoing(ac,ad)},callback:function(ac){this.up.callback(ac)},init:function(){this.down.init()},destroy:function(){this.down.destroy()}};for(var Y=0,X=aa.length;Y<X;Y++){ab=aa[Y];T(ab,Z,true);if(Y!==0){ab.down=aa[Y-1]}if(Y!==X-1){ab.up=aa[Y+1]}}return ab}function w(X){X.up.down=X.down;X.down.up=X.up;X.up=X.down=null}T(o,{version:"2.4.17.1",query:S,stack:{},apply:T,getJSONObject:O,whenReady:G,noConflict:e});o.DomHelper={on:v,un:x,requiresJSON:function(X){if(!u(N,"JSON")){d.write('<script type="text/javascript" src="'+X+'"><\/script>')}}};(function(){var X={};o.Fn={set:function(Y,Z){X[Y]=Z},get:function(Z,Y){var aa=X[Z];if(Y){delete X[Z]}return aa}}}());o.Socket=function(Y){var X=D(l(Y).concat([{incoming:function(ab,aa){Y.onMessage(ab,aa)},callback:function(aa){if(Y.onReady){Y.onReady(aa)}}}])),Z=j(Y.remote);this.origin=j(Y.remote);this.destroy=function(){X.destroy()};this.postMessage=function(aa){X.outgoing(aa,Z)};X.init()};o.Rpc=function(Z,Y){if(Y.local){for(var ab in Y.local){if(Y.local.hasOwnProperty(ab)){var aa=Y.local[ab];if(typeof aa==="function"){Y.local[ab]={method:aa}}}}}var X=D(l(Z).concat([new o.stack.RpcBehavior(this,Y),{callback:function(ac){if(Z.onReady){Z.onReady(ac)}}}]));this.origin=j(Z.remote);this.destroy=function(){X.destroy()};X.init()};o.stack.SameOriginTransport=function(Y){var Z,ab,aa,X;return(Z={outgoing:function(ad,ae,ac){aa(ad);if(ac){ac()}},destroy:function(){if(ab){ab.parentNode.removeChild(ab);ab=null}},onDOMReady:function(){X=j(Y.remote);if(Y.isHost){T(Y.props,{src:P(Y.remote,{xdm_e:p.protocol+"//"+p.host+p.pathname,xdm_c:Y.channel,xdm_p:4}),name:U+Y.channel+"_provider"});ab=A(Y);o.Fn.set(Y.channel,function(ac){aa=ac;K(function(){Z.up.callback(true)},0);return function(ad){Z.up.incoming(ad,X)}})}else{aa=m().Fn.get(Y.channel,true)(function(ac){Z.up.incoming(ac,X)});K(function(){Z.up.callback(true)},0)}},init:function(){G(Z.onDOMReady,Z)}})};o.stack.FlashTransport=function(aa){var ac,X,ab,ad,Y,ae;function af(ah,ag){K(function(){ac.up.incoming(ah,ad)},0)}function Z(ah){var ag=aa.swf+"?host="+aa.isHost;var aj="easyXDM_swf_"+Math.floor(Math.random()*10000);o.Fn.set("flash_loaded"+ah.replace(/[\-.]/g,"_"),function(){o.stack.FlashTransport[ah].swf=Y=ae.firstChild;var ak=o.stack.FlashTransport[ah].queue;for(var al=0;al<ak.length;al++){ak[al]()}ak.length=0});if(aa.swfContainer){ae=(typeof aa.swfContainer=="string")?d.getElementById(aa.swfContainer):aa.swfContainer}else{ae=d.createElement("div");T(ae.style,h&&aa.swfNoThrottle?{height:"20px",width:"20px",position:"fixed",right:0,top:0}:{height:"1px",width:"1px",position:"absolute",overflow:"hidden",right:0,top:0});d.body.appendChild(ae)}var ai="callback=flash_loaded"+ah.replace(/[\-.]/g,"_")+"&proto="+b.location.protocol+"&domain="+z(b.location.href)+"&port="+f(b.location.href)+"&ns="+I;ae.innerHTML="<object height='20' width='20' type='application/x-shockwave-flash' id='"+aj+"' data='"+ag+"'><param name='allowScriptAccess' value='always'></param><param name='wmode' value='transparent'><param name='movie' value='"+ag+"'></param><param name='flashvars' value='"+ai+"'></param><embed type='application/x-shockwave-flash' FlashVars='"+ai+"' allowScriptAccess='always' wmode='transparent' src='"+ag+"' height='1' width='1'></embed></object>"}return(ac={outgoing:function(ah,ai,ag){Y.postMessage(aa.channel,ah.toString());if(ag){ag()}},destroy:function(){try{Y.destroyChannel(aa.channel)}catch(ag){}Y=null;if(X){X.parentNode.removeChild(X);X=null}},onDOMReady:function(){ad=aa.remote;o.Fn.set("flash_"+aa.channel+"_init",function(){K(function(){ac.up.callback(true)})});o.Fn.set("flash_"+aa.channel+"_onMessage",af);aa.swf=B(aa.swf);var ah=z(aa.swf);var ag=function(){o.stack.FlashTransport[ah].init=true;Y=o.stack.FlashTransport[ah].swf;Y.createChannel(aa.channel,aa.secret,j(aa.remote),aa.isHost);if(aa.isHost){if(h&&aa.swfNoThrottle){T(aa.props,{position:"fixed",right:0,top:0,height:"20px",width:"20px"})}T(aa.props,{src:P(aa.remote,{xdm_e:j(p.href),xdm_c:aa.channel,xdm_p:6,xdm_s:aa.secret}),name:U+aa.channel+"_provider"});X=A(aa)}};if(o.stack.FlashTransport[ah]&&o.stack.FlashTransport[ah].init){ag()}else{if(!o.stack.FlashTransport[ah]){o.stack.FlashTransport[ah]={queue:[ag]};Z(ah)}else{o.stack.FlashTransport[ah].queue.push(ag)}}},init:function(){G(ac.onDOMReady,ac)}})};o.stack.PostMessageTransport=function(aa){var ac,ad,Y,Z;function X(ae){if(ae.origin){return j(ae.origin)}if(ae.uri){return j(ae.uri)}if(ae.domain){return p.protocol+"//"+ae.domain}throw"Unable to retrieve the origin of the event"}function ab(af){var ae=X(af);if(ae==Z&&af.data.substring(0,aa.channel.length+1)==aa.channel+" "){ac.up.incoming(af.data.substring(aa.channel.length+1),ae)}}return(ac={outgoing:function(af,ag,ae){Y.postMessage(aa.channel+" "+af,ag||Z);if(ae){ae()}},destroy:function(){x(N,"message",ab);if(ad){Y=null;ad.parentNode.removeChild(ad);ad=null}},onDOMReady:function(){Z=j(aa.remote);if(aa.isHost){var ae=function(af){if(af.data==aa.channel+"-ready"){Y=("postMessage" in ad.contentWindow)?ad.contentWindow:ad.contentWindow.document;x(N,"message",ae);v(N,"message",ab);K(function(){ac.up.callback(true)},0)}};v(N,"message",ae);T(aa.props,{src:P(aa.remote,{xdm_e:j(p.href),xdm_c:aa.channel,xdm_p:1}),name:U+aa.channel+"_provider"});ad=A(aa)}else{v(N,"message",ab);Y=("postMessage" in N.parent)?N.parent:N.parent.document;Y.postMessage(aa.channel+"-ready",Z);K(function(){ac.up.callback(true)},0)}},init:function(){G(ac.onDOMReady,ac)}})};o.stack.FrameElementTransport=function(Y){var Z,ab,aa,X;return(Z={outgoing:function(ad,ae,ac){aa.call(this,ad);if(ac){ac()}},destroy:function(){if(ab){ab.parentNode.removeChild(ab);ab=null}},onDOMReady:function(){X=j(Y.remote);if(Y.isHost){T(Y.props,{src:P(Y.remote,{xdm_e:j(p.href),xdm_c:Y.channel,xdm_p:5}),name:U+Y.channel+"_provider"});ab=A(Y);ab.fn=function(ac){delete ab.fn;aa=ac;K(function(){Z.up.callback(true)},0);return function(ad){Z.up.incoming(ad,X)}}}else{if(d.referrer&&j(d.referrer)!=S.xdm_e){N.top.location=S.xdm_e}aa=N.frameElement.fn(function(ac){Z.up.incoming(ac,X)});Z.up.callback(true)}},init:function(){G(Z.onDOMReady,Z)}})};o.stack.NameTransport=function(ab){var ac;var ae,ai,aa,ag,ah,Y,X;function af(al){var ak=ab.remoteHelper+(ae?"#_3":"#_2")+ab.channel;ai.contentWindow.sendMessage(al,ak)}function ad(){if(ae){if(++ag===2||!ae){ac.up.callback(true)}}else{af("ready");ac.up.callback(true)}}function aj(ak){ac.up.incoming(ak,Y)}function Z(){if(ah){K(function(){ah(true)},0)}}return(ac={outgoing:function(al,am,ak){ah=ak;af(al)},destroy:function(){ai.parentNode.removeChild(ai);ai=null;if(ae){aa.parentNode.removeChild(aa);aa=null}},onDOMReady:function(){ae=ab.isHost;ag=0;Y=j(ab.remote);ab.local=B(ab.local);if(ae){o.Fn.set(ab.channel,function(al){if(ae&&al==="ready"){o.Fn.set(ab.channel,aj);ad()}});X=P(ab.remote,{xdm_e:ab.local,xdm_c:ab.channel,xdm_p:2});T(ab.props,{src:X+"#"+ab.channel,name:U+ab.channel+"_provider"});aa=A(ab)}else{ab.remoteHelper=ab.remote;o.Fn.set(ab.channel,aj)}var ak=function(){var al=ai||this;x(al,"load",ak);o.Fn.set(ab.channel+"_load",Z);(function am(){if(typeof al.contentWindow.sendMessage=="function"){ad()}else{K(am,50)}}())};ai=A({props:{src:ab.local+"#_4"+ab.channel},onLoad:ak})},init:function(){G(ac.onDOMReady,ac)}})};o.stack.HashTransport=function(Z){var ac;var ah=this,af,aa,X,ad,am,ab,al;var ag,Y;function ak(ao){if(!al){return}var an=Z.remote+"#"+(am++)+"_"+ao;((af||!ag)?al.contentWindow:al).location=an}function ae(an){ad=an;ac.up.incoming(ad.substring(ad.indexOf("_")+1),Y)}function aj(){if(!ab){return}var an=ab.location.href,ap="",ao=an.indexOf("#");if(ao!=-1){ap=an.substring(ao)}if(ap&&ap!=ad){ae(ap)}}function ai(){aa=setInterval(aj,X)}return(ac={outgoing:function(an,ao){ak(an)},destroy:function(){N.clearInterval(aa);if(af||!ag){al.parentNode.removeChild(al)}al=null},onDOMReady:function(){af=Z.isHost;X=Z.interval;ad="#"+Z.channel;am=0;ag=Z.useParent;Y=j(Z.remote);if(af){T(Z.props,{src:Z.remote,name:U+Z.channel+"_provider"});if(ag){Z.onLoad=function(){ab=N;ai();ac.up.callback(true)}}else{var ap=0,an=Z.delay/50;(function ao(){if(++ap>an){throw new Error("Unable to reference listenerwindow")}try{ab=al.contentWindow.frames[U+Z.channel+"_consumer"]}catch(aq){}if(ab){ai();ac.up.callback(true)}else{K(ao,50)}}())}al=A(Z)}else{ab=N;ai();if(ag){al=parent;ac.up.callback(true)}else{T(Z,{props:{src:Z.remote+"#"+Z.channel+new Date(),name:U+Z.channel+"_consumer"},onLoad:function(){ac.up.callback(true)}});al=A(Z)}}},init:function(){G(ac.onDOMReady,ac)}})};o.stack.ReliableBehavior=function(Y){var aa,ac;var ab=0,X=0,Z="";return(aa={incoming:function(af,ad){var ae=af.indexOf("_"),ag=af.substring(0,ae).split(",");af=af.substring(ae+1);if(ag[0]==ab){Z="";if(ac){ac(true);ac=null}}if(af.length>0){aa.down.outgoing(ag[1]+","+ab+"_"+Z,ad);if(X!=ag[1]){X=ag[1];aa.up.incoming(af,ad)}}},outgoing:function(af,ad,ae){Z=af;ac=ae;aa.down.outgoing(X+","+(++ab)+"_"+af,ad)}})};o.stack.QueueBehavior=function(Z){var ac,ad=[],ag=true,aa="",af,X=0,Y=false,ab=false;function ae(){if(Z.remove&&ad.length===0){w(ac);return}if(ag||ad.length===0||af){return}ag=true;var ah=ad.shift();ac.down.outgoing(ah.data,ah.origin,function(ai){ag=false;if(ah.callback){K(function(){ah.callback(ai)},0)}ae()})}return(ac={init:function(){if(t(Z)){Z={}}if(Z.maxLength){X=Z.maxLength;ab=true}if(Z.lazy){Y=true}else{ac.down.init()}},callback:function(ai){ag=false;var ah=ac.up;ae();ah.callback(ai)},incoming:function(ak,ai){if(ab){var aj=ak.indexOf("_"),ah=parseInt(ak.substring(0,aj),10);aa+=ak.substring(aj+1);if(ah===0){if(Z.encode){aa=k(aa)}ac.up.incoming(aa,ai);aa=""}}else{ac.up.incoming(ak,ai)}},outgoing:function(al,ai,ak){if(Z.encode){al=H(al)}var ah=[],aj;if(ab){while(al.length!==0){aj=al.substring(0,X);al=al.substring(aj.length);ah.push(aj)}while((aj=ah.shift())){ad.push({data:ah.length+"_"+aj,origin:ai,callback:ah.length===0?ak:null})}}else{ad.push({data:al,origin:ai,callback:ak})}if(Y){ac.down.init()}else{ae()}},destroy:function(){af=true;ac.down.destroy()}})};o.stack.VerifyBehavior=function(ab){var ac,aa,Y,Z=false;function X(){aa=Math.random().toString(16).substring(2);ac.down.outgoing(aa)}return(ac={incoming:function(af,ad){var ae=af.indexOf("_");if(ae===-1){if(af===aa){ac.up.callback(true)}else{if(!Y){Y=af;if(!ab.initiate){X()}ac.down.outgoing(af)}}}else{if(af.substring(0,ae)===Y){ac.up.incoming(af.substring(ae+1),ad)}}},outgoing:function(af,ad,ae){ac.down.outgoing(aa+"_"+af,ad,ae)},callback:function(ad){if(ab.initiate){X()}}})};o.stack.RpcBehavior=function(ad,Y){var aa,af=Y.serializer||O();var ae=0,ac={};function X(ag){ag.jsonrpc="2.0";aa.down.outgoing(af.stringify(ag))}function ab(ag,ai){var ah=Array.prototype.slice;return function(){var aj=arguments.length,al,ak={method:ai};if(aj>0&&typeof arguments[aj-1]==="function"){if(aj>1&&typeof arguments[aj-2]==="function"){al={success:arguments[aj-2],error:arguments[aj-1]};ak.params=ah.call(arguments,0,aj-2)}else{al={success:arguments[aj-1]};ak.params=ah.call(arguments,0,aj-1)}ac[""+(++ae)]=al;ak.id=ae}else{ak.params=ah.call(arguments,0)}if(ag.namedParams&&ak.params.length===1){ak.params=ak.params[0]}X(ak)}}function Z(an,am,ai,al){if(!ai){if(am){X({id:am,error:{code:-32601,message:"Procedure not found."}})}return}var ak,ah;if(am){ak=function(ao){ak=q;X({id:am,result:ao})};ah=function(ao,ap){ah=q;var aq={id:am,error:{code:-32099,message:ao}};if(ap){aq.error.data=ap}X(aq)}}else{ak=ah=q}if(!r(al)){al=[al]}try{var ag=ai.method.apply(ai.scope,al.concat([ak,ah]));if(!t(ag)){ak(ag)}}catch(aj){ah(aj.message)}}return(aa={incoming:function(ah,ag){var ai=af.parse(ah);if(ai.method){if(Y.handle){Y.handle(ai,X)}else{Z(ai.method,ai.id,Y.local[ai.method],ai.params)}}else{var aj=ac[ai.id];if(ai.error){if(aj.error){aj.error(ai.error)}}else{if(aj.success){aj.success(ai.result)}}delete ac[ai.id]}},init:function(){if(Y.remote){for(var ag in Y.remote){if(Y.remote.hasOwnProperty(ag)){ad[ag]=ab(Y.remote[ag],ag)}}}aa.down.init()},destroy:function(){for(var ag in Y.remote){if(Y.remote.hasOwnProperty(ag)&&ad.hasOwnProperty(ag)){delete ad[ag]}}aa.down.destroy()}})};b.easyXDM=o})(window,document,location,window.setTimeout,decodeURIComponent,encodeURIComponent);
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/easyxdm.swf b/asterix-examples/src/main/resources/core/js/easyXDM/easyxdm.swf
new file mode 100644
index 0000000..0a82005
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/easyxdm.swf
Binary files differ
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/blank.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/blank.html
new file mode 100644
index 0000000..33b64d6
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/blank.html
@@ -0,0 +1,10 @@
+<!doctype html>

+<html>

+    <head>

+        <title>Blank page</title>

+		</head>

+		<body>

+        This page will be replaced with the actuall content in just a jiffy.. 

+		</body>

+</html>		

+		
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/bookmark.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/bookmark.html
new file mode 100644
index 0000000..2da7a2c
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/bookmark.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
+        <title></title>
+    </head>
+    <body>
+        <img src="../tests/s.gif" />
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+                document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+            }
+        </script>
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                try {
+                    var pageTracker = _gat._getTracker("UA-9535591-3");
+                    pageTracker._setDomainName(".easyxdm.net");
+                    pageTracker._trackPageview();
+                } 
+                catch (err) {
+                }
+            }
+        </script>
+        <a id="bookmark" src="">Bookmark</a>
+        <script type="text/javascript">
+            var baseUrl = location.href.substring(0, location.href.lastIndexOf("/"));
+            
+            // to simplify development, we create the bookmarklet as a regular function
+            function bookmark(){
+                if (typeof myBookmark === "undefined") {
+                    var script = document.createElement("script");
+                    script.type = "text/javascript";
+                    script.src = baseUrl + "/bookmark.js";
+                    document.getElementsByTagName("head")[0].appendChild(script);
+                }
+                else {
+                    myBookmark.run();
+                }
+            }
+            
+            // and then we include it using .toString().
+            document.getElementById("bookmark").href = 'javascript:(' +
+            (bookmark.toString().replace('baseUrl + "', '"' + baseUrl)).replace(/\s+/g, " ") +
+            ')();';
+            // when finished, you just copy the url from the rendered page
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/bookmark.js b/asterix-examples/src/main/resources/core/js/easyXDM/example/bookmark.js
new file mode 100644
index 0000000..7f0d0ff
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/bookmark.js
@@ -0,0 +1,74 @@
+var myBookmark = (function(){

+    var s1, s2, isLoaded = false, xhr, head = document.getElementsByTagName('head')[0];

+    var scripts = document.getElementsByTagName("script");

+    var REMOTE = (function(){

+        var remote = location.href;

+        switch (location.host) {

+            case "provider.easyxdm.net":

+                location.href = remote.replace("provider", "consumer");

+                break;

+            case "xdm1":

+                remote = remote.replace("xdm1", "xdm2");

+                break;

+            default:

+                remote = "http://provider.easyxdm.net/current/example/";

+        }

+        return remote.substring(0, remote.lastIndexOf("/"));

+    }());

+    

+    function run(){

+        if (typeof xhr === "undefined") {

+            return;

+        }

+        xhr.post("example/glossary.php", {

+            param1: "a",

+            param2: "b"

+        }, function(json){

+            alert(json.glossary.title);

+        });

+    }

+    

+    function scriptOnLoad(){

+        if (isLoaded || typeof easyXDM === "undefined" || typeof JSON === "undefined") {

+            return;

+        }

+        isLoaded = true;

+        xhr = new easyXDM.Rpc({

+            remote: REMOTE + "/../xhr.html",

+            onReady: function(){

+                run();

+            }

+        }, {

+            remote: {

+                post: {}

+            }

+        });

+        

+    }

+    s1 = document.createElement("script");

+    s1.type = "text/javascript";

+    s1.src = REMOTE + "/../easyXDM.debug.js";

+    s1.onreadystatechange = function(){

+        if (this.readyState === "complete" || this.readyState === "loaded") {

+            scriptOnLoad();

+        }

+    };

+    s1.onload = scriptOnLoad;

+    head.appendChild(s1);

+    

+    if (typeof JSON === "undefined" || !JSON) {

+        s2 = document.createElement("script");

+        s2.type = "text/javascript";

+        s2.src = REMOTE + "/../json2.js";

+        s2.onreadystatechange = function(){

+            if (this.readyState === "complete" || this.readyState === "loaded") {

+                scriptOnLoad();

+            }

+        };

+        s2.onload = scriptOnLoad;

+        head.appendChild(s2);

+    }

+    return {

+        run: run

+    };

+})();

diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/bridge.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/bridge.html
new file mode 100644
index 0000000..af840e8
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/bridge.html
@@ -0,0 +1,135 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            /**
+             * Request the use of the JSON object
+             */
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript">
+            /* Here we demo how to have two visible web applications communicate together.
+             * This is done by having the remote interface open a visible window and loading
+             * the application in this.
+             * Since the remote interface has access to the entire DOM (including javascript)
+             * of the opened window, the remote interface is able to interface freely with the
+             * remote web application and can serve as a bridge between the two applications.
+             */
+            var REMOTE = (function(){
+                var remote = location.href;
+                switch (location.host) {
+                    case "provider.easyxdm.net":
+                        location.href = remote.replace("provider", "consumer");
+                        break;
+                    case "easyxdm.net":
+                        remote = remote.replace("easyxdm.net", "consumer.easyxdm.net");
+                        break;
+                    case "consumer.easyxdm.net":
+                        remote = remote.replace("consumer", "provider");
+                        break;
+                    case "xdm1":
+                        remote = remote.replace("xdm1", "xdm2");
+                        break;
+                }
+                return remote.substring(0, remote.lastIndexOf("/"));
+            }());
+            
+            
+            
+            
+            var proxy, win;
+            function openPopup(){
+                if (win) {
+                    // this allows to open new windows if the popup was closed
+                    if (win.closed) {
+                        win = window.open(REMOTE + '/blank.html', 'mainapp', "width=400, height=400");
+                        proxy.open("mainapp");
+                    }
+                    return;
+                }
+                // open up the popup 
+                win = window.open(REMOTE + '/blank.html', 'mainapp', "width=400, height=400");
+                
+                document.getElementById("btn").disabled = "";
+                
+                proxy = new easyXDM.Rpc(/** The configuration */{
+                    /**
+                     * Register the url to name.html, this must be an absolute path
+                     * or a path relative to the root.
+                     * @field
+                     */
+                    local: "../name.html",
+                    swf: REMOTE + "/../easyxdm.swf",
+                    /**
+                     * Register the url to the remote interface
+                     * @field
+                     */
+                    remote: REMOTE + "/remote.html",
+                    remoteHelper: REMOTE + "/../name.html"
+                }, {
+                    remote: {
+                        open: {},
+                        postMessage: {}
+                    },
+                    local: {
+                        /**
+                         * Register the method that should handle incoming data
+                         * @param {Object} data
+                         * @param {String} origin
+                         */
+                        postMessage: function(data){
+                            var div = document.createElement("div");
+                            div.innerHTML = "data from '" + proxy.origin + "'";
+                            document.body.appendChild(div);
+                            for (var key in data) {
+                                if (data.hasOwnProperty(key)) {
+                                    div = document.createElement("div");
+                                    div.innerHTML = key + "=" + data[key];
+                                    document.body.appendChild(div);
+                                }
+                            }
+                        }
+                    }
+                });
+                
+                // lets tell the proxy to open up the window as soon as possible
+                proxy.open("mainapp");
+            }
+        </script>
+    </head>
+    <body>
+        <div style="border:1px solid black;padding:3px;margin:10px;">
+            <a href="index.html">Index of examples</a>
+            | <a href="http://github.com/oyvindkinsey/easyXDM/#readme">Readme at github</a>
+            | 
+            | <a href="http://easyxdm.net/">easyXDM.net</a>
+            | <a href="http://groups.google.com/group/easyxdm">easyXDM at Google Groups</a>
+            <br/>
+            The examples are executing slower than the production build due to the extensive tracing.
+            <br/>
+            If you are alerted about a popup, then this is only the trace log feature. You can ignore this.
+        </div>
+        <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+        <div id="log" style="height:100px;border:1px dotted black;overflow:auto">
+        </div>
+        <input id="btnOpen" type="button" onclick="openPopup();" value="Open popup"/><!-- Send som data to the other side --><input id="btn" disabled="disabled" type="button" onclick="proxy.postMessage({a:'b',c:'d',e:'f'});" value="send data to remote"/>
+        <script type="text/javascript">
+            var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+            document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+        </script>
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                try {
+                    var pageTracker = _gat._getTracker("UA-9535591-3");
+                    pageTracker._setDomainName(".easyxdm.net");
+                    pageTracker._trackPageview();
+                } 
+                catch (err) {
+                }
+            }
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/data.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/data.html
new file mode 100644
index 0000000..47eaeed
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/data.html
@@ -0,0 +1,133 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            var serializer = {
+                /**
+                 * Serializes a hashtable and returns it as a string
+                 * @param {Object} data The data to serialize
+                 * @returns The serialized string
+                 * @type {String}
+                 */
+                stringify: function(data){
+                    var message = "";
+                    for (var key in data) {
+                        if (data.hasOwnProperty(key)) {
+                            message += key + "=" + escape(data[key]) + "&";
+                        }
+                    }
+                    return message.substring(0, message.length - 1);
+                },
+                /**
+                 * Deserializes a string and returns a hashtable
+                 * @param {String} message The string to deserialize
+                 * @returns An hashtable populated with key-value pairs
+                 * @type {Object}
+                 */
+                parse: function(message){
+                    var data = {};
+                    var d = message.split("&");
+                    var pair, key, value;
+                    for (var i = 0, len = d.length; i < len; i++) {
+                        pair = d[i];
+                        key = pair.substring(0, pair.indexOf("="));
+                        value = pair.substring(key.length + 1);
+                        data[key] = unescape(value);
+                    }
+                    return data;
+                }
+            };
+            
+            var channel;
+            var REMOTE = (function(){
+                var remote = location.href;
+                switch (location.host) {
+                    case "provider.easyxdm.net":
+                        location.href = remote.replace("provider", "consumer");
+                        break;
+                    case "easyxdm.net":
+                        remote = remote.replace("easyxdm.net", "consumer.easyxdm.net");
+                        break;
+                    case "consumer.easyxdm.net":
+                        remote = remote.replace("consumer", "provider");
+                        break;
+                    case "xdm1":
+                        remote = remote.replace("xdm1", "xdm2");
+                        break;
+                }
+                return remote.substring(0, remote.lastIndexOf("/"));
+            }());
+            window.onload = function(){
+                /**
+                 * When the window is finished loading start setting up the channel
+                 */
+                channel = new easyXDM.Socket(/** The configuration */{
+                    /**
+                     * Register the url to hash.html, this must be an absolute path
+                     * or a path relative to the root.
+                     * @field
+                     */
+                    local: "../name.html",
+                    swf: REMOTE + "/../easyxdm.swf",
+                    /**
+                     * Register the url to the remote interface
+                     * @field
+                     */
+                    remote: REMOTE + "/remotedata.html",
+                    remoteHelper: REMOTE + "/../name.html",
+                    onReady: function(){
+                        /**
+                         * Send some data to the other side
+                         */
+                        channel.postMessage(serializer.stringify({
+                            propA: "abc",
+                            propB: "def",
+                            propC: 44
+                        }));
+                    }
+                });
+            };
+        </script>
+    </head>
+    <body>
+    <div style="border:1px solid black;padding:3px;margin:10px;">
+        <a href="index.html">Index of examples</a>
+        | <a href="http://github.com/oyvindkinsey/easyXDM/#readme">Readme at github</a>
+        | 
+        | <a href="http://easyxdm.net/">easyXDM.net</a>
+        | <a href="http://groups.google.com/group/easyxdm">easyXDM at Google Groups</a>
+        <br/>
+        The examples are executing slower than the production build due to the extensive tracing.
+        <br/>
+        If you are alerted about a popup, then this is only the trace log feature. You can ignore this.
+    </div>
+    <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+    <div id="log" style="height:100px;border:1px dotted black;overflow:auto">
+    </div>
+    </div>
+    <br/>
+    <br/>
+    <input type="text" id="code" size="100" value="channel.postMessage(serializer.stringify({propC:'c',procD:'d',propE:88}))"/>
+    <button onclick="eval(document.getElementById('code').value);">
+        eval code
+    </button>
+    <script type="text/javascript">
+        var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+        document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+    </script>
+    <script type="text/javascript">
+        if (location.host.indexOf("easyxdm.net") !== -1) {
+            try {
+                var pageTracker = _gat._getTracker("UA-9535591-3");
+                pageTracker._setDomainName(".easyxdm.net");
+                pageTracker._trackPageview();
+            } 
+            catch (err) {
+            }
+        }
+    </script>
+</body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/glossary.aspx b/asterix-examples/src/main/resources/core/js/easyXDM/example/glossary.aspx
new file mode 100644
index 0000000..c815101
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/glossary.aspx
@@ -0,0 +1,29 @@
+<%

+    Response.ContentType = "application/json"

+    Response.AddHeader("x-foo", "bar")

+    Response.AddHeader("Access-Control-Allow-Origin", "http://xdm4")

+    Response.AddHeader("Access-Control-Allow-Methods", "POST")

+

+%>

+{

+    "glossary": {

+        "title": "example glossary",

+        "GlossDiv": {

+            "title": "S",

+            "GlossList": {

+                "GlossEntry": {

+                    "ID": "SGML",

+                    "SortAs": "SGML",

+                    "GlossTerm": "Standard Generalized Markup Language",

+                    "Acronym": "SGML",

+                    "Abbrev": "ISO 8879:1986",

+                    "GlossDef": {

+                        "para": "A meta-markup language, used to create markup languages such as DocBook.",

+                        "GlossSeeAlso": ["GML", "XML"]

+                    },

+                    "GlossSee": "markup"

+                }

+            }

+        }

+    }

+}
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/index.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/index.html
new file mode 100644
index 0000000..3690577
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/index.html
@@ -0,0 +1,75 @@
+<!doctype html>

+<html>

+    <head>

+        <title>easyXDM</title>

+    </head>

+    <body>

+        <div style="border:1px solid black;padding:3px;margin:10px;">

+            <a href="http://github.com/oyvindkinsey/easyXDM/#readme">Readme at github</a>

+            | 

+            | <a href="http://easyxdm.net/">easyXDM.net</a>

+            | <a href="http://groups.google.com/group/easyxdm">easyXDM at Google Groups</a>

+            <br/>

+            The examples are executing slower than the production build due to the extensive tracing.

+            <br/>

+            If you are alerted about a popup, then this is only the trace log feature. You can ignore this.

+        </div>

+        <ul>

+        	<li>

+                <a href="transport.html">Transport</a>

+                <br/>

+                Example of passing a string message from one domain to another using the Socket.

+            </li>

+            <li>

+                <a href="data.html">Data</a>

+                <br/>

+                Example of passing data using a Socket and a custom serializer/deserializer.

+            </li>

+            <li>

+                <a href="methods.html">Methods</a>

+                <br/>

+                Example of using the Rpc object for executing Remote Procedure Calls with arguments and having results returned.

+            </li>

+            <li>

+                <a href="resize_iframe.html">Resize iframe</a>

+                <br/>

+                Example on how to use easyXDM to automatically resize an iframe. This uses an intermediate frame to enable navigation of the contained document

+            </li>

+            <li>

+                <a href="upload.html">Upload</a>

+                <br/>

+                Example on how to facilitate 'cross domain AJAX upload'. 

+            </li>

+            <li>

+                <a href="widgets.html">Widgets</a>

+                <br/>

+                Example on how to use easyXDM to build a framework for widgets using a pub/sub schema.

+            </li>

+            <li>

+                <a href="xhr.html">XHR</a>

+                <br/>

+                Example of using the shipped /cors/ endpoint to retrieve resources across the domain boundary.

+            </li>

+            <li>

+                <a href="bridge.html">Bridge</a>

+                <br/>

+                Experimental example of how to 'bridge' two web apps together. 

+            </li>

+        </ul>

+        <script type="text/javascript">

+            var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");

+            document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));

+        </script>

+        <script type="text/javascript">

+            if (location.host.indexOf("easyxdm.net") !== -1) {

+                try {

+                    var pageTracker = _gat._getTracker("UA-9535591-3");

+                    pageTracker._setDomainName(".easyxdm.net");

+                    pageTracker._trackPageview();

+                } 

+                catch (err) {

+                }

+            }

+        </script>

+    </body>

+</html>

diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/methods.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/methods.html
new file mode 100644
index 0000000..9bbd15a
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/methods.html
@@ -0,0 +1,148 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            /**
+             * Request the use of the JSON object
+             */
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript">
+            var REMOTE = (function(){
+                var remote = location.href;
+                switch (location.host) {
+                    case "provider.easyxdm.net":
+                        location.href = remote.replace("provider", "consumer");
+                        break;
+                    case "easyxdm.net":
+                        remote = remote.replace("easyxdm.net", "consumer.easyxdm.net");
+                        break;
+                    case "consumer.easyxdm.net":
+                        remote = remote.replace("consumer", "provider");
+                        break;
+                    case "xdm1":
+                        remote = remote.replace("xdm1", "xdm2");
+                        break;
+                }
+                return remote.substring(0, remote.lastIndexOf("/"));
+            }());
+            var remote = new easyXDM.Rpc(/** The channel configuration */{
+                /**
+                 * Register the url to hash.html, this must be an absolute path
+                 * or a path relative to the root.
+                 * @field
+                 */
+                local: "../name.html",
+                swf: REMOTE + "/../easyxdm.swf",
+                /**
+                 * Register the url to the remote interface
+                 * @field
+                 */
+                remote: REMOTE + "/remotemethods.html",
+                remoteHelper: REMOTE + "/../name.html",
+                /**
+                 * Register the DOMElement that the generated IFrame should be inserted into
+                 */
+                container: "embedded",
+                props: {
+                    style: {
+                        border: "2px dotted red",
+                        height: "200px"
+                    }
+                },
+                onReady: function(){
+                    /**
+                     * Call a method on the other side
+                     */
+                    remote.noOp();
+                }
+            }, /** The interface configuration */ {
+                remote: {
+                    addNumbers: {},
+                    multiplyNumbers: {},
+                    noOp: {}
+                },
+                local: {
+                    alertMessage: function(msg){
+                        alert(msg);
+                    }
+                }
+            });
+            
+            function add(a, b){
+                remote.addNumbers(a, b, function(result){
+                    alert(a + " + " + b + " = " + result);
+                });
+            }
+            
+            function multiply(a, b){
+                remote.multiplyNumbers(a, b, function(result){
+                    alert(a + " x " + b + " = " + result);
+                });
+            }
+        </script>
+        <style type="text/css">
+            
+            #embedded iframe {
+                width: 100%;
+                height: 100%;
+            }
+        </style>
+    </head>
+    <body>
+        <div style="border:1px solid black;padding:3px;margin:10px;">
+            <a href="index.html">Index of examples</a>
+            | <a href="http://github.com/oyvindkinsey/easyXDM/#readme">Readme at github</a>
+            | 
+            | <a href="http://easyxdm.net/">easyXDM.net</a>
+            | <a href="http://groups.google.com/group/easyxdm">easyXDM at Google Groups</a>
+            <br/>
+            The examples are executing slower than the production build due to the extensive tracing.
+            <br/>
+            If you are alerted about a popup, then this is only the trace log feature. You can ignore this.
+        </div>
+        <script type="text/javascript">
+            document.write("Domain: " + location.host);
+        </script>
+        <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+        <div id="log" style="height:100px;border:1px dotted black;overflow:auto">
+        </div>
+        <div id="embedded">
+        </div>
+        <div>
+            The remote implementation is synchronous and will return immediately
+            <br/>
+            <input type="button" onclick="add(3,5);" value="call addNumbers on remote domain"/>
+            <br/>
+            <br/>
+            The remote implementation of multiplyNumbers is asynchronous and will return after 5seconds
+            <br/>
+            This shows that you can use async calls in the remote method, eg. XHR calls
+            <br/>
+            <input type="button" onclick="multiply(3,5);" value="call multiplyNumbers on remote domain"/>
+            <br/>
+            <br/>
+            This calls a non-returning method on the remote side
+            <br/>
+            <input type="button" onclick="remote.noOp();" value="call noOp on the remote domain"/>
+        </div>
+        <script type="text/javascript">
+            var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+            document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+        </script>
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                try {
+                    var pageTracker = _gat._getTracker("UA-9535591-3");
+                    pageTracker._setDomainName(".easyxdm.net");
+                    pageTracker._trackPageview();
+                } 
+                catch (err) {
+                }
+            }
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/remote.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/remote.html
new file mode 100644
index 0000000..ad82e8a
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/remote.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            /**
+             * Request the use of the JSON object
+             */
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript">
+            var win, remoteapp; // reference to the popups window
+            var proxy = new easyXDM.Rpc(/** The configuration */{
+                local: "../name.html",
+                swf: "../easyxdm.swf"
+            }, {
+                local: {
+                    /**
+                     * This is used to open up the popup. A popup with the given name should already be opened
+                     * in the user click handler.
+                     */
+                    open: function(name){
+                        remoteapp = null;
+                        // we now open the window, passing the name of this window (includes the channel name)
+                        // in case it has to look us up using the framename
+                        win = window.open('remoteapp.html' + '#easyXDM_' + easyXDM.query.xdm_c + '_provider', name, "width=400, height=400");
+                    },
+                    /**
+                     * This is where we receive the data
+                     * @param {Object} data The data
+                     */
+                    postMessage: function(data){
+                        if (win.closed) {
+                            alert("the popup has been closed - please open it again");
+                            return;
+                        }
+                        var div = remoteapp.document.createElement("div");
+                        div.innerHTML = "data from '" + proxy.origin + "'";
+                        if (remoteapp) {
+                            remoteapp.document.body.appendChild(div);
+                            for (var key in data) {
+                                if (data.hasOwnProperty(key)) {
+                                    div = remoteapp.document.createElement("div");
+                                    div.innerHTML = key + "=" + data[key];
+                                    remoteapp.document.body.appendChild(div);
+                                }
+                            }
+                            remoteapp.focus();
+                        }
+                    }
+                },
+                remote: {
+                    postMessage: {}
+                }
+            });
+            
+            
+            /**
+             * The popup must use this window to register itself
+             * @param {DOMWindow} app The window object of the popup
+             */
+            function setApp(app){
+                remoteapp = app;
+            }
+            
+            /**
+             * The popup must use this method to send data. This clones the object in order to
+             * work around a but in IE
+             * @param {Object} data The data to send
+             */
+            function sendData(data){
+                var copy = {};
+                // copy the object in order to avoid the JSON serialization bug
+                easyXDM.apply(copy, data);
+                proxy.postMessage(copy);
+            }
+        </script>
+    </head>
+    <body>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/remoteapp.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/remoteapp.html
new file mode 100644
index 0000000..e493b68
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/remoteapp.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript">
+            var target = location.hash.substring(1);
+            
+            var host = window.opener.frames[target];
+            
+            if (window.opener) {
+                try {
+                    // test if we have access to the document 
+                    if (window.opener.document.title) {
+                        host = window.opener;
+                    }
+                    
+                } 
+                catch (xDomainError) {
+                    // we have an opener, but it's not on our domain, 
+                    host = window.opener.frames[target];
+                }
+                
+                if (host) {
+                    try {
+                        host.setApp(window);
+                    } 
+                    catch (browserHostError) {
+                        alert("was unable to gain a reference to the iframe");
+                    }
+                }
+            }
+        </script>
+    </head>
+    <body>
+        <!-- Send some data to the other side using the proxy --><input type="button" onclick="host.sendData({a:'b',c:'d',e:'f'});" value="send data to local"/>
+    </body>
+</html>
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/remotedata.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/remotedata.html
new file mode 100644
index 0000000..814355c
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/remotedata.html
@@ -0,0 +1,64 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            var serializer = {
+                /**
+                 * Serializes a hashtable and returns it as a string
+                 * @param {Object} data The data to serialize
+                 * @returns The serialized string
+                 * @type {String}
+                 */
+                stringify: function(data){
+                    var message = "";
+                    for (var key in data) {
+                        if (data.hasOwnProperty(key)) {
+                            message += key + "=" + escape(data[key]) + "&";
+                        }
+                    }
+                    return message.substring(0, message.length - 1);
+                },
+                /**
+                 * Deserializes a string and returns a hashtable
+                 * @param {String} message The string to deserialize
+                 * @returns An hashtable populated with key-value pairs
+                 * @type {Object}
+                 */
+                parse: function(message){
+                    var data = {};
+                    var d = message.split("&");
+                    var pair, key, value;
+                    for (var i = 0, len = d.length; i < len; i++) {
+                        pair = d[i];
+                        key = pair.substring(0, pair.indexOf("="));
+                        value = pair.substring(key.length + 1);
+                        data[key] = unescape(value);
+                    }
+                    return data;
+                }
+            };
+            
+            var socket = new easyXDM.Socket(/** The configuration */{
+                local: "../name.html",
+                swf: "../easyxdm.swf",
+                /**
+                 * Register the method that should handle incoming data
+                 * @param {Object} data
+                 * @param {String} origin
+                 */
+                onMessage: function(data, origin){
+                    data = serializer.parse(data);
+                    alert("Received data from '" + origin + "':");
+                    for (var key in data) {
+                        alert("Property '" + key + "'=" + data[key]);
+                    }
+                }
+            });
+        </script>
+    </head>
+    <body>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/remotemethods.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/remotemethods.html
new file mode 100644
index 0000000..2ea8c1f
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/remotemethods.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            /**
+             * Request the use of the JSON object
+             */
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript">
+            var remote = new easyXDM.Rpc(/** The channel configuration*/{
+                local: "../name.html",
+                swf: "../easyxdm.swf"
+            }, /** The configuration */ {
+                remote: {
+                    alertMessage: {}
+                },
+                local: {
+                    addNumbers: function(a, b){
+                        return a + b;
+                    },
+                    multiplyNumbers: function(a, b, fn){
+                        window.setTimeout(function(){
+                            fn(a * b);
+                        }, 5000);
+                    },
+                    noOp: function(){
+                        alert("Method not returning any data");
+                    }
+                }
+            });
+        </script>
+    </head>
+    <body>
+        <script type="text/javascript">
+            document.write("Domain: " + location.host);
+        </script>
+        <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+        <div id="log" style="height:100px;border:1px dotted black;overflow:auto">
+        </div>
+        <input type="button" onclick="remote.alertMessage('message from remote');" value="call alertMessage on local domain"/>
+    </body>
+</html>
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/remoterpcbackend.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/remoterpcbackend.html
new file mode 100644
index 0000000..59a411a
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/remoterpcbackend.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            /**
+             * Request the use of the JSON object
+             */
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript">
+            var remote = new easyXDM.Rpc(/** The channel configuration*/{
+                local: "../name.html"
+            }, /** The configuration */ {
+                /**
+                 *
+                 * @param {Object} rpc A JSON-RPC 2.0 request object
+                 * @param {Function} reply The callback method. Takes a single JSON-RPC 2.0 response object.
+                 */
+                handle: function(rpc, reply){
+                    alert("requested to execute procedure '" + rpc.method + "'");
+                }
+            });
+        </script>
+    </head>
+    <body>
+        <script type="text/javascript">
+            document.write("Domain: " + location.host);
+        </script>
+        <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+        <div id="log" style="height:100px;border:1px dotted black;overflow:auto">
+        </div>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/remotetransport.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/remotetransport.html
new file mode 100644
index 0000000..64093a7
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/remotetransport.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            var transport = new easyXDM.Socket(/** The configuration */{
+                local: "../name.html",
+                swf: "../easyxdm.swf",
+                /**
+                 * Register the method that should handle incoming messages
+                 * @param {String} data
+                 * @param {String} origin
+                 */
+                onMessage: function(message, origin){
+                    alert("Received '" + message + "' from '" + origin + "'");
+                }
+            });
+        </script>
+    </head>
+    <body>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/resize_iframe.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/resize_iframe.html
new file mode 100644
index 0000000..e0b0adb
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/resize_iframe.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            var REMOTE = (function(){
+                var remote = location.href;
+                switch (location.host) {
+                    case "provider.easyxdm.net":
+                        location.href = remote.replace("provider", "consumer");
+                        break;
+                    case "easyxdm.net":
+                        remote = remote.replace("easyxdm.net", "consumer.easyxdm.net");
+                        break;
+                    case "consumer.easyxdm.net":
+                        remote = remote.replace("consumer", "provider");
+                        break;
+                    case "xdm1":
+                        remote = remote.replace("xdm1", "xdm2");
+                        break;
+                }
+                return remote.substring(0, remote.lastIndexOf("/"));
+            }());
+            
+            var transport = new easyXDM.Socket(/** The configuration */{
+                remote: REMOTE + "/resize_intermediate.html?url=resized_iframe_1.html",
+                swf: REMOTE + "/../easyxdm.swf",
+                container: "embedded",
+                onMessage: function(message, origin){
+                    this.container.getElementsByTagName("iframe")[0].style.height = message + "px";
+                }
+            });
+        </script>
+    </head>
+    <body>
+        <div style="border:1px solid black;padding:3px;margin:10px;">
+            <a href="index.html">Index of examples</a>
+            | <a href="http://github.com/oyvindkinsey/easyXDM/#readme">Readme at github</a>
+            | 
+            | <a href="http://easyxdm.net/">easyXDM.net</a>
+            | <a href="http://groups.google.com/group/easyxdm">easyXDM at Google Groups</a>
+            <br/>
+            The examples are executing slower than the production build due to the extensive tracing.
+            <br/>
+            If you are alerted about a popup, then this is only the trace log feature. You can ignore this.
+        </div>
+        <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+        <div id="log" style="height:100px;border:1px dotted black;overflow:auto">
+        </div>
+        <div id="embedded">
+        </div>
+        <script type="text/javascript">
+            var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+            document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+        </script>
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                try {
+                    var pageTracker = _gat._getTracker("UA-9535591-3");
+                    pageTracker._setDomainName(".easyxdm.net");
+                    pageTracker._trackPageview();
+                } 
+                catch (err) {
+                }
+            }
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/resize_intermediate.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/resize_intermediate.html
new file mode 100644
index 0000000..8b5f03e
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/resize_intermediate.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js"></script>
+        <script type="text/javascript">
+            var iframe;
+            var socket = new easyXDM.Socket({
+                swf : "../easyxdm.swf",
+                onReady : function() {
+                    iframe = document.createElement("iframe");
+                    iframe.frameBorder = 0;
+                    document.body.appendChild(iframe);
+                    iframe.src = easyXDM.query.url;
+
+                    var timer;
+                    iframe.onload = function() {
+                        var d = iframe.contentWindow.document;
+                        var originalHeight = d.body.clientHeight || d.body.offsetHeight || d.body.scrollHeight;
+
+                        // We want to monitor the document for resize events in case of the use of accordions and such,
+                        // but unfortunately only the window node emits the resize event, and we need the body's.
+                        // The only solution then is to use polling..
+
+                        // Lets start the polling if not all ready started
+                        if(!timer) {
+                            timer = setInterval(function() {
+                                try {
+                                    var d = iframe.contentWindow.document;
+                                    var newHeight = d.body.clientHeight || d.body.offsetHeight || d.body.scrollHeight;
+                                    if(newHeight != originalHeight) {
+                                        // The height has changed since last we checked
+                                        originalHeight = newHeight;
+                                        socket.postMessage(originalHeight);
+                                    }
+                                } catch(e) {
+                                    // We tried to read the property at some point when it wasn't available
+                                }
+                            }, 300);
+                        }
+                        // Send the first message
+                        socket.postMessage(originalHeight);
+                    };
+                },
+                onMessage : function(url, origin) {
+                    iframe.src = url;
+                }
+            });
+
+        </script>
+        <style type="text/css">
+            html, body {
+                overflow: hidden;
+                margin: 0px;
+                padding: 0px;
+                width: 100%;
+                height: 100%;
+            }
+            iframe {
+                width: 100%;
+                height: 100%;
+                border: 0px;
+            }
+        </style>
+    </head>
+    <body></body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/resized_iframe_1.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/resized_iframe_1.html
new file mode 100644
index 0000000..8b4b7ad
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/resized_iframe_1.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <style type="text/css">
+            html, body {
+                overflow: hidden;
+                margin: 0px;
+                padding: 0px;
+                background-color: green;
+            }
+        </style>
+    </head>
+    <body>
+        <a href="resized_iframe_2.html">resized_iframe_2.html</a>
+        <br/>
+        Nam nulla nibh, tempus ut dictum eget, euismod vitae metus. Donec vitae nulla nec quam sagittis gravida vel quis eros. Nullam vel est justo. Donec euismod interdum magna, et rutrum libero tincidunt vel. Praesent imperdiet, magna et suscipit facilisis, nulla justo consequat nisl, et mollis elit nunc a est. Sed felis quam, condimentum eget gravida non, semper non quam. Duis vestibulum sem id erat tristique eleifend. Phasellus ante nunc, pulvinar nec facilisis at, hendrerit sed leo. Morbi lacinia nisl id nunc faucibus lacinia. Curabitur adipiscing leo a odio aliquet hendrerit. Nullam laoreet pulvinar suscipit.
+        Cras ante tortor, rutrum non pharetra vel, tempor et velit. Mauris semper, libero sit amet interdum interdum, metus purus rutrum libero, eget suscipit lectus augue eu magna. Aliquam quis dui a nunc luctus faucibus. Sed viverra augue rutrum odio placerat laoreet. Nulla scelerisque augue nec enim condimentum sollicitudin. Proin accumsan, turpis in viverra lobortis, nulla mauris euismod turpis, sit amet auctor felis lacus sed leo. Nullam posuere bibendum urna, ut mattis eros varius ac. Mauris sed metus orci, ut lobortis eros. Sed imperdiet bibendum tincidunt. Donec adipiscing sapien vitae ligula faucibus quis auctor nisi pretium. Morbi at nulla quam, in aliquet quam. Suspendisse potenti. Fusce varius gravida egestas. Nulla lectus velit, posuere et auctor a, congue id massa. Quisque ut lectus eu metus malesuada sollicitudin ac a risus.
+        Nullam massa ipsum, pulvinar ut facilisis a, commodo ut orci. Mauris ac ipsum diam, sit amet laoreet tortor. In pretium, nulla vel ornare euismod, nibh augue pharetra magna, at semper felis diam in ipsum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus blandit ornare dignissim. Fusce et nulla urna. Morbi nec ante erat. Nullam ut urna libero. Nulla non ipsum purus, et cursus lectus. Etiam vehicula, mauris in faucibus vehicula, dolor quam sodales neque, sed laoreet est augue at lacus. Nunc tincidunt lacinia elit eu dignissim. Mauris at enim mauris. Donec congue auctor dui, eget posuere ante accumsan in. Nulla non quam enim, eget tempor arcu. Suspendisse nec nibh diam, ut congue est. Fusce at urna eget velit posuere ornare nec eget mauris. Sed accumsan magna et enim mollis dignissim.
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/resized_iframe_2.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/resized_iframe_2.html
new file mode 100644
index 0000000..7c4085d
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/resized_iframe_2.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <style type="text/css">
+            html, body {
+                overflow: hidden;
+                margin: 0px;
+                padding: 0px;
+                background-color: red;
+            }
+        </style>
+    </head>
+    <body>
+        <a href="resized_iframe_1.html">resized_iframe_1.html</a>
+        <br/>
+        (This page will resize its content after three seconds)
+        <br/>
+        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eu felis libero, non ultricies ligula. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed in lorem libero. Phasellus malesuada, mauris eget suscipit tristique, dolor dui blandit purus, ut mollis eros dolor et elit. Ut consequat ultrices metus, pretium mattis dui adipiscing vitae. Nunc cursus, sapien vehicula auctor faucibus, enim orci pretium risus, id congue ligula justo sed felis. Proin nec quam justo. Cras tempor odio eget orci lacinia sit amet malesuada leo feugiat. In accumsan tincidunt enim, vitae ultricies arcu egestas in. Nulla rhoncus eros vel ipsum venenatis porta. Suspendisse id erat nec mauris ultricies consectetur id feugiat odio. Vestibulum pretium tristique magna sed ultrices. Suspendisse tortor mauris, facilisis et lobortis quis, suscipit sed est. Sed vitae tortor at lacus pretium blandit. Donec vitae nibh quis orci mollis fringilla. Duis tempus augue nec ipsum euismod elementum.
+        Donec pharetra sem nec lacus posuere et lacinia ligula sollicitudin. Morbi semper commodo posuere. In adipiscing nulla ut urna fermentum vestibulum. Sed consectetur massa non neque facilisis interdum. Quisque semper massa et urna euismod nec fermentum metus feugiat. Morbi tempor commodo enim non lacinia. Aliquam elementum tortor mattis odio congue a egestas lacus bibendum. Integer nec leo massa, a ullamcorper mi. Morbi vitae massa arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
+        Nam nulla nibh, tempus ut dictum eget, euismod vitae metus. Donec vitae nulla nec quam sagittis gravida vel quis eros. Nullam vel est justo. Donec euismod interdum magna, et rutrum libero tincidunt vel. Praesent imperdiet, magna et suscipit facilisis, nulla justo consequat nisl, et mollis elit nunc a est. Sed felis quam, condimentum eget gravida non, semper non quam. Duis vestibulum sem id erat tristique eleifend. Phasellus ante nunc, pulvinar nec facilisis at, hendrerit sed leo. Morbi lacinia nisl id nunc faucibus lacinia. Curabitur adipiscing leo a odio aliquet hendrerit. Nullam laoreet pulvinar suscipit.
+        Cras ante tortor, rutrum non pharetra vel, tempor et velit. Mauris semper, libero sit amet interdum interdum, metus purus rutrum libero, eget suscipit lectus augue eu magna. Aliquam quis dui a nunc luctus faucibus. Sed viverra augue rutrum odio placerat laoreet. Nulla scelerisque augue nec enim condimentum sollicitudin. Proin accumsan, turpis in viverra lobortis, nulla mauris euismod turpis, sit amet auctor felis lacus sed leo. Nullam posuere bibendum urna, ut mattis eros varius ac. Mauris sed metus orci, ut lobortis eros. Sed imperdiet bibendum tincidunt. Donec adipiscing sapien vitae ligula faucibus quis auctor nisi pretium. Morbi at nulla quam, in aliquet quam. Suspendisse potenti. Fusce varius gravida egestas. Nulla lectus velit, posuere et auctor a, congue id massa. Quisque ut lectus eu metus malesuada sollicitudin ac a risus.
+        Nullam massa ipsum, pulvinar ut facilisis a, commodo ut orci. Mauris ac ipsum diam, sit amet laoreet tortor. In pretium, nulla vel ornare euismod, nibh augue pharetra magna, at semper felis diam in ipsum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus blandit ornare dignissim. Fusce et nulla urna. Morbi nec ante erat. Nullam ut urna libero. Nulla non ipsum purus, et cursus lectus. Etiam vehicula, mauris in faucibus vehicula, dolor quam sodales neque, sed laoreet est augue at lacus. Nunc tincidunt lacinia elit eu dignissim. Mauris at enim mauris. Donec congue auctor dui, eget posuere ante accumsan in. Nulla non quam enim, eget tempor arcu. Suspendisse nec nibh diam, ut congue est. Fusce at urna eget velit posuere ornare nec eget mauris. Sed accumsan magna et enim mollis dignissim.
+        <script type="text/javascript">
+            // here we fake an action that would the casue the body's size to mutate.
+            setTimeout(function() {
+                var html = document.body.innerHTML;
+                document.body.innerHTML = html.substring(0, html.length / 2);
+            }, 3000);
+
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/transport.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/transport.html
new file mode 100644
index 0000000..769feb0
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/transport.html
@@ -0,0 +1,82 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            
+            var REMOTE = (function(){
+                var remote = location.href;
+                switch (location.host) {
+                    case "provider.easyxdm.net":
+                        location.href = remote.replace("provider", "consumer");
+                        break;
+                    case "easyxdm.net":
+                        remote = remote.replace("easyxdm.net", "consumer.easyxdm.net");
+                        break;
+                    case "consumer.easyxdm.net":
+                        remote = remote.replace("consumer", "provider");
+                        break;
+                    case "xdm1":
+                        remote = remote.replace("xdm1", "xdm2");
+                        break;
+                }
+                return remote.substring(0, remote.lastIndexOf("/"));
+            }());
+            var transport = new easyXDM.Socket(/** The configuration */{
+                /**
+                 * Register the url to name.html, this must be an absolute path
+                 * or a path relative to the root.
+                 * @field
+                 */
+                local: "../name.html",
+                swf: REMOTE + "/../easyxdm.swf",
+                /**
+                 * Register the url to the remote interface
+                 * @field
+                 */
+                remote: REMOTE + "/remotetransport.html",
+                remoteHelper: REMOTE + "/../name.html",
+                onReady: function(){
+                    /**
+                     * If we want to do something once the transport is ready then we can place it here
+                     */
+                }
+            });
+            // messages will be buffered until the transport is ready
+            transport.postMessage("This is a message sent from " + location);
+        </script>
+    </head>
+    <body>
+        <div style="border:1px solid black;padding:3px;margin:10px;">
+            <a href="index.html">Index of examples</a>
+            | <a href="http://github.com/oyvindkinsey/easyXDM/#readme">Readme at github</a>
+            | 
+            | <a href="http://easyxdm.net/">easyXDM.net</a>
+            | <a href="http://groups.google.com/group/easyxdm">easyXDM at Google Groups</a>
+            <br/>
+            The examples are executing slower than the production build due to the extensive tracing.
+            <br/>
+            If you are alerted about a popup, then this is only the trace log feature. You can ignore this.
+        </div>
+        <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+        <div id="log" style="height:100px;border:1px dotted black;overflow:auto">
+        </div>
+        <script type="text/javascript">
+            var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+            document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+        </script>
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                try {
+                    var pageTracker = _gat._getTracker("UA-9535591-3");
+                    pageTracker._setDomainName(".easyxdm.net");
+                    pageTracker._trackPageview();
+                } 
+                catch (err) {
+                }
+            }
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/upload.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/upload.html
new file mode 100644
index 0000000..569feb4
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/upload.html
@@ -0,0 +1,100 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            /**
+             * Request the use of the JSON object
+             */
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript">
+            
+            // this is just some bootstrapping code in order to provide
+            // the correct host name depending on where it is being run.
+            var REMOTE = (function(){
+                var remote = location.href;
+                switch (location.host) {
+                    case "provider.easyxdm.net":
+                        location.href = remote.replace("provider", "consumer");
+                        break;
+                    case "easyxdm.net":
+                        remote = remote.replace("easyxdm.net", "consumer.easyxdm.net");
+                        break;
+                    case "consumer.easyxdm.net":
+                        remote = remote.replace("consumer", "provider");
+                        break;
+                    case "xdm1":
+                        remote = remote.replace("xdm1", "xdm2");
+                        break;
+                }
+                return remote.substring(0, remote.lastIndexOf("/"));
+            }());
+            
+            
+            
+            var btn;
+            var remote = new easyXDM.Rpc({
+                remote: REMOTE + "/upload_rpc.html",
+                swf: REMOTE + "/../easyxdm.swf",
+                onReady: function(){
+                    //display the upload form
+                    var frm = document.getElementById("frmUpload");
+                    frm.action = REMOTE + "/upload_handler.aspx";
+                    frm.style.display = "block";
+                    btn = document.getElementById("btnSubmit");
+                    
+                    frm.onsubmit = function(){
+                        btn.disabled = "disabled";
+                    };
+                }
+            }, {
+                local: {
+                    returnUploadResponse: function(response){
+                        // here you should call back into your regular workflow
+                        btn.disabled = null;
+                        alert(response.msg);
+                    }
+                }
+            });
+        </script>
+    </head>
+    <body>
+        <div style="border:1px solid black;padding:3px;margin:10px;">
+            <a href="index.html">Index of examples</a>
+            | <a href="http://github.com/oyvindkinsey/easyXDM/#readme">Readme at github</a>
+            | 
+            | <a href="http://easyxdm.net/">easyXDM.net</a>
+            | <a href="http://groups.google.com/group/easyxdm">easyXDM at Google Groups</a>
+            <br/>
+            The examples are executing slower than the production build due to the extensive tracing.
+            <br/>
+            If you are alerted about a popup, then this is only the trace log feature. You can ignore this.
+        </div>
+        <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+        <div id="log" style="height:100px;border:1px dotted black;overflow:auto">
+        </div>
+        <form id="frmUpload" style="display:none" method="POST" target="upload_target" enctype="multipart/form-data">
+            <input type="file" name="upload_file"/><input type="submit" id="btnSubmit" value="Upload file"/>
+        </form><!--
+        tracking code
+        -->
+        <script type="text/javascript">
+            var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+            document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+        </script>
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                try {
+                    var pageTracker = _gat._getTracker("UA-9535591-3");
+                    pageTracker._setDomainName(".easyxdm.net");
+                    pageTracker._trackPageview();
+                } 
+                catch (err) {
+                }
+            }
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/upload_handler.aspx b/asterix-examples/src/main/resources/core/js/easyXDM/example/upload_handler.aspx
new file mode 100644
index 0000000..8c652ee
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/upload_handler.aspx
@@ -0,0 +1,15 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+    </head>
+    <body>
+        <script type="text/javascript">
+            // this should be outputted by the server side code 
+            parent.rpc.returnUploadResponse({
+                status: "success",
+                msg: "The upload succeeded!"
+            });
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/upload_rpc.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/upload_rpc.html
new file mode 100644
index 0000000..37123ec
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/upload_rpc.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript">
+            // the `rpc` object will be referenced by the upload handler
+            var rpc = new easyXDM.Rpc({
+                swf: "../easyxdm.swf"
+            }, {
+                remote: {
+                    returnUploadResponse: {}
+                }
+            });
+        </script>
+    </head>
+    <body>
+        <iframe name="upload_target" src="about:blank">
+        </iframe>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/widget.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/widget.html
new file mode 100644
index 0000000..5093eeb
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/widget.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM.Widget</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript" src="../easyXDM.Widgets.debug.js">
+        </script>
+        <script type="text/javascript">
+            easyXDM.whenReady(function(){
+                var widget = new easyXDM.Widget({
+                    subscriptions: ["testtopic"],
+                    swf: "../easyxdm.swf",
+                    initialize: function(widget, widgetManager){
+                        // Set up the widget
+                        var _container, _btnPublish;
+                        
+                        // Render the UI
+                        _container = document.body.appendChild(document.createElement("div"));
+                        _btnPublish = _container.appendChild(document.createElement("button"));
+                        _btnPublish.innerHTML = "Publish";
+                        easyXDM.DomHelper.on(_btnPublish, "click", function(){
+                            widget.publish("testtopic", {
+                                latitude: 1,
+                                longitude: 2
+                            });
+                        });
+                        
+                        // Register the handler for incoming messages
+                        widget.registerMessageHandler(function(url, topic, data){
+                            _container.appendChild(document.createElement("div")).innerHTML = "got data on topic " + topic + " from " + url;
+                        });
+                    },
+                    initialized: function(widget, widgetManager){
+                        widget.publish("testtopic", {
+                            latitude: 1,
+                            longitude: 2
+                        });
+                    }
+                });
+            });
+        </script>
+    </head>
+    <body>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/widgets.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/widgets.html
new file mode 100644
index 0000000..17bff03
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/widgets.html
@@ -0,0 +1,75 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript" src="../easyXDM.Widgets.debug.js">
+        </script>
+        <script type="text/javascript">
+            var _widgetManager;
+            easyXDM.whenReady(function(){
+                _widgetManager = new easyXDM.WidgetManager({
+                    swf: "../easyxdm.swf",
+                    container: document.getElementById("widgets")
+                });
+                document.getElementById("widget1url").value = location.href.replace("consumer", "provider").replace("widgets.html", "widget.html");
+                document.getElementById("widget2url").value = location.href.replace("consumer.", "").replace("widgets.html", "widget.html");
+            });
+        </script>
+        <style type="text/css">
+            
+            #widgets {
+                height: 400px;
+            }
+            
+            #widgets iframe {
+                width: 200px;
+                height: 300px;
+                float: left;
+            }
+        </style>
+    </head>
+    <body>
+        <div style="border:1px solid black;padding:3px;margin:10px;">
+            <a href="index.html">Index of examples</a>
+            | <a href="http://github.com/oyvindkinsey/easyXDM/#readme">Readme at github</a>
+            | 
+            | <a href="http://easyxdm.net/">easyXDM.net</a>
+            | <a href="http://groups.google.com/group/easyxdm">easyXDM at Google Groups</a>
+            <br/>
+            The examples are executing slower than the production build due to the extensive tracing.
+            <br/>
+            If you are alerted about a popup, then this is only the trace log feature. You can ignore this.
+        </div>
+        <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+        <div id="log" style="height:100px;border:1px dotted black;overflow:auto">
+        </div>
+        <div>
+            <input type="text" id="widget1url" style="width:300px" value=""/><input type="button" onclick="_widgetManager.addWidget(document.getElementById('widget1url').value,{});" value="Add Widget"/><input type="button" onclick="_widgetManager.removeWidget(document.getElementById('widget1url').value);" value="Remove Widget"/>
+        </div>
+        <div>
+            <input type="text" id="widget2url" style="width:300px" value=""/><input type="button" onclick="_widgetManager.addWidget(document.getElementById('widget2url').value,{});" value="Add Widget"/><input type="button" onclick="_widgetManager.removeWidget(document.getElementById('widget2url').value);" value="Remove Widget"/>
+        </div><input type="button" onclick="_widgetManager.publish('testtopic','abc');" value="publish"/>
+        <div id="widgets">
+        </div>
+        <script type="text/javascript">
+            var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+            document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+        </script>
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                try {
+                    var pageTracker = _gat._getTracker("UA-9535591-3");
+                    pageTracker._setDomainName(".easyxdm.net");
+                    pageTracker._trackPageview();
+                } 
+                catch (err) {
+                }
+            }
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/example/xhr.html b/asterix-examples/src/main/resources/core/js/easyXDM/example/xhr.html
new file mode 100644
index 0000000..a6d7f5d
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/example/xhr.html
@@ -0,0 +1,112 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            /**
+             * Request the use of the JSON object
+             */
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript">
+            // this is only bootstrapping code
+            var REMOTE = (function(){
+                var remote = location.href;
+                switch (location.host) {
+                    case "provider.easyxdm.net":
+                        location.href = remote.replace("provider", "consumer");
+                        break;
+                    case "easyxdm.net":
+                        remote = remote.replace("easyxdm.net", "consumer.easyxdm.net");
+                        break;
+                    case "consumer.easyxdm.net":
+                        remote = remote.replace("consumer", "provider");
+                        break;
+                    case "xdm1":
+                        remote = remote.replace("xdm1", "xdm2");
+                        break;
+                }
+                return remote.substring(0, remote.lastIndexOf("/"));
+            }());
+            
+            // this is really what you are after
+            var xhr = new easyXDM.Rpc({
+                local: "../name.html",
+                swf: REMOTE + "/../easyxdm.swf",
+                remote: REMOTE + "/../cors/",
+                remoteHelper: REMOTE + "/../name.html"
+            }, {
+                remote: {
+                    request: {}
+                }
+            });
+            
+            function getGlossary(){
+                xhr.request({
+                    url: "../example/glossary.aspx",
+                    method: "POST",
+                    headers: {
+                        "x-auth-token": "abcde"
+                    },
+                    data: {
+                        param1: "a",
+                        param2: "b"
+                    }
+                }, function(rpcdata){
+                    var json = easyXDM.getJSONObject().parse(rpcdata.data);
+                    
+                    document.getElementById("response").innerHTML = json.glossary.title;
+                    document.getElementById("header").innerHTML = rpcdata.headers["x-foo"];
+                });
+                
+            }
+        </script>
+    </head>
+    <body>
+        <div style="border:1px solid black;padding:3px;margin:10px;">
+            <a href="index.html">Index of examples</a>
+            | <a href="http://github.com/oyvindkinsey/easyXDM/#readme">Readme at github</a>
+            | 
+            | <a href="http://easyxdm.net/">easyXDM.net</a>
+            | <a href="http://groups.google.com/group/easyxdm">easyXDM at Google Groups</a>
+            <br/>
+            The examples are executing slower than the production build due to the extensive tracing.
+            <br/>
+            If you are alerted about a popup, then this is only the trace log feature. You can ignore this.
+        </div>
+        <script type="text/javascript">
+            document.write("Domain: " + location.host);
+        </script>
+        <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+        <div id="log" style="height:100px;border:1px dotted black;overflow:auto">
+        </div>
+        <div id="embedded">
+        </div>
+        <div>
+            This example shows how to use easyXDM to call regular ajax/cors services (no JSONP) from remote domains.
+            <br/>
+            <input type="button" onclick="getGlossary()" value="Call getGlossary using the exposed method"/>
+            <br/>
+            Data from response:<span id="response"></span>
+            <br/>
+            Data from header:<span id="header"></span>
+        </div>
+        <script type="text/javascript">
+            var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+            document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+        </script>
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                try {
+                    var pageTracker = _gat._getTracker("UA-9535591-3");
+                    pageTracker._setDomainName(".easyxdm.net");
+                    pageTracker._trackPageview();
+                } 
+                catch (err) {
+                }
+            }
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/json2.js b/asterix-examples/src/main/resources/core/js/easyXDM/json2.js
new file mode 100644
index 0000000..a1a3b17
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/json2.js
@@ -0,0 +1,482 @@
+/*
+    http://www.JSON.org/json2.js
+    2010-03-20
+
+    Public Domain.
+
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+    See http://www.JSON.org/js.html
+
+
+    This code should be minified before deployment.
+    See http://javascript.crockford.com/jsmin.html
+
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+    NOT CONTROL.
+
+
+    This file creates a global JSON object containing two methods: stringify
+    and parse.
+
+        JSON.stringify(value, replacer, space)
+            value       any JavaScript value, usually an object or array.
+
+            replacer    an optional parameter that determines how object
+                        values are stringified for objects. It can be a
+                        function or an array of strings.
+
+            space       an optional parameter that specifies the indentation
+                        of nested structures. If it is omitted, the text will
+                        be packed without extra whitespace. If it is a number,
+                        it will specify the number of spaces to indent at each
+                        level. If it is a string (such as '\t' or '&nbsp;'),
+                        it contains the characters used to indent at each level.
+
+            This method produces a JSON text from a JavaScript value.
+
+            When an object value is found, if the object contains a toJSON
+            method, its toJSON method will be called and the result will be
+            stringified. A toJSON method does not serialize: it returns the
+            value represented by the name/value pair that should be serialized,
+            or undefined if nothing should be serialized. The toJSON method
+            will be passed the key associated with the value, and this will be
+            bound to the value
+
+            For example, this would serialize Dates as ISO strings.
+
+                Date.prototype.toJSON = function (key) {
+                    function f(n) {
+                        // Format integers to have at least two digits.
+                        return n < 10 ? '0' + n : n;
+                    }
+
+                    return this.getUTCFullYear()   + '-' +
+                         f(this.getUTCMonth() + 1) + '-' +
+                         f(this.getUTCDate())      + 'T' +
+                         f(this.getUTCHours())     + ':' +
+                         f(this.getUTCMinutes())   + ':' +
+                         f(this.getUTCSeconds())   + 'Z';
+                };
+
+            You can provide an optional replacer method. It will be passed the
+            key and value of each member, with this bound to the containing
+            object. The value that is returned from your method will be
+            serialized. If your method returns undefined, then the member will
+            be excluded from the serialization.
+
+            If the replacer parameter is an array of strings, then it will be
+            used to select the members to be serialized. It filters the results
+            such that only members with keys listed in the replacer array are
+            stringified.
+
+            Values that do not have JSON representations, such as undefined or
+            functions, will not be serialized. Such values in objects will be
+            dropped; in arrays they will be replaced with null. You can use
+            a replacer function to replace those with JSON values.
+            JSON.stringify(undefined) returns undefined.
+
+            The optional space parameter produces a stringification of the
+            value that is filled with line breaks and indentation to make it
+            easier to read.
+
+            If the space parameter is a non-empty string, then that string will
+            be used for indentation. If the space parameter is a number, then
+            the indentation will be that many spaces.
+
+            Example:
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}]);
+            // text is '["e",{"pluribus":"unum"}]'
+
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+            text = JSON.stringify([new Date()], function (key, value) {
+                return this[key] instanceof Date ?
+                    'Date(' + this[key] + ')' : value;
+            });
+            // text is '["Date(---current time---)"]'
+
+
+        JSON.parse(text, reviver)
+            This method parses a JSON text to produce an object or array.
+            It can throw a SyntaxError exception.
+
+            The optional reviver parameter is a function that can filter and
+            transform the results. It receives each of the keys and values,
+            and its return value is used instead of the original value.
+            If it returns what it received, then the structure is not modified.
+            If it returns undefined then the member is deleted.
+
+            Example:
+
+            // Parse the text. Values that look like ISO date strings will
+            // be converted to Date objects.
+
+            myData = JSON.parse(text, function (key, value) {
+                var a;
+                if (typeof value === 'string') {
+                    a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+                    if (a) {
+                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+                            +a[5], +a[6]));
+                    }
+                }
+                return value;
+            });
+
+            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+                var d;
+                if (typeof value === 'string' &&
+                        value.slice(0, 5) === 'Date(' &&
+                        value.slice(-1) === ')') {
+                    d = new Date(value.slice(5, -1));
+                    if (d) {
+                        return d;
+                    }
+                }
+                return value;
+            });
+
+
+    This is a reference implementation. You are free to copy, modify, or
+    redistribute.
+*/
+
+/*jslint evil: true, strict: false */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+    lastIndex, length, parse, prototype, push, replace, slice, stringify,
+    test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (!this.JSON) {
+    this.JSON = {};
+}
+
+(function () {
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    if (typeof Date.prototype.toJSON !== 'function') {
+
+        Date.prototype.toJSON = function (key) {
+
+            return isFinite(this.valueOf()) ?
+                   this.getUTCFullYear()   + '-' +
+                 f(this.getUTCMonth() + 1) + '-' +
+                 f(this.getUTCDate())      + 'T' +
+                 f(this.getUTCHours())     + ':' +
+                 f(this.getUTCMinutes())   + ':' +
+                 f(this.getUTCSeconds())   + 'Z' : null;
+        };
+
+        String.prototype.toJSON =
+        Number.prototype.toJSON =
+        Boolean.prototype.toJSON = function (key) {
+            return this.valueOf();
+        };
+    }
+
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        gap,
+        indent,
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        },
+        rep;
+
+
+    function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ?
+            '"' + string.replace(escapable, function (a) {
+                var c = meta[a];
+                return typeof c === 'string' ? c :
+                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+            }) + '"' :
+            '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+// Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value && typeof value === 'object' &&
+                typeof value.toJSON === 'function') {
+            value = value.toJSON(key);
+        }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+// What happens next depends on the value's type.
+
+        switch (typeof value) {
+        case 'string':
+            return quote(value);
+
+        case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+            return isFinite(value) ? String(value) : 'null';
+
+        case 'boolean':
+        case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+            return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+        case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+            if (!value) {
+                return 'null';
+            }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+            gap += indent;
+            partial = [];
+
+// Is the value an array?
+
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                length = value.length;
+                for (i = 0; i < length; i += 1) {
+                    partial[i] = str(i, value) || 'null';
+                }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+                v = partial.length === 0 ? '[]' :
+                    gap ? '[\n' + gap +
+                            partial.join(',\n' + gap) + '\n' +
+                                mind + ']' :
+                          '[' + partial.join(',') + ']';
+                gap = mind;
+                return v;
+            }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+            if (rep && typeof rep === 'object') {
+                length = rep.length;
+                for (i = 0; i < length; i += 1) {
+                    k = rep[i];
+                    if (typeof k === 'string') {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                for (k in value) {
+                    if (Object.hasOwnProperty.call(value, k)) {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+            v = partial.length === 0 ? '{}' :
+                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+                        mind + '}' : '{' + partial.join(',') + '}';
+            gap = mind;
+            return v;
+        }
+    }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+    if (typeof JSON.stringify !== 'function') {
+        JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+            var i;
+            gap = '';
+            indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+            if (typeof space === 'number') {
+                for (i = 0; i < space; i += 1) {
+                    indent += ' ';
+                }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+            } else if (typeof space === 'string') {
+                indent = space;
+            }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+            rep = replacer;
+            if (replacer && typeof replacer !== 'function' &&
+                    (typeof replacer !== 'object' ||
+                     typeof replacer.length !== 'number')) {
+                throw new Error('JSON.stringify');
+            }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+            return str('', {'': value});
+        };
+    }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+    if (typeof JSON.parse !== 'function') {
+        JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+            var j;
+
+            function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+                var k, v, value = holder[key];
+                if (value && typeof value === 'object') {
+                    for (k in value) {
+                        if (Object.hasOwnProperty.call(value, k)) {
+                            v = walk(value, k);
+                            if (v !== undefined) {
+                                value[k] = v;
+                            } else {
+                                delete value[k];
+                            }
+                        }
+                    }
+                }
+                return reviver.call(holder, key, value);
+            }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+            text = String(text);
+            cx.lastIndex = 0;
+            if (cx.test(text)) {
+                text = text.replace(cx, function (a) {
+                    return '\\u' +
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                });
+            }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+            if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+                return typeof reviver === 'function' ?
+                    walk({'': j}, '') : j;
+            }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+            throw new SyntaxError('JSON.parse');
+        };
+    }
+}());
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/name.html b/asterix-examples/src/main/resources/core/js/easyXDM/name.html
new file mode 100644
index 0000000..cc403b1
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/name.html
@@ -0,0 +1,55 @@
+<!doctype html>

+<html>

+    <head>

+        <title></title>

+        <meta http-equiv="CACHE-CONTROL" content="PUBLIC"/>

+        <meta http-equiv="EXPIRES" content="Sat, 01 Jan 2050 00:00:00 GMT"/>

+    </head>

+    <body>

+        <script type="text/javascript">

+        

+        function sendMessage(message, url){

+            window.setTimeout(function(){

+                window.name = message;

+                location.href = url + "," + encodeURIComponent(location.protocol + "//" + location.host + location.pathname);

+            }, 0);

+        }

+        

+        if (location.hash) {

+            if (location.hash.substring(1, 2) === "_") {

+                var channel, url, hash = location.href.substring(location.href.indexOf("#") + 3), indexOf = hash.indexOf(",");

+                if (indexOf == -1) {

+                    channel = hash;

+                }

+                else {

+                    channel = hash.substring(0, indexOf);

+                    url = decodeURIComponent(hash.substring(indexOf + 1));

+                }

+                switch (location.hash.substring(2, 3)) {

+                    case "2":

+                        // NameTransport local

+                        window.parent.parent.easyXDM.Fn.get(channel)(window.name);

+                        location.href = url + "#_4" + channel + ",";

+                        break;

+                    case "3":

+                        // NameTransport remote

+                        var guest = window.parent.frames["easyXDM_" + channel + "_provider"];

+                        if (!guest) {

+                            throw new Error("unable to reference window");

+                        }

+                        guest.easyXDM.Fn.get(channel)(window.name);

+                        location.href = url + "#_4" + channel + ",";

+                        break;

+                    case "4":

+                        // NameTransport idle

+                        var fn = window.parent.easyXDM.Fn.get(channel + "_load");

+                        if (fn) {

+                            fn();

+                        }

+                        break;

+                }

+            }

+        }

+        </script>

+    </body>

+</html>

diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/tests/easyTest.css b/asterix-examples/src/main/resources/core/js/easyXDM/tests/easyTest.css
new file mode 100644
index 0000000..0df87e3
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/tests/easyTest.css
@@ -0,0 +1,14 @@
+.easyTest_messages {

+}

+

+.easyTest_error {

+    color: red;

+}

+

+.easyTest_success {

+    color: green;

+}

+

+.easyTest_msg {

+    color: black;

+}
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/tests/easyTest.js b/asterix-examples/src/main/resources/core/js/easyXDM/tests/easyTest.js
new file mode 100644
index 0000000..1da4812
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/tests/easyTest.js
@@ -0,0 +1,262 @@
+var easyTest = (function(){
+    var _messages;
+    var _start;
+    var MessageType = {
+        Error: 1,
+        Success: 2,
+        Info: 3
+    };
+    
+    /**
+     * Logs the message to the body
+     * @param {String} msg The message to displey
+     * @param {MessageType} type The messagetype
+     */
+    function _log(msg, type){
+        var el = _messages.appendChild(document.createElement("div"));
+        el.innerHTML = msg;
+        _messages.scrollTop = _messages.scrollHeight;
+        switch (type) {
+            case MessageType.Error:
+                el.className = "easyTest_error";
+                break;
+            case MessageType.Success:
+                el.className = "easyTest_success";
+                break;
+            default:
+                el.className = "easyTest_msg";
+                break;
+        }
+    }
+    
+    var Assert = {
+        // Type checks
+        isTypeOf: function(type, obj){
+            return typeof obj === type;
+        },
+        isInstanceOf: function(type, obj){
+            return obj instanceof type;
+        },
+        isString: function(obj){
+            return this.isTypeOf("string", obj);
+        },
+        isNumber: function(obj){
+            return this.isTypeOf("number", obj);
+        },
+        isObject: function(obj){
+            return this.isTypeOf("object", obj);
+        },
+        isBoolean: function(obj){
+            return this.isTypeOf("boolean", obj);
+        },
+        isFunction: function(obj){
+            return this.isTypeOf("function", obj);
+        },
+        // Equality
+        areEqual: function(a, b){
+            return a == b;
+        },
+        areNotEqual: function(a, b){
+            return a != b;
+        },
+        // Identical
+        areSame: function(a, b){
+            return a === b;
+        },
+        areNotSame: function(a, b){
+            return a !== b;
+        }
+        
+    };
+    
+    function Test(test, fn){
+        var _scope, _steps = test.steps, _step, _stepIndex = 0;
+        var _timer, _runStep, _startedAt, _stepStartedAt;
+        
+        /**
+         * Clean up and tear down the test.<br/>
+         * Calls back to notify that the test is complete
+         */
+        function _endTest(){
+            // Tear down the test
+            if (test.tearDown) {
+                try {
+                    test.tearDown.call(_scope);
+                } 
+                catch (ex) {
+                    _log("Teardown '" + ex.message + "(" + ex.fileName + ", " + ex.lineNumber + ")" + "'", MessageType.Error);
+                }
+            }
+            for (var key in _scope) {
+                if (_scope.hasOwnProperty(key)) {
+                    delete _scope[key];
+                }
+            }
+            
+            // Call back
+            fn();
+        }
+        
+        /**
+         * Used to notify the framework of the result of the test
+         * @param {String} name The name of the test
+         * @param {Boolean} result The result of the test
+         * @param {String} reason An optional reason why the test returned the result
+         */
+        function _notifyResult(name, result, reason){
+            var now = new Date().getTime();
+            var testsetTime = now - _start.getTime();
+            var testTime = now - _startedAt.getTime();
+            var stepTime = now - _stepStartedAt.getTime();
+            
+            var times = testsetTime + "ms, " + testTime + "ms, " + stepTime + "ms - ";
+            if (result) {
+                _log(times + name + " succeeded! " + (reason || ""), MessageType.Success);
+            }
+            else {
+                _log(times + name + " failed! " + (reason || ""), MessageType.Error);
+                if (test.failedMessage) {
+                    _log(test.failedMessage, MessageType.Info);
+                }
+            }
+            // Go to next step
+            if (result) {
+                _stepIndex++;
+                window.setTimeout(function(){
+                    _runStep();
+                }, 0);
+            }
+            else {
+                _endTest();
+            }
+        }
+        
+        
+        /**
+         * Runs through the test step
+         */
+        _runStep = function(){
+            if (_stepIndex < _steps.length) {
+                // We still have steps to run
+                _step = _steps[_stepIndex];
+                _stepStartedAt = new Date();
+                if (_step.timeout) {
+                    // This an asynchronous test
+                    _timer = window.setTimeout(function(){
+                        _notifyResult(_step.name, false, "Failed due to timeout.");
+                    }, _step.timeout);
+                    try {
+                        _step.run.call(_scope);
+                    } 
+                    catch (ex) {
+                        //If it fails we cancel the timeout
+                        window.clearTimeout(_timer);
+                        _notifyResult(_step.name, false, "'" + ex.message + "(" + ex.fileName + ", " + ex.lineNumber + ")" + "'");
+                    }
+                }
+                else {
+                    // This is a synchronous test
+                    try {
+                        var result = _step.run.call(_scope);
+                        _notifyResult(_step.name, result);
+                    } 
+                    catch (ex) {
+                        _notifyResult(_step.name, false, "'" + ex.message + "(" + ex.fileName + ", " + ex.lineNumber + ")" + "'");
+                    }
+                }
+            }
+            else {
+                _endTest();
+            }
+        };
+        
+        return {
+            /**
+             * Runs the test.
+             * Will first try to execute the setup method before continuing the steps
+             */
+            run: function(){
+                var excuse;
+                if (test.runIf) {
+                    excuse = test.runIf();
+                }
+                if (excuse) {
+                    _log("Skipping test ' " + test.name + "'. " + excuse);
+                    fn();
+                }
+                else {
+                    _log("Running test '" + test.name + "'");
+                    _scope = {
+                        Assert: Assert,
+                        log: _log,
+                        notifyResult: function(result){
+                            window.clearTimeout(_timer);
+                            _notifyResult(_step.name, result);
+                        }
+                    };
+                    if (test.setUp) {
+                        // Setup the test
+                        try {
+                            test.setUp.call(_scope);
+                            _log("Setup succeeded", MessageType.Success);
+                        } 
+                        catch (ex) {
+                            _log("Setup failed", MessageType.Error);
+                        }
+                    }
+                    _startedAt = new Date();
+                    _runStep();
+                }
+            }
+        };
+    }
+    
+    return {
+        /**
+         * Runs through all the tests
+         * @param {Array} tests The tests to run
+         */
+        test: function(testset){
+            var tests = [], testConfig, i = testset.length, test;
+            
+            // Prepare the messaging facilities
+            if (!_messages) {
+                _messages = document.createElement("div");
+                _messages.className = "easyTest_messages";
+                (document.getElementById("messages") || document.body).appendChild(_messages);
+            }
+            else {
+                _messages.innerHTML = "";
+            }
+            
+            // Convert the testset
+            while (i--) {
+                testConfig = testset[i];
+                if (!testConfig.steps) {
+                    // Convert a single step test to a proper test
+                    testConfig = {
+                        steps: testConfig
+                    };
+                }
+                
+                tests.push(new Test(testConfig, function(){
+                    // Get the next test to run
+                    test = tests.pop();
+                    if (test) {
+                        // This is needed to avoid a strange bug in Opera,
+                        window.setTimeout(function(){
+                            test.run();
+                        }, 0);
+                    }
+                    else {
+                        // No more tests to run
+                        _log("Test run complete", MessageType.Info);
+                    }
+                }));
+            }
+            // Start the first test
+            _start = new Date();
+            tests.pop().run();
+        }
+    };
+}());
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/tests/easyXDM.debug.js b/asterix-examples/src/main/resources/core/js/easyXDM/tests/easyXDM.debug.js
new file mode 100644
index 0000000..c1c614a
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/tests/easyXDM.debug.js
@@ -0,0 +1,2848 @@
+(function (window, document, location, setTimeout, decodeURIComponent, encodeURIComponent) {

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global JSON, XMLHttpRequest, window, escape, unescape, ActiveXObject */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+var global = this;

+var channelId = Math.floor(Math.random() * 10000); // randomize the initial id in case of multiple closures loaded 

+var emptyFn = Function.prototype;

+var reURI = /^((http.?:)\/\/([^:\/\s]+)(:\d+)*)/; // returns groups for protocol (2), domain (3) and port (4) 

+var reParent = /[\-\w]+\/\.\.\//; // matches a foo/../ expression 

+var reDoubleSlash = /([^:])\/\//g; // matches // anywhere but in the protocol

+var namespace = ""; // stores namespace under which easyXDM object is stored on the page (empty if object is global)

+var easyXDM = {};

+var _easyXDM = window.easyXDM; // map over global easyXDM in case of overwrite

+var IFRAME_PREFIX = "easyXDM_";

+var HAS_NAME_PROPERTY_BUG;

+var useHash = false; // whether to use the hash over the query

+var flashVersion; // will be set if using flash

+var HAS_FLASH_THROTTLED_BUG;

+var _trace = emptyFn;

+

+

+// http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting

+function isHostMethod(object, property){

+    var t = typeof object[property];

+    return t == 'function' ||

+    (!!(t == 'object' && object[property])) ||

+    t == 'unknown';

+}

+

+function isHostObject(object, property){

+    return !!(typeof(object[property]) == 'object' && object[property]);

+}

+

+// end

+

+// http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/

+function isArray(o){

+    return Object.prototype.toString.call(o) === '[object Array]';

+}

+

+// end

+function hasFlash(){

+    var name = "Shockwave Flash", mimeType = "application/x-shockwave-flash";

+    

+    if (!undef(navigator.plugins) && typeof navigator.plugins[name] == "object") {

+        // adapted from the swfobject code

+        var description = navigator.plugins[name].description;

+        if (description && !undef(navigator.mimeTypes) && navigator.mimeTypes[mimeType] && navigator.mimeTypes[mimeType].enabledPlugin) {

+            flashVersion = description.match(/\d+/g);

+        }

+    }

+    if (!flashVersion) {

+        var flash;

+        try {

+            flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");

+            flashVersion = Array.prototype.slice.call(flash.GetVariable("$version").match(/(\d+),(\d+),(\d+),(\d+)/), 1);

+            flash = null;

+        } 

+        catch (notSupportedException) {

+        }

+    }

+    if (!flashVersion) {

+        return false;

+    }

+    var major = parseInt(flashVersion[0], 10), minor = parseInt(flashVersion[1], 10);

+    HAS_FLASH_THROTTLED_BUG = major > 9 && minor > 0;

+    return true;

+}

+

+/*

+ * Cross Browser implementation for adding and removing event listeners.

+ */

+var on, un;

+if (isHostMethod(window, "addEventListener")) {

+    on = function(target, type, listener){

+        _trace("adding listener " + type);

+        target.addEventListener(type, listener, false);

+    };

+    un = function(target, type, listener){

+        _trace("removing listener " + type);

+        target.removeEventListener(type, listener, false);

+    };

+}

+else if (isHostMethod(window, "attachEvent")) {

+    on = function(object, sEvent, fpNotify){

+        _trace("adding listener " + sEvent);

+        object.attachEvent("on" + sEvent, fpNotify);

+    };

+    un = function(object, sEvent, fpNotify){

+        _trace("removing listener " + sEvent);

+        object.detachEvent("on" + sEvent, fpNotify);

+    };

+}

+else {

+    throw new Error("Browser not supported");

+}

+

+/*

+ * Cross Browser implementation of DOMContentLoaded.

+ */

+var domIsReady = false, domReadyQueue = [], readyState;

+if ("readyState" in document) {

+    // If browser is WebKit-powered, check for both 'loaded' (legacy browsers) and

+    // 'interactive' (HTML5 specs, recent WebKit builds) states.

+    // https://bugs.webkit.org/show_bug.cgi?id=45119

+    readyState = document.readyState;

+    domIsReady = readyState == "complete" || (~ navigator.userAgent.indexOf('AppleWebKit/') && (readyState == "loaded" || readyState == "interactive"));

+}

+else {

+    // If readyState is not supported in the browser, then in order to be able to fire whenReady functions apropriately

+    // when added dynamically _after_ DOM load, we have to deduce wether the DOM is ready or not.

+    // We only need a body to add elements to, so the existence of document.body is enough for us.

+    domIsReady = !!document.body;

+}

+

+function dom_onReady(){

+    if (domIsReady) {

+        return;

+    }

+    domIsReady = true;

+    _trace("firing dom_onReady");

+    for (var i = 0; i < domReadyQueue.length; i++) {

+        domReadyQueue[i]();

+    }

+    domReadyQueue.length = 0;

+}

+

+

+if (!domIsReady) {

+    if (isHostMethod(window, "addEventListener")) {

+        on(document, "DOMContentLoaded", dom_onReady);

+    }

+    else {

+        on(document, "readystatechange", function(){

+            if (document.readyState == "complete") {

+                dom_onReady();

+            }

+        });

+        if (document.documentElement.doScroll && window === top) {

+            var doScrollCheck = function(){

+                if (domIsReady) {

+                    return;

+                }

+                // http://javascript.nwbox.com/IEContentLoaded/

+                try {

+                    document.documentElement.doScroll("left");

+                } 

+                catch (e) {

+                    setTimeout(doScrollCheck, 1);

+                    return;

+                }

+                dom_onReady();

+            };

+            doScrollCheck();

+        }

+    }

+    

+    // A fallback to window.onload, that will always work

+    on(window, "load", dom_onReady);

+}

+/**

+ * This will add a function to the queue of functions to be run once the DOM reaches a ready state.

+ * If functions are added after this event then they will be executed immediately.

+ * @param {function} fn The function to add

+ * @param {Object} scope An optional scope for the function to be called with.

+ */

+function whenReady(fn, scope){

+    if (domIsReady) {

+        fn.call(scope);

+        return;

+    }

+    domReadyQueue.push(function(){

+        fn.call(scope);

+    });

+}

+

+/**

+ * Returns an instance of easyXDM from the parent window with

+ * respect to the namespace.

+ *

+ * @return An instance of easyXDM (in the parent window)

+ */

+function getParentObject(){

+    var obj = parent;

+    if (namespace !== "") {

+        for (var i = 0, ii = namespace.split("."); i < ii.length; i++) {

+            if (!obj) {

+                throw new Error(ii.slice(0, i + 1).join('.') + ' is not an object');

+            }

+            obj = obj[ii[i]];

+        }

+    }

+    if (!obj || !obj.easyXDM) {

+        throw new Error('Could not find easyXDM in parent.' + namespace);

+    }

+    return obj.easyXDM;

+}

+

+/**

+ * Removes easyXDM variable from the global scope. It also returns control

+ * of the easyXDM variable to whatever code used it before.

+ *

+ * @param {String} ns A string representation of an object that will hold

+ *                    an instance of easyXDM.

+ * @return An instance of easyXDM

+ */

+function noConflict(ns){

+    if (typeof ns != "string" || !ns) {

+        throw new Error('namespace must be a non-empty string');

+    }

+    _trace("Settings namespace to '" + ns + "'");

+    

+    window.easyXDM = _easyXDM;

+    namespace = ns;

+    if (namespace) {

+        IFRAME_PREFIX = "easyXDM_" + namespace.replace(".", "_") + "_";

+    }

+    return easyXDM;

+}

+

+/*

+ * Methods for working with URLs

+ */

+/**

+ * Get the domain name from a url.

+ * @param {String} url The url to extract the domain from.

+ * @return The domain part of the url.

+ * @type {String}

+ */

+function getDomainName(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    return url.match(reURI)[3];

+}

+

+/**

+ * Get the port for a given URL, or "" if none

+ * @param {String} url The url to extract the port from.

+ * @return The port part of the url.

+ * @type {String}

+ */

+function getPort(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    return url.match(reURI)[4] || "";

+}

+

+/**

+ * Returns  a string containing the schema, domain and if present the port

+ * @param {String} url The url to extract the location from

+ * @return {String} The location part of the url

+ */

+function getLocation(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    if (/^file/.test(url)) {

+        throw new Error("The file:// protocol is not supported");

+    }

+    var m = url.toLowerCase().match(reURI);

+    var proto = m[2], domain = m[3], port = m[4] || "";

+    if ((proto == "http:" && port == ":80") || (proto == "https:" && port == ":443")) {

+        port = "";

+    }

+    return proto + "//" + domain + port;

+}

+

+/**

+ * Resolves a relative url into an absolute one.

+ * @param {String} url The path to resolve.

+ * @return {String} The resolved url.

+ */

+function resolveUrl(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    

+    // replace all // except the one in proto with /

+    url = url.replace(reDoubleSlash, "$1/");

+    

+    // If the url is a valid url we do nothing

+    if (!url.match(/^(http||https):\/\//)) {

+        // If this is a relative path

+        var path = (url.substring(0, 1) === "/") ? "" : location.pathname;

+        if (path.substring(path.length - 1) !== "/") {

+            path = path.substring(0, path.lastIndexOf("/") + 1);

+        }

+        

+        url = location.protocol + "//" + location.host + path + url;

+    }

+    

+    // reduce all 'xyz/../' to just '' 

+    while (reParent.test(url)) {

+        url = url.replace(reParent, "");

+    }

+    

+    _trace("resolved url '" + url + "'");

+    return url;

+}

+

+/**

+ * Appends the parameters to the given url.<br/>

+ * The base url can contain existing query parameters.

+ * @param {String} url The base url.

+ * @param {Object} parameters The parameters to add.

+ * @return {String} A new valid url with the parameters appended.

+ */

+function appendQueryParameters(url, parameters){

+    if (!parameters) {

+        throw new Error("parameters is undefined or null");

+    }

+    

+    var hash = "", indexOf = url.indexOf("#");

+    if (indexOf !== -1) {

+        hash = url.substring(indexOf);

+        url = url.substring(0, indexOf);

+    }

+    var q = [];

+    for (var key in parameters) {

+        if (parameters.hasOwnProperty(key)) {

+            q.push(key + "=" + encodeURIComponent(parameters[key]));

+        }

+    }

+    return url + (useHash ? "#" : (url.indexOf("?") == -1 ? "?" : "&")) + q.join("&") + hash;

+}

+

+

+// build the query object either from location.query, if it contains the xdm_e argument, or from location.hash

+var query = (function(input){

+    input = input.substring(1).split("&");

+    var data = {}, pair, i = input.length;

+    while (i--) {

+        pair = input[i].split("=");

+        data[pair[0]] = decodeURIComponent(pair[1]);

+    }

+    return data;

+}(/xdm_e=/.test(location.search) ? location.search : location.hash));

+

+/*

+ * Helper methods

+ */

+/**

+ * Helper for checking if a variable/property is undefined

+ * @param {Object} v The variable to test

+ * @return {Boolean} True if the passed variable is undefined

+ */

+function undef(v){

+    return typeof v === "undefined";

+}

+

+/**

+ * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.

+ * @return {JSON} A valid JSON conforming object, or null if not found.

+ */

+var getJSON = function(){

+    var cached = {};

+    var obj = {

+        a: [1, 2, 3]

+    }, json = "{\"a\":[1,2,3]}";

+    

+    if (typeof JSON != "undefined" && typeof JSON.stringify === "function" && JSON.stringify(obj).replace((/\s/g), "") === json) {

+        // this is a working JSON instance

+        return JSON;

+    }

+    if (Object.toJSON) {

+        if (Object.toJSON(obj).replace((/\s/g), "") === json) {

+            // this is a working stringify method

+            cached.stringify = Object.toJSON;

+        }

+    }

+    

+    if (typeof String.prototype.evalJSON === "function") {

+        obj = json.evalJSON();

+        if (obj.a && obj.a.length === 3 && obj.a[2] === 3) {

+            // this is a working parse method           

+            cached.parse = function(str){

+                return str.evalJSON();

+            };

+        }

+    }

+    

+    if (cached.stringify && cached.parse) {

+        // Only memoize the result if we have valid instance

+        getJSON = function(){

+            return cached;

+        };

+        return cached;

+    }

+    return null;

+};

+

+/**

+ * Applies properties from the source object to the target object.<br/>

+ * @param {Object} target The target of the properties.

+ * @param {Object} source The source of the properties.

+ * @param {Boolean} noOverwrite Set to True to only set non-existing properties.

+ */

+function apply(destination, source, noOverwrite){

+    var member;

+    for (var prop in source) {

+        if (source.hasOwnProperty(prop)) {

+            if (prop in destination) {

+                member = source[prop];

+                if (typeof member === "object") {

+                    apply(destination[prop], member, noOverwrite);

+                }

+                else if (!noOverwrite) {

+                    destination[prop] = source[prop];

+                }

+            }

+            else {

+                destination[prop] = source[prop];

+            }

+        }

+    }

+    return destination;

+}

+

+// This tests for the bug in IE where setting the [name] property using javascript causes the value to be redirected into [submitName].

+function testForNamePropertyBug(){

+    var form = document.body.appendChild(document.createElement("form")), input = form.appendChild(document.createElement("input"));

+    input.name = IFRAME_PREFIX + "TEST" + channelId; // append channelId in order to avoid caching issues

+    HAS_NAME_PROPERTY_BUG = input !== form.elements[input.name];

+    document.body.removeChild(form);

+    _trace("HAS_NAME_PROPERTY_BUG: " + HAS_NAME_PROPERTY_BUG);

+}

+

+/**

+ * Creates a frame and appends it to the DOM.

+ * @param config {object} This object can have the following properties

+ * <ul>

+ * <li> {object} prop The properties that should be set on the frame. This should include the 'src' property.</li>

+ * <li> {object} attr The attributes that should be set on the frame.</li>

+ * <li> {DOMElement} container Its parent element (Optional).</li>

+ * <li> {function} onLoad A method that should be called with the frames contentWindow as argument when the frame is fully loaded. (Optional)</li>

+ * </ul>

+ * @return The frames DOMElement

+ * @type DOMElement

+ */

+function createFrame(config){

+    _trace("creating frame: " + config.props.src);

+    if (undef(HAS_NAME_PROPERTY_BUG)) {

+        testForNamePropertyBug();

+    }

+    var frame;

+    // This is to work around the problems in IE6/7 with setting the name property. 

+    // Internally this is set as 'submitName' instead when using 'iframe.name = ...'

+    // This is not required by easyXDM itself, but is to facilitate other use cases 

+    if (HAS_NAME_PROPERTY_BUG) {

+        frame = document.createElement("<iframe name=\"" + config.props.name + "\"/>");

+    }

+    else {

+        frame = document.createElement("IFRAME");

+        frame.name = config.props.name;

+    }

+    

+    frame.id = frame.name = config.props.name;

+    delete config.props.name;

+    

+    if (typeof config.container == "string") {

+        config.container = document.getElementById(config.container);

+    }

+    

+    if (!config.container) {

+        // This needs to be hidden like this, simply setting display:none and the like will cause failures in some browsers.

+        apply(frame.style, {

+            position: "absolute",

+            top: "-2000px",

+            // Avoid potential horizontal scrollbar

+            left: "0px"

+        });

+        config.container = document.body;

+    }

+    

+    // HACK: IE cannot have the src attribute set when the frame is appended

+    //       into the container, so we set it to "javascript:false" as a

+    //       placeholder for now.  If we left the src undefined, it would

+    //       instead default to "about:blank", which causes SSL mixed-content

+    //       warnings in IE6 when on an SSL parent page.

+    var src = config.props.src;

+    config.props.src = "javascript:false";

+    

+    // transfer properties to the frame

+    apply(frame, config.props);

+    

+    frame.border = frame.frameBorder = 0;

+    frame.allowTransparency = true;

+    config.container.appendChild(frame);

+    

+    if (config.onLoad) {

+        on(frame, "load", config.onLoad);

+    }

+    

+    // set the frame URL to the proper value (we previously set it to

+    // "javascript:false" to work around the IE issue mentioned above)

+    if(config.usePost) {

+        var form = config.container.appendChild(document.createElement('form')), input;

+        form.target = frame.name;

+        form.action = src;

+        form.method = 'POST';

+        if (typeof(config.usePost) === 'object') {

+            for (var i in config.usePost) {

+                if (config.usePost.hasOwnProperty(i)) {

+                    if (HAS_NAME_PROPERTY_BUG) {

+                        input = document.createElement('<input name="' + i + '"/>');

+                    } else {

+                        input = document.createElement("INPUT");

+                        input.name = i;

+                    }

+                    input.value = config.usePost[i];

+                    form.appendChild(input);

+                }

+            }

+        }

+        form.submit();

+        form.parentNode.removeChild(form);

+    } else {

+        frame.src = src;

+    }

+    config.props.src = src;

+    

+    return frame;

+}

+

+/**

+ * Check whether a domain is allowed using an Access Control List.

+ * The ACL can contain * and ? as wildcards, or can be regular expressions.

+ * If regular expressions they need to begin with ^ and end with $.

+ * @param {Array/String} acl The list of allowed domains

+ * @param {String} domain The domain to test.

+ * @return {Boolean} True if the domain is allowed, false if not.

+ */

+function checkAcl(acl, domain){

+    // normalize into an array

+    if (typeof acl == "string") {

+        acl = [acl];

+    }

+    var re, i = acl.length;

+    while (i--) {

+        re = acl[i];

+        re = new RegExp(re.substr(0, 1) == "^" ? re : ("^" + re.replace(/(\*)/g, ".$1").replace(/\?/g, ".") + "$"));

+        if (re.test(domain)) {

+            return true;

+        }

+    }

+    return false;

+}

+

+/*

+ * Functions related to stacks

+ */

+/**

+ * Prepares an array of stack-elements suitable for the current configuration

+ * @param {Object} config The Transports configuration. See easyXDM.Socket for more.

+ * @return {Array} An array of stack-elements with the TransportElement at index 0.

+ */

+function prepareTransportStack(config){

+    var protocol = config.protocol, stackEls;

+    config.isHost = config.isHost || undef(query.xdm_p);

+    useHash = config.hash || false;

+    _trace("preparing transport stack");

+    

+    if (!config.props) {

+        config.props = {};

+    }

+    if (!config.isHost) {

+        _trace("using parameters from query");

+        config.channel = query.xdm_c.replace(/["'<>\\]/g, "");

+        config.secret = query.xdm_s;

+        config.remote = query.xdm_e.replace(/["'<>\\]/g, "");

+        ;

+        protocol = query.xdm_p;

+        if (config.acl && !checkAcl(config.acl, config.remote)) {

+            throw new Error("Access denied for " + config.remote);

+        }

+    }

+    else {

+        config.remote = resolveUrl(config.remote);

+        config.channel = config.channel || "default" + channelId++;

+        config.secret = Math.random().toString(16).substring(2);

+        if (undef(protocol)) {

+            if (getLocation(location.href) == getLocation(config.remote)) {

+                /*

+                 * Both documents has the same origin, lets use direct access.

+                 */

+                protocol = "4";

+            }

+            else if (isHostMethod(window, "postMessage") || isHostMethod(document, "postMessage")) {

+                /*

+                 * This is supported in IE8+, Firefox 3+, Opera 9+, Chrome 2+ and Safari 4+

+                 */

+                protocol = "1";

+            }

+            else if (config.swf && isHostMethod(window, "ActiveXObject") && hasFlash()) {

+                /*

+                 * The Flash transport superseedes the NixTransport as the NixTransport has been blocked by MS

+                 */

+                protocol = "6";

+            }

+            else if (navigator.product === "Gecko" && "frameElement" in window && navigator.userAgent.indexOf('WebKit') == -1) {

+                /*

+                 * This is supported in Gecko (Firefox 1+)

+                 */

+                protocol = "5";

+            }

+            else if (config.remoteHelper) {

+                /*

+                 * This is supported in all browsers that retains the value of window.name when

+                 * navigating from one domain to another, and where parent.frames[foo] can be used

+                 * to get access to a frame from the same domain

+                 */

+                protocol = "2";

+            }

+            else {

+                /*

+                 * This is supported in all browsers where [window].location is writable for all

+                 * The resize event will be used if resize is supported and the iframe is not put

+                 * into a container, else polling will be used.

+                 */

+                protocol = "0";

+            }

+            _trace("selecting protocol: " + protocol);

+        }

+        else {

+            _trace("using protocol: " + protocol);

+        }

+    }

+    config.protocol = protocol; // for conditional branching

+    switch (protocol) {

+        case "0":// 0 = HashTransport

+            apply(config, {

+                interval: 100,

+                delay: 2000,

+                useResize: true,

+                useParent: false,

+                usePolling: false

+            }, true);

+            if (config.isHost) {

+                if (!config.local) {

+                    _trace("looking for image to use as local");

+                    // If no local is set then we need to find an image hosted on the current domain

+                    var domain = location.protocol + "//" + location.host, images = document.body.getElementsByTagName("img"), image;

+                    var i = images.length;

+                    while (i--) {

+                        image = images[i];

+                        if (image.src.substring(0, domain.length) === domain) {

+                            config.local = image.src;

+                            break;

+                        }

+                    }

+                    if (!config.local) {

+                        _trace("no image found, defaulting to using the window");

+                        // If no local was set, and we are unable to find a suitable file, then we resort to using the current window 

+                        config.local = window;

+                    }

+                }

+                

+                var parameters = {

+                    xdm_c: config.channel,

+                    xdm_p: 0

+                };

+                

+                if (config.local === window) {

+                    // We are using the current window to listen to

+                    config.usePolling = true;

+                    config.useParent = true;

+                    config.local = location.protocol + "//" + location.host + location.pathname + location.search;

+                    parameters.xdm_e = config.local;

+                    parameters.xdm_pa = 1; // use parent

+                }

+                else {

+                    parameters.xdm_e = resolveUrl(config.local);

+                }

+                

+                if (config.container) {

+                    config.useResize = false;

+                    parameters.xdm_po = 1; // use polling

+                }

+                config.remote = appendQueryParameters(config.remote, parameters);

+            }

+            else {

+                apply(config, {

+                    channel: query.xdm_c,

+                    remote: query.xdm_e,

+                    useParent: !undef(query.xdm_pa),

+                    usePolling: !undef(query.xdm_po),

+                    useResize: config.useParent ? false : config.useResize

+                });

+            }

+            stackEls = [new easyXDM.stack.HashTransport(config), new easyXDM.stack.ReliableBehavior({}), new easyXDM.stack.QueueBehavior({

+                encode: true,

+                maxLength: 4000 - config.remote.length

+            }), new easyXDM.stack.VerifyBehavior({

+                initiate: config.isHost

+            })];

+            break;

+        case "1":

+            stackEls = [new easyXDM.stack.PostMessageTransport(config)];

+            break;

+        case "2":

+            config.remoteHelper = resolveUrl(config.remoteHelper);

+            stackEls = [new easyXDM.stack.NameTransport(config), new easyXDM.stack.QueueBehavior(), new easyXDM.stack.VerifyBehavior({

+                initiate: config.isHost

+            })];

+            break;

+        case "3":

+            stackEls = [new easyXDM.stack.NixTransport(config)];

+            break;

+        case "4":

+            stackEls = [new easyXDM.stack.SameOriginTransport(config)];

+            break;

+        case "5":

+            stackEls = [new easyXDM.stack.FrameElementTransport(config)];

+            break;

+        case "6":

+            if (!flashVersion) {

+                hasFlash();

+            }

+            stackEls = [new easyXDM.stack.FlashTransport(config)];

+            break;

+    }

+    // this behavior is responsible for buffering outgoing messages, and for performing lazy initialization

+    stackEls.push(new easyXDM.stack.QueueBehavior({

+        lazy: config.lazy,

+        remove: true

+    }));

+    return stackEls;

+}

+

+/**

+ * Chains all the separate stack elements into a single usable stack.<br/>

+ * If an element is missing a necessary method then it will have a pass-through method applied.

+ * @param {Array} stackElements An array of stack elements to be linked.

+ * @return {easyXDM.stack.StackElement} The last element in the chain.

+ */

+function chainStack(stackElements){

+    var stackEl, defaults = {

+        incoming: function(message, origin){

+            this.up.incoming(message, origin);

+        },

+        outgoing: function(message, recipient){

+            this.down.outgoing(message, recipient);

+        },

+        callback: function(success){

+            this.up.callback(success);

+        },

+        init: function(){

+            this.down.init();

+        },

+        destroy: function(){

+            this.down.destroy();

+        }

+    };

+    for (var i = 0, len = stackElements.length; i < len; i++) {

+        stackEl = stackElements[i];

+        apply(stackEl, defaults, true);

+        if (i !== 0) {

+            stackEl.down = stackElements[i - 1];

+        }

+        if (i !== len - 1) {

+            stackEl.up = stackElements[i + 1];

+        }

+    }

+    return stackEl;

+}

+

+/**

+ * This will remove a stackelement from its stack while leaving the stack functional.

+ * @param {Object} element The elment to remove from the stack.

+ */

+function removeFromStack(element){

+    element.up.down = element.down;

+    element.down.up = element.up;

+    element.up = element.down = null;

+}

+

+/*

+ * Export the main object and any other methods applicable

+ */

+/** 

+ * @class easyXDM

+ * A javascript library providing cross-browser, cross-domain messaging/RPC.

+ * @version 2.4.17.1

+ * @singleton

+ */

+apply(easyXDM, {

+    /**

+     * The version of the library

+     * @type {string}

+     */

+    version: "2.4.17.1",

+    /**

+     * This is a map containing all the query parameters passed to the document.

+     * All the values has been decoded using decodeURIComponent.

+     * @type {object}

+     */

+    query: query,

+    /**

+     * @private

+     */

+    stack: {},

+    /**

+     * Applies properties from the source object to the target object.<br/>

+     * @param {object} target The target of the properties.

+     * @param {object} source The source of the properties.

+     * @param {boolean} noOverwrite Set to True to only set non-existing properties.

+     */

+    apply: apply,

+    

+    /**

+     * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.

+     * @return {JSON} A valid JSON conforming object, or null if not found.

+     */

+    getJSONObject: getJSON,

+    /**

+     * This will add a function to the queue of functions to be run once the DOM reaches a ready state.

+     * If functions are added after this event then they will be executed immediately.

+     * @param {function} fn The function to add

+     * @param {object} scope An optional scope for the function to be called with.

+     */

+    whenReady: whenReady,

+    /**

+     * Removes easyXDM variable from the global scope. It also returns control

+     * of the easyXDM variable to whatever code used it before.

+     *

+     * @param {String} ns A string representation of an object that will hold

+     *                    an instance of easyXDM.

+     * @return An instance of easyXDM

+     */

+    noConflict: noConflict

+});

+

+// Expose helper functions so we can test them

+apply(easyXDM, {

+    checkAcl: checkAcl,

+    getDomainName: getDomainName,

+    getLocation: getLocation,

+    appendQueryParameters: appendQueryParameters

+});

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global console, _FirebugCommandLine,  easyXDM, window, escape, unescape, isHostObject, undef, _trace, domIsReady, emptyFn, namespace */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+var debug = {

+    _deferred: [],

+    flush: function(){

+        this.trace("... deferred messages ...");

+        for (var i = 0, len = this._deferred.length; i < len; i++) {

+            this.trace(this._deferred[i]);

+        }

+        this._deferred.length = 0;

+        this.trace("... end of deferred messages ...");

+    },

+    getTime: function(){

+        var d = new Date(), h = d.getHours() + "", m = d.getMinutes() + "", s = d.getSeconds() + "", ms = d.getMilliseconds() + "", zeros = "000";

+        if (h.length == 1) {

+            h = "0" + h;

+        }

+        if (m.length == 1) {

+            m = "0" + m;

+        }

+        if (s.length == 1) {

+            s = "0" + s;

+        }

+        ms = zeros.substring(ms.length) + ms;

+        return h + ":" + m + ":" + s + "." + ms;

+    },

+    /**

+     * Logs the message to console.log if available

+     * @param {String} msg The message to log

+     */

+    log: function(msg){

+        // Uses memoizing to cache the implementation

+        if (!isHostObject(window, "console") || undef(console.log)) {

+            /**

+             * Sets log to be an empty function since we have no output available

+             * @ignore

+             */

+            this.log = emptyFn;

+        }

+        else {

+            /**

+             * Sets log to be a wrapper around console.log

+             * @ignore

+             * @param {String} msg

+             */

+            this.log = function(msg){

+                console.log(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ": " + msg);

+            };

+        }

+        this.log(msg);

+    },

+    /**

+     * Will try to trace the given message either to a DOMElement with the id "log",

+     * or by using console.info.

+     * @param {String} msg The message to trace

+     */

+    trace: function(msg){

+        // Uses memoizing to cache the implementation

+        if (!domIsReady) {

+            if (this._deferred.length === 0) {

+                easyXDM.whenReady(debug.flush, debug);

+            }

+            this._deferred.push(msg);

+            this.log(msg);

+        }

+        else {

+            var el = document.getElementById("log");

+            // is there a log element present?

+            if (el) {

+                /**

+                 * Sets trace to be a function that outputs the messages to the DOMElement with id "log"

+                 * @ignore

+                 * @param {String} msg

+                 */

+                this.trace = function(msg){

+                    try {

+                        el.appendChild(document.createElement("div")).appendChild(document.createTextNode(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg));

+                        el.scrollTop = el.scrollHeight;

+                    } 

+                    catch (e) {

+                        //In case we are unloading

+                    }

+                };

+            }

+            else if (isHostObject(window, "console") && !undef(console.info)) {

+                /**

+                 * Sets trace to be a wrapper around console.info

+                 * @ignore

+                 * @param {String} msg

+                 */

+                this.trace = function(msg){

+                    console.info(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg);

+                };

+            }

+            else {

+                /**

+                 * Create log window

+                 * @ignore

+                 */

+                var domain = location.host, windowname = domain.replace(/[\-.:]/g, "") + "easyxdm_log", logWin;

+                try {

+                    logWin = window.open("", windowname, "width=800,height=200,status=0,navigation=0,scrollbars=1");

+                } 

+                catch (e) {

+                }

+                if (logWin) {

+                    var doc = logWin.document;

+                    el = doc.getElementById("log");

+                    if (!el) {

+                        doc.write("<html><head><title>easyXDM log " + domain + "</title></head>");

+                        doc.write("<body><div id=\"log\"></div></body></html>");

+                        doc.close();

+                        el = doc.getElementById("log");

+                    }

+                    this.trace = function(msg){

+                        try {

+                            el.appendChild(doc.createElement("div")).appendChild(doc.createTextNode(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg));

+                            el.scrollTop = el.scrollHeight;

+                        } 

+                        catch (e) {

+                            //In case we are unloading

+                        }

+                    };

+                    this.trace("---- new logger at " + location.href);

+                }

+                

+                if (!el) {

+                    // We are unable to use any logging

+                    this.trace = emptyFn;

+                }

+            }

+            this.trace(msg);

+        }

+    },

+    /**

+     * Creates a method usable for tracing.

+     * @param {String} name The name the messages should be marked with

+     * @return {Function} A function that accepts a single string as argument.

+     */

+    getTracer: function(name){

+        return function(msg){

+            debug.trace(name + ": " + msg);

+        };

+    }

+};

+debug.log("easyXDM present on '" + location.href);

+easyXDM.Debug = debug;

+_trace = debug.getTracer("{Private}");

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, isHostObject, isHostMethod, un, on, createFrame, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/** 

+ * @class easyXDM.DomHelper

+ * Contains methods for dealing with the DOM

+ * @singleton

+ */

+easyXDM.DomHelper = {

+    /**

+     * Provides a consistent interface for adding eventhandlers

+     * @param {Object} target The target to add the event to

+     * @param {String} type The name of the event

+     * @param {Function} listener The listener

+     */

+    on: on,

+    /**

+     * Provides a consistent interface for removing eventhandlers

+     * @param {Object} target The target to remove the event from

+     * @param {String} type The name of the event

+     * @param {Function} listener The listener

+     */

+    un: un,

+    /**

+     * Checks for the presence of the JSON object.

+     * If it is not present it will use the supplied path to load the JSON2 library.

+     * This should be called in the documents head right after the easyXDM script tag.

+     * http://json.org/json2.js

+     * @param {String} path A valid path to json2.js

+     */

+    requiresJSON: function(path){

+        if (!isHostObject(window, "JSON")) {

+            debug.log("loading external JSON");

+            // we need to encode the < in order to avoid an illegal token error

+            // when the script is inlined in a document.

+            document.write('<' + 'script type="text/javascript" src="' + path + '"><' + '/script>');

+        }

+        else {

+            debug.log("native JSON found");

+        }

+    }

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+(function(){

+    // The map containing the stored functions

+    var _map = {};

+    

+    /**

+     * @class easyXDM.Fn

+     * This contains methods related to function handling, such as storing callbacks.

+     * @singleton

+     * @namespace easyXDM

+     */

+    easyXDM.Fn = {

+        /**

+         * Stores a function using the given name for reference

+         * @param {String} name The name that the function should be referred by

+         * @param {Function} fn The function to store

+         * @namespace easyXDM.fn

+         */

+        set: function(name, fn){

+            this._trace("storing function " + name);

+            _map[name] = fn;

+        },

+        /**

+         * Retrieves the function referred to by the given name

+         * @param {String} name The name of the function to retrieve

+         * @param {Boolean} del If the function should be deleted after retrieval

+         * @return {Function} The stored function

+         * @namespace easyXDM.fn

+         */

+        get: function(name, del){

+            this._trace("retrieving function " + name);

+            var fn = _map[name];

+            if (!fn) {

+                this._trace(name + " not found");

+            }

+            

+            if (del) {

+                delete _map[name];

+            }

+            return fn;

+        }

+    };

+    

+    easyXDM.Fn._trace = debug.getTracer("easyXDM.Fn");

+}());

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, chainStack, prepareTransportStack, getLocation, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.Socket

+ * This class creates a transport channel between two domains that is usable for sending and receiving string-based messages.<br/>

+ * The channel is reliable, supports queueing, and ensures that the message originates from the expected domain.<br/>

+ * Internally different stacks will be used depending on the browsers features and the available parameters.

+ * <h2>How to set up</h2>

+ * Setting up the provider:

+ * <pre><code>

+ * var socket = new easyXDM.Socket({

+ * &nbsp; local: "name.html",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket

+ * &nbsp; &nbsp; socket.postMessage("foo-message");

+ * &nbsp; },

+ * &nbsp; onMessage: function(message, origin) {

+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * Setting up the consumer:

+ * <pre><code>

+ * var socket = new easyXDM.Socket({

+ * &nbsp; remote: "http:&#47;&#47;remotedomain/page.html",

+ * &nbsp; remoteHelper: "http:&#47;&#47;remotedomain/name.html",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket

+ * &nbsp; &nbsp; socket.postMessage("foo-message");

+ * &nbsp; },

+ * &nbsp; onMessage: function(message, origin) {

+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * If you are unable to upload the <code>name.html</code> file to the consumers domain then remove the <code>remoteHelper</code> property

+ * and easyXDM will fall back to using the HashTransport instead of the NameTransport when not able to use any of the primary transports.

+ * @namespace easyXDM

+ * @constructor

+ * @cfg {String/Window} local The url to the local name.html document, a local static file, or a reference to the local window.

+ * @cfg {Boolean} lazy (Consumer only) Set this to true if you want easyXDM to defer creating the transport until really needed. 

+ * @cfg {String} remote (Consumer only) The url to the providers document.

+ * @cfg {String} remoteHelper (Consumer only) The url to the remote name.html file. This is to support NameTransport as a fallback. Optional.

+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.  Optional, defaults to 2000.

+ * @cfg {Number} interval The interval used when polling for messages. Optional, defaults to 300.

+ * @cfg {String} channel (Consumer only) The name of the channel to use. Can be used to set consistent iframe names. Must be unique. Optional.

+ * @cfg {Function} onMessage The method that should handle incoming messages.<br/> This method should accept two arguments, the message as a string, and the origin as a string. Optional.

+ * @cfg {Function} onReady A method that should be called when the transport is ready. Optional.

+ * @cfg {DOMElement|String} container (Consumer only) The element, or the id of the element that the primary iframe should be inserted into. If not set then the iframe will be positioned off-screen. Optional.

+ * @cfg {Array/String} acl (Provider only) Here you can specify which '[protocol]://[domain]' patterns that should be allowed to act as the consumer towards this provider.<br/>

+ * This can contain the wildcards ? and *.  Examples are 'http://example.com', '*.foo.com' and '*dom?.com'. If you want to use reqular expressions then you pattern needs to start with ^ and end with $.

+ * If none of the patterns match an Error will be thrown.  

+ * @cfg {Object} props (Consumer only) Additional properties that should be applied to the iframe. This can also contain nested objects e.g: <code>{style:{width:"100px", height:"100px"}}</code>. 

+ * Properties such as 'name' and 'src' will be overrided. Optional.

+ */

+easyXDM.Socket = function(config){

+    var trace = debug.getTracer("easyXDM.Socket");

+    trace("constructor");

+    

+    // create the stack

+    var stack = chainStack(prepareTransportStack(config).concat([{

+        incoming: function(message, origin){

+            config.onMessage(message, origin);

+        },

+        callback: function(success){

+            if (config.onReady) {

+                config.onReady(success);

+            }

+        }

+    }])), recipient = getLocation(config.remote);

+    

+    // set the origin

+    this.origin = getLocation(config.remote);

+	

+    /**

+     * Initiates the destruction of the stack.

+     */

+    this.destroy = function(){

+        stack.destroy();

+    };

+    

+    /**

+     * Posts a message to the remote end of the channel

+     * @param {String} message The message to send

+     */

+    this.postMessage = function(message){

+        stack.outgoing(message, recipient);

+    };

+    

+    stack.init();

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef,, chainStack, prepareTransportStack, debug, getLocation */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/** 

+ * @class easyXDM.Rpc

+ * Creates a proxy object that can be used to call methods implemented on the remote end of the channel, and also to provide the implementation

+ * of methods to be called from the remote end.<br/>

+ * The instantiated object will have methods matching those specified in <code>config.remote</code>.<br/>

+ * This requires the JSON object present in the document, either natively, using json.org's json2 or as a wrapper around library spesific methods.

+ * <h2>How to set up</h2>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; &#47;&#47; this configuration is equal to that used by the Socket.

+ * &nbsp; remote: "http:&#47;&#47;remotedomain/...",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the proxy

+ * &nbsp; &nbsp; rpc.foo(...

+ * &nbsp; }

+ * },{

+ * &nbsp; local: {..},

+ * &nbsp; remote: {..}

+ * });

+ * </code></pre>

+ * 

+ * <h2>Exposing functions (procedures)</h2>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {

+ * &nbsp; &nbsp; nameOfMethod: {

+ * &nbsp; &nbsp; &nbsp; method: function(arg1, arg2, success, error){

+ * &nbsp; &nbsp; &nbsp; &nbsp; ...

+ * &nbsp; &nbsp; &nbsp; }

+ * &nbsp; &nbsp; },

+ * &nbsp; &nbsp; &#47;&#47; with shorthand notation 

+ * &nbsp; &nbsp; nameOfAnotherMethod:  function(arg1, arg2, success, error){

+ * &nbsp; &nbsp; }

+ * &nbsp; },

+ * &nbsp; remote: {...}

+ * });

+ * </code></pre>

+

+ * The function referenced by  [method] will receive the passed arguments followed by the callback functions <code>success</code> and <code>error</code>.<br/>

+ * To send a successfull result back you can use

+ *     <pre><code>

+ *     return foo;

+ *     </pre></code>

+ * or

+ *     <pre><code>

+ *     success(foo);

+ *     </pre></code>

+ *  To return an error you can use

+ *     <pre><code>

+ *     throw new Error("foo error");

+ *     </code></pre>

+ * or

+ *     <pre><code>

+ *     error("foo error");

+ *     </code></pre>

+ *

+ * <h2>Defining remotely exposed methods (procedures/notifications)</h2>

+ * The definition of the remote end is quite similar:

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {...},

+ * &nbsp; remote: {

+ * &nbsp; &nbsp; nameOfMethod: {}

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * To call a remote method use

+ * <pre><code>

+ * rpc.nameOfMethod("arg1", "arg2", function(value) {

+ * &nbsp; alert("success: " + value);

+ * }, function(message) {

+ * &nbsp; alert("error: " + message + );

+ * });

+ * </code></pre>

+ * Both the <code>success</code> and <code>errror</code> callbacks are optional.<br/>

+ * When called with no callback a JSON-RPC 2.0 notification will be executed.

+ * Be aware that you will not be notified of any errors with this method.

+ * <br/>

+ * <h2>Specifying a custom serializer</h2>

+ * If you do not want to use the JSON2 library for non-native JSON support, but instead capabilities provided by some other library

+ * then you can specify a custom serializer using <code>serializer: foo</code>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {...},

+ * &nbsp; remote: {...},

+ * &nbsp; serializer : {

+ * &nbsp; &nbsp; parse: function(string){ ... },

+ * &nbsp; &nbsp; stringify: function(object) {...}

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * If <code>serializer</code> is set then the class will not attempt to use the native implementation.

+ * @namespace easyXDM

+ * @constructor

+ * @param {Object} config The underlying transports configuration. See easyXDM.Socket for available parameters.

+ * @param {Object} jsonRpcConfig The description of the interface to implement.

+ */

+easyXDM.Rpc = function(config, jsonRpcConfig){

+    var trace = debug.getTracer("easyXDM.Rpc");

+    trace("constructor");

+    

+    // expand shorthand notation

+    if (jsonRpcConfig.local) {

+        for (var method in jsonRpcConfig.local) {

+            if (jsonRpcConfig.local.hasOwnProperty(method)) {

+                var member = jsonRpcConfig.local[method];

+                if (typeof member === "function") {

+                    jsonRpcConfig.local[method] = {

+                        method: member

+                    };

+                }

+            }

+        }

+    }

+	

+    // create the stack

+    var stack = chainStack(prepareTransportStack(config).concat([new easyXDM.stack.RpcBehavior(this, jsonRpcConfig), {

+        callback: function(success){

+            if (config.onReady) {

+                config.onReady(success);

+            }

+        }

+    }]));

+	

+    // set the origin 

+    this.origin = getLocation(config.remote);

+	

+    

+    /**

+     * Initiates the destruction of the stack.

+     */

+    this.destroy = function(){

+        stack.destroy();

+    };

+    

+    stack.init();

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, getParentObject, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.SameOriginTransport

+ * SameOriginTransport is a transport class that can be used when both domains have the same origin.<br/>

+ * This can be useful for testing and for when the main application supports both internal and external sources.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote document to communicate with.

+ */

+easyXDM.stack.SameOriginTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.SameOriginTransport");

+    trace("constructor");

+    var pub, frame, send, targetOrigin;

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            send(message);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            

+            if (config.isHost) {

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: location.protocol + "//" + location.host + location.pathname,

+                        xdm_c: config.channel,

+                        xdm_p: 4 // 4 = SameOriginTransport

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+                easyXDM.Fn.set(config.channel, function(sendFn){

+                    send = sendFn;

+                    setTimeout(function(){

+                        pub.up.callback(true);

+                    }, 0);

+                    return function(msg){

+                        pub.up.incoming(msg, targetOrigin);

+                    };

+                });

+            }

+            else {

+                send = getParentObject().Fn.get(config.channel, true)(function(msg){

+                    pub.up.incoming(msg, targetOrigin);

+                });

+                setTimeout(function(){

+                    pub.up.callback(true);

+                }, 0);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global global, easyXDM, window, getLocation, appendQueryParameters, createFrame, debug, apply, whenReady, IFRAME_PREFIX, namespace, resolveUrl, getDomainName, HAS_FLASH_THROTTLED_BUG, getPort, query*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.FlashTransport

+ * FlashTransport is a transport class that uses an SWF with LocalConnection to pass messages back and forth.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote domain to communicate with.

+ * @cfg {String} secret the pre-shared secret used to secure the communication.

+ * @cfg {String} swf The path to the swf file

+ * @cfg {Boolean} swfNoThrottle Set this to true if you want to take steps to avoid beeing throttled when hidden.

+ * @cfg {String || DOMElement} swfContainer Set this if you want to control where the swf is placed

+ */

+easyXDM.stack.FlashTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.FlashTransport");

+    trace("constructor");

+    if (!config.swf) {

+        throw new Error("Path to easyxdm.swf is missing");

+    }

+    var pub, // the public interface

+ frame, send, targetOrigin, swf, swfContainer;

+    

+    function onMessage(message, origin){

+        setTimeout(function(){

+            trace("received message");

+            pub.up.incoming(message, targetOrigin);

+        }, 0);

+    }

+    

+    /**

+     * This method adds the SWF to the DOM and prepares the initialization of the channel

+     */

+    function addSwf(domain){

+        trace("creating factory with SWF from " + domain);

+        // the differentiating query argument is needed in Flash9 to avoid a caching issue where LocalConnection would throw an error.

+        var url = config.swf + "?host=" + config.isHost;

+        var id = "easyXDM_swf_" + Math.floor(Math.random() * 10000);

+        

+        // prepare the init function that will fire once the swf is ready

+        easyXDM.Fn.set("flash_loaded" + domain.replace(/[\-.]/g, "_"), function(){

+            easyXDM.stack.FlashTransport[domain].swf = swf = swfContainer.firstChild;

+            var queue = easyXDM.stack.FlashTransport[domain].queue;

+            for (var i = 0; i < queue.length; i++) {

+                queue[i]();

+            }

+            queue.length = 0;

+        });

+        

+        if (config.swfContainer) {

+            swfContainer = (typeof config.swfContainer == "string") ? document.getElementById(config.swfContainer) : config.swfContainer;

+        }

+        else {

+            // create the container that will hold the swf

+            swfContainer = document.createElement('div');

+            

+            // http://bugs.adobe.com/jira/browse/FP-4796

+            // http://tech.groups.yahoo.com/group/flexcoders/message/162365

+            // https://groups.google.com/forum/#!topic/easyxdm/mJZJhWagoLc

+            apply(swfContainer.style, HAS_FLASH_THROTTLED_BUG && config.swfNoThrottle ? {

+                height: "20px",

+                width: "20px",

+                position: "fixed",

+                right: 0,

+                top: 0

+            } : {

+                height: "1px",

+                width: "1px",

+                position: "absolute",

+                overflow: "hidden",

+                right: 0,

+                top: 0

+            });

+            document.body.appendChild(swfContainer);

+        }

+        

+        // create the object/embed

+        var flashVars = "callback=flash_loaded" + domain.replace(/[\-.]/g, "_") + "&proto=" + global.location.protocol + "&domain=" + getDomainName(global.location.href) + "&port=" + getPort(global.location.href) + "&ns=" + namespace;

+        flashVars += "&log=true";

+        swfContainer.innerHTML = "<object height='20' width='20' type='application/x-shockwave-flash' id='" + id + "' data='" + url + "'>" +

+        "<param name='allowScriptAccess' value='always'></param>" +

+        "<param name='wmode' value='transparent'>" +

+        "<param name='movie' value='" +

+        url +

+        "'></param>" +

+        "<param name='flashvars' value='" +

+        flashVars +

+        "'></param>" +

+        "<embed type='application/x-shockwave-flash' FlashVars='" +

+        flashVars +

+        "' allowScriptAccess='always' wmode='transparent' src='" +

+        url +

+        "' height='1' width='1'></embed>" +

+        "</object>";

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            swf.postMessage(config.channel, message.toString());

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            try {

+                swf.destroyChannel(config.channel);

+            } 

+            catch (e) {

+            }

+            swf = null;

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            

+            targetOrigin = config.remote;

+            

+            // Prepare the code that will be run after the swf has been intialized

+            easyXDM.Fn.set("flash_" + config.channel + "_init", function(){

+                setTimeout(function(){

+                    trace("firing onReady");

+                    pub.up.callback(true);

+                });

+            });

+            

+            // set up the omMessage handler

+            easyXDM.Fn.set("flash_" + config.channel + "_onMessage", onMessage);

+            

+            config.swf = resolveUrl(config.swf); // reports have been made of requests gone rogue when using relative paths

+            var swfdomain = getDomainName(config.swf);

+            var fn = function(){

+                // set init to true in case the fn was called was invoked from a separate instance

+                easyXDM.stack.FlashTransport[swfdomain].init = true;

+                swf = easyXDM.stack.FlashTransport[swfdomain].swf;

+                // create the channel

+                swf.createChannel(config.channel, config.secret, getLocation(config.remote), config.isHost);

+                

+                if (config.isHost) {

+                    // if Flash is going to be throttled and we want to avoid this

+                    if (HAS_FLASH_THROTTLED_BUG && config.swfNoThrottle) {

+                        apply(config.props, {

+                            position: "fixed",

+                            right: 0,

+                            top: 0,

+                            height: "20px",

+                            width: "20px"

+                        });

+                    }

+                    // set up the iframe

+                    apply(config.props, {

+                        src: appendQueryParameters(config.remote, {

+                            xdm_e: getLocation(location.href),

+                            xdm_c: config.channel,

+                            xdm_p: 6, // 6 = FlashTransport

+                            xdm_s: config.secret

+                        }),

+                        name: IFRAME_PREFIX + config.channel + "_provider"

+                    });

+                    frame = createFrame(config);

+                }

+            };

+            

+            if (easyXDM.stack.FlashTransport[swfdomain] && easyXDM.stack.FlashTransport[swfdomain].init) {

+                // if the swf is in place and we are the consumer

+                fn();

+            }

+            else {

+                // if the swf does not yet exist

+                if (!easyXDM.stack.FlashTransport[swfdomain]) {

+                    // add the queue to hold the init fn's

+                    easyXDM.stack.FlashTransport[swfdomain] = {

+                        queue: [fn]

+                    };

+                    addSwf(swfdomain);

+                }

+                else {

+                    easyXDM.stack.FlashTransport[swfdomain].queue.push(fn);

+                }

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.PostMessageTransport

+ * PostMessageTransport is a transport class that uses HTML5 postMessage for communication.<br/>

+ * <a href="http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx</a><br/>

+ * <a href="https://developer.mozilla.org/en/DOM/window.postMessage">https://developer.mozilla.org/en/DOM/window.postMessage</a>

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote domain to communicate with.

+ */

+easyXDM.stack.PostMessageTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.PostMessageTransport");

+    trace("constructor");

+    var pub, // the public interface

+ frame, // the remote frame, if any

+ callerWindow, // the window that we will call with

+ targetOrigin; // the domain to communicate with

+    /**

+     * Resolves the origin from the event object

+     * @private

+     * @param {Object} event The messageevent

+     * @return {String} The scheme, host and port of the origin

+     */

+    function _getOrigin(event){

+        if (event.origin) {

+            // This is the HTML5 property

+            return getLocation(event.origin);

+        }

+        if (event.uri) {

+            // From earlier implementations 

+            return getLocation(event.uri);

+        }

+        if (event.domain) {

+            // This is the last option and will fail if the 

+            // origin is not using the same schema as we are

+            return location.protocol + "//" + event.domain;

+        }

+        throw "Unable to retrieve the origin of the event";

+    }

+    

+    /**

+     * This is the main implementation for the onMessage event.<br/>

+     * It checks the validity of the origin and passes the message on if appropriate.

+     * @private

+     * @param {Object} event The messageevent

+     */

+    function _window_onMessage(event){

+        var origin = _getOrigin(event);

+        trace("received message '" + event.data + "' from " + origin);

+        if (origin == targetOrigin && event.data.substring(0, config.channel.length + 1) == config.channel + " ") {

+            pub.up.incoming(event.data.substring(config.channel.length + 1), origin);

+        }

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            callerWindow.postMessage(config.channel + " " + message, domain || targetOrigin);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            un(window, "message", _window_onMessage);

+            if (frame) {

+                callerWindow = null;

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            if (config.isHost) {

+                // add the event handler for listening

+                var waitForReady = function(event){  

+                    if (event.data == config.channel + "-ready") {

+                        trace("firing onReady");

+                        // replace the eventlistener

+                        callerWindow = ("postMessage" in frame.contentWindow) ? frame.contentWindow : frame.contentWindow.document;

+                        un(window, "message", waitForReady);

+                        on(window, "message", _window_onMessage);

+                        setTimeout(function(){

+                            pub.up.callback(true);

+                        }, 0);

+                    }

+                };

+                on(window, "message", waitForReady);

+                

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: getLocation(location.href),

+                        xdm_c: config.channel,

+                        xdm_p: 1 // 1 = PostMessage

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+            }

+            else {

+                // add the event handler for listening

+                on(window, "message", _window_onMessage);

+                callerWindow = ("postMessage" in window.parent) ? window.parent : window.parent.document;

+                callerWindow.postMessage(config.channel + "-ready", targetOrigin);

+                

+                setTimeout(function(){

+                    pub.up.callback(true);

+                }, 0);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, apply, query, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.FrameElementTransport

+ * FrameElementTransport is a transport class that can be used with Gecko-browser as these allow passing variables using the frameElement property.<br/>

+ * Security is maintained as Gecho uses Lexical Authorization to determine under which scope a function is running.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote document to communicate with.

+ */

+easyXDM.stack.FrameElementTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.FrameElementTransport");

+    trace("constructor");

+    var pub, frame, send, targetOrigin;

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            send.call(this, message);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            

+            if (config.isHost) {

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: getLocation(location.href),

+                        xdm_c: config.channel,

+                        xdm_p: 5 // 5 = FrameElementTransport

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+                frame.fn = function(sendFn){

+                    delete frame.fn;

+                    send = sendFn;

+                    setTimeout(function(){

+                        pub.up.callback(true);

+                    }, 0);

+                    // remove the function so that it cannot be used to overwrite the send function later on

+                    return function(msg){

+                        pub.up.incoming(msg, targetOrigin);

+                    };

+                };

+            }

+            else {

+                // This is to mitigate origin-spoofing

+                if (document.referrer && getLocation(document.referrer) != query.xdm_e) {

+                    window.top.location = query.xdm_e;

+                }

+                send = window.frameElement.fn(function(msg){

+                    pub.up.incoming(msg, targetOrigin);

+                });

+                pub.up.callback(true);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, getLocation, appendQueryParameters, resolveUrl, createFrame, debug, un, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.NameTransport

+ * NameTransport uses the window.name property to relay data.

+ * The <code>local</code> parameter needs to be set on both the consumer and provider,<br/>

+ * and the <code>remoteHelper</code> parameter needs to be set on the consumer.

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remoteHelper The url to the remote instance of hash.html - this is only needed for the host.

+ * @namespace easyXDM.stack

+ */

+easyXDM.stack.NameTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.NameTransport");

+    trace("constructor");

+    if (config.isHost && undef(config.remoteHelper)) {

+        trace("missing remoteHelper");

+        throw new Error("missing remoteHelper");

+    }

+    

+    var pub; // the public interface

+    var isHost, callerWindow, remoteWindow, readyCount, callback, remoteOrigin, remoteUrl;

+    

+    function _sendMessage(message){

+        var url = config.remoteHelper + (isHost ? "#_3" : "#_2") + config.channel;

+        trace("sending message " + message);

+        trace("navigating to  '" + url + "'");

+        callerWindow.contentWindow.sendMessage(message, url);

+    }

+    

+    function _onReady(){

+        if (isHost) {

+            if (++readyCount === 2 || !isHost) {

+                pub.up.callback(true);

+            }

+        }

+        else {

+            _sendMessage("ready");

+            trace("calling onReady");

+            pub.up.callback(true);

+        }

+    }

+    

+    function _onMessage(message){

+        trace("received message " + message);

+        pub.up.incoming(message, remoteOrigin);

+    }

+    

+    function _onLoad(){

+        if (callback) {

+            setTimeout(function(){

+                callback(true);

+            }, 0);

+        }

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            callback = fn;

+            _sendMessage(message);

+        },

+        destroy: function(){

+            trace("destroy");

+            callerWindow.parentNode.removeChild(callerWindow);

+            callerWindow = null;

+            if (isHost) {

+                remoteWindow.parentNode.removeChild(remoteWindow);

+                remoteWindow = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            isHost = config.isHost;

+            readyCount = 0;

+            remoteOrigin = getLocation(config.remote);

+            config.local = resolveUrl(config.local);

+            

+            if (isHost) {

+                // Register the callback

+                easyXDM.Fn.set(config.channel, function(message){

+                    trace("received initial message " + message);

+                    if (isHost && message === "ready") {

+                        // Replace the handler

+                        easyXDM.Fn.set(config.channel, _onMessage);

+                        _onReady();

+                    }

+                });

+                

+                // Set up the frame that points to the remote instance

+                remoteUrl = appendQueryParameters(config.remote, {

+                    xdm_e: config.local,

+                    xdm_c: config.channel,

+                    xdm_p: 2

+                });

+                apply(config.props, {

+                    src: remoteUrl + '#' + config.channel,

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                remoteWindow = createFrame(config);

+            }

+            else {

+                config.remoteHelper = config.remote;

+                easyXDM.Fn.set(config.channel, _onMessage);

+            }

+            

+            // Set up the iframe that will be used for the transport

+            var onLoad = function(){

+                // Remove the handler

+                var w = callerWindow || this;

+                un(w, "load", onLoad);

+                easyXDM.Fn.set(config.channel + "_load", _onLoad);

+                (function test(){

+                    if (typeof w.contentWindow.sendMessage == "function") {

+                        _onReady();

+                    }

+                    else {

+                        setTimeout(test, 50);

+                    }

+                }());

+            };

+            

+            callerWindow = createFrame({

+                props: {

+                    src: config.local + "#_4" + config.channel

+                },

+                onLoad: onLoad

+            });

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.HashTransport

+ * HashTransport is a transport class that uses the IFrame URL Technique for communication.<br/>

+ * <a href="http://msdn.microsoft.com/en-us/library/bb735305.aspx">http://msdn.microsoft.com/en-us/library/bb735305.aspx</a><br/>

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String/Window} local The url to the local file used for proxying messages, or the local window.

+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.

+ * @cfg {Number} interval The interval used when polling for messages.

+ */

+easyXDM.stack.HashTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.HashTransport");

+    trace("constructor");

+    var pub;

+    var me = this, isHost, _timer, pollInterval, _lastMsg, _msgNr, _listenerWindow, _callerWindow;

+    var useParent, _remoteOrigin;

+    

+    function _sendMessage(message){

+        trace("sending message '" + (_msgNr + 1) + " " + message + "' to " + _remoteOrigin);

+        if (!_callerWindow) {

+            trace("no caller window");

+            return;

+        }

+        var url = config.remote + "#" + (_msgNr++) + "_" + message;

+        ((isHost || !useParent) ? _callerWindow.contentWindow : _callerWindow).location = url;

+    }

+    

+    function _handleHash(hash){

+        _lastMsg = hash;

+        trace("received message '" + _lastMsg + "' from " + _remoteOrigin);

+        pub.up.incoming(_lastMsg.substring(_lastMsg.indexOf("_") + 1), _remoteOrigin);

+    }

+    

+    /**

+     * Checks location.hash for a new message and relays this to the receiver.

+     * @private

+     */

+    function _pollHash(){

+        if (!_listenerWindow) {

+            return;

+        }

+        var href = _listenerWindow.location.href, hash = "", indexOf = href.indexOf("#");

+        if (indexOf != -1) {

+            hash = href.substring(indexOf);

+        }

+        if (hash && hash != _lastMsg) {

+            trace("poll: new message");

+            _handleHash(hash);

+        }

+    }

+    

+    function _attachListeners(){

+        trace("starting polling");

+        _timer = setInterval(_pollHash, pollInterval);

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain){

+            _sendMessage(message);

+        },

+        destroy: function(){

+            window.clearInterval(_timer);

+            if (isHost || !useParent) {

+                _callerWindow.parentNode.removeChild(_callerWindow);

+            }

+            _callerWindow = null;

+        },

+        onDOMReady: function(){

+            isHost = config.isHost;

+            pollInterval = config.interval;

+            _lastMsg = "#" + config.channel;

+            _msgNr = 0;

+            useParent = config.useParent;

+            _remoteOrigin = getLocation(config.remote);

+            if (isHost) {

+                apply(config.props, {

+                    src: config.remote,

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                if (useParent) {

+                    config.onLoad = function(){

+                        _listenerWindow = window;

+                        _attachListeners();

+                        pub.up.callback(true);

+                    };

+                }

+                else {

+                    var tries = 0, max = config.delay / 50;

+                    (function getRef(){

+                        if (++tries > max) {

+                            trace("unable to get reference to _listenerWindow, giving up");

+                            throw new Error("Unable to reference listenerwindow");

+                        }

+                        try {

+                            _listenerWindow = _callerWindow.contentWindow.frames[IFRAME_PREFIX + config.channel + "_consumer"];

+                        } 

+                        catch (ex) {

+                        }

+                        if (_listenerWindow) {

+                            _attachListeners();

+                            trace("got a reference to _listenerWindow");

+                            pub.up.callback(true);

+                        }

+                        else {

+                            setTimeout(getRef, 50);

+                        }

+                    }());

+                }

+                _callerWindow = createFrame(config);

+            }

+            else {

+                _listenerWindow = window;

+                _attachListeners();

+                if (useParent) {

+                    _callerWindow = parent;

+                    pub.up.callback(true);

+                }

+                else {

+                    apply(config, {

+                        props: {

+                            src: config.remote + "#" + config.channel + new Date(),

+                            name: IFRAME_PREFIX + config.channel + "_consumer"

+                        },

+                        onLoad: function(){

+                            pub.up.callback(true);

+                        }

+                    });

+                    _callerWindow = createFrame(config);

+                }

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.ReliableBehavior

+ * This is a behavior that tries to make the underlying transport reliable by using acknowledgements.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration.

+ */

+easyXDM.stack.ReliableBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.ReliableBehavior");

+    trace("constructor");

+    var pub, // the public interface

+ callback; // the callback to execute when we have a confirmed success/failure

+    var idOut = 0, idIn = 0, currentMessage = "";

+    

+    return (pub = {

+        incoming: function(message, origin){

+            trace("incoming: " + message);

+            var indexOf = message.indexOf("_"), ack = message.substring(0, indexOf).split(",");

+            message = message.substring(indexOf + 1);

+            

+            if (ack[0] == idOut) {

+                trace("message delivered");

+                currentMessage = "";

+                if (callback) {

+                    callback(true);

+                    callback = null;

+                }

+            }

+            if (message.length > 0) {

+                trace("sending ack, and passing on " + message);

+                pub.down.outgoing(ack[1] + "," + idOut + "_" + currentMessage, origin);

+                if (idIn != ack[1]) {

+                    idIn = ack[1];

+                    pub.up.incoming(message, origin);

+                }

+            }

+            

+        },

+        outgoing: function(message, origin, fn){

+            currentMessage = message;

+            callback = fn;

+            pub.down.outgoing(idIn + "," + (++idOut) + "_" + message, origin);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug, undef, removeFromStack*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.QueueBehavior

+ * This is a behavior that enables queueing of messages. <br/>

+ * It will buffer incoming messages and dispach these as fast as the underlying transport allows.

+ * This will also fragment/defragment messages so that the outgoing message is never bigger than the

+ * set length.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration. Optional.

+ * @cfg {Number} maxLength The maximum length of each outgoing message. Set this to enable fragmentation.

+ */

+easyXDM.stack.QueueBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.QueueBehavior");

+    trace("constructor");

+    var pub, queue = [], waiting = true, incoming = "", destroying, maxLength = 0, lazy = false, doFragment = false;

+    

+    function dispatch(){

+        if (config.remove && queue.length === 0) {

+            trace("removing myself from the stack");

+            removeFromStack(pub);

+            return;

+        }

+        if (waiting || queue.length === 0 || destroying) {

+            return;

+        }

+        trace("dispatching from queue");

+        waiting = true;

+        var message = queue.shift();

+        

+        pub.down.outgoing(message.data, message.origin, function(success){

+            waiting = false;

+            if (message.callback) {

+                setTimeout(function(){

+                    message.callback(success);

+                }, 0);

+            }

+            dispatch();

+        });

+    }

+    return (pub = {

+        init: function(){

+            if (undef(config)) {

+                config = {};

+            }

+            if (config.maxLength) {

+                maxLength = config.maxLength;

+                doFragment = true;

+            }

+            if (config.lazy) {

+                lazy = true;

+            }

+            else {

+                pub.down.init();

+            }

+        },

+        callback: function(success){

+            waiting = false;

+            var up = pub.up; // in case dispatch calls removeFromStack

+            dispatch();

+            up.callback(success);

+        },

+        incoming: function(message, origin){

+            if (doFragment) {

+                var indexOf = message.indexOf("_"), seq = parseInt(message.substring(0, indexOf), 10);

+                incoming += message.substring(indexOf + 1);

+                if (seq === 0) {

+                    trace("received the last fragment");

+                    if (config.encode) {

+                        incoming = decodeURIComponent(incoming);

+                    }

+                    pub.up.incoming(incoming, origin);

+                    incoming = "";

+                }

+                else {

+                    trace("waiting for more fragments, seq=" + message);

+                }

+            }

+            else {

+                pub.up.incoming(message, origin);

+            }

+        },

+        outgoing: function(message, origin, fn){

+            if (config.encode) {

+                message = encodeURIComponent(message);

+            }

+            var fragments = [], fragment;

+            if (doFragment) {

+                // fragment into chunks

+                while (message.length !== 0) {

+                    fragment = message.substring(0, maxLength);

+                    message = message.substring(fragment.length);

+                    fragments.push(fragment);

+                }

+                // enqueue the chunks

+                while ((fragment = fragments.shift())) {

+                    trace("enqueuing");

+                    queue.push({

+                        data: fragments.length + "_" + fragment,

+                        origin: origin,

+                        callback: fragments.length === 0 ? fn : null

+                    });

+                }

+            }

+            else {

+                queue.push({

+                    data: message,

+                    origin: origin,

+                    callback: fn

+                });

+            }

+            if (lazy) {

+                pub.down.init();

+            }

+            else {

+                dispatch();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            destroying = true;

+            pub.down.destroy();

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.VerifyBehavior

+ * This behavior will verify that communication with the remote end is possible, and will also sign all outgoing,

+ * and verify all incoming messages. This removes the risk of someone hijacking the iframe to send malicious messages.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration.

+ * @cfg {Boolean} initiate If the verification should be initiated from this end.

+ */

+easyXDM.stack.VerifyBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.VerifyBehavior");

+    trace("constructor");

+    if (undef(config.initiate)) {

+        throw new Error("settings.initiate is not set");

+    }

+    var pub, mySecret, theirSecret, verified = false;

+    

+    function startVerification(){

+        trace("requesting verification");

+        mySecret = Math.random().toString(16).substring(2);

+        pub.down.outgoing(mySecret);

+    }

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var indexOf = message.indexOf("_");

+            if (indexOf === -1) {

+                if (message === mySecret) {

+                    trace("verified, calling callback");

+                    pub.up.callback(true);

+                }

+                else if (!theirSecret) {

+                    trace("returning secret");

+                    theirSecret = message;

+                    if (!config.initiate) {

+                        startVerification();

+                    }

+                    pub.down.outgoing(message);

+                }

+            }

+            else {

+                if (message.substring(0, indexOf) === theirSecret) {

+                    pub.up.incoming(message.substring(indexOf + 1), origin);

+                }

+            }

+        },

+        outgoing: function(message, origin, fn){

+            pub.down.outgoing(mySecret + "_" + message, origin, fn);

+        },

+        callback: function(success){

+            if (config.initiate) {

+                startVerification();

+            }

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, getJSON, debug, emptyFn, isArray */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// Permission is hereby granted, free of charge, to any person obtaining a copy

+// of this software and associated documentation files (the "Software"), to deal

+// in the Software without restriction, including without limitation the rights

+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+// copies of the Software, and to permit persons to whom the Software is

+// furnished to do so, subject to the following conditions:

+//

+// The above copyright notice and this permission notice shall be included in

+// all copies or substantial portions of the Software.

+//

+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+// THE SOFTWARE.

+//

+

+/**

+ * @class easyXDM.stack.RpcBehavior

+ * This uses JSON-RPC 2.0 to expose local methods and to invoke remote methods and have responses returned over the the string based transport stack.<br/>

+ * Exposed methods can return values synchronous, asyncronous, or bet set up to not return anything.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} proxy The object to apply the methods to.

+ * @param {Object} config The definition of the local and remote interface to implement.

+ * @cfg {Object} local The local interface to expose.

+ * @cfg {Object} remote The remote methods to expose through the proxy.

+ * @cfg {Object} serializer The serializer to use for serializing and deserializing the JSON. Should be compatible with the HTML5 JSON object. Optional, will default to JSON.

+ */

+easyXDM.stack.RpcBehavior = function(proxy, config){

+    var trace = debug.getTracer("easyXDM.stack.RpcBehavior");

+    var pub, serializer = config.serializer || getJSON();

+    var _callbackCounter = 0, _callbacks = {};

+    

+    /**

+     * Serializes and sends the message

+     * @private

+     * @param {Object} data The JSON-RPC message to be sent. The jsonrpc property will be added.

+     */

+    function _send(data){

+        data.jsonrpc = "2.0";

+        pub.down.outgoing(serializer.stringify(data));

+    }

+    

+    /**

+     * Creates a method that implements the given definition

+     * @private

+     * @param {Object} The method configuration

+     * @param {String} method The name of the method

+     * @return {Function} A stub capable of proxying the requested method call

+     */

+    function _createMethod(definition, method){

+        var slice = Array.prototype.slice;

+        

+        trace("creating method " + method);

+        return function(){

+            trace("executing method " + method);

+            var l = arguments.length, callback, message = {

+                method: method

+            };

+            

+            if (l > 0 && typeof arguments[l - 1] === "function") {

+                //with callback, procedure

+                if (l > 1 && typeof arguments[l - 2] === "function") {

+                    // two callbacks, success and error

+                    callback = {

+                        success: arguments[l - 2],

+                        error: arguments[l - 1]

+                    };

+                    message.params = slice.call(arguments, 0, l - 2);

+                }

+                else {

+                    // single callback, success

+                    callback = {

+                        success: arguments[l - 1]

+                    };

+                    message.params = slice.call(arguments, 0, l - 1);

+                }

+                _callbacks["" + (++_callbackCounter)] = callback;

+                message.id = _callbackCounter;

+            }

+            else {

+                // no callbacks, a notification

+                message.params = slice.call(arguments, 0);

+            }

+            if (definition.namedParams && message.params.length === 1) {

+                message.params = message.params[0];

+            }

+            // Send the method request

+            _send(message);

+        };

+    }

+    

+    /**

+     * Executes the exposed method

+     * @private

+     * @param {String} method The name of the method

+     * @param {Number} id The callback id to use

+     * @param {Function} method The exposed implementation

+     * @param {Array} params The parameters supplied by the remote end

+     */

+    function _executeMethod(method, id, fn, params){

+        if (!fn) {

+            trace("requested to execute non-existent procedure " + method);

+            if (id) {

+                _send({

+                    id: id,

+                    error: {

+                        code: -32601,

+                        message: "Procedure not found."

+                    }

+                });

+            }

+            return;

+        }

+        

+        trace("requested to execute procedure " + method);

+        var success, error;

+        if (id) {

+            success = function(result){

+                success = emptyFn;

+                _send({

+                    id: id,

+                    result: result

+                });

+            };

+            error = function(message, data){

+                error = emptyFn;

+                var msg = {

+                    id: id,

+                    error: {

+                        code: -32099,

+                        message: message

+                    }

+                };

+                if (data) {

+                    msg.error.data = data;

+                }

+                _send(msg);

+            };

+        }

+        else {

+            success = error = emptyFn;

+        }

+        // Call local method

+        if (!isArray(params)) {

+            params = [params];

+        }

+        try {

+            var result = fn.method.apply(fn.scope, params.concat([success, error]));

+            if (!undef(result)) {

+                success(result);

+            }

+        } 

+        catch (ex1) {

+            error(ex1.message);

+        }

+    }

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var data = serializer.parse(message);

+            if (data.method) {

+                trace("received request to execute method " + data.method + (data.id ? (" using callback id " + data.id) : ""));

+                // A method call from the remote end

+                if (config.handle) {

+                    config.handle(data, _send);

+                }

+                else {

+                    _executeMethod(data.method, data.id, config.local[data.method], data.params);

+                }

+            }

+            else {

+                trace("received return value destined to callback with id " + data.id);

+                // A method response from the other end

+                var callback = _callbacks[data.id];

+                if (data.error) {

+                    if (callback.error) {

+                        callback.error(data.error);

+                    }

+                    else {

+                        trace("unhandled error returned.");

+                    }

+                }

+                else if (callback.success) {

+                    callback.success(data.result);

+                }

+                delete _callbacks[data.id];

+            }

+        },

+        init: function(){

+            trace("init");

+            if (config.remote) {

+                trace("creating stubs");

+                // Implement the remote sides exposed methods

+                for (var method in config.remote) {

+                    if (config.remote.hasOwnProperty(method)) {

+                        proxy[method] = _createMethod(config.remote[method], method);

+                    }

+                }

+            }

+            pub.down.init();

+        },

+        destroy: function(){

+            trace("destroy");

+            for (var method in config.remote) {

+                if (config.remote.hasOwnProperty(method) && proxy.hasOwnProperty(method)) {

+                    delete proxy[method];

+                }

+            }

+            pub.down.destroy();

+        }

+    });

+};

+global.easyXDM = easyXDM;

+})(window, document, location, window.setTimeout, decodeURIComponent, encodeURIComponent);

diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/tests/index.html b/asterix-examples/src/main/resources/core/js/easyXDM/tests/index.html
new file mode 100644
index 0000000..0232da9
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/tests/index.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
+        <meta http-equiv="X-UA-Compatible" content="IE=100">
+        <title>easyTest results</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+            // The first instance of easyXDM
+        </script>
+        <script type="text/javascript">
+            easyXDM._test_global = true;
+        </script>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+            // The second instance of easyXDM (to test noConflict)
+        </script>
+        <script type="text/javascript">
+            // Used in the noConflict test
+            var modules = {
+                easyXDM: easyXDM.noConflict("modules")
+            };
+        </script>
+        <script type="text/javascript">
+            if (location.href.indexOf("src") !== -1) {
+                if (typeof JSON === "undefined") {
+                    document.write(unescape("%3Cscript src='../../tools/json2.js' type='text/javascript'%3E%3C/script%3E"));
+                }
+            }
+            else {
+                if (typeof JSON === "undefined") {
+                    document.write(unescape("%3Cscript src='../json2.js' type='text/javascript'%3E%3C/script%3E"));
+                }
+            }
+        </script>
+        <script type="text/javascript" src="easyTest.js">
+        </script>
+        <link type="text/css" rel="stylesheet" href="easyTest.css"/>
+        <script type="text/javascript" src="tests.js">
+        </script>
+        <style type="text/css">
+            
+            #embedded {
+                height: 100px;
+            }
+            
+            #embedded iframe {
+                height: 50px;
+            }
+            
+            #log {
+                height: 100px;
+                border: 1px dotted black;
+                overflow: auto
+            }
+            
+            .easyTest_messages {
+                height: 300px;
+                border: 1px dotted black;
+                overflow: auto;
+            }
+        </style>
+    </head>
+    <body onload="runTests();">
+        <h1>easyXDM test suite</h1>
+        <h4>easyTest messages</h4>
+        <div id="messages">
+        </div>
+        <h4>easyXDM tracelog</h4>
+        <!-- easyXDM.Debug.trace(msg) will output its messages to any element with the id "log" -->
+        <div id="log">
+        </div>
+        <div id="embedded">
+        </div>
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+                document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+            }
+        </script>
+        <script type="text/javascript">
+            if (location.host.indexOf("easyxdm.net") !== -1) {
+                try {
+                    var pageTracker = _gat._getTracker("UA-9535591-3");
+                    pageTracker._setDomainName(".easyxdm.net");
+                    pageTracker._trackPageview();
+                } 
+                catch (err) {
+                }
+            }
+        </script>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/tests/s.gif b/asterix-examples/src/main/resources/core/js/easyXDM/tests/s.gif
new file mode 100644
index 0000000..1d11fa9
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/tests/s.gif
Binary files differ
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/tests/test_namespace.html b/asterix-examples/src/main/resources/core/js/easyXDM/tests/test_namespace.html
new file mode 100644
index 0000000..63d7a3e
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/tests/test_namespace.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            var modules = {
+                easyXDM: easyXDM.noConflict("modules")
+            };
+            
+            var transport;
+            window.onload = function(){
+                transport = new modules.easyXDM.Socket({
+                    local: "../name.html",
+                    swf: "../easyxdm.swf",
+                    onMessage: function(message, origin){
+                        // Echo back the message
+                        transport.postMessage(message);
+                    }
+                });
+            };
+            window.onunload = function(){
+                if (transport) {
+                    transport.destroy();
+                }
+            };
+        </script>
+    </head>
+    <body>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/tests/test_rpc.html b/asterix-examples/src/main/resources/core/js/easyXDM/tests/test_rpc.html
new file mode 100644
index 0000000..11a489f
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/tests/test_rpc.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<html>
+    <head>
+        <title>easyXDM</title>
+        <script type="text/javascript" src="../easyXDM.debug.js">
+        </script>
+        <script type="text/javascript">
+            if (location.href.indexOf("src") !== -1) {
+                if (typeof JSON === "undefined") {
+                    document.write(unescape("%3Cscript src='../../tools/json2.js' type='text/javascript'%3E%3C/script%3E"));
+                }
+            }
+            else {
+                if (typeof JSON === "undefined") {
+                    document.write(unescape("%3Cscript src='../json2.js' type='text/javascript'%3E%3C/script%3E"));
+                }
+            }
+        </script>
+        <script type="text/javascript">
+            easyXDM.DomHelper.requiresJSON("../json2.js");
+        </script>
+        <script type="text/javascript">
+            var remote = new easyXDM.Rpc({
+                local: "../name.html",
+                swf: "../easyxdm.swf"
+            }, {
+                remote: {
+                    voidCallback: {}
+                },
+                local: {
+                    voidMethod: function(msg){
+                        // Echo back the message
+                        remote.voidCallback(msg);
+                    },
+                    asyncMethod: function(msg, fn){
+                        window.setTimeout(function(){
+                            // Echo back the msg
+                            fn(msg);
+                        }, 100);
+                    },
+                    // use the shorthand notation
+                    method: function(msg){
+                        // Echo back the msg
+                        return msg;
+                    },
+                    error: function(){
+                        var a, b = a.c;
+                    },
+                    namedParamsMethod: {
+                        method: function(params){
+                            return params.msg;
+                        }
+                    }
+                }
+            });
+            window.onunload = function(){
+                if (remote) {
+                    remote.destroy();
+                }
+            };
+        </script>
+    </head>
+    <body>
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/tests/test_transport.html b/asterix-examples/src/main/resources/core/js/easyXDM/tests/test_transport.html
new file mode 100644
index 0000000..eb405cf
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/tests/test_transport.html
@@ -0,0 +1,28 @@
+<!doctype html>

+<html>

+    <head>

+        <title>easyXDM</title>

+        <script type="text/javascript" src="../easyXDM.debug.js">

+        </script>

+        <script type="text/javascript">

+            var transport;

+            window.onload = function(){

+                transport = new easyXDM.Socket({

+                    local: "../name.html",

+                    swf: "../easyxdm.swf",

+                    onMessage: function(message, origin){

+                        // Echo back the message

+                        transport.postMessage(message);

+                    }

+                });

+            };

+            window.onunload = function(){

+                if (transport) {

+                    transport.destroy();

+                }

+            };

+        </script>

+    </head>

+    <body>

+    </body>

+</html>

diff --git a/asterix-examples/src/main/resources/core/js/easyXDM/tests/tests.js b/asterix-examples/src/main/resources/core/js/easyXDM/tests/tests.js
new file mode 100644
index 0000000..d0a940a
--- /dev/null
+++ b/asterix-examples/src/main/resources/core/js/easyXDM/tests/tests.js
@@ -0,0 +1,855 @@
+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
+/*global easyTest, easyXDM, window, modules*/
+var REMOTE = (function(){
+    var remote = location.href;
+    switch (location.host) {
+        case "provider.easyxdm.net":
+            location.href = remote.replace("provider", "consumer");
+            break;
+        case "easyxdm.net":
+            remote = remote.replace("easyxdm.net", "consumer.easyxdm.net");
+            break;
+        case "consumer.easyxdm.net":
+            remote = remote.replace("consumer", "provider");
+            break;
+        case "xdm1":
+            remote = remote.replace("xdm1", "xdm2");
+            break;
+    }
+    return remote.substring(0, remote.lastIndexOf("/"));
+}());
+
+var LOCAL = location.protocol + "//" + location.host + location.pathname.substring(0, location.pathname.lastIndexOf("/"));
+
+function runTests(){
+    var i = 0;
+    easyTest.test([/**Tests for the presence of namespaces and classes*/{
+        name: "Check that the library is complete",
+        steps: [{
+            name: "check for the presence of easyXDM",
+            run: function(){
+                if (this.Assert.isObject(easyXDM) && this.Assert.isString(easyXDM.version)) {
+                    this.log("found easyXDM, version=" + easyXDM.version);
+                    return true;
+                }
+                return false;
+            }
+        }, {
+            name: "check for the presence of easyXDM.DomHelper",
+            run: function(){
+                return this.Assert.isObject(easyXDM.DomHelper);
+            }
+        }, {
+            name: "check for the presence of easyXDM.Socket",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.Socket);
+            }
+        }, {
+            name: "check for the presence of easyXDM.Rpc",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.Rpc);
+            }
+        }, {
+            name: "check for the presence of easyXDM.stack",
+            run: function(){
+                return this.Assert.isObject(easyXDM.stack);
+            }
+        }, {
+            name: "check for the presence of easyXDM.stack.SameOriginTransport",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.stack.SameOriginTransport);
+            }
+        }, {
+            name: "check for the presence of easyXDM.stack.PostMessageTransport",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.stack.PostMessageTransport);
+            }
+        }, {
+            name: "check for the presence of easyXDM.stack.FlashTransport",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.stack.FlashTransport);
+            }
+        }, {
+            name: "check for the presence of easyXDM.stack.NameTransport",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.stack.NameTransport);
+            }
+        }, {
+            name: "check for the presence of easyXDM.stack.HashTransport",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.stack.HashTransport);
+            }
+        }, {
+            name: "check for the presence of easyXDM.stack.ReliableBehavior",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.stack.ReliableBehavior);
+            }
+        }, {
+            name: "check for the presence of easyXDM.stack.QueueBehavior",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.stack.QueueBehavior);
+            }
+        }, {
+            name: "check for the presence of easyXDM.stack.VerifyBehavior",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.stack.VerifyBehavior);
+            }
+        }, {
+            name: "check for the presence of easyXDM.stack.RpcBehavior",
+            run: function(){
+                return this.Assert.isFunction(easyXDM.stack.RpcBehavior);
+            }
+        }]
+    }, {
+        name: "Check helper functions",
+        runIf: function(){
+            if (location.href.indexOf("/src/") == -1) {
+                return "This can only be run in development.";
+            }
+        },
+        setUp: function(){
+            this.url1 = "http://foo.bar/a/b/c?d=e#f";
+            this.url2 = "http://foo.bar:80/a/b/c?d=e#f";
+            this.url3 = "http://foo.bar:88/a/b/c?d=e#f";
+            this.url4 = "hTtp://Foo.Bar:88/a/b/c?d=e#f";
+            
+        },
+        steps: [{
+            name: "getDomainName",
+            run: function(){
+                return easyXDM.getDomainName(this.url1) === "foo.bar";
+            }
+        }, {
+            name: "getLocation",
+            run: function(){
+                return easyXDM.getLocation(this.url1) === "http://foo.bar";
+            }
+        }, {
+            name: "getLocation with standard port",
+            run: function(){
+                return easyXDM.getLocation(this.url2) === "http://foo.bar";
+            }
+        }, {
+            name: "getLocation with non-standard port",
+            run: function(){
+                return easyXDM.getLocation(this.url3) === "http://foo.bar:88";
+            }
+        }, {
+            name: "getLocation with capitals",
+            run: function(){
+                return easyXDM.getLocation(this.url4) === "http://foo.bar:88";
+            }
+        }, {
+            name: "appendQueryParameters",
+            run: function(){
+                return easyXDM.appendQueryParameters(this.url2, {
+                    g: "h"
+                }) ===
+                "http://foo.bar:80/a/b/c?d=e&g=h#f";
+            }
+        }]
+    }, {
+        name: "Check the ACL feature",
+        runIf: function(){
+            if (location.href.indexOf("/src/") == -1) {
+                return "This can only be run in development.";
+            }
+        },
+        setUp: function(){
+            this.acl = ["http://www.domain.invalid", "*.domaina.com", "http://dom?inb.com", "^http://domc{3}ain\\.com$"];
+        },
+        steps: [{
+            name: "Match complete string",
+            run: function(){
+                return easyXDM.checkAcl(this.acl, "http://www.domain.invalid");
+            }
+        }, {
+            name: "Match *",
+            run: function(){
+                return easyXDM.checkAcl(this.acl, "http://www.domaina.com");
+            }
+        }, {
+            name: "Match ?",
+            run: function(){
+                return easyXDM.checkAcl(this.acl, "http://domainb.com");
+            }
+        }, {
+            name: "Match RegExp",
+            run: function(){
+                return easyXDM.checkAcl(this.acl, "http://domcccain.com");
+            }
+        }, {
+            name: "No match",
+            run: function(){
+                return !easyXDM.checkAcl(this.acl, "http://foo.com");
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{SameOriginTransport}",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                var messages = 0;
+                this.transport = new easyXDM.Socket({
+                    protocol: "4",
+                    remote: LOCAL + "/test_transport.html",
+                    onMessage: function(message, origin){
+                        if (scope.expectedMessage === message) {
+                            if (++messages === 2) {
+                                scope.notifyResult(true);
+                            }
+                        }
+                    },
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }, {
+            name: "destroy",
+            run: function(){
+                this.transport.destroy();
+                return ((document.getElementsByTagName("iframe").length === 0));
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{PostMessageTransport}",
+        runIf: function(){
+            if (!("postMessage" in window || "postMessage" in document)) {
+                return "This test requires the HTML5 postMessage interface.";
+            }
+        },
+        
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                var messages = 0;
+                this.transport = new easyXDM.Socket({
+                    protocol: "1",
+                    local: "../name.html",
+                    remote: REMOTE + "/test_transport.html",
+                    onMessage: function(message, origin){
+                        if (scope.expectedMessage === message) {
+                            if (++messages === 2) {
+                                scope.notifyResult(true);
+                            }
+                        }
+                    },
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }, {
+            name: "destroy",
+            run: function(){
+                this.transport.destroy();
+                return ((document.getElementsByTagName("iframe").length === 0));
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{FlashTransport}",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                var messages = 0;
+                this.transport = new easyXDM.Socket({
+                    protocol: "6",
+                    remote: REMOTE + "/test_transport.html",
+                    swf: REMOTE + "/../easyxdm.swf",
+                    onMessage: function(message, origin){
+                        if (scope.expectedMessage === message) {
+                            if (++messages === 2) {
+                                scope.notifyResult(true);
+                            }
+                        }
+                    },
+                    container: "embedded",
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }, {
+            name: "destroy",
+            run: function(){
+                this.transport.destroy();
+                return ((document.getElementsByTagName("iframe").length === 0));
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{FrameElementTransport}",
+        runIf: function(){
+            if (!(navigator.product === "Gecko" && "frameElement" in window && !("postMessage" in window) && navigator.userAgent.indexOf('WebKit') == -1)) {
+                return "This test requires an older Gecko browser and the presence of the frameElement object";
+            }
+        },
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                var messages = 0;
+                this.transport = new easyXDM.Socket({
+                    protocol: "5",
+                    remote: REMOTE + "/test_transport.html",
+                    onMessage: function(message, origin){
+                        if (scope.expectedMessage === message) {
+                            if (++messages === 2) {
+                                scope.notifyResult(true);
+                            }
+                        }
+                    },
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }, {
+            name: "destroy",
+            run: function(){
+                this.transport.destroy();
+                return ((document.getElementsByTagName("iframe").length === 0));
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{NameTransport}",
+        failedMessage: "This might fail in modern browsers due to restrictions in referencing existing windows",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        tearDown: function(){
+            this.transport.destroy();
+            if (document.getElementsByTagName("iframe").length !== 0) {
+                throw new Error("iframe still present");
+            }
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                var messages = 0;
+                this.transport = new easyXDM.Socket({
+                    protocol: "2", // This is just to override the automatic selection
+                    local: "../name.html",
+                    remote: REMOTE + "/test_transport.html",
+                    remoteHelper: REMOTE + "/../name.html",
+                    onMessage: function(message, origin){
+                        if (scope.expectedMessage === message) {
+                            if (++messages === 2) {
+                                scope.notifyResult(true);
+                            }
+                        }
+                    },
+                    container: document.getElementById("embedded"),
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{HashTransport} using window",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        tearDown: function(){
+            this.transport.destroy();
+            if (document.getElementsByTagName("iframe").length !== 0) {
+                throw new Error("iframe still present");
+            }
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                var messages = 0;
+                this.transport = new easyXDM.Socket({
+                    protocol: "0", // This is just to override the automatic selection
+                    local: window,
+                    remote: REMOTE + "/test_transport.html",
+                    onMessage: function(message, origin){
+                        if (scope.expectedMessage === message) {
+                            if (++messages === 2) {
+                                scope.notifyResult(true);
+                            }
+                        }
+                    },
+                    container: document.getElementById("embedded"),
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{HashTransport} with no blank local, available image and resize",
+        failedMessage: "This might fail in modern browsers due to restrictions in referencing existing windows",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+            this.img = document.createElement("img");
+            this.img.src = "s.gif";
+            document.body.appendChild(this.img);
+        },
+        tearDown: function(){
+            document.body.removeChild(this.img);
+            this.transport.destroy();
+            if (document.getElementsByTagName("iframe").length !== 0) {
+                throw new Error("iframe still present");
+            }
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                var messages = 0;
+                this.transport = new easyXDM.Socket({
+                    protocol: "0", // This is just to override the automatic selection
+                    remote: REMOTE + "/test_transport.html",
+                    onMessage: function(message, origin){
+                        if (++messages === 2) {
+                            scope.notifyResult(true);
+                        }
+                    },
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{HashTransport} with s.gif and polling",
+        failedMessage: "This might fail in modern browsers due to restrictions in referencing existing windows",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        tearDown: function(){
+            this.transport.destroy();
+            if (document.getElementsByTagName("iframe").length !== 0) {
+                throw new Error("iframe still present");
+            }
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                var messages = 0;
+                this.transport = new easyXDM.Socket({
+                    protocol: "0", // This is just to override the automatic selection
+                    local: "s.gif",
+                    remote: REMOTE + "/test_transport.html",
+                    onMessage: function(message, origin){
+                        if (++messages === 2) {
+                            scope.notifyResult(true);
+                        }
+                    },
+                    container: document.getElementById("embedded"),
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{HashTransport} with fragmentation (8192)",
+        failedMessage: "This might fail in modern browsers due to restrictions in referencing existing windows",
+        setUp: function(){
+            var i = 11;
+            this.expectedMessage = "aaaa";
+            while (i--) {
+                this.expectedMessage += this.expectedMessage;
+            }
+        },
+        tearDown: function(){
+            this.transport.destroy();
+            if (document.getElementsByTagName("iframe").length !== 0) {
+                throw new Error("iframe still present");
+            }
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.transport = new easyXDM.Socket({
+                    protocol: "0", // This is just to override the automatic selection
+                    local: "../name.html",
+                    remote: REMOTE + "/test_transport.html",
+                    onMessage: function(message, origin){
+                        scope.notifyResult(scope.expectedMessage === message);
+                    },
+                    container: document.getElementById("embedded"),
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }]
+    }, {
+        name: "test easyXDM.noConflict {SameOriginTransport}",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        steps: [{
+            name: "window.easyXDM is released {namespace}",
+            timeout: 5000,
+            run: function(){
+                this.notifyResult(window.easyXDM._test_global && !modules.easyXDM._test_global);
+            }
+        }, {
+            name: "onReady is fired {namespace}",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                var messages = 0;
+                this.transport = new modules.easyXDM.Socket({
+                    protocol: "4",
+                    remote: LOCAL + "/test_namespace.html",
+                    onMessage: function(message, origin){
+                        if (scope.expectedMessage === message) {
+                            if (++messages === 2) {
+                                scope.notifyResult(true);
+                            }
+                        }
+                    },
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back {namespace}",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }, {
+            name: "destroy {namespace}",
+            run: function(){
+                this.transport.destroy();
+                return ((document.getElementsByTagName("iframe").length === 0));
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{}",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        tearDown: function(){
+            this.transport.destroy();
+            if (document.getElementsByTagName("iframe").length !== 0) {
+                throw new Error("iframe still present");
+            }
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.transport = new easyXDM.Socket({
+                    local: "../name.html",
+                    swf: REMOTE + "/../easyxdm.swf",
+                    remote: REMOTE + "/test_transport.html",
+                    onMessage: function(message, origin){
+                        scope.notifyResult((scope.expectedMessage === message));
+                    },
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{} using hash for passing data",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        tearDown: function(){
+            this.transport.destroy();
+            if (document.getElementsByTagName("iframe").length !== 0) {
+                throw new Error("iframe still present");
+            }
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.transport = new easyXDM.Socket({
+                    local: "../name.html",
+                    swf: REMOTE + "/../easyxdm.swf",
+                    remote: REMOTE + "/test_transport.html?foo=bar",
+                    hash: true,
+                    onMessage: function(message, origin){
+                        scope.notifyResult((scope.expectedMessage === message));
+                    },
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{} with buffering",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        tearDown: function(){
+            this.transport.destroy();
+            if (document.getElementsByTagName("iframe").length !== 0) {
+                throw new Error("iframe still present");
+            }
+        },
+        steps: [{
+            name: "Buffered messages are sent",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.transport = new easyXDM.Socket({
+                    local: "../name.html",
+                    swf: REMOTE + "/../easyxdm.swf",
+                    remote: REMOTE + "/test_transport.html",
+                    onMessage: function(message, origin){
+                        scope.notifyResult((scope.expectedMessage === message));
+                    }
+                });
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }]
+    }, {
+        name: "test easyXDM.Socket{} with query parameters",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        tearDown: function(){
+            this.transport.destroy();
+            if (document.getElementsByTagName("iframe").length !== 0) {
+                throw new Error("iframe still present");
+            }
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.transport = new easyXDM.Socket({
+                    local: "../name.html",
+                    swf: REMOTE + "/../easyxdm.swf",
+                    remote: REMOTE + "/test_transport.html?a=b&c=d#foo,faa",
+                    onMessage: function(message, origin){
+                        scope.notifyResult((scope.expectedMessage === message));
+                    },
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                });
+            }
+        }, {
+            name: "message is echoed back",
+            timeout: 5000,
+            run: function(){
+                this.transport.postMessage(this.expectedMessage);
+            }
+        }]
+    }, {
+        name: "test easyXDM.Rpc",
+        setUp: function(){
+            this.expectedMessage = ++i + "_abcd1234%@¤/";
+        },
+        tearDown: function(){
+            this.remote.destroy();
+            if (document.getElementsByTagName("iframe").length !== 0) {
+                throw new Error("iframe still present");
+            }
+        },
+        steps: [{
+            name: "onReady is fired",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.remote = new easyXDM.Rpc({
+                    local: "../name.html",
+                    swf: REMOTE + "/../easyxdm.swf",
+                    remote: REMOTE + "/test_rpc.html",
+                    remoteHelper: REMOTE + "/../name.html",
+                    container: document.getElementById("embedded"),
+                    onReady: function(){
+                        scope.notifyResult(true);
+                    }
+                }, {
+                    remote: {
+                        voidMethod: {},
+                        asyncMethod: {},
+                        method: {},
+                        error: {},
+                        nonexistent: {},
+                        namedParamsMethod: {
+                            namedParams: true
+                        }
+                    },
+                    local: {
+                        voidCallback: {
+                            method: function(message){
+                                scope.notifyResult((scope.expectedMessage === message));
+                            }
+                        }
+                    }
+                });
+            }
+        }, {
+            name: "void method",
+            timeout: 5000,
+            run: function(){
+                this.remote.voidMethod(this.expectedMessage);
+            }
+        }, {
+            name: "async method",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.remote.asyncMethod(this.expectedMessage, function(message){
+                    scope.notifyResult((scope.expectedMessage === message));
+                });
+            }
+        }, {
+            name: "regular method",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.remote.method(this.expectedMessage, function(message){
+                    scope.notifyResult((scope.expectedMessage === message));
+                });
+            }
+        }, {
+            name: "with error",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.remote.error(this.expectedMessage, function(){
+                    this.notifyResult(false, "success handler called");
+                }, function(message){
+                    scope.notifyResult(true);
+                });
+            }
+        }, {
+            name: "calling nonexistent method",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.remote.nonexistent(this.expectedMessage, function(){
+                    this.notifyResult(false, "success handler called");
+                }, function(message){
+                    scope.notifyResult(true);
+                });
+            }
+        }, {
+            name: "using named parameters",
+            timeout: 5000,
+            run: function(){
+                var scope = this;
+                this.remote.namedParamsMethod({
+                    msg: this.expectedMessage
+                }, function(message){
+                    scope.notifyResult((scope.expectedMessage === message));
+                });
+            }
+        }]
+    }]);
+}
diff --git a/asterix-examples/src/main/resources/html/example.html b/asterix-examples/src/main/resources/html/example.html
new file mode 100644
index 0000000..f0373ff
--- /dev/null
+++ b/asterix-examples/src/main/resources/html/example.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
+        <script src="../js/easyXDM/easyXDM.debug.js" type="text/javascript"></script>
+        <script src="http://localhost:19101/sdk/static/js/asterix-api-core.js" type="text/javascript"></script>
+        <script src="../js/example.js" type="text/javascript"></script> 
+        <script>
+            $(function () {
+                var as = new AsterixSDK();
+                var c = new CreateExpression(tinySocialCreate.join("\n"));
+                as.send(c);
+
+                var as = new AsterixSDK();
+
+                $('#ddl').html(tinySocialCreate.join("<br/>"));
+            });
+        </script>
+    </head>
+    <body>
+        <div>
+            Example: DDL
+            <div class="syntax-box" id="ddl">
+                Query:
+            </div>
+            <button>Run</button>
+            <hr>
+        </div>
+
+        <div>
+            Example: 
+            <div class="syntax-box">
+                Query:
+            </div>
+            <button>Run</button>
+            <hr>
+        </div>
+
+        <div>
+            Example: 
+            <div class="syntax-box">
+                Query:
+            </div>
+            <button>Run</button>
+            <hr>
+        </div>
+        
+        <div>
+            Example: 
+            <div class="syntax-box">
+                Query:
+            </div>
+            <button>Run</button>
+            <hr>
+        </div>
+
+    </body>
+</html>
diff --git a/asterix-examples/src/main/resources/js/example.js b/asterix-examples/src/main/resources/js/example.js
new file mode 100644
index 0000000..cf5d02b
--- /dev/null
+++ b/asterix-examples/src/main/resources/js/example.js
@@ -0,0 +1,39 @@
+var tinySocialCreate = ["drop dataverse TinySocial if exists;",
+"create dataverse TinySocial;",
+"use dataverse TinySocial;",
+"create type TwitterUserType as open {",
+"screen-name: string,",
+"lang: string,",
+"friends_count: int32,",
+"statuses_count: int32,",
+"name: string,",
+"followers_count: int32",
+"}",
+"create type TweetMessageType as closed {",
+"tweetid: string,",
+"user: TwitterUserType,",
+"sender-location: point?,",
+"send-time: datetime,",
+"referred-topics: {{ string }},",
+"message-text: string",
+"}",
+"create type EmploymentType as open {",
+"organization-name: string,",
+"start-date: date,",
+"end-date: date?",
+"}",
+"create type FacebookUserType as closed {",
+"id: int32,",
+"alias: string,",
+"name: string,",
+"user-since: datetime,",
+"friend-ids: {{ int32 }},",
+"employment: [EmploymentType]",
+"}",
+"create type FacebookMessageType as closed {",
+"message-id: int32,",
+"author-id: int32,",
+"in-response-to: int32?,",
+"sender-location: point?,",
+"message: string",
+"}"];
diff --git a/asterix-examples/src/main/resources/js/jquery.min.js b/asterix-examples/src/main/resources/js/jquery.min.js
new file mode 100644
index 0000000..b18e05a
--- /dev/null
+++ b/asterix-examples/src/main/resources/js/jquery.min.js
@@ -0,0 +1,6 @@
+/*! jQuery v2.0.0 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
+//@ sourceMappingURL=jquery.min.map
+*/
+(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],f="2.0.0",p=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=f.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return p.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,f,p,h,d,g,m,y="sizzle"+-new Date,v=e.document,b={},w=0,T=0,C=ot(),k=ot(),N=ot(),E=!1,S=function(){return 0},j=typeof undefined,D=1<<31,A=[],L=A.pop,q=A.push,H=A.push,O=A.slice,F=A.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},P="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",R="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=M.replace("w","w#"),$="\\["+R+"*("+M+")"+R+"*(?:([*^$|!~]?=)"+R+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+R+"*\\]",B=":("+M+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",I=RegExp("^"+R+"+|((?:^|[^\\\\])(?:\\\\.)*)"+R+"+$","g"),z=RegExp("^"+R+"*,"+R+"*"),_=RegExp("^"+R+"*([>+~]|"+R+")"+R+"*"),X=RegExp(R+"*[+~]"),U=RegExp("="+R+"*([^\\]'\"]*)"+R+"*\\]","g"),Y=RegExp(B),V=RegExp("^"+W+"$"),G={ID:RegExp("^#("+M+")"),CLASS:RegExp("^\\.("+M+")"),TAG:RegExp("^("+M.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+B),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),"boolean":RegExp("^(?:"+P+")$","i"),needsContext:RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},J=/^[^{]+\{\s*\[native \w/,Q=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,et=/'|\\/g,tt=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,nt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{H.apply(A=O.call(v.childNodes),v.childNodes),A[v.childNodes.length].nodeType}catch(rt){H={apply:A.length?function(e,t){q.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function it(e){return J.test(e+"")}function ot(){var e,t=[];return e=function(n,i){return t.push(n+=" ")>r.cacheLength&&delete e[t.shift()],e[n]=i}}function st(e){return e[y]=!0,e}function at(e){var t=c.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ut(e,t,n,r){var i,o,s,a,u,f,d,g,x,w;if((t?t.ownerDocument||t:v)!==c&&l(t),t=t||c,n=n||[],!e||"string"!=typeof e)return n;if(1!==(a=t.nodeType)&&9!==a)return[];if(p&&!r){if(i=Q.exec(e))if(s=i[1]){if(9===a){if(o=t.getElementById(s),!o||!o.parentNode)return n;if(o.id===s)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(s))&&m(t,o)&&o.id===s)return n.push(o),n}else{if(i[2])return H.apply(n,t.getElementsByTagName(e)),n;if((s=i[3])&&b.getElementsByClassName&&t.getElementsByClassName)return H.apply(n,t.getElementsByClassName(s)),n}if(b.qsa&&(!h||!h.test(e))){if(g=d=y,x=t,w=9===a&&e,1===a&&"object"!==t.nodeName.toLowerCase()){f=gt(e),(d=t.getAttribute("id"))?g=d.replace(et,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=f.length;while(u--)f[u]=g+mt(f[u]);x=X.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return H.apply(n,x.querySelectorAll(w)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(I,"$1"),t,n,r)}o=ut.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},l=ut.setDocument=function(e){var t=e?e.ownerDocument||e:v;return t!==c&&9===t.nodeType&&t.documentElement?(c=t,f=t.documentElement,p=!o(t),b.getElementsByTagName=at(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),b.attributes=at(function(e){return e.className="i",!e.getAttribute("className")}),b.getElementsByClassName=at(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),b.sortDetached=at(function(e){return 1&e.compareDocumentPosition(c.createElement("div"))}),b.getById=at(function(e){return f.appendChild(e).id=y,!t.getElementsByName||!t.getElementsByName(y).length}),b.getById?(r.find.ID=function(e,t){if(typeof t.getElementById!==j&&p){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},r.filter.ID=function(e){var t=e.replace(tt,nt);return function(e){return e.getAttribute("id")===t}}):(r.find.ID=function(e,t){if(typeof t.getElementById!==j&&p){var n=t.getElementById(e);return n?n.id===e||typeof n.getAttributeNode!==j&&n.getAttributeNode("id").value===e?[n]:undefined:[]}},r.filter.ID=function(e){var t=e.replace(tt,nt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),r.find.TAG=b.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=b.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&p?t.getElementsByClassName(e):undefined},d=[],h=[],(b.qsa=it(t.querySelectorAll))&&(at(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||h.push("\\["+R+"*(?:value|"+P+")"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){var t=c.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&h.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(b.matchesSelector=it(g=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){b.disconnectedMatch=g.call(e,"div"),g.call(e,"[s!='']:x"),d.push("!=",B)}),h=h.length&&RegExp(h.join("|")),d=d.length&&RegExp(d.join("|")),m=it(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},S=f.compareDocumentPosition?function(e,n){if(e===n)return E=!0,0;var r=n.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(n);return r?1&r||!b.sortDetached&&n.compareDocumentPosition(e)===r?e===t||m(v,e)?-1:n===t||m(v,n)?1:u?F.call(u,e)-F.call(u,n):0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],l=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:u?F.call(u,e)-F.call(u,n):0;if(o===s)return lt(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)l.unshift(r);while(a[i]===l[i])i++;return i?lt(a[i],l[i]):a[i]===v?-1:l[i]===v?1:0},c):c},ut.matches=function(e,t){return ut(e,null,null,t)},ut.matchesSelector=function(e,t){if((e.ownerDocument||e)!==c&&l(e),t=t.replace(U,"='$1']"),!(!b.matchesSelector||!p||d&&d.test(t)||h&&h.test(t)))try{var n=g.call(e,t);if(n||b.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return ut(t,c,null,[e]).length>0},ut.contains=function(e,t){return(e.ownerDocument||e)!==c&&l(e),m(e,t)},ut.attr=function(e,t){(e.ownerDocument||e)!==c&&l(e);var n=r.attrHandle[t.toLowerCase()],i=n&&n(e,t,!p);return i===undefined?b.attributes||!p?e.getAttribute(t):(i=e.getAttributeNode(t))&&i.specified?i.value:null:i},ut.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ut.uniqueSort=function(e){var t,n=[],r=0,i=0;if(E=!b.detectDuplicates,u=!b.sortStable&&e.slice(0),e.sort(S),E){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return e};function lt(e,t){var n=t&&e,r=n&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ct(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}function ft(e,t,n){var r;return n?undefined:r=e.getAttribute(t,"type"===t.toLowerCase()?1:2)}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ht(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function dt(e){return st(function(t){return t=+t,st(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}i=ut.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else for(;t=e[r];r++)n+=i(t);return n},r=ut.selectors={cacheLength:50,createPseudo:st,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(tt,nt),e[3]=(e[4]||e[5]||"").replace(tt,nt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ut.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ut.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return G.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&Y.test(n)&&(t=gt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(tt,nt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ut.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,v=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){f=t;while(f=f[g])if(a?f.nodeName.toLowerCase()===v:1===f.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[y]||(m[y]={}),l=c[e]||[],h=l[0]===w&&l[1],p=l[0]===w&&l[2],f=h&&m.childNodes[h];while(f=++h&&f&&f[g]||(p=h=0)||d.pop())if(1===f.nodeType&&++p&&f===t){c[e]=[w,h,p];break}}else if(x&&(l=(t[y]||(t[y]={}))[e])&&l[0]===w)p=l[1];else while(f=++h&&f&&f[g]||(p=h=0)||d.pop())if((a?f.nodeName.toLowerCase()===v:1===f.nodeType)&&++p&&(x&&((f[y]||(f[y]={}))[e]=[w,p]),f===t))break;return p-=i,p===r||0===p%r&&p/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||ut.error("unsupported pseudo: "+e);return i[y]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?st(function(e,n){var r,o=i(e,t),s=o.length;while(s--)r=F.call(e,o[s]),e[r]=!(n[r]=o[s])}):function(e){return i(e,0,n)}):i}},pseudos:{not:st(function(e){var t=[],n=[],r=s(e.replace(I,"$1"));return r[y]?st(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:st(function(e){return function(t){return ut(e,t).length>0}}),contains:st(function(e){return function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:st(function(e){return V.test(e||"")||ut.error("unsupported lang: "+e),e=e.replace(tt,nt).toLowerCase(),function(t){var n;do if(n=p?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===c.activeElement&&(!c.hasFocus||c.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Z.test(e.nodeName)},input:function(e){return K.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:dt(function(){return[0]}),last:dt(function(e,t){return[t-1]}),eq:dt(function(e,t,n){return[0>n?n+t:n]}),even:dt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:dt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:dt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:dt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})r.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})r.pseudos[t]=ht(t);function gt(e,t){var n,i,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=r.preFilter;while(a){(!n||(i=z.exec(a)))&&(i&&(a=a.slice(i[0].length)||a),u.push(o=[])),n=!1,(i=_.exec(a))&&(n=i.shift(),o.push({value:n,type:i[0].replace(I," ")}),a=a.slice(n.length));for(s in r.filter)!(i=G[s].exec(a))||l[s]&&!(i=l[s](i))||(n=i.shift(),o.push({value:n,type:s,matches:i}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ut.error(e):k(e,u).slice(0)}function mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(e,t,r){var i=t.dir,o=r&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,r,a){var u,l,c,f=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,r,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[y]||(t[y]={}),(l=c[i])&&l[0]===f){if((u=l[1])===!0||u===n)return u===!0}else if(l=c[i]=[f],l[1]=e(t,r,a)||n,l[1]===!0)return!0}}function vt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function bt(e,t,n,r,i,o){return r&&!r[y]&&(r=bt(r)),i&&!i[y]&&(i=bt(i,o)),st(function(o,s,a,u){var l,c,f,p=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,p,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(f=l[c])&&(y[h[c]]=!(m[h[c]]=f))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(f=y[c])&&l.push(m[c]=f);i(null,y=[],l,u)}c=y.length;while(c--)(f=y[c])&&(l=i?F.call(o,f):p[c])>-1&&(o[l]=!(s[l]=f))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):H.apply(s,y)})}function wt(e){var t,n,i,o=e.length,s=r.relative[e[0].type],u=s||r.relative[" "],l=s?1:0,c=yt(function(e){return e===t},u,!0),f=yt(function(e){return F.call(t,e)>-1},u,!0),p=[function(e,n,r){return!s&&(r||n!==a)||((t=n).nodeType?c(e,n,r):f(e,n,r))}];for(;o>l;l++)if(n=r.relative[e[l].type])p=[yt(vt(p),n)];else{if(n=r.filter[e[l].type].apply(null,e[l].matches),n[y]){for(i=++l;o>i;i++)if(r.relative[e[i].type])break;return bt(l>1&&vt(p),l>1&&mt(e.slice(0,l-1)).replace(I,"$1"),n,i>l&&wt(e.slice(l,i)),o>i&&wt(e=e.slice(i)),o>i&&mt(e))}p.push(n)}return vt(p)}function Tt(e,t){var i=0,o=t.length>0,s=e.length>0,u=function(u,l,f,p,h){var d,g,m,y=[],v=0,x="0",b=u&&[],T=null!=h,C=a,k=u||s&&r.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(a=l!==c&&l,n=i);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,f)){p.push(d);break}T&&(w=N,n=++i)}o&&((d=!m&&d)&&v--,u&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,f);if(u){if(v>0)while(x--)b[x]||y[x]||(y[x]=L.call(p));y=xt(y)}H.apply(p,y),T&&!u&&y.length>0&&v+t.length>1&&ut.uniqueSort(p)}return T&&(w=N,a=C),b};return o?st(u):u}s=ut.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[y]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ut(e,t[r],n);return n}function kt(e,t,n,i){var o,a,u,l,c,f=gt(e);if(!i&&1===f.length){if(a=f[0]=f[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&p&&r.relative[a[1].type]){if(t=(r.find.ID(u.matches[0].replace(tt,nt),t)||[])[0],!t)return n;e=e.slice(a.shift().value.length)}o=G.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],r.relative[l=u.type])break;if((c=r.find[l])&&(i=c(u.matches[0].replace(tt,nt),X.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=i.length&&mt(a),!e)return H.apply(n,i),n;break}}}return s(e,f)(i,t,!p,n,X.test(e)),n}r.pseudos.nth=r.pseudos.eq;function Nt(){}Nt.prototype=r.filters=r.pseudos,r.setFilters=new Nt,b.sortStable=y.split("").sort(S).join("")===y,l(),[0,0].sort(S),b.detectDuplicates=E,at(function(e){if(e.innerHTML="<a href='#'></a>","#"!==e.firstChild.getAttribute("href")){var t="type|href|height|width".split("|"),n=t.length;while(n--)r.attrHandle[t[n]]=ft}}),at(function(e){if(null!=e.getAttribute("disabled")){var t=P.split("|"),n=t.length;while(n--)r.attrHandle[t[n]]=ct}}),x.find=ut,x.expr=ut.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ut.uniqueSort,x.text=ut.getText,x.isXMLDoc=ut.isXML,x.contains=ut.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(f){for(t=e.memory&&f,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(f[0],f[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!a||n&&!u||(r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,q,H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))this.cache[i]=t;else for(r in t)o[r]=t[r]},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){return t===undefined||t&&"string"==typeof t&&n===undefined?this.get(e,t):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i=this.key(e),o=this.cache[i];if(t===undefined)this.cache[i]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):t in o?r=[t]:(r=x.camelCase(t),r=r in o?[r]:r.match(w)||[]),n=r.length;while(n--)delete o[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){delete this.cache[this.key(e)]}},L=new F,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return q.access(e,t,n)},_removeData:function(e,t){q.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!q.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.substring(5)),P(i,r,s[r]));q.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:H.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=q.get(e,t),n&&(!r||x.isArray(n)?r=q.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);
+x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,i="boolean"==typeof t;return x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,s=0,a=x(this),u=t,l=e.match(w)||[];while(o=l[s++])u=i?u:!a.hasClass(o),a[u?"addClass":"removeClass"](o)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i,o=x(this);1===this.nodeType&&(i=r?e.call(this,n,o.val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.boolean.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.boolean.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.boolean.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,f,p,h,d,g,m,y=q.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(p=x.event.special[d]||{},d=(o?p.delegateType:p.bindType)||d,p=x.event.special[d]||{},f=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,p.setup&&p.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),p.add&&(p.add.call(e,f),f.handler.guid||(f.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,f):h.push(f),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,f,p,h,d,g,m=q.hasData(e)&&q.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){f=x.event.special[h]||{},h=(r?f.delegateType:f.bindType)||h,p=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));s&&!p.length&&(f.teardown&&f.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,f,p,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),p=x.event.special[d]||{},i||!p.trigger||p.trigger.apply(r,n)!==!1)){if(!i&&!p.noBubble&&!x.isWindow(r)){for(l=p.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:p.bindType||d,f=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),f&&f.apply(a,n),f=c&&a[c],f&&x.acceptData(a)&&f.apply&&f.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||p._default&&p._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(q.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return 3===e.target.nodeType&&(e.target=e.target.parentNode),s.filter?s.filter(e,o):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=x.expr.match.needsContext,Q={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return t=this,this.pushStack(x(e).filter(function(){for(r=0;i>r;r++)if(x.contains(t[r],this))return!0}));for(n=[],r=0;i>r;r++)x.find(e,this[r],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(Z(this,e||[],!0))},filter:function(e){return this.pushStack(Z(this,e||[],!1))},is:function(e){return!!e&&("string"==typeof e?J.test(e)?x(e,this.context).index(this[0])>=0:x.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],s=J.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function K(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return K(e,"nextSibling")},prev:function(e){return K(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(Q[e]||x.unique(i),"p"===e[0]&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function Z(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var et=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,tt=/<([\w:]+)/,nt=/<|&#?\w+;/,rt=/<(?:script|style|link)/i,it=/^(?:checkbox|radio)$/i,ot=/checked\s*(?:[^=]|=\s*.checked.)/i,st=/^$|\/(?:java|ecma)script/i,at=/^true\/(.*)/,ut=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,lt={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};lt.optgroup=lt.option,lt.tbody=lt.tfoot=lt.colgroup=lt.caption=lt.col=lt.thead,lt.th=lt.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=ct(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=ct(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(gt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&ht(gt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(gt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!rt.test(e)&&!lt[(tt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(et,"<$1></$2>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(gt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=p.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,f=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&ot.test(d))return this.each(function(r){var i=f.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(gt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,gt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,pt),l=0;s>l;l++)a=o[l],st.test(a.type||"")&&!q.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(ut,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=gt(a),o=gt(e),r=0,i=o.length;i>r;r++)mt(o[r],s[r]);if(t)if(n)for(o=o||gt(e),s=s||gt(a),r=0,i=o.length;i>r;r++)dt(o[r],s[r]);else dt(e,a);return s=gt(a,"script"),s.length>0&&ht(s,!u&&gt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,f=e.length,p=t.createDocumentFragment(),h=[];for(;f>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(nt.test(i)){o=o||p.appendChild(t.createElement("div")),s=(tt.exec(i)||["",""])[1].toLowerCase(),a=lt[s]||lt._default,o.innerHTML=a[1]+i.replace(et,"<$1></$2>")+a[2],l=a[0];while(l--)o=o.firstChild;x.merge(h,o.childNodes),o=p.firstChild,o.textContent=""}else h.push(t.createTextNode(i));p.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=gt(p.appendChild(i),"script"),u&&ht(o),n)){l=0;while(i=o[l++])st.test(i.type||"")&&n.push(i)}return p},cleanData:function(e){var t,n,r,i=e.length,o=0,s=x.event.special;for(;i>o;o++){if(n=e[o],x.acceptData(n)&&(t=q.access(n)))for(r in t.events)s[r]?x.event.remove(n,r):x.removeEvent(n,r,t.handle);L.discard(n),q.discard(n)}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"text",async:!1,global:!1,success:x.globalEval})}});function ct(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function pt(e){var t=at.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function ht(e,t){var n=e.length,r=0;for(;n>r;r++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function dt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=x.extend({},o),l=o.events,q.set(t,s),l)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function gt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function mt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&it.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var yt,vt,xt=/^(none|table(?!-c[ea]).+)/,bt=/^margin/,wt=RegExp("^("+b+")(.*)$","i"),Tt=RegExp("^("+b+")(?!px)[a-z%]+$","i"),Ct=RegExp("^([+-])=("+b+")","i"),kt={BODY:"block"},Nt={position:"absolute",visibility:"hidden",display:"block"},Et={letterSpacing:0,fontWeight:400},St=["Top","Right","Bottom","Left"],jt=["Webkit","O","Moz","ms"];function Dt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=jt.length;while(i--)if(t=jt[i]+n,t in e)return t;return r}function At(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function Lt(t){return e.getComputedStyle(t,null)}function qt(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&At(r)&&(o[s]=q.access(r,"olddisplay",Pt(r.nodeName)))):o[s]||(i=At(r),(n&&"none"!==n||!i)&&q.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=Lt(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return qt(this,!0)},hide:function(){return qt(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:At(this))?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=yt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=Dt(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=Ct.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=Dt(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=yt(e,t,r)),"normal"===i&&t in Et&&(i=Et[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),yt=function(e,t,n){var r,i,o,s=n||Lt(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Tt.test(a)&&bt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ht(e,t,n){var r=wt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ot(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+St[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+St[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+St[o]+"Width",!0,i))):(s+=x.css(e,"padding"+St[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+St[o]+"Width",!0,i)));return s}function Ft(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Lt(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=yt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Tt.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ot(e,t,n||(s?"border":"content"),r,o)+"px"}function Pt(e){var t=o,n=kt[e];return n||(n=Rt(e,t),"none"!==n&&n||(vt=(vt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(vt[0].contentWindow||vt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=Rt(e,t),vt.detach()),kt[e]=n),n}function Rt(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,t){x.cssHooks[t]={get:function(e,n,r){return n?0===e.offsetWidth&&xt.test(x.css(e,"display"))?x.swap(e,Nt,function(){return Ft(e,t,r)}):Ft(e,t,r):undefined},set:function(e,n,r){var i=r&&Lt(e);return Ht(e,n,r?Ot(e,t,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,t){return t?x.swap(e,{display:"inline-block"},yt,[e,"marginRight"]):undefined}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,t){x.cssHooks[t]={get:function(e,n){return n?(n=yt(e,t),Tt.test(n)?x(e).position()[t]+"px":n):undefined}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+St[r]+t]=o[r]||o[r-2]||o[0];return i}},bt.test(e)||(x.cssHooks[e+t].set=Ht)});var Mt=/%20/g,Wt=/\[\]$/,$t=/\r?\n/g,Bt=/^(?:submit|button|image|reset|file)$/i,It=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&It.test(this.nodeName)&&!Bt.test(e)&&(this.checked||!it.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace($t,"\r\n")}}):{name:t.name,value:n.replace($t,"\r\n")}}).get()}}),x.param=function(e,t){var n,r=[],i=function(e,t){t=x.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(t===undefined&&(t=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){i(this.name,this.value)});else for(n in e)zt(n,e[n],t,i);return r.join("&").replace(Mt,"+")};function zt(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||Wt.test(e)?r(e,i):zt(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)zt(e+"["+i+"]",t[i],n,r)}x.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(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var _t,Xt,Ut=x.now(),Yt=/\?/,Vt=/#.*$/,Gt=/([?&])_=[^&]*/,Jt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Qt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Kt=/^(?:GET|HEAD)$/,Zt=/^\/\//,en=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,tn=x.fn.load,nn={},rn={},on="*/".concat("*");try{Xt=i.href}catch(sn){Xt=o.createElement("a"),Xt.href="",Xt=Xt.href}_t=en.exec(Xt.toLowerCase())||[];function an(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];
+if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function un(e,t,n,r){var i={},o=e===rn;function s(a){var u;return i[a]=!0,x.each(e[a]||[],function(e,a){var l=a(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):undefined:(t.dataTypes.unshift(l),s(l),!1)}),u}return s(t.dataTypes[0])||!i["*"]&&s("*")}function ln(e,t){var n,r,i=x.ajaxSettings.flatOptions||{};for(n in t)t[n]!==undefined&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,t,n){if("string"!=typeof e&&tn)return tn.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return a>=0&&(r=e.slice(a),e=e.slice(0,a)),x.isFunction(t)?(n=t,t=undefined):t&&"object"==typeof t&&(i="POST"),s.length>0&&x.ajax({url:e,type:i,dataType:"html",data:t}).done(function(e){o=arguments,s.html(r?x("<div>").append(x.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Xt,type:"GET",isLocal:Qt.test(_t[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":on,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?ln(ln(e,x.ajaxSettings),t):ln(x.ajaxSettings,e)},ajaxPrefilter:an(nn),ajaxTransport:an(rn),ajax:function(e,t){"object"==typeof e&&(t=e,e=undefined),t=t||{};var n,r,i,o,s,a,u,l,c=x.ajaxSetup({},t),f=c.context||c,p=c.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),d=x.Callbacks("once memory"),g=c.statusCode||{},m={},y={},v=0,b="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===v){if(!o){o={};while(t=Jt.exec(i))o[t[1].toLowerCase()]=t[2]}t=o[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===v?i:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return v||(e=y[n]=y[n]||e,m[e]=t),this},overrideMimeType:function(e){return v||(c.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>v)for(t in e)g[t]=[g[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||b;return n&&n.abort(t),k(0,t),this}};if(h.promise(T).complete=d.add,T.success=T.done,T.error=T.fail,c.url=((e||c.url||Xt)+"").replace(Vt,"").replace(Zt,_t[1]+"//"),c.type=t.method||t.type||c.method||c.type,c.dataTypes=x.trim(c.dataType||"*").toLowerCase().match(w)||[""],null==c.crossDomain&&(a=en.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===_t[1]&&a[2]===_t[2]&&(a[3]||("http:"===a[1]?"80":"443"))===(_t[3]||("http:"===_t[1]?"80":"443")))),c.data&&c.processData&&"string"!=typeof c.data&&(c.data=x.param(c.data,c.traditional)),un(nn,c,t,T),2===v)return T;u=c.global,u&&0===x.active++&&x.event.trigger("ajaxStart"),c.type=c.type.toUpperCase(),c.hasContent=!Kt.test(c.type),r=c.url,c.hasContent||(c.data&&(r=c.url+=(Yt.test(r)?"&":"?")+c.data,delete c.data),c.cache===!1&&(c.url=Gt.test(r)?r.replace(Gt,"$1_="+Ut++):r+(Yt.test(r)?"&":"?")+"_="+Ut++)),c.ifModified&&(x.lastModified[r]&&T.setRequestHeader("If-Modified-Since",x.lastModified[r]),x.etag[r]&&T.setRequestHeader("If-None-Match",x.etag[r])),(c.data&&c.hasContent&&c.contentType!==!1||t.contentType)&&T.setRequestHeader("Content-Type",c.contentType),T.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+("*"!==c.dataTypes[0]?", "+on+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)T.setRequestHeader(l,c.headers[l]);if(c.beforeSend&&(c.beforeSend.call(f,T,c)===!1||2===v))return T.abort();b="abort";for(l in{success:1,error:1,complete:1})T[l](c[l]);if(n=un(rn,c,t,T)){T.readyState=1,u&&p.trigger("ajaxSend",[T,c]),c.async&&c.timeout>0&&(s=setTimeout(function(){T.abort("timeout")},c.timeout));try{v=1,n.send(m,k)}catch(C){if(!(2>v))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,t,o,a){var l,m,y,b,w,C=t;2!==v&&(v=2,s&&clearTimeout(s),n=undefined,i=a||"",T.readyState=e>0?4:0,l=e>=200&&300>e||304===e,o&&(b=cn(c,T,o)),b=fn(c,b,T,l),l?(c.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(x.lastModified[r]=w),w=T.getResponseHeader("etag"),w&&(x.etag[r]=w)),204===e?C="nocontent":304===e?C="notmodified":(C=b.state,m=b.data,y=b.error,l=!y)):(y=C,(e||!C)&&(C="error",0>e&&(e=0))),T.status=e,T.statusText=(t||C)+"",l?h.resolveWith(f,[m,C,T]):h.rejectWith(f,[T,C,y]),T.statusCode(g),g=undefined,u&&p.trigger(l?"ajaxSuccess":"ajaxError",[T,c,l?m:y]),d.fireWith(f,[T,C]),u&&(p.trigger("ajaxComplete",[T,c]),--x.active||x.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,t){return x.get(e,undefined,t,"script")}}),x.each(["get","post"],function(e,t){x[t]=function(e,n,r,i){return x.isFunction(n)&&(i=i||r,r=n,n=undefined),x.ajax({url:e,type:t,dataType:i,data:n,success:r})}});function cn(e,t,n){var r,i,o,s,a=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),r===undefined&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in a)if(a[i]&&a[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}s||(s=i)}o=o||s}return o?(o!==u[0]&&u.unshift(o),n[o]):undefined}function fn(e,t,n,r){var i,o,s,a,u,l={},c=e.dataTypes.slice();if(c[1])for(s in e.converters)l[s.toLowerCase()]=e.converters[s];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(s=l[u+" "+o]||l["* "+o],!s)for(i in l)if(a=i.split(" "),a[1]===o&&(s=l[u+" "+a[0]]||l["* "+a[0]])){s===!0?s=l[i]:l[i]!==!0&&(o=a[0],c.unshift(a[1]));break}if(s!==!0)if(s&&e["throws"])t=s(t);else try{t=s(t)}catch(f){return{state:"parsererror",error:s?f:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===undefined&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),x.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,i){t=x("<script>").prop({async:!0,charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&i("error"===e.type?404:200,e.type)}),o.head.appendChild(t[0])},abort:function(){n&&n()}}}});var pn=[],hn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=pn.pop()||x.expando+"_"+Ut++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,s,a=t.jsonp!==!1&&(hn.test(t.url)?"url":"string"==typeof t.data&&!(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&hn.test(t.data)&&"data");return a||"jsonp"===t.dataTypes[0]?(i=t.jsonpCallback=x.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,a?t[a]=t[a].replace(hn,"$1"+i):t.jsonp!==!1&&(t.url+=(Yt.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return s||x.error(i+" was not called"),s[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){s=arguments},r.always(function(){e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,pn.push(i)),s&&x.isFunction(o)&&o(s[0]),s=o=undefined}),"script"):undefined}),x.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(e){}};var dn=x.ajaxSettings.xhr(),gn={0:200,1223:204},mn=0,yn={};e.ActiveXObject&&x(e).on("unload",function(){for(var e in yn)yn[e]();yn=undefined}),x.support.cors=!!dn&&"withCredentials"in dn,x.support.ajax=dn=!!dn,x.ajaxTransport(function(e){var t;return x.support.cors||dn&&!e.crossDomain?{send:function(n,r){var i,o,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(i in e.xhrFields)s[i]=e.xhrFields[i];e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||n["X-Requested-With"]||(n["X-Requested-With"]="XMLHttpRequest");for(i in n)s.setRequestHeader(i,n[i]);t=function(e){return function(){t&&(delete yn[o],t=s.onload=s.onerror=null,"abort"===e?s.abort():"error"===e?r(s.status||404,s.statusText):r(gn[s.status]||s.status,s.statusText,"string"==typeof s.responseText?{text:s.responseText}:undefined,s.getAllResponseHeaders()))}},s.onload=t(),s.onerror=t("error"),t=yn[o=mn++]=t("abort"),s.send(e.hasContent&&e.data||null)},abort:function(){t&&t()}}:undefined});var vn,xn,bn=/^(?:toggle|show|hide)$/,wn=RegExp("^(?:([+-])=|)("+b+")([a-z%]*)$","i"),Tn=/queueHooks$/,Cn=[Dn],kn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=wn.exec(t),s=i.cur(),a=+s||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(x.cssNumber[e]?"":"px"),"px"!==r&&a){a=x.css(i.elem,e,!0)||n||1;do u=u||".5",a/=u,x.style(i.elem,e,a+r);while(u!==(u=i.cur()/s)&&1!==u&&--l)}i.unit=r,i.start=a,i.end=o[1]?a+(o[1]+1)*n:n}return i}]};function Nn(){return setTimeout(function(){vn=undefined}),vn=x.now()}function En(e,t){x.each(t,function(t,n){var r=(kn[t]||[]).concat(kn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function Sn(e,t,n){var r,i,o=0,s=Cn.length,a=x.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=vn||Nn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,s=0,u=l.tweens.length;for(;u>s;s++)l.tweens[s].run(o);return a.notifyWith(e,[l,o,n]),1>o&&u?n:(a.resolveWith(e,[l]),!1)},l=a.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:vn||Nn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?a.resolveWith(e,[l,t]):a.rejectWith(e,[l,t]),this}}),c=l.props;for(jn(c,l.opts.specialEasing);s>o;o++)if(r=Cn[o].call(l,e,c,l.opts))return r;return En(l,c),x.isFunction(l.opts.start)&&l.opts.start.call(e,l),x.fx.timer(x.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function jn(e,t){var n,r,i,o,s;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),s=x.cssHooks[r],s&&"expand"in s){o=s.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(Sn,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],kn[n]=kn[n]||[],kn[n].unshift(t)},prefilter:function(e,t){t?Cn.unshift(e):Cn.push(e)}});function Dn(e,t,n){var r,i,o,s,a,u,l,c,f,p=this,h=e.style,d={},g=[],m=e.nodeType&&At(e);n.queue||(c=x._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,f=c.empty.fire,c.empty.fire=function(){c.unqueued||f()}),c.unqueued++,p.always(function(){p.always(function(){c.unqueued--,x.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),a=q.get(e,"fxshow");for(r in t)if(o=t[r],bn.exec(o)){if(delete t[r],u=u||"toggle"===o,o===(m?"hide":"show")){if("show"!==o||a===undefined||a[r]===undefined)continue;m=!0}g.push(r)}if(s=g.length){a=q.get(e,"fxshow")||q.access(e,"fxshow",{}),"hidden"in a&&(m=a.hidden),u&&(a.hidden=!m),m?x(e).show():p.done(function(){x(e).hide()}),p.done(function(){var t;q.remove(e,"fxshow");for(t in d)x.style(e,t,d[t])});for(r=0;s>r;r++)i=g[r],l=p.createTween(i,m?a[i]:0),d[i]=a[i]||x.style(e,i),i in a||(a[i]=l.start,m&&(l.end=l.start,l.start="width"===i||"height"===i?1:0))}}function An(e,t,n,r,i){return new An.prototype.init(e,t,n,r,i)}x.Tween=An,An.prototype={constructor:An,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=An.propHooks[this.prop];return e&&e.get?e.get(this):An.propHooks._default.get(this)},run:function(e){var t,n=An.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):An.propHooks._default.set(this),this}},An.prototype.init.prototype=An.prototype,An.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},An.propHooks.scrollTop=An.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(Ln(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(At).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),s=function(){var t=Sn(this,x.extend({},e),o);s.finish=function(){t.stop(!0)},(i||q.get(this,"finish"))&&t.stop(!0)};return s.finish=s,i||o.queue===!1?this.each(s):this.queue(o.queue,s)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=undefined),t&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=x.timers,s=q.get(this);if(i)s[i]&&s[i].stop&&r(s[i]);else for(i in s)s[i]&&s[i].stop&&Tn.test(i)&&r(s[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));(t||!n)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=q.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,s=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;s>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function Ln(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=St[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:Ln("show"),slideUp:Ln("hide"),slideToggle:Ln("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=An.prototype.init,x.fx.tick=function(){var e,t=x.timers,n=0;for(vn=x.now();t.length>n;n++)e=t[n],e()||t[n]!==e||t.splice(n--,1);t.length||x.fx.stop(),vn=undefined},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){xn||(xn=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(xn),xn=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===undefined?this:this.each(function(t){x.offset.setOffset(this,e,t)});var t,n,i=this[0],o={top:0,left:0},s=i&&i.ownerDocument;if(s)return t=s.documentElement,x.contains(t,i)?(typeof i.getBoundingClientRect!==r&&(o=i.getBoundingClientRect()),n=qn(s),{top:o.top+n.pageYOffset-t.clientTop,left:o.left+n.pageXOffset-t.clientLeft}):o},x.offset={setOffset:function(e,t,n){var r,i,o,s,a,u,l,c=x.css(e,"position"),f=x(e),p={};"static"===c&&(e.style.position="relative"),a=f.offset(),o=x.css(e,"top"),u=x.css(e,"left"),l=("absolute"===c||"fixed"===c)&&(o+u).indexOf("auto")>-1,l?(r=f.position(),s=r.top,i=r.left):(s=parseFloat(o)||0,i=parseFloat(u)||0),x.isFunction(t)&&(t=t.call(e,n,a)),null!=t.top&&(p.top=t.top-a.top+s),null!=t.left&&(p.left=t.left-a.left+i),"using"in t?t.using.call(e,p):f.css(p)}},x.fn.extend({position:function(){if(this[0]){var e,t,n=this[0],r={top:0,left:0};return"fixed"===x.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(r=e.offset()),r.top+=x.css(e[0],"borderTopWidth",!0),r.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-r.top-x.css(n,"marginTop",!0),left:t.left-r.left-x.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,n){var r="pageYOffset"===n;x.fn[t]=function(i){return x.access(this,function(t,i,o){var s=qn(t);return o===undefined?s?s[n]:t[i]:(s?s.scrollTo(r?e.pageXOffset:o,r?o:e.pageYOffset):t[i]=o,undefined)},t,i,arguments.length,null)}});function qn(e){return x.isWindow(e)?e:9===e.nodeType&&e.defaultView}x.each({Height:"height",Width:"width"},function(e,t){x.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){x.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),s=n||(r===!0||i===!0?"margin":"border");return x.access(this,function(t,n,r){var i;return x.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):r===undefined?x.css(t,n,s):x.style(t,n,r,s)},t,o?r:undefined,o,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&"object"==typeof module.exports?module.exports=x:"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}),"object"==typeof e&&"object"==typeof e.document&&(e.jQuery=e.$=x)})(window);
\ No newline at end of file
diff --git a/asterix-examples/src/main/resources/tiny-social/js/tinysocial.js b/asterix-examples/src/main/resources/tiny-social/js/tinysocial.js
new file mode 100644
index 0000000..b767757
--- /dev/null
+++ b/asterix-examples/src/main/resources/tiny-social/js/tinysocial.js
@@ -0,0 +1,30 @@
+$(function() {
+
+    // Exact-Match Lookup
+    $('#run0a').click(function () {
+        var a = new AsterixSDK();
+        var q = new FLWOGRExpression()
+            .use_dataverse("Twitter")
+            .bind(new ForClause("user", new AsterixClause().set("dataset FacebookUsers")))
+            .bind(new WhereClause(new BooleanExpression("=", "$user.id", 8)))
+            .return({ "$user" : "$user" });
+        alert(q.clauses);
+    });
+
+    // Range Scan
+    $('#run0b').click(function () {
+        alert("0b");
+    });
+    
+    // Other Query Filter
+    $('#run1').click(function () {
+        alert("1");
+    });
+
+});
+
+// Bootstraps social data
+function bootstrap() {
+    var loc = window.location.pathname;
+    var dir = loc.substring(0, loc.lastIndexOf('/'));
+}
diff --git a/asterix-examples/src/main/resources/tiny-social/tinysocial.html b/asterix-examples/src/main/resources/tiny-social/tinysocial.html
new file mode 100644
index 0000000..104f19c
--- /dev/null
+++ b/asterix-examples/src/main/resources/tiny-social/tinysocial.html
@@ -0,0 +1,227 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <title>AsterixDB TinySocial Demo</title>
+
+    <style>
+        .pretty-printed {
+            background-color: #eeeeee;
+            margin-bottom: 1em;
+        }
+
+        .how-to-run {
+            background-color: #c8c8c8;
+            margin-bottom: 1em;
+        }
+
+        body {
+            font-family : "Helvetica";
+            margin-bottom: 1em;
+        }
+    </style>
+
+    <script src="../js/jquery.min.js"></script>
+    <script src="../core/js/easyXDM/easyXDM.debug.js"></script>
+    <script src="http://localhost:19101/sdk/static/js/asterix-api-core.js"></script>
+    <script src="js/tinysocial.js"></script>
+</head>
+<body>
+    <h1>AQL: Querying TinySocial AsterixDB</h1>
+    
+    <h2>Query 0-A - Exact-Match Lookup</h2>
+    <div class="sample-query">
+
+        <div class="pretty-printed">
+            use dataverse TinySocial;<br/><br/>
+
+            for $user in dataset FacebookUsers<br/>
+            where $user.id = 8<br/>
+            return $user;<br/>
+        </div>
+
+        <div class="how-to-run">
+            javascript here
+        </div>
+
+        <button id="run0a">Run #0-A</button>
+    </div>
+    <hr/>
+    <h2>Query 0-B - Range Scan</h2>
+    <div class="sample-query">
+        
+        <div class="pretty-printed">
+            use dataverse TinySocial;<br/><br/>
+
+            for $user in dataset FacebookUsers<br/>
+            where $user.id >= 2 and $user.id <= 4<br/>
+            return $user;<br/>
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run0b">Run #0-B</button>
+    </div>
+    <hr/>
+
+    <h2>Query 1 - Other Query Filters</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+            use dataverse TinySocial;<br/><br/>
+
+            for $user in dataset FacebookUsers<br/>
+            where $user.user-since >= datetime('2010-07-22T00:00:00')<br/>
+            and $user.user-since <= datetime('2012-07-29T23:59:59')<br/>
+            return $user;<br/>
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run1">Run #1</button>
+    </div>
+    <hr/>
+
+    <h2>Query 2-A - Equijoin</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <button id="run2a">Run #2-A</button>
+    </div>
+    <hr/>
+
+    <h2>Query 2-B - Index join</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run2b">Run #2-B</button>
+    </div>
+    <hr/>
+
+    <h2>Query 3 - Nested Outer Join</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run3">Run #3</button>
+    </div>
+    <hr/>
+
+    <h2>Query 4 - Theta Join</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run4">Run #4</button>
+    </div>
+    <hr/>
+
+    <h2>Query 5 - Fuzzy Join</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run5">Run #5</button>
+    </div>
+    <hr/>
+
+    <h2>Query 6 - Existential Quantification</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run6">Run #6</button>
+    </div>
+    <hr/>
+
+    <h2>Query 7 - Universal Quantification</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run7">Run #7</button>
+    </div>
+    <hr/>
+
+    <h2>Query 8 - Simple Aggregation</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run8">Run #8</button>
+    </div>
+    <hr/>
+
+    <h2>Query 9-A - Grouping and Aggregation</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run9a">Run #9-A</button>
+    </div>
+    <hr/>
+
+    <h2>Query 9-B - (Hash-Based) Grouping and Aggregation</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run9b">Run #9-B</button>
+    </div>
+    <hr/>
+
+    <h2>Query 10 - Grouping and Limits</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run10">Run #10</button>
+    </div>
+    <hr/>
+
+    <h2>Query 11 - Left Outer Fuzzy Join</h2>
+    <div class="sample-query">
+        <div class="pretty-printed">
+        </div>
+        
+        <div class="how-to-run">
+        </div>
+
+        <button id="run11">Run #11</button>
+    </div>
+
+</body>
+</html>