summaryrefslogtreecommitdiffstats
path: root/src/civetweb/examples/_obsolete
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
commit19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch)
tree42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/civetweb/examples/_obsolete
parentInitial commit. (diff)
downloadceph-upstream/16.2.11+ds.tar.xz
ceph-upstream/16.2.11+ds.zip
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/civetweb/examples/_obsolete')
-rw-r--r--src/civetweb/examples/_obsolete/chat/Makefile40
-rw-r--r--src/civetweb/examples/_obsolete/chat/chat.c403
-rw-r--r--src/civetweb/examples/_obsolete/docroot/favicon.icobin0 -> 1406 bytes
-rw-r--r--src/civetweb/examples/_obsolete/docroot/index.html73
-rw-r--r--src/civetweb/examples/_obsolete/docroot/jquery.js154
-rw-r--r--src/civetweb/examples/_obsolete/docroot/login.html43
-rw-r--r--src/civetweb/examples/_obsolete/docroot/logo.pngbin0 -> 1601 bytes
-rw-r--r--src/civetweb/examples/_obsolete/docroot/main.js107
-rw-r--r--src/civetweb/examples/_obsolete/docroot/prime_numbers.lp46
-rw-r--r--src/civetweb/examples/_obsolete/docroot/style.css154
-rw-r--r--src/civetweb/examples/_obsolete/hello/Makefile36
-rw-r--r--src/civetweb/examples/_obsolete/hello/hello.c53
-rw-r--r--src/civetweb/examples/_obsolete/lua/lua_dll.c21
-rw-r--r--src/civetweb/examples/_obsolete/post/Makefile36
-rw-r--r--src/civetweb/examples/_obsolete/post/post.c58
-rw-r--r--src/civetweb/examples/_obsolete/upload/Makefile36
-rw-r--r--src/civetweb/examples/_obsolete/upload/upload.c110
-rw-r--r--src/civetweb/examples/_obsolete/websocket/Makefile36
-rw-r--r--src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.c225
-rw-r--r--src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.h44
-rw-r--r--src/civetweb/examples/_obsolete/websocket/websock.htm55
-rw-r--r--src/civetweb/examples/_obsolete/websocket/websocket.c65
-rw-r--r--src/civetweb/examples/_obsolete/websocket_client/Makefile37
-rw-r--r--src/civetweb/examples/_obsolete/websocket_client/ssl/server.crt13
-rw-r--r--src/civetweb/examples/_obsolete/websocket_client/ssl/server.csr11
-rw-r--r--src/civetweb/examples/_obsolete/websocket_client/ssl/server.key15
-rw-r--r--src/civetweb/examples/_obsolete/websocket_client/ssl/server.key.orig18
-rw-r--r--src/civetweb/examples/_obsolete/websocket_client/ssl/server.pem28
-rw-r--r--src/civetweb/examples/_obsolete/websocket_client/websocket_client.c421
-rw-r--r--src/civetweb/examples/_obsolete/ws_server/Makefile36
-rw-r--r--src/civetweb/examples/_obsolete/ws_server/docroot/index.html316
-rw-r--r--src/civetweb/examples/_obsolete/ws_server/ws_server.c271
32 files changed, 2961 insertions, 0 deletions
diff --git a/src/civetweb/examples/_obsolete/chat/Makefile b/src/civetweb/examples/_obsolete/chat/Makefile
new file mode 100644
index 000000000..e8d12be69
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/chat/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2013 No Face Press, LLC
+# License http://opensource.org/licenses/mit-license.php MIT License
+#
+
+#This makefile is used to test the other Makefiles
+
+
+PROG = chat
+SRC = chat.c
+
+TOP = ../..
+CIVETWEB_LIB = libcivetweb.a
+SSL_CERT = ssl_cert.pem
+
+CFLAGS = -I$(TOP)/include $(COPT)
+LIBS = -lpthread
+
+include $(TOP)/resources/Makefile.in-os
+
+ifeq ($(TARGET_OS),LINUX)
+ LIBS += -ldl
+endif
+
+all: $(PROG) $(SSL_CERT)
+
+$(PROG): $(CIVETWEB_LIB) $(SRC)
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS)
+
+$(CIVETWEB_LIB):
+ $(MAKE) -C $(TOP) clean lib
+ cp $(TOP)/$(CIVETWEB_LIB) .
+
+$(SSL_CERT):
+ cp $(TOP)/resources/$(SSL_CERT) .
+
+clean:
+ rm -f $(CIVETWEB_LIB) $(PROG) $(SSL_CERT)
+
+.PHONY: all clean
diff --git a/src/civetweb/examples/_obsolete/chat/chat.c b/src/civetweb/examples/_obsolete/chat/chat.c
new file mode 100644
index 000000000..ad146183b
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/chat/chat.c
@@ -0,0 +1,403 @@
+// This file is part of the Civetweb project, http://code.google.com/p/civetweb
+// It implements an online chat server. For more details,
+// see the documentation on the project web site.
+// To test the application,
+// 1. type "make" in the directory where this file lives
+// 2. point your browser to http://127.0.0.1:8081
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <pthread.h>
+
+#include "civetweb.h"
+
+#define MAX_USER_LEN 20
+#define MAX_MESSAGE_LEN 100
+#define MAX_MESSAGES 5
+#define MAX_SESSIONS 2
+#define SESSION_TTL 120
+
+static const char *authorize_url = "/authorize";
+static const char *login_url = "/login.html";
+static const char *ajax_reply_start =
+ "HTTP/1.1 200 OK\r\n"
+ "Cache: no-cache\r\n"
+ "Content-Type: application/x-javascript\r\n"
+ "\r\n";
+
+// Describes single message sent to a chat. If user is empty (0 length),
+// the message is then originated from the server itself.
+struct message {
+ long id; // Message ID
+ char user[MAX_USER_LEN]; // User that have sent the message
+ char text[MAX_MESSAGE_LEN]; // Message text
+ time_t timestamp; // Message timestamp, UTC
+};
+
+// Describes web session.
+struct session {
+ char session_id[33]; // Session ID, must be unique
+ char random[20]; // Random data used for extra user validation
+ char user[MAX_USER_LEN]; // Authenticated user
+ time_t expire; // Expiration timestamp, UTC
+};
+
+static struct message messages[MAX_MESSAGES]; // Ringbuffer for messages
+static struct session sessions[MAX_SESSIONS]; // Current sessions
+static long last_message_id;
+
+// Protects messages, sessions, last_message_id
+static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
+
+// Get session object for the connection. Caller must hold the lock.
+static struct session *get_session(const struct mg_connection *conn)
+{
+ int i;
+ const char *cookie = mg_get_header(conn, "Cookie");
+ char session_id[33];
+ time_t now = time(NULL);
+ mg_get_cookie(cookie, "session", session_id, sizeof(session_id));
+ for (i = 0; i < MAX_SESSIONS; i++) {
+ if (sessions[i].expire != 0 &&
+ sessions[i].expire > now &&
+ strcmp(sessions[i].session_id, session_id) == 0) {
+ break;
+ }
+ }
+ return i == MAX_SESSIONS ? NULL : &sessions[i];
+}
+
+static void get_qsvar(const struct mg_request_info *request_info,
+ const char *name, char *dst, size_t dst_len)
+{
+ const char *qs = request_info->query_string;
+ mg_get_var(qs, strlen(qs == NULL ? "" : qs), name, dst, dst_len);
+}
+
+// Get a get of messages with IDs greater than last_id and transform them
+// into a JSON string. Return that string to the caller. The string is
+// dynamically allocated, caller must free it. If there are no messages,
+// NULL is returned.
+static char *messages_to_json(long last_id)
+{
+ const struct message *message;
+ int max_msgs, len;
+ char buf[sizeof(messages)]; // Large enough to hold all messages
+
+ // Read-lock the ringbuffer. Loop over all messages, making a JSON string.
+ pthread_rwlock_rdlock(&rwlock);
+ len = 0;
+ max_msgs = sizeof(messages) / sizeof(messages[0]);
+ // If client is too far behind, return all messages.
+ if (last_message_id - last_id > max_msgs) {
+ last_id = last_message_id - max_msgs;
+ }
+ for (; last_id < last_message_id; last_id++) {
+ message = &messages[last_id % max_msgs];
+ if (message->timestamp == 0) {
+ break;
+ }
+ // buf is allocated on stack and hopefully is large enough to hold all
+ // messages (it may be too small if the ringbuffer is full and all
+ // messages are large. in this case asserts will trigger).
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "{user: '%s', text: '%s', timestamp: %lu, id: %ld},",
+ message->user, message->text, message->timestamp, message->id);
+ assert(len > 0);
+ assert((size_t) len < sizeof(buf));
+ }
+ pthread_rwlock_unlock(&rwlock);
+
+ return len == 0 ? NULL : strdup(buf);
+}
+
+// If "callback" param is present in query string, this is JSONP call.
+// Return 1 in this case, or 0 if "callback" is not specified.
+// Wrap an output in Javascript function call.
+static int handle_jsonp(struct mg_connection *conn,
+ const struct mg_request_info *request_info)
+{
+ char cb[64];
+
+ get_qsvar(request_info, "callback", cb, sizeof(cb));
+ if (cb[0] != '\0') {
+ mg_printf(conn, "%s(", cb);
+ }
+
+ return cb[0] == '\0' ? 0 : 1;
+}
+
+// A handler for the /ajax/get_messages endpoint.
+// Return a list of messages with ID greater than requested.
+static void ajax_get_messages(struct mg_connection *conn,
+ const struct mg_request_info *request_info)
+{
+ char last_id[32], *json;
+ int is_jsonp;
+
+ mg_printf(conn, "%s", ajax_reply_start);
+ is_jsonp = handle_jsonp(conn, request_info);
+
+ get_qsvar(request_info, "last_id", last_id, sizeof(last_id));
+ if ((json = messages_to_json(strtoul(last_id, NULL, 10))) != NULL) {
+ mg_printf(conn, "[%s]", json);
+ free(json);
+ }
+
+ if (is_jsonp) {
+ mg_printf(conn, "%s", ")");
+ }
+}
+
+// Allocate new message. Caller must hold the lock.
+static struct message *new_message(void)
+{
+ static int size = sizeof(messages) / sizeof(messages[0]);
+ struct message *message = &messages[last_message_id % size];
+ message->id = last_message_id++;
+ message->timestamp = time(0);
+ return message;
+}
+
+static void my_strlcpy(char *dst, const char *src, size_t len)
+{
+ strncpy(dst, src, len);
+ dst[len - 1] = '\0';
+}
+
+// A handler for the /ajax/send_message endpoint.
+static void ajax_send_message(struct mg_connection *conn,
+ const struct mg_request_info *request_info)
+{
+ struct message *message;
+ struct session *session;
+ char text[sizeof(message->text) - 1];
+ int is_jsonp;
+
+ mg_printf(conn, "%s", ajax_reply_start);
+ is_jsonp = handle_jsonp(conn, request_info);
+
+ get_qsvar(request_info, "text", text, sizeof(text));
+ if (text[0] != '\0') {
+ // We have a message to store. Write-lock the ringbuffer,
+ // grab the next message and copy data into it.
+ pthread_rwlock_wrlock(&rwlock);
+ message = new_message();
+ // TODO(lsm): JSON-encode all text strings
+ session = get_session(conn);
+ assert(session != NULL);
+ my_strlcpy(message->text, text, sizeof(text));
+ my_strlcpy(message->user, session->user, sizeof(message->user));
+ pthread_rwlock_unlock(&rwlock);
+ }
+
+ mg_printf(conn, "%s", text[0] == '\0' ? "false" : "true");
+
+ if (is_jsonp) {
+ mg_printf(conn, "%s", ")");
+ }
+}
+
+// Redirect user to the login form. In the cookie, store the original URL
+// we came from, so that after the authorization we could redirect back.
+static void redirect_to_login(struct mg_connection *conn,
+ const struct mg_request_info *request_info)
+{
+ mg_printf(conn, "HTTP/1.1 302 Found\r\n"
+ "Set-Cookie: original_url=%s\r\n"
+ "Location: %s\r\n\r\n",
+ request_info->uri, login_url);
+}
+
+// Return 1 if username/password is allowed, 0 otherwise.
+static int check_password(const char *user, const char *password)
+{
+ // In production environment we should ask an authentication system
+ // to authenticate the user.
+ // Here however we do trivial check that user and password are not empty
+ return (user[0] && password[0]);
+}
+
+// Allocate new session object
+static struct session *new_session(void)
+{
+ int i;
+ time_t now = time(NULL);
+ pthread_rwlock_wrlock(&rwlock);
+ for (i = 0; i < MAX_SESSIONS; i++) {
+ if (sessions[i].expire == 0 || sessions[i].expire < now) {
+ sessions[i].expire = time(0) + SESSION_TTL;
+ break;
+ }
+ }
+ pthread_rwlock_unlock(&rwlock);
+ return i == MAX_SESSIONS ? NULL : &sessions[i];
+}
+
+// Generate session ID. buf must be 33 bytes in size.
+// Note that it is easy to steal session cookies by sniffing traffic.
+// This is why all communication must be SSL-ed.
+static void generate_session_id(char *buf, const char *random,
+ const char *user)
+{
+ mg_md5(buf, random, user, NULL);
+}
+
+static void send_server_message(const char *fmt, ...)
+{
+ va_list ap;
+ struct message *message;
+
+ pthread_rwlock_wrlock(&rwlock);
+ message = new_message();
+ message->user[0] = '\0'; // Empty user indicates server message
+ va_start(ap, fmt);
+ vsnprintf(message->text, sizeof(message->text), fmt, ap);
+ va_end(ap);
+
+ pthread_rwlock_unlock(&rwlock);
+}
+
+// A handler for the /authorize endpoint.
+// Login page form sends user name and password to this endpoint.
+static void authorize(struct mg_connection *conn,
+ const struct mg_request_info *request_info)
+{
+ char user[MAX_USER_LEN], password[MAX_USER_LEN];
+ struct session *session;
+
+ // Fetch user name and password.
+ get_qsvar(request_info, "user", user, sizeof(user));
+ get_qsvar(request_info, "password", password, sizeof(password));
+
+ if (check_password(user, password) && (session = new_session()) != NULL) {
+ // Authentication success:
+ // 1. create new session
+ // 2. set session ID token in the cookie
+ // 3. remove original_url from the cookie - not needed anymore
+ // 4. redirect client back to the original URL
+ //
+ // The most secure way is to stay HTTPS all the time. However, just to
+ // show the technique, we redirect to HTTP after the successful
+ // authentication. The danger of doing this is that session cookie can
+ // be stolen and an attacker may impersonate the user.
+ // Secure application must use HTTPS all the time.
+ my_strlcpy(session->user, user, sizeof(session->user));
+ snprintf(session->random, sizeof(session->random), "%d", rand());
+ generate_session_id(session->session_id, session->random, session->user);
+ send_server_message("<%s> joined", session->user);
+ mg_printf(conn, "HTTP/1.1 302 Found\r\n"
+ "Set-Cookie: session=%s; max-age=3600; http-only\r\n" // Session ID
+ "Set-Cookie: user=%s\r\n" // Set user, needed by Javascript code
+ "Set-Cookie: original_url=/; max-age=0\r\n" // Delete original_url
+ "Location: /\r\n\r\n",
+ session->session_id, session->user);
+ } else {
+ // Authentication failure, redirect to login.
+ redirect_to_login(conn, request_info);
+ }
+}
+
+// Return 1 if request is authorized, 0 otherwise.
+static int is_authorized(const struct mg_connection *conn,
+ const struct mg_request_info *request_info)
+{
+ struct session *session;
+ char valid_id[33];
+ int authorized = 0;
+
+ // Always authorize accesses to login page and to authorize URI
+ if (!strcmp(request_info->uri, login_url) ||
+ !strcmp(request_info->uri, authorize_url)) {
+ return 1;
+ }
+
+ pthread_rwlock_rdlock(&rwlock);
+ if ((session = get_session(conn)) != NULL) {
+ generate_session_id(valid_id, session->random, session->user);
+ if (strcmp(valid_id, session->session_id) == 0) {
+ session->expire = time(0) + SESSION_TTL;
+ authorized = 1;
+ }
+ }
+ pthread_rwlock_unlock(&rwlock);
+
+ return authorized;
+}
+
+static void redirect_to_ssl(struct mg_connection *conn,
+ const struct mg_request_info *request_info)
+{
+ const char *p, *host = mg_get_header(conn, "Host");
+ if (host != NULL && (p = strchr(host, ':')) != NULL) {
+ mg_printf(conn, "HTTP/1.1 302 Found\r\n"
+ "Location: https://%.*s:8082/%s:8082\r\n\r\n",
+ (int) (p - host), host, request_info->uri);
+ } else {
+ mg_printf(conn, "%s", "HTTP/1.1 500 Error\r\n\r\nHost: header is not set");
+ }
+}
+
+static int begin_request_handler(struct mg_connection *conn)
+{
+ const struct mg_request_info *request_info = mg_get_request_info(conn);
+ int processed = 1;
+
+ if (!request_info->is_ssl) {
+ redirect_to_ssl(conn, request_info);
+ } else if (!is_authorized(conn, request_info)) {
+ redirect_to_login(conn, request_info);
+ } else if (strcmp(request_info->uri, authorize_url) == 0) {
+ authorize(conn, request_info);
+ } else if (strcmp(request_info->uri, "/ajax/get_messages") == 0) {
+ ajax_get_messages(conn, request_info);
+ } else if (strcmp(request_info->uri, "/ajax/send_message") == 0) {
+ ajax_send_message(conn, request_info);
+ } else {
+ // No suitable handler found, mark as not processed. Civetweb will
+ // try to serve the request.
+ processed = 0;
+ }
+ return processed;
+}
+
+static const char *options[] = {
+ "document_root", "html",
+ "listening_ports", "8081,8082s",
+ "ssl_certificate", "ssl_cert.pem",
+ "num_threads", "5",
+ NULL
+};
+
+int main(void)
+{
+ struct mg_callbacks callbacks;
+ struct mg_context *ctx;
+
+ // Initialize random number generator. It will be used later on for
+ // the session identifier creation.
+ srand((unsigned) time(0));
+
+ // Setup and start Civetweb
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.begin_request = begin_request_handler;
+ if ((ctx = mg_start(&callbacks, NULL, options)) == NULL) {
+ printf("%s\n", "Cannot start chat server, fatal exit");
+ exit(EXIT_FAILURE);
+ }
+
+ // Wait until enter is pressed, then exit
+ printf("Chat server started on ports %s, press enter to quit.\n",
+ mg_get_option(ctx, "listening_ports"));
+ getchar();
+ mg_stop(ctx);
+ printf("%s\n", "Chat server stopped.");
+
+ return EXIT_SUCCESS;
+}
+
+// vim:ts=2:sw=2:et
diff --git a/src/civetweb/examples/_obsolete/docroot/favicon.ico b/src/civetweb/examples/_obsolete/docroot/favicon.ico
new file mode 100644
index 000000000..2179aba89
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/docroot/favicon.ico
Binary files differ
diff --git a/src/civetweb/examples/_obsolete/docroot/index.html b/src/civetweb/examples/_obsolete/docroot/index.html
new file mode 100644
index 000000000..c85bec992
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/docroot/index.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" dir="ltr">
+ <!-- This file is part of the Civetweb project,
+ http://sourceforge.net/projects/civetweb/ -->
+ <head>
+ <title>Civetweb chat server</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
+ <link type="text/css" rel="stylesheet" href="style.css"/>
+ <script src="jquery.js"></script>
+ <script src="main.js"></script>
+ </head>
+
+ <body>
+ <div id="header">
+ <div id="logo"></div>
+ <div class="rounded infobox help-message" id="motd">
+ Chat room implemented using
+ <a href="http://sourceforge.net/projects/civetweb/" target="_blank">Civetweb</a>
+ embeddable web server.
+ This application was written for educational purposes demonstrating
+ how web interface could be decoupled from the business logic. Not a
+ single line of HTML is generated by the server, instead, server
+ gives data to the client in JSON format.
+ </div>
+ </div>
+ <div>
+
+ <div id="middle">
+ <div><center><span id="error" class="rounded"></span><center></div>
+
+ <div id="menu">
+ <div class="menu-item left-rounded menu-item-selected"
+ name="chat">Chat</div>
+ <div class="menu-item left-rounded" name="settings">Settings</div>
+ </div>
+
+ <div id="content" class="rounded">
+
+ <div id="chat" class="main">
+ <div class="chat-window">
+ <span class="top-rounded chat-title">Main room</span>
+ <div class="bottom-rounded chat-content">
+ <div class="message-list" id="mml">
+ </div>
+ <input type="text" size="40" class="message-input"></input>
+ <span class="help-message">
+ Type your message here and press enter</span>
+ </div>
+ </div>
+ </div>
+
+ <div id="settings" class="hidden main">
+ <div>
+ <span class="top-rounded chat-title">Settings</span>
+ <div class="bottom-rounded chat-content">
+ <table>
+ <tr><td>Max messages to display:</td><td>blah blah</td></tr>
+ <tr><td>Text color:</td><td>blah blah</td></tr>
+ </table>
+ </div>
+ </div>
+ </div>
+
+ </div>
+ </div>
+
+ <div id="footer">
+ Copyright &copy; 2004-2010 by Sergey Lyubka
+ </div>
+
+ </body>
+</html>
diff --git a/src/civetweb/examples/_obsolete/docroot/jquery.js b/src/civetweb/examples/_obsolete/docroot/jquery.js
new file mode 100644
index 000000000..7c2430802
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/docroot/jquery.js
@@ -0,0 +1,154 @@
+/*!
+ * jQuery JavaScript Library v1.4.2
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Sat Feb 13 22:33:48 2010 -0500
+ */
+(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
+e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
+j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
+"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
+true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
+Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
+(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
+a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
+"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
+function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
+c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
+L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
+"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
+a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
+d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
+a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
+!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
+true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
+parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
+s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
+applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
+else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
+a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
+w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
+cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
+i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
+" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
+this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
+e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
+function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
+k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
+C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
+null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
+e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
+f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
+if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
+"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
+a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
+isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
+{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
+if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
+e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
+"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
+d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
+!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
+toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
+u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.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".split(" "),
+function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
+if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
+t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
+g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
+for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
+1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
+CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
+relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
+l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
+h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
+CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
+g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
+text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
+setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
+h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
+m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
+"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
+h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
+!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
+h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
+q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
+if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
+(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
+function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
+gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
+c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
+{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
+"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
+d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
+a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
+1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
+a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
+""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
+this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
+u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
+1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
+return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
+""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
+c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
+c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
+function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
+Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
+"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
+a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
+a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
+"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
+serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
+function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
+global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
+e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
+"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
+false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
+false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
+c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
+d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
+g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
+1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
+"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
+if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
+this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
+"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
+animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
+j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
+this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
+"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
+c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
+this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
+this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
+e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
+c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
+function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
+this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
+k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
+f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
+c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
+d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
+f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
+"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
+e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
diff --git a/src/civetweb/examples/_obsolete/docroot/login.html b/src/civetweb/examples/_obsolete/docroot/login.html
new file mode 100644
index 000000000..2b09f01c5
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/docroot/login.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" dir="ltr">
+ <!-- This file is part of the Civetweb project,
+ http://sourceforge.net/projects/civetweb/ -->
+ <head>
+ <title>Civetweb chat: login</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
+ <!--
+ Note that this page is self-sufficient, it does not load any other
+ CSS or Javascript file. This is done so because only this page is
+ allowed for non-authorized users. If we want to load other files
+ from the frontend, we need to change backend code to allow those
+ for non-authorized users. See chat.c :: must_authorize() function.
+ -->
+ </head>
+
+ <script>
+ window.onload = function() {
+ // Set correct action for the login form. We assume that the SSL port
+ // is the next one to insecure one.
+ var httpsPort = location.protocol.match(/https/) ? location.port :
+ parseInt(location.port) + 1;
+ document.forms[0].action = 'https://' + location.hostname + ':' +
+ httpsPort + '/authorize';
+ };
+ </script>
+
+ <body>
+ <center>
+ <h2>Civetweb chat server login</h2>
+ <div style="max-width: 30em;">
+ Username and password can be any non-empty strings.
+ </div>
+ <br/>
+ <form>
+ <input type="text" name="user"></input><br/>
+ <input type="text" name="password"></input><br/>
+ <input type="submit" value="Login"></input>
+ </form>
+ </center>
+ </body>
+</html>
diff --git a/src/civetweb/examples/_obsolete/docroot/logo.png b/src/civetweb/examples/_obsolete/docroot/logo.png
new file mode 100644
index 000000000..8a47c0ab8
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/docroot/logo.png
Binary files differ
diff --git a/src/civetweb/examples/_obsolete/docroot/main.js b/src/civetweb/examples/_obsolete/docroot/main.js
new file mode 100644
index 000000000..d4af86ddb
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/docroot/main.js
@@ -0,0 +1,107 @@
+// This file is part of Civetweb project,
+// http://sourceforge.net/projects/civetweb/
+
+var chat = {
+ // Backend URL, string.
+ // 'http://backend.address.com' or '' if backend is the same as frontend
+ backendUrl: '',
+ maxVisibleMessages: 10,
+ errorMessageFadeOutTimeoutMs: 2000,
+ errorMessageFadeOutTimer: null,
+ lastMessageId: 0,
+ getMessagesIntervalMs: 1000,
+};
+
+chat.normalizeText = function(text) {
+ return text.replace('<', '&lt;').replace('>', '&gt;');
+};
+
+chat.refresh = function(data) {
+
+ if (data === undefined) {
+ return;
+ }
+
+ $.each(data, function(index, entry) {
+ var row = $('<div>').addClass('message-row').appendTo('#mml');
+ var timestamp = (new Date(entry.timestamp * 1000)).toLocaleTimeString();
+ $('<span>')
+ .addClass('message-timestamp')
+ .html('[' + timestamp + ']')
+ .prependTo(row);
+ $('<span>')
+ .addClass('message-user')
+ .addClass(entry.user ? '' : 'message-user-server')
+ .html(chat.normalizeText((entry.user || '[server]') + ':'))
+ .appendTo(row);
+ $('<span>')
+ .addClass('message-text')
+ .addClass(entry.user ? '' : 'message-text-server')
+ .html(chat.normalizeText(entry.text))
+ .appendTo(row);
+ chat.lastMessageId = Math.max(chat.lastMessageId, entry.id) + 1;
+ });
+
+ // Keep only chat.maxVisibleMessages, delete older ones.
+ while ($('#mml').children().length > chat.maxVisibleMessages) {
+ $('#mml div:first-child').remove();
+ }
+};
+
+chat.getMessages = function(enter_loop) {
+ $.ajax({
+ dataType: 'jsonp',
+ url: chat.backendUrl + '/ajax/get_messages',
+ data: {last_id: chat.lastMessageId},
+ success: chat.refresh,
+ error: function() {
+ },
+ });
+ if (enter_loop) {
+ window.setTimeout('chat.getMessages(true)', chat.getMessagesIntervalMs);
+ }
+};
+
+chat.handleMenuItemClick = function(ev) {
+ $('.menu-item').removeClass('menu-item-selected'); // Deselect menu buttons
+ $(this).addClass('menu-item-selected'); // Select clicked button
+ $('.main').addClass('hidden'); // Hide all main windows
+ $('#' + $(this).attr('name')).removeClass('hidden'); // Show main window
+};
+
+chat.showError = function(message) {
+ $('#error').html(message).fadeIn('fast');
+ window.clearTimeout(chat.errorMessageFadeOutTimer);
+ chat.errorMessageFadeOutTimer = window.setTimeout(function() {
+ $('#error').fadeOut('slow');
+ }, chat.errorMessageFadeOutTimeoutMs);
+};
+
+chat.handleMessageInput = function(ev) {
+ var input = ev.target;
+ if (ev.keyCode != 13 || !input.value)
+ return;
+ //input.disabled = true;
+ $.ajax({
+ dataType: 'jsonp',
+ url: chat.backendUrl + '/ajax/send_message',
+ data: {text: input.value},
+ success: function(ev) {
+ input.value = '';
+ input.disabled = false;
+ chat.getMessages(false);
+ },
+ error: function(ev) {
+ chat.showError('Error sending message');
+ input.disabled = false;
+ },
+ });
+};
+
+$(document).ready(function() {
+ $('.menu-item').click(chat.handleMenuItemClick);
+ $('.message-input').keypress(chat.handleMessageInput);
+ chat.getMessages(true);
+});
+
+// vim:ts=2:sw=2:et
diff --git a/src/civetweb/examples/_obsolete/docroot/prime_numbers.lp b/src/civetweb/examples/_obsolete/docroot/prime_numbers.lp
new file mode 100644
index 000000000..0c71bb824
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/docroot/prime_numbers.lp
@@ -0,0 +1,46 @@
+HTTP/1.0 200 OK
+Content-Type: text/html
+
+<html>
+ <p>Prime numbers from 0 to 100, calculated by Lua:</p>
+ <?
+ function is_prime(n)
+ if n <= 0 then return false end
+ if n <= 2 then return true end
+ if (n % 2 == 0) then return false end
+ for i = 3, n / 2, 2 do
+ if (n % i == 0) then return false end
+ end
+ return true
+ end
+
+ for i = 1, 100 do
+ if is_prime(i) then mg.write('<span>' .. i .. '</span>&nbsp;') end
+ end
+
+ ?>
+
+ <p>Reading POST data from Lua (click submit):</p>
+ <form method="POST" ><input type="text" name="t1"/><input type="submit"></form>
+
+ <pre>
+ POST data: [<?
+ local post_data = ''
+ if mg.request_info.request_method == 'POST' then
+ post_data = mg.read()
+ end
+ mg.write(post_data)
+ ?>]
+ request method: [<? mg.write(mg.request_info.request_method) ?>]
+ IP/port: [<? mg.write(mg.request_info.remote_ip, ':',
+ mg.request_info.remote_port) ?>]
+ URI: [<? mg.write(mg.request_info.uri) ?>]
+ HTTP version [<? mg.write(mg.request_info.http_version) ?>]
+ HEADERS:
+ <?
+ for name, value in pairs(mg.request_info.http_headers) do
+ mg.write(name, ':', value, '\n')
+ end
+ ?>
+</pre>
+</html>
diff --git a/src/civetweb/examples/_obsolete/docroot/style.css b/src/civetweb/examples/_obsolete/docroot/style.css
new file mode 100644
index 000000000..716351d2d
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/docroot/style.css
@@ -0,0 +1,154 @@
+/*
+ * vim:ts=2:sw=2:et:ai
+ */
+
+body {
+ font: 13px Arial; margin: 0.5em 1em;
+}
+
+#logo {
+ background: url('logo.png') no-repeat ;
+ width: 160px;
+ height: 40px;
+ float: left;
+}
+
+td {
+ text-align: left;
+}
+
+#motd {
+ margin-left: 170px;
+}
+
+.infobox {
+ background: #eed;
+ padding: 1px 1em;
+}
+
+.help-message {
+ color: #aaa;
+}
+
+#middle {
+ margin: 0.5em 0;
+}
+
+#error {
+ background: #c44;
+ color: white;
+ font-weight: bold;
+}
+
+#content, .menu-item-selected, .chat-title, .chat-content {
+ background: #c3d9ff;
+}
+
+#content {
+ overflow: hidden;
+ min-height: 7em;
+ padding: 1em;
+}
+
+.chat-title {
+ padding: 1px 1ex;
+}
+
+.chat-content {
+ padding: 1ex;
+}
+
+.chat-window {
+}
+
+.message-row {
+ margin: 2px;
+ border-bottom: 1px solid #bbb;
+}
+
+.message-timestamp {
+ color: #484;
+}
+
+.message-user {
+ margin-left: 0.5em;
+ font-weight: bold;
+}
+
+.message-text {
+ margin-left: 0.5em;
+}
+
+.message-user-server {
+ color: purple;
+}
+
+.message-text-server {
+ font-style: italic;
+}
+
+.main {
+ padding: 0.5em;
+ background: #f0fcff;
+}
+
+#menu {
+ margin-top: 1em;
+ min-width: 7em;
+ float: left;
+}
+
+#footer {
+ position: fixed;
+ bottom: 0;
+ right: 0;
+ color: #ccc;
+ padding: 0.5em;
+}
+
+.section {
+ clear: both;
+}
+
+.hidden {
+ display: none;
+}
+
+.menu-item {
+ cursor: pointer;
+ padding: 0.1em 0.5em;
+}
+
+.menu-item-selected {
+ font-weight: bold;
+}
+
+.message-list {
+ min-height: 1em;
+ background: white;
+ margin: 0.5em 0;
+}
+
+.rounded {
+ border-radius: 6px;
+ -moz-border-radius: 6px;
+ -webkit-border-radius: 6px;
+}
+
+.left-rounded {
+ border-radius: 6px 0 0 6px;
+ -moz-border-radius: 6px 0 0 6px;
+ -webkit-border-radius: 6px 0 0 6px;
+}
+
+.bottom-rounded {
+ border-radius: 0 0 6px 6px;
+ -moz-border-radius: 0 0 6px 6px;
+ -webkit-border-radius: 0 0 6px 6px;
+}
+
+.top-rounded {
+ border-radius: 6px 6px 0 0;
+ -moz-border-radius: 6px 6px 0 0;
+ -webkit-border-radius: 6px 6px 0 0;
+}
diff --git a/src/civetweb/examples/_obsolete/hello/Makefile b/src/civetweb/examples/_obsolete/hello/Makefile
new file mode 100644
index 000000000..4424e3b58
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/hello/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2013 No Face Press, LLC
+# License http://opensource.org/licenses/mit-license.php MIT License
+#
+
+#This makefile is used to test the other Makefiles
+
+
+PROG = hello
+SRC = hello.c
+
+TOP = ../..
+CIVETWEB_LIB = libcivetweb.a
+
+CFLAGS = -I$(TOP)/include $(COPT)
+LIBS = -lpthread
+
+include $(TOP)/resources/Makefile.in-os
+
+ifeq ($(TARGET_OS),LINUX)
+ LIBS += -ldl
+endif
+
+all: $(PROG)
+
+$(PROG): $(CIVETWEB_LIB) $(SRC)
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS)
+
+$(CIVETWEB_LIB):
+ $(MAKE) -C $(TOP) clean lib
+ cp $(TOP)/$(CIVETWEB_LIB) .
+
+clean:
+ rm -f $(CIVETWEB_LIB) $(PROG)
+
+.PHONY: all clean
diff --git a/src/civetweb/examples/_obsolete/hello/hello.c b/src/civetweb/examples/_obsolete/hello/hello.c
new file mode 100644
index 000000000..39253c1ad
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/hello/hello.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <string.h>
+#include "civetweb.h"
+
+// This function will be called by civetweb on every new request.
+static int begin_request_handler(struct mg_connection *conn)
+{
+ const struct mg_request_info *request_info = mg_get_request_info(conn);
+ char content[100];
+
+ // Prepare the message we're going to send
+ int content_length = snprintf(content, sizeof(content),
+ "Hello from civetweb! Remote port: %d",
+ request_info->remote_port);
+
+ // Send HTTP reply to the client
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Length: %d\r\n" // Always set Content-Length
+ "\r\n"
+ "%s",
+ content_length, content);
+
+ // Returning non-zero tells civetweb that our function has replied to
+ // the client, and civetweb should not send client any more data.
+ return 1;
+}
+
+int main(void)
+{
+ struct mg_context *ctx;
+ struct mg_callbacks callbacks;
+
+ // List of options. Last element must be NULL.
+ const char *options[] = {"listening_ports", "8080", NULL};
+
+ // Prepare callbacks structure. We have only one callback, the rest are NULL.
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.begin_request = begin_request_handler;
+
+ // Start the web server.
+ ctx = mg_start(&callbacks, NULL, options);
+
+ // Wait until user hits "enter". Server is running in separate thread.
+ // Navigating to http://localhost:8080 will invoke begin_request_handler().
+ getchar();
+
+ // Stop the server.
+ mg_stop(ctx);
+
+ return 0;
+}
diff --git a/src/civetweb/examples/_obsolete/lua/lua_dll.c b/src/civetweb/examples/_obsolete/lua/lua_dll.c
new file mode 100644
index 000000000..79e6b97c0
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/lua/lua_dll.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+
+static int smile(lua_State *L)
+{
+ (void) L; // Unused
+ printf("%s\n", ":-)");
+ return 0;
+}
+
+int LUA_API luaopen_lua_dll(lua_State *L)
+{
+ static const struct luaL_Reg api[] = {
+ {"smile", smile},
+ {NULL, NULL},
+ };
+ luaL_openlib(L, "lua_dll", api, 0);
+ return 1;
+}
diff --git a/src/civetweb/examples/_obsolete/post/Makefile b/src/civetweb/examples/_obsolete/post/Makefile
new file mode 100644
index 000000000..6e504f437
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/post/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2013 No Face Press, LLC
+# License http://opensource.org/licenses/mit-license.php MIT License
+#
+
+#This makefile is used to test the other Makefiles
+
+
+PROG = post
+SRC = post.c
+
+TOP = ../..
+CIVETWEB_LIB = libcivetweb.a
+
+CFLAGS = -I$(TOP)/include $(COPT)
+LIBS = -lpthread
+
+include $(TOP)/resources/Makefile.in-os
+
+ifeq ($(TARGET_OS),LINUX)
+ LIBS += -ldl
+endif
+
+all: $(PROG)
+
+$(PROG): $(CIVETWEB_LIB) $(SRC)
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS)
+
+$(CIVETWEB_LIB):
+ $(MAKE) -C $(TOP) clean lib
+ cp $(TOP)/$(CIVETWEB_LIB) .
+
+clean:
+ rm -f $(CIVETWEB_LIB) $(PROG)
+
+.PHONY: all clean
diff --git a/src/civetweb/examples/_obsolete/post/post.c b/src/civetweb/examples/_obsolete/post/post.c
new file mode 100644
index 000000000..3c5c68c8d
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/post/post.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <string.h>
+#include "civetweb.h"
+
+static const char *html_form =
+ "<html><body>POST example."
+ "<form method=\"POST\" action=\"/handle_post_request\">"
+ "Input 1: <input type=\"text\" name=\"input_1\" /> <br/>"
+ "Input 2: <input type=\"text\" name=\"input_2\" /> <br/>"
+ "<input type=\"submit\" />"
+ "</form></body></html>";
+
+static int begin_request_handler(struct mg_connection *conn)
+{
+ const struct mg_request_info *ri = mg_get_request_info(conn);
+ char post_data[1024], input1[sizeof(post_data)], input2[sizeof(post_data)];
+ int post_data_len;
+
+ if (!strcmp(ri->uri, "/handle_post_request")) {
+ // User has submitted a form, show submitted data and a variable value
+ post_data_len = mg_read(conn, post_data, sizeof(post_data));
+
+ // Parse form data. input1 and input2 are guaranteed to be NUL-terminated
+ mg_get_var(post_data, post_data_len, "input_1", input1, sizeof(input1));
+ mg_get_var(post_data, post_data_len, "input_2", input2, sizeof(input2));
+
+ // Send reply to the client, showing submitted form values.
+ mg_printf(conn, "HTTP/1.0 200 OK\r\n"
+ "Content-Type: text/plain\r\n\r\n"
+ "Submitted data: [%.*s]\n"
+ "Submitted data length: %d bytes\n"
+ "input_1: [%s]\n"
+ "input_2: [%s]\n",
+ post_data_len, post_data, post_data_len, input1, input2);
+ } else {
+ // Show HTML form.
+ mg_printf(conn, "HTTP/1.0 200 OK\r\n"
+ "Content-Length: %d\r\n"
+ "Content-Type: text/html\r\n\r\n%s",
+ (int) strlen(html_form), html_form);
+ }
+ return 1; // Mark request as processed
+}
+
+int main(void)
+{
+ struct mg_context *ctx;
+ const char *options[] = {"listening_ports", "8080", NULL};
+ struct mg_callbacks callbacks;
+
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.begin_request = begin_request_handler;
+ ctx = mg_start(&callbacks, NULL, options);
+ getchar(); // Wait until user hits "enter"
+ mg_stop(ctx);
+
+ return 0;
+}
diff --git a/src/civetweb/examples/_obsolete/upload/Makefile b/src/civetweb/examples/_obsolete/upload/Makefile
new file mode 100644
index 000000000..9c6270fb2
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/upload/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2013 No Face Press, LLC
+# License http://opensource.org/licenses/mit-license.php MIT License
+#
+
+#This makefile is used to test the other Makefiles
+
+
+PROG = upload
+SRC = upload.c
+
+TOP = ../..
+CIVETWEB_LIB = libcivetweb.a
+
+CFLAGS = -I$(TOP)/include $(COPT)
+LIBS = -lpthread
+
+include $(TOP)/resources/Makefile.in-os
+
+ifeq ($(TARGET_OS),LINUX)
+ LIBS += -ldl
+endif
+
+all: $(PROG)
+
+$(PROG): $(CIVETWEB_LIB) $(SRC)
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS)
+
+$(CIVETWEB_LIB):
+ $(MAKE) -C $(TOP) clean lib
+ cp $(TOP)/$(CIVETWEB_LIB) .
+
+clean:
+ rm -f $(CIVETWEB_LIB) $(PROG)
+
+.PHONY: all clean
diff --git a/src/civetweb/examples/_obsolete/upload/upload.c b/src/civetweb/examples/_obsolete/upload/upload.c
new file mode 100644
index 000000000..56c4be4f3
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/upload/upload.c
@@ -0,0 +1,110 @@
+/* Copyright (c) 2014 the Civetweb developers
+ * Copyright (c) 2004-2012 Sergey Lyubka
+ * This file is a part of civetweb project, http://github.com/bel2125/civetweb
+ */
+
+/* This example is deprecated and no longer maintained.
+ * All relevant parts have been merged into the embedded_c example. */
+
+
+#ifdef _WIN32
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+#include <windows.h>
+#include <io.h>
+#define strtoll strtol
+typedef __int64 int64_t;
+#else
+#include <inttypes.h>
+#include <unistd.h>
+#endif /* !_WIN32 */
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "civetweb.h"
+
+
+/* callback: used to generate all content */
+static int begin_request_handler(struct mg_connection *conn)
+{
+ const char * tempPath = ".";
+#ifdef _WIN32
+ const char * env = getenv("TEMP");
+ if (!env) env = getenv("TMP");
+ if (env) tempPath = env;
+#else
+ tempPath = "/tmp";
+#endif
+
+ if (!strcmp(mg_get_request_info(conn)->uri, "/handle_post_request")) {
+
+ mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n\r\n");
+ mg_upload(conn, tempPath);
+ } else {
+ /* Show HTML form. */
+ /* See http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 */
+ static const char *html_form =
+ "<html><body>Upload example."
+ ""
+ /* enctype="multipart/form-data" */
+ "<form method=\"POST\" action=\"/handle_post_request\" "
+ " enctype=\"multipart/form-data\">"
+ "<input type=\"file\" name=\"file\" /> <br/>"
+ "<input type=\"file\" name=\"file2\" /> <br/>"
+ "<input type=\"submit\" value=\"Upload\" />"
+ "</form>"
+ ""
+ "</body></html>";
+
+ mg_printf(conn, "HTTP/1.0 200 OK\r\n"
+ "Content-Length: %d\r\n"
+ "Content-Type: text/html\r\n\r\n%s",
+ (int) strlen(html_form), html_form);
+ }
+
+ /* Mark request as processed */
+ return 1;
+}
+
+
+/* callback: called after uploading a file is completed */
+static void upload_handler(struct mg_connection *conn, const char *path)
+{
+ mg_printf(conn, "Saved [%s]", path);
+}
+
+
+/* Main program: Set callbacks and start the server. */
+int main(void)
+{
+ /* Test server will use this port */
+ const char * PORT = "8080";
+
+ /* Startup options for the server */
+ struct mg_context *ctx;
+ const char *options[] = {
+ "listening_ports", PORT,
+ NULL};
+ struct mg_callbacks callbacks;
+
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.begin_request = begin_request_handler;
+ callbacks.upload = upload_handler;
+
+ /* Display a welcome message */
+ printf("File upload demo.\n");
+ printf("Open http://localhost:%s/ in your browser.\n\n", PORT);
+
+ /* Start the server */
+ ctx = mg_start(&callbacks, NULL, options);
+
+ /* Wait until thr user hits "enter", then stop the server */
+ getchar();
+ mg_stop(ctx);
+
+ return 0;
+}
diff --git a/src/civetweb/examples/_obsolete/websocket/Makefile b/src/civetweb/examples/_obsolete/websocket/Makefile
new file mode 100644
index 000000000..3d6549297
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2013 No Face Press, LLC
+# License http://opensource.org/licenses/mit-license.php MIT License
+#
+
+#This makefile is used to test the other Makefiles
+
+
+PROG = websocket
+SRC = WebSockCallbacks.c websocket.c
+
+TOP = ../..
+CIVETWEB_LIB = libcivetweb.a
+
+CFLAGS = -I$(TOP)/include $(COPT)
+LIBS = -lpthread
+
+include $(TOP)/resources/Makefile.in-os
+
+ifeq ($(TARGET_OS),LINUX)
+ LIBS += -ldl
+endif
+
+all: $(PROG)
+
+$(PROG): $(CIVETWEB_LIB) $(SRC)
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS)
+
+$(CIVETWEB_LIB):
+ $(MAKE) -C $(TOP) clean lib WITH_WEBSOCKET=1
+ cp $(TOP)/$(CIVETWEB_LIB) .
+
+clean:
+ rm -f $(CIVETWEB_LIB) $(PROG)
+
+.PHONY: all clean
diff --git a/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.c b/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.c
new file mode 100644
index 000000000..bb81fb0cc
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.c
@@ -0,0 +1,225 @@
+/* This example uses deprecated interfaces: global websocket callbacks.
+ They have been superseeded by URI specific callbacks.
+ See examples/embedded_c for an up to date example.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include "WebSockCallbacks.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#define mg_sleep(x) Sleep(x)
+#else
+#include <unistd.h>
+#include <pthread.h>
+#define mg_sleep(x) usleep((x)*1000)
+#endif
+
+
+static void
+send_to_all_websockets(struct mg_context *ctx, const char *data, int data_len)
+{
+
+ int i;
+ tWebSockContext *ws_ctx = (tWebSockContext *)mg_get_user_data(ctx);
+
+ mg_lock_context(ctx);
+ for (i = 0; i < MAX_NUM_OF_WEBSOCKS; i++) {
+ if (ws_ctx->socketList[i]
+ && (ws_ctx->socketList[i]->webSockState == 2)) {
+ mg_websocket_write(ws_ctx->socketList[i]->conn,
+ WEBSOCKET_OPCODE_TEXT,
+ data,
+ data_len);
+ }
+ }
+ mg_unlock_context(ctx);
+}
+
+
+void
+websocket_ready_handler(struct mg_connection *conn, void *_ignored)
+{
+
+ int i;
+ const struct mg_request_info *rq = mg_get_request_info(conn);
+ struct mg_context *ctx = mg_get_context(conn);
+ tWebSockContext *ws_ctx = (tWebSockContext *)mg_get_user_data(ctx);
+ tWebSockInfo *wsock = malloc(sizeof(tWebSockInfo));
+ assert(wsock);
+ wsock->webSockState = 0;
+ mg_set_user_connection_data(conn, wsock);
+
+ mg_lock_context(ctx);
+ for (i = 0; i < MAX_NUM_OF_WEBSOCKS; i++) {
+ if (0 == ws_ctx->socketList[i]) {
+ ws_ctx->socketList[i] = wsock;
+ wsock->conn = conn;
+ wsock->webSockState = 1;
+ break;
+ }
+ }
+ printf("\nNew websocket attached: %s:%u\n",
+ rq->remote_addr,
+ rq->remote_port);
+ mg_unlock_context(ctx);
+}
+
+
+static void
+websocket_done(tWebSockContext *ws_ctx, tWebSockInfo *wsock)
+{
+
+ int i;
+
+ if (wsock) {
+ wsock->webSockState = 99;
+ for (i = 0; i < MAX_NUM_OF_WEBSOCKS; i++) {
+ if (wsock == ws_ctx->socketList[i]) {
+ ws_ctx->socketList[i] = 0;
+ break;
+ }
+ }
+ printf("\nClose websocket attached: %s:%u\n",
+ mg_get_request_info(wsock->conn)->remote_addr,
+ mg_get_request_info(wsock->conn)->remote_port);
+ free(wsock);
+ }
+}
+
+
+int
+websocket_data_handler(struct mg_connection *conn,
+ int flags,
+ char *data,
+ size_t data_len,
+ void *_ignored)
+{
+
+ const struct mg_request_info *rq = mg_get_request_info(conn);
+ tWebSockInfo *wsock = (tWebSockInfo *)rq->conn_data;
+ struct mg_context *ctx = mg_get_context(conn);
+ tWebSockContext *ws_ctx = (tWebSockContext *)mg_get_user_data(ctx);
+ char msg[128];
+
+ mg_lock_context(ctx);
+ if (flags == 136) {
+ // close websock
+ websocket_done(ws_ctx, wsock);
+ mg_set_user_connection_data(conn, NULL);
+ mg_unlock_context(ctx);
+ return 1;
+ }
+ if (((data_len >= 5) && (data_len < 100) && (flags == 129))
+ || (flags == 130)) {
+
+ // init command
+ if ((wsock->webSockState == 1) && (!memcmp(data, "init ", 5))) {
+ char *chk;
+ unsigned long gid;
+ memcpy(msg, data + 5, data_len - 5);
+ msg[data_len - 5] = 0;
+ gid = strtoul(msg, &chk, 10);
+ wsock->initId = gid;
+ if (gid > 0 && chk != NULL && *chk == 0) {
+ wsock->webSockState = 2;
+ }
+ mg_unlock_context(ctx);
+ return 1;
+ }
+
+ // chat message
+ if ((wsock->webSockState == 2) && (!memcmp(data, "msg ", 4))) {
+ send_to_all_websockets(ctx, data, data_len);
+ mg_unlock_context(ctx);
+ return 1;
+ }
+ }
+
+ // keep alive
+ if ((data_len == 4) && !memcmp(data, "ping", 4)) {
+ mg_unlock_context(ctx);
+ return 1;
+ }
+
+ mg_unlock_context(ctx);
+ return 0;
+}
+
+
+void
+connection_close_handler(const struct mg_connection *conn, void *_ignored)
+{
+
+ const struct mg_request_info *rq = mg_get_request_info(conn);
+ tWebSockInfo *wsock = (tWebSockInfo *)rq->conn_data;
+ struct mg_context *ctx = mg_get_context(conn);
+ tWebSockContext *ws_ctx = (tWebSockContext *)mg_get_user_data(ctx);
+
+ mg_lock_context(ctx);
+ websocket_done(ws_ctx, wsock);
+ mg_set_user_connection_data(conn, NULL);
+ mg_unlock_context(ctx);
+}
+
+
+static void *
+eventMain(void *arg)
+{
+
+ char msg[256];
+ struct mg_context *ctx = (struct mg_context *)arg;
+ tWebSockContext *ws_ctx = (tWebSockContext *)mg_get_user_data(ctx);
+
+ ws_ctx->runLoop = 1;
+ while (ws_ctx->runLoop) {
+ time_t t = time(0);
+ struct tm *timestr = localtime(&t);
+ strftime(msg, sizeof(msg), "title %c", timestr);
+ send_to_all_websockets(ctx, msg, strlen(msg));
+
+ mg_sleep(1000);
+ }
+
+ return NULL;
+}
+
+
+void
+websock_send_broadcast(struct mg_context *ctx, const char *data, int data_len)
+{
+
+ char buffer[260];
+
+ if (data_len <= 256) {
+ strcpy(buffer, "msg ");
+ memcpy(buffer + 4, data, data_len);
+
+ send_to_all_websockets(ctx, buffer, data_len + 4);
+ }
+}
+
+
+void
+websock_init_lib(const struct mg_context *ctx)
+{
+
+ tWebSockContext *ws_ctx = (tWebSockContext *)mg_get_user_data(ctx);
+ memset(ws_ctx, 0, sizeof(*ws_ctx));
+ /* todo: use mg_start_thread_id instead of mg_start_thread */
+ mg_start_thread(eventMain, (void *)ctx);
+}
+
+
+void
+websock_exit_lib(const struct mg_context *ctx)
+{
+
+ tWebSockContext *ws_ctx = (tWebSockContext *)mg_get_user_data(ctx);
+ ws_ctx->runLoop = 0;
+ /* todo: wait for the thread instead of a timeout */
+ mg_sleep(2000);
+}
diff --git a/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.h b/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.h
new file mode 100644
index 000000000..f44821daf
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket/WebSockCallbacks.h
@@ -0,0 +1,44 @@
+
+#ifndef WEBSOCKCALLBACKS_H_INCLUDED
+#define WEBSOCKCALLBACKS_H_INCLUDED
+
+#include "civetweb.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct tWebSockInfo {
+ int webSockState;
+ unsigned long initId;
+ struct mg_connection *conn;
+} tWebSockInfo;
+
+#define MAX_NUM_OF_WEBSOCKS (256)
+typedef struct tWebSockContext {
+ int runLoop;
+ void *thread_id;
+ tWebSockInfo *socketList[MAX_NUM_OF_WEBSOCKS];
+} tWebSockContext;
+
+
+void websock_init_lib(const struct mg_context *ctx);
+void websock_exit_lib(const struct mg_context *ctx);
+
+void
+websock_send_broadcast(struct mg_context *ctx, const char *data, int data_len);
+
+void websocket_ready_handler(struct mg_connection *conn, void *_ignored);
+int websocket_data_handler(struct mg_connection *conn,
+ int flags,
+ char *data,
+ size_t data_len,
+ void *_ignored);
+void connection_close_handler(const struct mg_connection *conn, void *_ignored);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/src/civetweb/examples/_obsolete/websocket/websock.htm b/src/civetweb/examples/_obsolete/websocket/websock.htm
new file mode 100644
index 000000000..4ff3a5fae
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket/websock.htm
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Test</title>
+ <script type='text/javascript' language="javascript">
+ <!--
+ var connection;
+ var keepAlive = false;
+
+ function webSockKeepAlive() {
+ if (keepAlive) {
+ connection.send('ping'); // Send the message 'ping' to the server
+ setTimeout("webSockKeepAlive()", 10000);
+ }
+ }
+
+ function load() {
+ connection = new WebSocket("ws://127.0.0.1/MyWebSock");
+
+ connection.onopen = function () {
+ var send = "init " + Math.round(Math.random()*4294967294+1);
+ console.log('Client: ' + send);
+ connection.send(send);
+ keepAlive = true;
+ webSockKeepAlive();
+ };
+
+ connection.onerror = function (error) {
+ keepAlive = false;
+ connection.close();
+ console.log('WebSocket error: ' + error);
+ alert("WebSocket error");
+ };
+
+ connection.onmessage = function (e) {
+ console.log('Server: ' + e.data);
+ if (e.data.substring(0,5) == "title") {window.document.title = e.data.substring(6);}
+ else if (e.data.substring(0,3) == "msg") {
+ var msgStr = document.getElementById('msg');
+ msgStr.innerHTML = msgStr.innerHTML + e.data.substring(4);
+ }
+ };
+ }
+ //-->
+ </script>
+
+</head>
+<body onload="load()">
+ <input type="button" onclick="connection.send('msg A');" value="A"></button>
+ <input type="button" onclick="connection.send('msg B');" value="B"></button>
+ <input type="button" onclick="connection.send('msg C');" value="C"></button>
+ <input type="button" onclick="connection.send('msg D');" value="D"></button>
+ <b id="msg"></b>
+</body>
+</html> \ No newline at end of file
diff --git a/src/civetweb/examples/_obsolete/websocket/websocket.c b/src/civetweb/examples/_obsolete/websocket/websocket.c
new file mode 100644
index 000000000..3aadf98b8
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket/websocket.c
@@ -0,0 +1,65 @@
+/* This example uses deprecated interfaces: global websocket callbacks.
+ They have been superseeded by URI specific callbacks.
+ See examples/embedded_c for an up to date example.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "civetweb.h"
+#include "WebSockCallbacks.h"
+
+int
+main(void)
+{
+ struct mg_context *ctx = 0;
+ struct mg_callbacks callback_funcs = {0};
+ tWebSockContext ws_ctx;
+ char inbuf[4];
+
+ const char *server_options[] = {
+ /* document_root: The path to the test function websock.htm */
+ "document_root",
+ "../../examples/websocket",
+
+ /* port: use http standard to match websocket url in websock.htm:
+ ws://127.0.0.1/MyWebSock */
+ /* if the port is changed here, it needs to be changed in
+ websock.htm as well */
+ "listening_ports",
+ "80",
+
+ NULL};
+
+ callback_funcs.init_context = websock_init_lib;
+ callback_funcs.exit_context = websock_exit_lib;
+
+ ctx = mg_start(&callback_funcs, &ws_ctx, server_options);
+
+ mg_set_websocket_handler(ctx,
+ "/MyWebSock",
+ NULL,
+ websocket_ready_handler,
+ websocket_data_handler,
+ connection_close_handler,
+ NULL);
+
+ printf("Connect to localhost:%s/websock.htm\n",
+ mg_get_option(ctx, "listening_ports"));
+
+ puts("Enter an (ASCII) character or * to exit:");
+ for (;;) {
+ fgets(inbuf, sizeof(inbuf), stdin);
+
+ if (inbuf[0] == '*') {
+ break;
+ }
+ inbuf[0] = toupper(inbuf[0]);
+ websock_send_broadcast(ctx, inbuf, 1);
+ }
+
+ mg_stop(ctx);
+
+ return 0;
+}
diff --git a/src/civetweb/examples/_obsolete/websocket_client/Makefile b/src/civetweb/examples/_obsolete/websocket_client/Makefile
new file mode 100644
index 000000000..e3ef13468
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket_client/Makefile
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2014 Jordan Shelley
+# https://github.com/jshelley
+# License http://opensource.org/licenses/mit-license.php MIT License
+#
+
+#This makefile is used to test the other Makefiles
+
+
+PROG = websocket_client
+SRC = websocket_client.c
+
+TOP = ../..
+CIVETWEB_LIB = libcivetweb.a
+
+CFLAGS = -I$(TOP)/include $(COPT)
+LIBS = -lpthread
+
+include $(TOP)/resources/Makefile.in-os
+
+ifeq ($(TARGET_OS),LINUX)
+ LIBS += -ldl
+endif
+
+all: $(PROG)
+
+$(PROG): $(CIVETWEB_LIB) $(SRC)
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS)
+
+$(CIVETWEB_LIB):
+ $(MAKE) -C $(TOP) clean lib WITH_WEBSOCKET=1
+ cp $(TOP)/$(CIVETWEB_LIB) .
+
+clean:
+ rm -f $(CIVETWEB_LIB) $(PROG)
+
+.PHONY: all clean
diff --git a/src/civetweb/examples/_obsolete/websocket_client/ssl/server.crt b/src/civetweb/examples/_obsolete/websocket_client/ssl/server.crt
new file mode 100644
index 000000000..a26359abf
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket_client/ssl/server.crt
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQC2BCIqIvgSUTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE0MDgyMTEyMzAwMVoXDTI0MDgxODEyMzAwMVowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA9k9s
+gH22BCo9neTeB/YnilK7n0sMe0+pjS9KSWhU59Q4w8hqPrW0tuYikIDd0wVggkJF
+BZNg4WPoulTdwXsgNBeG88q2wnNtUosXTS+KQTQBSiQof9Ay9GHQtgxnogI1zIXb
+HOppyyG5zre8a/X6fzDOnFc4iJMBwxTAnjCqObkCAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQBX9V46VUVsB9P9fb8sFuMx2ezFE42ynEeJPrKRrof+dFYbjvR1OUZFSLCy
+aZKwVH7iCnVBJiU12JxO7PR3L6ob3FYPyNHQWYq1/IFUvqBRagehldj5H8iFeEDz
+Wtz2+p1rUyVxcSUqTjobaji0aC8lzPZio0nd1KKM6A92/adHyQ==
+-----END CERTIFICATE-----
diff --git a/src/civetweb/examples/_obsolete/websocket_client/ssl/server.csr b/src/civetweb/examples/_obsolete/websocket_client/ssl/server.csr
new file mode 100644
index 000000000..4d4723b24
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket_client/ssl/server.csr
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
+MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQD2T2yAfbYEKj2d5N4H9ieKUrufSwx7T6mNL0pJaFTn1DjD
+yGo+tbS25iKQgN3TBWCCQkUFk2DhY+i6VN3BeyA0F4bzyrbCc21SixdNL4pBNAFK
+JCh/0DL0YdC2DGeiAjXMhdsc6mnLIbnOt7xr9fp/MM6cVziIkwHDFMCeMKo5uQID
+AQABoAAwDQYJKoZIhvcNAQEFBQADgYEA1EOFwyFJ2NAnRNktZCy5yVcLx9C78HoC
+oHPPCOElu0VDIqe6ZecYdaqWbYlhGE0+isbOQn2CwHOeBGN8mIDsNUYzVEpsEfgg
+9OK873LpE5pf4mdjSiRBXkk/h8BxuqkcKi+Qx+qEE7+dH2nK5aKeIHVvbLyfGOch
+9I85q+msBNE=
+-----END CERTIFICATE REQUEST-----
diff --git a/src/civetweb/examples/_obsolete/websocket_client/ssl/server.key b/src/civetweb/examples/_obsolete/websocket_client/ssl/server.key
new file mode 100644
index 000000000..f09cc38cb
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket_client/ssl/server.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQD2T2yAfbYEKj2d5N4H9ieKUrufSwx7T6mNL0pJaFTn1DjDyGo+
+tbS25iKQgN3TBWCCQkUFk2DhY+i6VN3BeyA0F4bzyrbCc21SixdNL4pBNAFKJCh/
+0DL0YdC2DGeiAjXMhdsc6mnLIbnOt7xr9fp/MM6cVziIkwHDFMCeMKo5uQIDAQAB
+AoGAYwospr3lomcZv5N3c9wWqhf6OWMD8dFma87IIBxDh7Rd3tuHXQ/TSnffDhvD
+FkbjN31OI5/PJNH3knTtdg78MywPloE4jYsbt4+fEaW7Fzww2nU61N1p+mYk5d/b
+SCTAHhGzF9g9ZMw25CCUFGjDU2z+Ty6my22Euxhk2Qq8tMECQQD9ZYIxWkPhywDW
+pX3v70dqIv7411hEYpuL/ZJl26UCmQsj4HPtXQCraQksVPs74WY5aTtd6MAV9V3M
+UnErHO5/AkEA+NdG2MmfBOBPusDB/WwQaUPiCWGITS9llGTR2JXbvDqmKgL1+UTG
+o27sLNIFCrF1wejpyRGqwjcObFYR0yKrxwJBAOB2uPuK4DL1psp9Uq/mIDbOxVod
+OF1rlCpP9w0vol5Iv+uJ+mc7SUqOAsg4h0yl/+2/YA1yDiXlcq96IDF2sXUCQGAv
+Nh9Nr72+xpK1N0axopZNuu1NWdYb3/PAFKzXIBxdvyS2CEXVo8JAeeHJPFGpzo6p
+bNRfk9WGWnjdu/4UhLkCQQCekR9zpIpzdJiPYCd6XMya+TPCDYlOQL1jlnJIRa2V
+BEOz0rSpzXAGh0PyCB/kMneyVk87LWn8joE6179RoUfv
+-----END RSA PRIVATE KEY-----
diff --git a/src/civetweb/examples/_obsolete/websocket_client/ssl/server.key.orig b/src/civetweb/examples/_obsolete/websocket_client/ssl/server.key.orig
new file mode 100644
index 000000000..58e5653ca
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket_client/ssl/server.key.orig
@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,89778A6427F05D4A
+
+4aXqO/8oCHVfMLB+a1DfjbXyEddjbd7nB+YVFLPKy68Tam9PRTvC1zRHBet59ll0
+1w7R8tXR6/xH7HRhBeqDHCcuvBhtw3xGxtXWv54WBFhzuq7TvKOAaCFl++cw/JHq
+PCS0rAaYnqF2MAgMi7QBjZKmHFHL43Gy60VfOrB0mmOdxqqXA0NBFC2uEd7Z/MAx
+S2A85bNJJKQaWEeDThP1u0OOlNCq99lkLJ31jiOH7ntdL0/vqcbZ+PUtdPLwAG4L
+1GUHuiC2v5FvDlPiejMk2dvrxCNpcu2e3tQKHpg2KcsTVrpB7EVzRSazln4HywUZ
+EJfBvxqqrS7plImZgj4LXSnln0JPuBb+aHnhKIFvisjYSwqDGJnnp/OaD7YdRhYh
+UCcL011Ge+yUbRipeAmHdtJlSUSdB14KWq+WdIX/KgCRGx06QZm9s1PBLH+fww+I
+EL3A/LFX0a5KUHkCp29akYYv9bUYaQ79Nt7BlaEON+/SW3pJMbGr+nx8aqogr0Yo
+SJ/Zz5TSDBhecRjbCDGkT6DizVZ8cbm2xl8QLBd0H+ZA6uYMgfpAOJGrJx3Nm4Lv
+prEApgFtjSrsQDGYHAcmDMW1UWOVHuNp7BSvwUze9Ftnzr/jlpdzES2rhgMyGhg1
+0Szbsfs3vgw4iM83LFJXza07GQJzF8gRF79dY5JiQX/sOKUprA6Lofk631jE0G8r
+3z59cxblaq9y7EgFsE944Gk7/HIEimBRiqIZzGVJVukD0itynQ+XmYTdbyH1lpvi
+c0ZheZPUoGwUW9RYy+nle5gEDFyZWXcCAuJasQvDBXt//r/bso3ZpA==
+-----END RSA PRIVATE KEY-----
diff --git a/src/civetweb/examples/_obsolete/websocket_client/ssl/server.pem b/src/civetweb/examples/_obsolete/websocket_client/ssl/server.pem
new file mode 100644
index 000000000..300834e39
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket_client/ssl/server.pem
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQC2BCIqIvgSUTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE0MDgyMTEyMzAwMVoXDTI0MDgxODEyMzAwMVowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA9k9s
+gH22BCo9neTeB/YnilK7n0sMe0+pjS9KSWhU59Q4w8hqPrW0tuYikIDd0wVggkJF
+BZNg4WPoulTdwXsgNBeG88q2wnNtUosXTS+KQTQBSiQof9Ay9GHQtgxnogI1zIXb
+HOppyyG5zre8a/X6fzDOnFc4iJMBwxTAnjCqObkCAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQBX9V46VUVsB9P9fb8sFuMx2ezFE42ynEeJPrKRrof+dFYbjvR1OUZFSLCy
+aZKwVH7iCnVBJiU12JxO7PR3L6ob3FYPyNHQWYq1/IFUvqBRagehldj5H8iFeEDz
+Wtz2+p1rUyVxcSUqTjobaji0aC8lzPZio0nd1KKM6A92/adHyQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQD2T2yAfbYEKj2d5N4H9ieKUrufSwx7T6mNL0pJaFTn1DjDyGo+
+tbS25iKQgN3TBWCCQkUFk2DhY+i6VN3BeyA0F4bzyrbCc21SixdNL4pBNAFKJCh/
+0DL0YdC2DGeiAjXMhdsc6mnLIbnOt7xr9fp/MM6cVziIkwHDFMCeMKo5uQIDAQAB
+AoGAYwospr3lomcZv5N3c9wWqhf6OWMD8dFma87IIBxDh7Rd3tuHXQ/TSnffDhvD
+FkbjN31OI5/PJNH3knTtdg78MywPloE4jYsbt4+fEaW7Fzww2nU61N1p+mYk5d/b
+SCTAHhGzF9g9ZMw25CCUFGjDU2z+Ty6my22Euxhk2Qq8tMECQQD9ZYIxWkPhywDW
+pX3v70dqIv7411hEYpuL/ZJl26UCmQsj4HPtXQCraQksVPs74WY5aTtd6MAV9V3M
+UnErHO5/AkEA+NdG2MmfBOBPusDB/WwQaUPiCWGITS9llGTR2JXbvDqmKgL1+UTG
+o27sLNIFCrF1wejpyRGqwjcObFYR0yKrxwJBAOB2uPuK4DL1psp9Uq/mIDbOxVod
+OF1rlCpP9w0vol5Iv+uJ+mc7SUqOAsg4h0yl/+2/YA1yDiXlcq96IDF2sXUCQGAv
+Nh9Nr72+xpK1N0axopZNuu1NWdYb3/PAFKzXIBxdvyS2CEXVo8JAeeHJPFGpzo6p
+bNRfk9WGWnjdu/4UhLkCQQCekR9zpIpzdJiPYCd6XMya+TPCDYlOQL1jlnJIRa2V
+BEOz0rSpzXAGh0PyCB/kMneyVk87LWn8joE6179RoUfv
+-----END RSA PRIVATE KEY-----
diff --git a/src/civetweb/examples/_obsolete/websocket_client/websocket_client.c b/src/civetweb/examples/_obsolete/websocket_client/websocket_client.c
new file mode 100644
index 000000000..158ad7d85
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/websocket_client/websocket_client.c
@@ -0,0 +1,421 @@
+/*
+* Copyright (c) 2014-2016 the Civetweb developers
+* Copyright (c) 2014 Jordan Shelley
+* https://github.com/jshelley
+* License http://opensource.org/licenses/mit-license.php MIT License
+*/
+
+/* This example is superseeded by other examples, and no longer
+ * actively maintained.
+ * See examples/embedded_c for an up to date example.
+ */
+
+// Simple example program on how to use websocket client embedded C interface.
+#ifdef _WIN32
+#include <windows.h>
+#define sleep(x) Sleep(1000 * (x))
+#else
+#include <unistd.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include "civetweb.h"
+
+#define DOCUMENT_ROOT "."
+#define PORT "8888"
+#define SSL_CERT "./ssl/server.pem"
+
+const char *websocket_welcome_msg = "websocket welcome\n";
+const size_t websocket_welcome_msg_len = 18 /* strlen(websocket_welcome_msg) */;
+const char *websocket_acknowledge_msg = "websocket msg ok\n";
+const size_t websocket_acknowledge_msg_len =
+ 17 /* strlen(websocket_acknowledge_msg) */;
+const char *websocket_goodbye_msg = "websocket bye\n";
+const size_t websocket_goodbye_msg_len = 14 /* strlen(websocket_goodbye_msg) */;
+
+
+/*************************************************************************************/
+/* WEBSOCKET SERVER */
+/*************************************************************************************/
+#if defined(MG_LEGACY_INTERFACE)
+int
+websock_server_connect(const struct mg_connection *conn)
+#else
+int
+websocket_server_connect(const struct mg_connection *conn, void *_ignored)
+#endif
+{
+ printf("Server: Websocket connected\n");
+ return 0; /* return 0 to accept every connection */
+}
+
+
+#if defined(MG_LEGACY_INTERFACE)
+void
+websocket_server_ready(struct mg_connection *conn)
+#else
+void
+websocket_server_ready(struct mg_connection *conn, void *_ignored)
+#endif
+{
+ printf("Server: Websocket ready\n");
+
+ /* Send websocket welcome message */
+ mg_lock_connection(conn);
+ mg_websocket_write(conn,
+ WEBSOCKET_OPCODE_TEXT,
+ websocket_welcome_msg,
+ websocket_welcome_msg_len);
+ mg_unlock_connection(conn);
+}
+
+
+#if defined(MG_LEGACY_INTERFACE)
+int
+websocket_server_data(struct mg_connection *conn,
+ int bits,
+ char *data,
+ size_t data_len)
+#else
+int
+websocket_server_data(struct mg_connection *conn,
+ int bits,
+ char *data,
+ size_t data_len,
+ void *_ignored)
+#endif
+{
+ printf("Server: Got %lu bytes from the client\n", (unsigned long)data_len);
+ printf("Server received data from client: ");
+ fwrite(data, 1, data_len, stdout);
+ printf("\n");
+
+ if (data_len < 3 || 0 != memcmp(data, "bye", 3)) {
+ /* Send websocket acknowledge message */
+ mg_lock_connection(conn);
+ mg_websocket_write(conn,
+ WEBSOCKET_OPCODE_TEXT,
+ websocket_acknowledge_msg,
+ websocket_acknowledge_msg_len);
+ mg_unlock_connection(conn);
+ } else {
+ /* Send websocket acknowledge message */
+ mg_lock_connection(conn);
+ mg_websocket_write(conn,
+ WEBSOCKET_OPCODE_TEXT,
+ websocket_goodbye_msg,
+ websocket_goodbye_msg_len);
+ mg_unlock_connection(conn);
+ }
+
+ return 1; /* return 1 to keep the connetion open */
+}
+
+
+#if defined(MG_LEGACY_INTERFACE)
+void
+websocket_server_connection_close(const struct mg_connection *conn)
+#else
+void
+websocket_server_connection_close(const struct mg_connection *conn,
+ void *_ignored)
+#endif
+{
+ printf("Server: Close connection\n");
+
+ /* Can not send a websocket goodbye message here - the connection is already
+ * closed */
+}
+
+
+struct mg_context *
+start_websocket_server()
+{
+ const char *options[] = {"document_root",
+ DOCUMENT_ROOT,
+ "ssl_certificate",
+ SSL_CERT,
+ "listening_ports",
+ PORT,
+ "request_timeout_ms",
+ "5000",
+ 0};
+ struct mg_callbacks callbacks;
+ struct mg_context *ctx;
+
+ memset(&callbacks, 0, sizeof(callbacks));
+
+#if defined(MG_LEGACY_INTERFACE)
+ /* Obsolete: */
+ callbacks.websocket_connect = websock_server_connect;
+ callbacks.websocket_ready = websocket_server_ready;
+ callbacks.websocket_data = websocket_server_data;
+ callbacks.connection_close = websocket_server_connection_close;
+
+ ctx = mg_start(&callbacks, 0, options);
+#else
+ /* New interface: */
+ ctx = mg_start(&callbacks, 0, options);
+
+ mg_set_websocket_handler(ctx,
+ "/websocket",
+ websocket_server_connect,
+ websocket_server_ready,
+ websocket_server_data,
+ websocket_server_connection_close,
+ NULL);
+#endif
+
+ return ctx;
+}
+
+
+/*************************************************************************************/
+/* WEBSOCKET CLIENT */
+/*************************************************************************************/
+struct tclient_data {
+ void *data;
+ size_t len;
+ int closed;
+};
+
+static int
+websocket_client_data_handler(struct mg_connection *conn,
+ int flags,
+ char *data,
+ size_t data_len,
+ void *user_data)
+{
+ struct mg_context *ctx = mg_get_context(conn);
+ struct tclient_data *pclient_data =
+ (struct tclient_data *)mg_get_user_data(ctx);
+
+ printf("Client received data from server: ");
+ fwrite(data, 1, data_len, stdout);
+ printf("\n");
+
+ pclient_data->data = malloc(data_len);
+ assert(pclient_data->data != NULL);
+ memcpy(pclient_data->data, data, data_len);
+ pclient_data->len = data_len;
+
+ return 1;
+}
+
+static void
+websocket_client_close_handler(const struct mg_connection *conn,
+ void *user_data)
+{
+ struct mg_context *ctx = mg_get_context(conn);
+ struct tclient_data *pclient_data =
+ (struct tclient_data *)mg_get_user_data(ctx);
+
+ printf("Client: Close handler\n");
+ pclient_data->closed++;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ struct mg_context *ctx = NULL;
+ struct tclient_data client1_data = {NULL, 0, 0};
+ struct tclient_data client2_data = {NULL, 0, 0};
+ struct tclient_data client3_data = {NULL, 0, 0};
+ struct mg_connection *newconn1 = NULL;
+ struct mg_connection *newconn2 = NULL;
+ struct mg_connection *newconn3 = NULL;
+ char ebuf[100] = {0};
+
+ assert(websocket_welcome_msg_len == strlen(websocket_welcome_msg));
+
+ /* First set up a websocket server */
+ ctx = start_websocket_server();
+ assert(ctx != NULL);
+ printf("Server init\n\n");
+
+ /* Then connect a first client */
+ newconn1 = mg_connect_websocket_client("localhost",
+ atoi(PORT),
+ 0,
+ ebuf,
+ sizeof(ebuf),
+ "/websocket",
+ NULL,
+ websocket_client_data_handler,
+ websocket_client_close_handler,
+ &client1_data);
+
+ if (newconn1 == NULL) {
+ printf("Error: %s", ebuf);
+ return 1;
+ }
+
+ sleep(1); /* Should get the websocket welcome message */
+ assert(client1_data.closed == 0);
+ assert(client2_data.closed == 0);
+ assert(client2_data.data == NULL);
+ assert(client2_data.len == 0);
+ assert(client1_data.data != NULL);
+ assert(client1_data.len == websocket_welcome_msg_len);
+ assert(!memcmp(client1_data.data,
+ websocket_welcome_msg,
+ websocket_welcome_msg_len));
+ free(client1_data.data);
+ client1_data.data = NULL;
+ client1_data.len = 0;
+
+ mg_websocket_client_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data1", 5);
+
+ sleep(1); /* Should get the acknowledge message */
+ assert(client1_data.closed == 0);
+ assert(client2_data.closed == 0);
+ assert(client2_data.data == NULL);
+ assert(client2_data.len == 0);
+ assert(client1_data.data != NULL);
+ assert(client1_data.len == websocket_acknowledge_msg_len);
+ assert(!memcmp(client1_data.data,
+ websocket_acknowledge_msg,
+ websocket_acknowledge_msg_len));
+ free(client1_data.data);
+ client1_data.data = NULL;
+ client1_data.len = 0;
+
+ /* Now connect a second client */
+ newconn2 = mg_connect_websocket_client("localhost",
+ atoi(PORT),
+ 0,
+ ebuf,
+ sizeof(ebuf),
+ "/websocket",
+ NULL,
+ websocket_client_data_handler,
+ websocket_client_close_handler,
+ &client2_data);
+
+ if (newconn2 == NULL) {
+ printf("Error: %s", ebuf);
+ return 1;
+ }
+
+ sleep(1); /* Client 2 should get the websocket welcome message */
+ assert(client1_data.closed == 0);
+ assert(client2_data.closed == 0);
+ assert(client1_data.data == NULL);
+ assert(client1_data.len == 0);
+ assert(client2_data.data != NULL);
+ assert(client2_data.len == websocket_welcome_msg_len);
+ assert(!memcmp(client2_data.data,
+ websocket_welcome_msg,
+ websocket_welcome_msg_len));
+ free(client2_data.data);
+ client2_data.data = NULL;
+ client2_data.len = 0;
+
+ mg_websocket_client_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data2", 5);
+
+ sleep(1); /* Should get the acknowledge message */
+ assert(client1_data.closed == 0);
+ assert(client2_data.closed == 0);
+ assert(client2_data.data == NULL);
+ assert(client2_data.len == 0);
+ assert(client1_data.data != NULL);
+ assert(client1_data.len == websocket_acknowledge_msg_len);
+ assert(!memcmp(client1_data.data,
+ websocket_acknowledge_msg,
+ websocket_acknowledge_msg_len));
+ free(client1_data.data);
+ client1_data.data = NULL;
+ client1_data.len = 0;
+
+ mg_websocket_client_write(newconn1, WEBSOCKET_OPCODE_TEXT, "bye", 3);
+
+ sleep(1); /* Should get the goodbye message */
+ assert(client1_data.closed == 0);
+ assert(client2_data.closed == 0);
+ assert(client2_data.data == NULL);
+ assert(client2_data.len == 0);
+ assert(client1_data.data != NULL);
+ assert(client1_data.len == websocket_goodbye_msg_len);
+ assert(!memcmp(client1_data.data,
+ websocket_goodbye_msg,
+ websocket_goodbye_msg_len));
+ free(client1_data.data);
+ client1_data.data = NULL;
+ client1_data.len = 0;
+
+ mg_close_connection(newconn1);
+
+ sleep(1); /* Won't get any message */
+ assert(client1_data.closed == 1);
+ assert(client2_data.closed == 0);
+ assert(client1_data.data == NULL);
+ assert(client1_data.len == 0);
+ assert(client2_data.data == NULL);
+ assert(client2_data.len == 0);
+
+ mg_websocket_client_write(newconn2, WEBSOCKET_OPCODE_TEXT, "bye", 3);
+
+ sleep(1); /* Should get the goodbye message */
+ assert(client1_data.closed == 1);
+ assert(client2_data.closed == 0);
+ assert(client1_data.data == NULL);
+ assert(client1_data.len == 0);
+ assert(client2_data.data != NULL);
+ assert(client2_data.len == websocket_goodbye_msg_len);
+ assert(!memcmp(client2_data.data,
+ websocket_goodbye_msg,
+ websocket_goodbye_msg_len));
+ free(client2_data.data);
+ client2_data.data = NULL;
+ client2_data.len = 0;
+
+ mg_close_connection(newconn2);
+
+ sleep(1); /* Won't get any message */
+ assert(client1_data.closed == 1);
+ assert(client2_data.closed == 1);
+ assert(client1_data.data == NULL);
+ assert(client1_data.len == 0);
+ assert(client2_data.data == NULL);
+ assert(client2_data.len == 0);
+
+ /* Connect client 3 */
+ newconn3 = mg_connect_websocket_client("localhost",
+ atoi(PORT),
+ 0,
+ ebuf,
+ sizeof(ebuf),
+ "/websocket",
+ NULL,
+ websocket_client_data_handler,
+ websocket_client_close_handler,
+ &client3_data);
+
+ sleep(1); /* Client 3 should get the websocket welcome message */
+ assert(client1_data.closed == 1);
+ assert(client2_data.closed == 1);
+ assert(client3_data.closed == 0);
+ assert(client1_data.data == NULL);
+ assert(client1_data.len == 0);
+ assert(client2_data.data == NULL);
+ assert(client2_data.len == 0);
+ assert(client3_data.data != NULL);
+ assert(client3_data.len == websocket_welcome_msg_len);
+ assert(!memcmp(client3_data.data,
+ websocket_welcome_msg,
+ websocket_welcome_msg_len));
+ free(client3_data.data);
+ client3_data.data = NULL;
+ client3_data.len = 0;
+
+ mg_stop(ctx);
+ printf("Server shutdown\n");
+
+ sleep(10);
+
+ assert(client3_data.closed == 1);
+
+ return 0;
+}
diff --git a/src/civetweb/examples/_obsolete/ws_server/Makefile b/src/civetweb/examples/_obsolete/ws_server/Makefile
new file mode 100644
index 000000000..60d9dbedb
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/ws_server/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2013 No Face Press, LLC
+# License http://opensource.org/licenses/mit-license.php MIT License
+#
+
+#This makefile is used to test the other Makefiles
+
+
+PROG = ws_server
+SRC = ws_server.c
+
+TOP = ../..
+CIVETWEB_LIB = libcivetweb.a
+
+CFLAGS = -I$(TOP)/include $(COPT)
+LIBS = -lpthread
+
+include $(TOP)/resources/Makefile.in-os
+
+ifeq ($(TARGET_OS),LINUX)
+ LIBS += -ldl -DMG_LEGACY_INTERFACE=1
+endif
+
+all: $(PROG)
+
+$(PROG): $(CIVETWEB_LIB) $(SRC)
+ $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS)
+
+$(CIVETWEB_LIB):
+ $(MAKE) -C $(TOP) clean lib WITH_WEBSOCKET=1
+ cp $(TOP)/$(CIVETWEB_LIB) .
+
+clean:
+ rm -f $(CIVETWEB_LIB) $(PROG)
+
+.PHONY: all clean
diff --git a/src/civetweb/examples/_obsolete/ws_server/docroot/index.html b/src/civetweb/examples/_obsolete/ws_server/docroot/index.html
new file mode 100644
index 000000000..f1d1af3eb
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/ws_server/docroot/index.html
@@ -0,0 +1,316 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset='UTF-8'>
+
+ <title>Websocket Meters</title>
+ <!--
+ Version 0.1 Contributed by William Greathouse 9-Sep-2013
+ Simple demo of WebSocket connection use. Not a great example of web coding,
+ but it is functional.
+
+ The meter displays are adapted from CSS-TRICKS Progress Bars by Chris Coyier
+ at http://css-tricks.com/css3-progress-bars/
+ -->
+ <style>
+ body {
+ background: #222;
+ }
+ h1 {
+ color: white;
+ text-align: center;
+ }
+ button {
+ width: 225px;
+ height: 30px;
+ margin: auto 10px;
+ background-color: #ccc;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ border-radius:6px;
+ color: blue;
+ font-size: 20px;
+ }
+ button:hover {
+ background-color: #888;
+ }
+ button:hover:disabled {
+ background-color: #ccc;
+ }
+ button:disabled {
+ color: lightgray;
+ }
+
+ .button_container {
+ width:550px;
+ display:block;
+ margin-left:auto;
+ margin-right:auto;
+ }
+
+ .meter {
+ height: 20px; /* Can be anything */
+ position: relative;
+ background: #555;
+ -moz-border-radius: 25px;
+ -webkit-border-radius: 25px;
+ border-radius: 25px;
+ padding: 10px;
+ -webkit-box-shadow: inset 0 -1px 1px rgba(255,255,255,0.3);
+ -moz-box-shadow : inset 0 -1px 1px rgba(255,255,255,0.3);
+ box-shadow : inset 0 -1px 1px rgba(255,255,255,0.3);
+ }
+ .meter > span {
+ display: block;
+ height: 100%;
+ -webkit-border-top-right-radius: 20px;
+ -webkit-border-bottom-right-radius: 20px;
+ -moz-border-radius-topright: 20px;
+ -moz-border-radius-bottomright: 20px;
+ border-top-right-radius: 20px;
+ border-bottom-right-radius: 20px;
+ -webkit-border-top-left-radius: 20px;
+ -webkit-border-bottom-left-radius: 20px;
+ -moz-border-radius-topleft: 20px;
+ -moz-border-radius-bottomleft: 20px;
+ border-top-left-radius: 20px;
+ border-bottom-left-radius: 20px;
+ background-color: rgb(43,194,83);
+ background-image: -webkit-gradient(
+ linear,
+ left bottom,
+ left top,
+ color-stop(0, rgb(43,194,83)),
+ color-stop(1, rgb(84,240,84))
+ );
+ background-image: -moz-linear-gradient(
+ center bottom,
+ rgb(43,194,83) 37%,
+ rgb(84,240,84) 69%
+ );
+ -webkit-box-shadow:
+ inset 0 2px 9px rgba(255,255,255,0.3),
+ inset 0 -2px 6px rgba(0,0,0,0.4);
+ -moz-box-shadow:
+ inset 0 2px 9px rgba(255,255,255,0.3),
+ inset 0 -2px 6px rgba(0,0,0,0.4);
+ box-shadow:
+ inset 0 2px 9px rgba(255,255,255,0.3),
+ inset 0 -2px 6px rgba(0,0,0,0.4);
+ position: relative;
+ overflow: hidden;
+ }
+ .meter > span:after, .animate > span > span {
+ content: "";
+ position: absolute;
+ top: 0; left: 0; bottom: 0; right: 0;
+ background-image:
+ -webkit-gradient(linear, 0 0, 100% 100%,
+ color-stop(.25, rgba(255, 255, 255, .2)),
+ color-stop(.25, transparent), color-stop(.5, transparent),
+ color-stop(.5, rgba(255, 255, 255, .2)),
+ color-stop(.75, rgba(255, 255, 255, .2)),
+ color-stop(.75, transparent), to(transparent)
+ );
+ background-image:
+ -moz-linear-gradient(
+ -45deg,
+ rgba(255, 255, 255, .2) 25%,
+ transparent 25%,
+ transparent 50%,
+ rgba(255, 255, 255, .2) 50%,
+ rgba(255, 255, 255, .2) 75%,
+ transparent 75%,
+ transparent
+ );
+ z-index: 1;
+ -webkit-background-size: 50px 50px;
+ -moz-background-size: 50px 50px;
+ -webkit-animation: move 2s linear infinite;
+ -webkit-border-top-right-radius: 20px;
+ -webkit-border-bottom-right-radius: 20px;
+ -moz-border-radius-topright: 20px;
+ -moz-border-radius-bottomright: 20px;
+ border-top-right-radius: 20px;
+ border-bottom-right-radius: 20px;
+ -webkit-border-top-left-radius: 20px;
+ -webkit-border-bottom-left-radius: 20px;
+ -moz-border-radius-topleft: 20px;
+ -moz-border-radius-bottomleft: 20px;
+ border-top-left-radius: 20px;
+ border-bottom-left-radius: 20px;
+ overflow: hidden;
+ }
+
+ .animate > span:after {
+ display: none;
+ }
+
+ @-webkit-keyframes move {
+ 0% {
+ background-position: 0 0;
+ }
+ 100% {
+ background-position: 50px 50px;
+ }
+ }
+
+ .orange > span {
+ background-color: #f1a165;
+ background-image: -moz-linear-gradient(top, #f1a165, #f36d0a);
+ background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #f1a165),color-stop(1, #f36d0a));
+ background-image: -webkit-linear-gradient(#f1a165, #f36d0a);
+ }
+
+ .red > span {
+ background-color: #f0a3a3;
+ background-image: -moz-linear-gradient(top, #f0a3a3, #f42323);
+ background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #f0a3a3),color-stop(1, #f42323));
+ background-image: -webkit-linear-gradient(#f0a3a3, #f42323);
+ }
+
+ .nostripes > span > span, .nostripes > span:after {
+ -webkit-animation: none;
+ background-image: none;
+ }
+
+ #output {
+ background-color: #ccc;
+ height: 240px;
+ overflow-y: auto;
+ }
+
+ </style>
+</head>
+
+<body>
+ <div id="page_wrap">
+
+ <h1>Meter Updates via WebSocket</h1>
+
+ <p/>
+
+ <div class="meter">
+ <span id="meter1" style="width: 25%"></span>
+ </div>
+
+ <p/>
+
+ <div class="meter orange nostripes">
+ <span id="meter2" style="width: 33.3%"></span>
+ </div>
+
+ <p/>
+
+ <div class="meter red">
+ <span id="meter3" style="width: 80%"></span>
+ </div>
+
+ <p/>
+
+ </div>
+ <div class="button_container">
+ <div>
+ <button id="connection" onclick="toggleConnection(this)">WebSocket Connect</button>
+ <button id="update" disabled onclick="toggleUpdate(this)">Disable Update</button>
+ </div>
+ </div>
+ <p/>
+ <div id="output"></div>
+
+</body>
+
+<script language="javascript" type="text/javascript">
+ var connection; // websocket connection
+
+ function writeToScreen (message) {
+ var div = document.createElement('div');
+ var output = document.getElementById('output');
+ div.innerHTML = message;
+ output.appendChild(div);
+ output.scrollTop = output.scrollHeight;
+ }
+
+ function ws_connect() {
+ // check for websocket support
+ // for Internet Explorer < 10 there are options for websocket support that
+ // could be integrated into production code, but for now, we are expecting
+ // browser support to be present for this demo
+ if ('WebSocket' in window) {
+
+ writeToScreen('Connecting');
+ connection = new WebSocket('ws://' + window.location.host + '/meters');
+ connection.onopen = function(ev) {
+ document.getElementById("connection").innerHTML = "WebSocket Disconnect";
+ document.getElementById("update").disabled=false;
+ document.getElementById("update").innerHTML = "Disable Update";
+ writeToScreen('CONNECTED');
+ var message = 'update on';
+ writeToScreen('SENT: ' + message);
+ connection.send(message);
+ };
+
+ connection.onclose = function(ev) {
+ document.getElementById("update").disabled=true;
+ document.getElementById("update").innerHTML = "Enable Update";
+ document.getElementById("connection").innerHTML = "WebSocket Connect";
+ writeToScreen('DISCONNECTED');
+ };
+
+ connection.onmessage = function(ev) {
+ if (ev.data.substr(0,5) == "meter")
+ {
+ var target = ev.data.split(":")[0];
+ var meter = document.getElementById(target);
+ var data = ev.data.split(":")[1].split(",");
+ var percent = (data[0]*100)/data[1];
+ meter.style.width = percent+"%";
+ }
+ else
+ writeToScreen('RECEIVED: ' + ev.data);
+ };
+
+ connection.onerror = function(ev) {
+ alert("WebSocket error");
+ };
+
+ } else {
+ alert("WebSocket is not available!!!\n" +
+ "Demo will not function.");
+ }
+ }
+
+ // user connect/disconnect
+ function toggleConnection(el) {
+ var tag=el.innerHTML;
+ if (tag == "WebSocket Connect")
+ {
+ ws_connect();
+ }
+ else
+ {
+ connection.close();
+ }
+ }
+
+ // user turn updates on/off
+ function toggleUpdate(el) {
+ var tag=el.innerHTML;
+ var message;
+ if (tag == "Enable Update")
+ {
+ message = 'update on';
+ el.innerHTML = "Disable Update";
+ }
+ else
+ {
+ message = 'update off';
+ el.innerHTML = "Enable Update";
+ }
+ writeToScreen('SENT: ' + message);
+ connection.send(message);
+ }
+</script>
+
+</html>
diff --git a/src/civetweb/examples/_obsolete/ws_server/ws_server.c b/src/civetweb/examples/_obsolete/ws_server/ws_server.c
new file mode 100644
index 000000000..575a26a69
--- /dev/null
+++ b/src/civetweb/examples/_obsolete/ws_server/ws_server.c
@@ -0,0 +1,271 @@
+// Copyright (c) 2004-2012 Sergey Lyubka
+// This file is a part of civetweb project, http://github.com/bel2125/civetweb
+//
+// v 0.1 Contributed by William Greathouse 9-Sep-2013
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "civetweb.h"
+
+// simple structure for keeping track of websocket connection
+struct ws_connection {
+ struct mg_connection *conn;
+ int update;
+ int closing;
+};
+
+// time base and structure periodic updates to client for demo
+#define BASETIME 100000 /* 0.1 seconds */
+struct progress {
+ int limit;
+ int increment;
+ int period;
+ int value;
+};
+
+// up to 16 independent client connections
+#define CONNECTIONS 16
+static struct ws_connection ws_conn[CONNECTIONS];
+
+
+// ws_server_thread()
+// Simple demo server thread. Sends periodic updates to connected clients
+static void *ws_server_thread(void *parm)
+{
+ int wsd = (long)parm;
+ struct mg_connection *conn = ws_conn[wsd].conn;
+ int timer = 0;
+ char tstr[32];
+ int i;
+ struct progress meter[] = {
+ /* first meter 0 to 1000, by 5 every 0.1 second */
+ { 1000, 5, 1, 0 },
+ /* second meter 0 to 500, by 10 every 0.5 second */
+ { 500, 10, 5, 0 },
+ /* third meter 0 to 100, by 10 every 1.0 second */
+ { 100, 10, 10, 0},
+ /* end of list */
+ { 0, 0, 0, 0}
+ };
+
+ fprintf(stderr, "ws_server_thread %d\n", wsd);
+
+ /* Send initial meter updates */
+ for (i=0; meter[i].period != 0; i++) {
+ if (meter[i].value >= meter[i].limit)
+ meter[i].value = 0;
+ if (meter[i].value >= meter[i].limit)
+ meter[i].value = meter[i].limit;
+ sprintf(tstr, "meter%d:%d,%d", i+1,
+ meter[i].value, meter[i].limit);
+ mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, tstr, strlen(tstr));
+ }
+
+ /* While the connection is open, send periodic updates */
+ while(!ws_conn[wsd].closing) {
+ usleep(100000); /* 0.1 second */
+ timer++;
+
+ /* Send meter updates */
+ if (ws_conn[wsd].update) {
+ for (i=0; meter[i].period != 0; i++) {
+ if (timer%meter[i].period == 0) {
+ if (meter[i].value >= meter[i].limit)
+ meter[i].value = 0;
+ else
+ meter[i].value += meter[i].increment;
+ if (meter[i].value >= meter[i].limit)
+ meter[i].value = meter[i].limit;
+ // if we are closing, server should not send new data
+ if (!ws_conn[wsd].closing) {
+ sprintf(tstr, "meter%d:%d,%d", i+1,
+ meter[i].value, meter[i].limit);
+ mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, tstr, strlen(tstr));
+ }
+ }
+ }
+ }
+
+ /* Send periodic PING to assure websocket remains connected, except if we are closing */
+ if (timer%100 == 0 && !ws_conn[wsd].closing)
+ mg_websocket_write(conn, WEBSOCKET_OPCODE_PING, NULL, 0);
+ }
+
+ fprintf(stderr, "ws_server_thread %d exiting\n", wsd);
+
+ // reset connection information to allow reuse by new client
+ ws_conn[wsd].conn = NULL;
+ ws_conn[wsd].update = 0;
+ ws_conn[wsd].closing = 2;
+
+ return NULL;
+}
+
+// websocket_connect_handler()
+// On new client connection, find next available server connection and store
+// new connection information. If no more server connections are available
+// tell civetweb to not accept the client request.
+static int websocket_connect_handler(const struct mg_connection *conn)
+{
+ int i;
+
+ fprintf(stderr, "connect handler\n");
+
+ for(i=0; i < CONNECTIONS; ++i) {
+ if (ws_conn[i].conn == NULL) {
+ fprintf(stderr, "...prep for server %d\n", i);
+ ws_conn[i].conn = (struct mg_connection *)conn;
+ ws_conn[i].closing = 0;
+ ws_conn[i].update = 0;
+ break;
+ }
+ }
+ if (i >= CONNECTIONS) {
+ fprintf(stderr, "Refused connection: Max connections exceeded\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+// websocket_ready_handler()
+// Once websocket negotiation is complete, start a server for the connection
+static void websocket_ready_handler(struct mg_connection *conn)
+{
+ int i;
+
+ fprintf(stderr, "ready handler\n");
+
+ for(i=0; i < CONNECTIONS; ++i) {
+ if (ws_conn[i].conn == conn) {
+ fprintf(stderr, "...start server %d\n", i);
+ mg_start_thread(ws_server_thread, (void *)(long)i);
+ break;
+ }
+ }
+}
+
+// websocket_close_handler()
+// When websocket is closed, tell the associated server to shut down
+static void websocket_close_handler(struct mg_connection *conn)
+{
+ int i;
+
+ //fprintf(stderr, "close handler\n"); /* called for every close, not just websockets */
+
+ for(i=0; i < CONNECTIONS; ++i) {
+ if (ws_conn[i].conn == conn) {
+ fprintf(stderr, "...close server %d\n", i);
+ ws_conn[i].closing = 1;
+ }
+ }
+}
+
+// Arguments:
+// flags: first byte of websocket frame, see websocket RFC,
+// http://tools.ietf.org/html/rfc6455, section 5.2
+// data, data_len: payload data. Mask, if any, is already applied.
+static int websocket_data_handler(struct mg_connection *conn, int flags,
+ char *data, size_t data_len)
+{
+ int i;
+ int wsd;
+
+ for(i=0; i < CONNECTIONS; ++i) {
+ if (ws_conn[i].conn == conn) {
+ wsd = i;
+ break;
+ }
+ }
+ if (i >= CONNECTIONS) {
+ fprintf(stderr, "Received websocket data from unknown connection\n");
+ return 1;
+ }
+
+ if (flags & 0x80) {
+ flags &= 0x7f;
+ switch (flags) {
+ case WEBSOCKET_OPCODE_CONTINUATION:
+ fprintf(stderr, "CONTINUATION...\n");
+ break;
+ case WEBSOCKET_OPCODE_TEXT:
+ fprintf(stderr, "TEXT: %-.*s\n", (int)data_len, data);
+ /*** interpret data as commands here ***/
+ if (strncmp("update on", data, data_len)== 0) {
+ /* turn on updates */
+ ws_conn[wsd].update = 1;
+ /* echo back */
+ mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, data, data_len);
+ } else if (strncmp("update off", data, data_len)== 0) {
+ /* turn off updates */
+ ws_conn[wsd].update = 0;
+ /* echo back */
+ mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, data, data_len);
+ }
+ break;
+ case WEBSOCKET_OPCODE_BINARY:
+ fprintf(stderr, "BINARY...\n");
+ break;
+ case WEBSOCKET_OPCODE_CONNECTION_CLOSE:
+ fprintf(stderr, "CLOSE...\n");
+ /* If client initiated close, respond with close message in acknowlegement */
+ if (!ws_conn[wsd].closing) {
+ mg_websocket_write(conn, WEBSOCKET_OPCODE_CONNECTION_CLOSE, data, data_len);
+ ws_conn[wsd].closing = 1; /* we should not send addional messages when close requested/acknowledged */
+ }
+ return 0; /* time to close the connection */
+ break;
+ case WEBSOCKET_OPCODE_PING:
+ /* client sent PING, respond with PONG */
+ mg_websocket_write(conn, WEBSOCKET_OPCODE_PONG, data, data_len);
+ break;
+ case WEBSOCKET_OPCODE_PONG:
+ /* received PONG to our PING, no action */
+ break;
+ default:
+ fprintf(stderr, "Unknown flags: %02x\n", flags);
+ break;
+ }
+ }
+
+ return 1; /* keep connection open */
+}
+
+
+int main(void)
+{
+ char server_name[40];
+ struct mg_context *ctx;
+ struct mg_callbacks callbacks;
+ const char *options[] = {
+ "listening_ports", "8080",
+ "document_root", "docroot",
+ NULL
+ };
+
+ /* get simple greeting for the web server */
+ snprintf(server_name, sizeof(server_name),
+ "Civetweb websocket server v. %s",
+ mg_version());
+
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.websocket_connect = websocket_connect_handler;
+ callbacks.websocket_ready = websocket_ready_handler;
+ callbacks.websocket_data = websocket_data_handler;
+ callbacks.connection_close = websocket_close_handler;
+
+ ctx = mg_start(&callbacks, NULL, options);
+
+ /* show the greeting and some basic information */
+ printf("%s started on port(s) %s with web root [%s]\n",
+ server_name, mg_get_option(ctx, "listening_ports"),
+ mg_get_option(ctx, "document_root"));
+
+ getchar(); // Wait until user hits "enter"
+ mg_stop(ctx);
+
+ return 0;
+}