Subversion Repositories Code-Repo

Compare Revisions

No changes between revisions

Ignore whitespace Rev 140 → Rev 141

/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/Makefile
0,0 → 1,13
 
CC = gcc
#CFLAGS=-Wall -O3 -Werror
CFLAGS=-Wall -O1 -g -Werror
LDLIBS=-lpthread
 
# Use make's default rules
all: sysstatd
 
sysstatd: sysstatd.o csapp.o threadpool_exec.o list.o
 
clean:
rm -f *.o sysstatd
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/README
0,0 → 1,15
Group members: Kevin Lee (klee482)
 
Sysstatd is a simple webserver that allows a client to send commands
and pull data from the webserver. The code for binding a TCP socket
that listens for clients is seperated from the HTTP parsing code. This
allows the webserver to easily be reimplemented to connect to a relay
server instead of hosting. For each connection, the processing is sent
to a thread pool that parses the HTTP request that the client sends.
This allows the webserver to server multiple clients at once. The
webserver also keeps the connection open, thus it implements persistant
connections as according to HTTP/1.1. Within each processing thread,
the data header is checked and the specified action is taken. The
webserver supports querying for files, loadavg, and meminfo. It also
provides an interface for calling a runloop, allocanon, and freeanon
function. 404s are returned for unknown queries.
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/csapp.c
0,0 → 1,828
/* $begin csapp.c */
#include "csapp.h"
 
/**************************
* Error-handling functions
**************************/
/* $begin errorfuns */
/* $begin unixerror */
void unix_error(char *msg) /* unix-style error */
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
// exit(0);
}
/* $end unixerror */
 
void posix_error(int code, char *msg) /* posix-style error */
{
fprintf(stderr, "%s: %s\n", msg, strerror(code));
// exit(0);
}
 
void dns_error(char *msg) /* dns-style error */
{
fprintf(stderr, "%s: DNS error %d\n", msg, h_errno);
// exit(0);
}
 
void app_error(char *msg) /* application error */
{
fprintf(stderr, "%s\n", msg);
// exit(0);
}
/* $end errorfuns */
 
/*********************************************
* Wrappers for Unix process control functions
********************************************/
 
/* $begin forkwrapper */
pid_t Fork(void)
{
pid_t pid;
 
if ((pid = fork()) < 0)
unix_error("Fork error");
return pid;
}
/* $end forkwrapper */
 
void Execve(const char *filename, char *const argv[], char *const envp[])
{
if (execve(filename, argv, envp) < 0)
unix_error("Execve error");
}
 
/* $begin wait */
pid_t Wait(int *status)
{
pid_t pid;
 
if ((pid = wait(status)) < 0)
unix_error("Wait error");
return pid;
}
/* $end wait */
 
pid_t Waitpid(pid_t pid, int *iptr, int options)
{
pid_t retpid;
 
if ((retpid = waitpid(pid, iptr, options)) < 0)
unix_error("Waitpid error");
return(retpid);
}
 
/* $begin kill */
void Kill(pid_t pid, int signum)
{
int rc;
 
if ((rc = kill(pid, signum)) < 0)
unix_error("Kill error");
}
/* $end kill */
 
void Pause()
{
(void)pause();
return;
}
 
unsigned int Sleep(unsigned int secs)
{
unsigned int rc;
 
if ((rc = sleep(secs)) < 0)
unix_error("Sleep error");
return rc;
}
 
unsigned int Alarm(unsigned int seconds) {
return alarm(seconds);
}
void Setpgid(pid_t pid, pid_t pgid) {
int rc;
 
if ((rc = setpgid(pid, pgid)) < 0)
unix_error("Setpgid error");
return;
}
 
pid_t Getpgrp(void) {
return getpgrp();
}
 
/************************************
* Wrappers for Unix signal functions
***********************************/
 
/* $begin sigaction */
handler_t *Signal(int signum, handler_t *handler)
{
struct sigaction action, old_action;
 
action.sa_handler = handler;
sigemptyset(&action.sa_mask); /* block sigs of type being handled */
action.sa_flags = SA_RESTART; /* restart syscalls if possible */
 
if (sigaction(signum, &action, &old_action) < 0)
unix_error("Signal error");
return (old_action.sa_handler);
}
/* $end sigaction */
 
void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
{
if (sigprocmask(how, set, oldset) < 0)
unix_error("Sigprocmask error");
return;
}
 
void Sigemptyset(sigset_t *set)
{
if (sigemptyset(set) < 0)
unix_error("Sigemptyset error");
return;
}
 
void Sigfillset(sigset_t *set)
{
if (sigfillset(set) < 0)
unix_error("Sigfillset error");
return;
}
 
void Sigaddset(sigset_t *set, int signum)
{
if (sigaddset(set, signum) < 0)
unix_error("Sigaddset error");
return;
}
 
void Sigdelset(sigset_t *set, int signum)
{
if (sigdelset(set, signum) < 0)
unix_error("Sigdelset error");
return;
}
 
int Sigismember(const sigset_t *set, int signum)
{
int rc;
if ((rc = sigismember(set, signum)) < 0)
unix_error("Sigismember error");
return rc;
}
 
 
/********************************
* Wrappers for Unix I/O routines
********************************/
 
int Open(const char *pathname, int flags, mode_t mode)
{
int rc;
 
if ((rc = open(pathname, flags, mode)) < 0)
unix_error("Open error");
return rc;
}
 
ssize_t Read(int fd, void *buf, size_t count)
{
ssize_t rc;
 
if ((rc = read(fd, buf, count)) < 0)
unix_error("Read error");
return rc;
}
 
ssize_t Write(int fd, const void *buf, size_t count)
{
ssize_t rc;
 
if ((rc = write(fd, buf, count)) < 0)
unix_error("Write error");
return rc;
}
 
off_t Lseek(int fildes, off_t offset, int whence)
{
off_t rc;
 
if ((rc = lseek(fildes, offset, whence)) < 0)
unix_error("Lseek error");
return rc;
}
 
void Close(int fd)
{
int rc;
 
if ((rc = close(fd)) < 0)
unix_error("Close error");
}
 
int Select(int n, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout)
{
int rc;
 
if ((rc = select(n, readfds, writefds, exceptfds, timeout)) < 0)
unix_error("Select error");
return rc;
}
 
int Dup2(int fd1, int fd2)
{
int rc;
 
if ((rc = dup2(fd1, fd2)) < 0)
unix_error("Dup2 error");
return rc;
}
 
void Stat(const char *filename, struct stat *buf)
{
if (stat(filename, buf) < 0)
unix_error("Stat error");
}
 
void Fstat(int fd, struct stat *buf)
{
if (fstat(fd, buf) < 0)
unix_error("Fstat error");
}
 
/***************************************
* Wrappers for memory mapping functions
***************************************/
void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
{
void *ptr;
 
if ((ptr = mmap(addr, len, prot, flags, fd, offset)) == ((void *) -1))
unix_error("mmap error");
return(ptr);
}
 
void Munmap(void *start, size_t length)
{
if (munmap(start, length) < 0)
unix_error("munmap error");
}
 
/***************************************************
* Wrappers for dynamic storage allocation functions
***************************************************/
 
void *Malloc(size_t size)
{
void *p;
 
if ((p = malloc(size)) == NULL)
unix_error("Malloc error");
return p;
}
 
void *Realloc(void *ptr, size_t size)
{
void *p;
 
if ((p = realloc(ptr, size)) == NULL)
unix_error("Realloc error");
return p;
}
 
void *Calloc(size_t nmemb, size_t size)
{
void *p;
 
if ((p = calloc(nmemb, size)) == NULL)
unix_error("Calloc error");
return p;
}
 
void Free(void *ptr)
{
free(ptr);
}
 
/******************************************
* Wrappers for the Standard I/O functions.
******************************************/
void Fclose(FILE *fp)
{
if (fclose(fp) != 0)
unix_error("Fclose error");
}
 
FILE *Fdopen(int fd, const char *type)
{
FILE *fp;
 
if ((fp = fdopen(fd, type)) == NULL)
unix_error("Fdopen error");
 
return fp;
}
 
char *Fgets(char *ptr, int n, FILE *stream)
{
char *rptr;
 
if (((rptr = fgets(ptr, n, stream)) == NULL) && ferror(stream))
app_error("Fgets error");
 
return rptr;
}
 
FILE *Fopen(const char *filename, const char *mode)
{
FILE *fp;
 
if ((fp = fopen(filename, mode)) == NULL)
unix_error("Fopen error");
 
return fp;
}
 
void Fputs(const char *ptr, FILE *stream)
{
if (fputs(ptr, stream) == EOF)
unix_error("Fputs error");
}
 
size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
size_t n;
 
if (((n = fread(ptr, size, nmemb, stream)) < nmemb) && ferror(stream))
unix_error("Fread error");
return n;
}
 
void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
if (fwrite(ptr, size, nmemb, stream) < nmemb)
unix_error("Fwrite error");
}
 
 
/****************************
* Sockets interface wrappers
****************************/
 
int Socket(int domain, int type, int protocol)
{
int rc;
 
if ((rc = socket(domain, type, protocol)) < 0)
unix_error("Socket error");
return rc;
}
 
void Setsockopt(int s, int level, int optname, const void *optval, int optlen)
{
int rc;
 
if ((rc = setsockopt(s, level, optname, optval, optlen)) < 0)
unix_error("Setsockopt error");
}
 
void Bind(int sockfd, struct sockaddr *my_addr, int addrlen)
{
int rc;
 
if ((rc = bind(sockfd, my_addr, addrlen)) < 0)
unix_error("Bind error");
}
 
void Listen(int s, int backlog)
{
int rc;
 
if ((rc = listen(s, backlog)) < 0)
unix_error("Listen error");
}
 
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
int rc;
 
if ((rc = accept(s, addr, addrlen)) < 0)
unix_error("Accept error");
return rc;
}
 
void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen)
{
int rc;
 
if ((rc = connect(sockfd, serv_addr, addrlen)) < 0)
unix_error("Connect error");
}
 
/************************
* DNS interface wrappers
***********************/
 
/* $begin gethostbyname */
struct hostent *Gethostbyname(const char *name)
{
struct hostent *p;
 
if ((p = gethostbyname(name)) == NULL)
dns_error("Gethostbyname error");
return p;
}
/* $end gethostbyname */
 
struct hostent *Gethostbyaddr(const char *addr, int len, int type)
{
struct hostent *p;
 
if ((p = gethostbyaddr(addr, len, type)) == NULL)
dns_error("Gethostbyaddr error");
return p;
}
 
/************************************************
* Wrappers for Pthreads thread control functions
************************************************/
 
void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp,
void * (*routine)(void *), void *argp)
{
int rc;
 
if ((rc = pthread_create(tidp, attrp, routine, argp)) != 0)
posix_error(rc, "Pthread_create error");
}
 
void Pthread_cancel(pthread_t tid) {
int rc;
 
if ((rc = pthread_cancel(tid)) != 0)
posix_error(rc, "Pthread_cancel error");
}
 
void Pthread_join(pthread_t tid, void **thread_return) {
int rc;
 
if ((rc = pthread_join(tid, thread_return)) != 0)
posix_error(rc, "Pthread_join error");
}
 
/* $begin detach */
void Pthread_detach(pthread_t tid) {
int rc;
 
if ((rc = pthread_detach(tid)) != 0)
posix_error(rc, "Pthread_detach error");
}
/* $end detach */
 
void Pthread_exit(void *retval) {
pthread_exit(retval);
}
 
pthread_t Pthread_self(void) {
return pthread_self();
}
void Pthread_once(pthread_once_t *once_control, void (*init_function)()) {
pthread_once(once_control, init_function);
}
 
/*******************************
* Wrappers for Posix semaphores
*******************************/
 
void Sem_init(sem_t *sem, int pshared, unsigned int value)
{
if (sem_init(sem, pshared, value) < 0)
unix_error("Sem_init error");
}
 
void P(sem_t *sem)
{
if (sem_wait(sem) < 0)
unix_error("P error");
}
 
void V(sem_t *sem)
{
if (sem_post(sem) < 0)
unix_error("V error");
}
 
/*********************************************************************
* The Rio package - robust I/O functions
**********************************************************************/
/*
* rio_readn - robustly read n bytes (unbuffered)
*/
/* $begin rio_readn */
ssize_t rio_readn(int fd, void *usrbuf, size_t n)
{
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf;
 
while (nleft > 0) {
if ((nread = read(fd, bufp, nleft)) < 0) {
if (errno == EINTR) /* interrupted by sig handler return */
nread = 0; /* and call read() again */
else
return -1; /* errno set by read() */
}
else if (nread == 0)
break; /* EOF */
nleft -= nread;
bufp += nread;
}
return (n - nleft); /* return >= 0 */
}
/* $end rio_readn */
 
/*
* rio_writen - robustly write n bytes (unbuffered)
*/
/* $begin rio_writen */
ssize_t rio_writen(int fd, void *usrbuf, size_t n)
{
size_t nleft = n;
ssize_t nwritten;
char *bufp = usrbuf;
 
while (nleft > 0) {
if ((nwritten = write(fd, bufp, nleft)) <= 0) {
if (errno == EINTR) /* interrupted by sig handler return */
nwritten = 0; /* and call write() again */
else
return -1; /* errno set by write() */
}
nleft -= nwritten;
bufp += nwritten;
}
return n;
}
/* $end rio_writen */
 
 
/*
* rio_read - This is a wrapper for the Unix read() function that
* transfers min(n, rio_cnt) bytes from an internal buffer to a user
* buffer, where n is the number of bytes requested by the user and
* rio_cnt is the number of unread bytes in the internal buffer. On
* entry, rio_read() refills the internal buffer via a call to
* read() if the internal buffer is empty.
*/
/* $begin rio_read */
static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)
{
int cnt;
 
while (rp->rio_cnt <= 0) { /* refill if buf is empty */
rp->rio_cnt = read(rp->rio_fd, rp->rio_buf,
sizeof(rp->rio_buf));
if (rp->rio_cnt < 0) {
if (errno != EINTR) /* interrupted by sig handler return */
return -1;
}
else if (rp->rio_cnt == 0) /* EOF */
return 0;
else
rp->rio_bufptr = rp->rio_buf; /* reset buffer ptr */
}
 
/* Copy min(n, rp->rio_cnt) bytes from internal buf to user buf */
cnt = n;
if (rp->rio_cnt < n)
cnt = rp->rio_cnt;
memcpy(usrbuf, rp->rio_bufptr, cnt);
rp->rio_bufptr += cnt;
rp->rio_cnt -= cnt;
return cnt;
}
/* $end rio_read */
 
/*
* rio_readinitb - Associate a descriptor with a read buffer and reset buffer
*/
/* $begin rio_readinitb */
void rio_readinitb(rio_t *rp, int fd)
{
rp->rio_fd = fd;
rp->rio_cnt = 0;
rp->rio_bufptr = rp->rio_buf;
}
/* $end rio_readinitb */
 
/*
* rio_readnb - Robustly read n bytes (buffered)
*/
/* $begin rio_readnb */
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n)
{
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf;
while (nleft > 0) {
if ((nread = rio_read(rp, bufp, nleft)) < 0) {
if (errno == EINTR) /* interrupted by sig handler return */
nread = 0; /* call read() again */
else
return -1; /* errno set by read() */
}
else if (nread == 0)
break; /* EOF */
nleft -= nread;
bufp += nread;
}
return (n - nleft); /* return >= 0 */
}
/* $end rio_readnb */
 
/*
* rio_readlineb - robustly read a text line (buffered)
*/
/* $begin rio_readlineb */
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
{
int n, rc;
char c, *bufp = usrbuf;
 
for (n = 1; n < maxlen; n++) {
if ((rc = rio_read(rp, &c, 1)) == 1) {
*bufp++ = c;
if (c == '\n')
break;
} else if (rc == 0) {
if (n == 1)
return 0; /* EOF, no data read */
else
break; /* EOF, some data was read */
} else
return -1; /* error */
}
*bufp = 0;
return n;
}
/* $end rio_readlineb */
 
/**********************************
* Wrappers for robust I/O routines
**********************************/
ssize_t Rio_readn(int fd, void *ptr, size_t nbytes)
{
ssize_t n;
if ((n = rio_readn(fd, ptr, nbytes)) < 0) {
unix_error("Rio_readn error");
return -1;
}
return n;
}
 
void Rio_writen(int fd, void *usrbuf, size_t n)
{
if (rio_writen(fd, usrbuf, n) != n)
unix_error("Rio_writen error");
}
 
void Rio_readinitb(rio_t *rp, int fd)
{
rio_readinitb(rp, fd);
}
 
ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n)
{
ssize_t rc;
 
if ((rc = rio_readnb(rp, usrbuf, n)) < 0) {
unix_error("Rio_readnb error");
return -1;
}
return rc;
}
 
ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
{
ssize_t rc;
 
if ((rc = rio_readlineb(rp, usrbuf, maxlen)) < 0) {
unix_error("Rio_readlineb error");
return -1;
}
return rc;
}
 
/********************************
* Client/server helper functions
********************************/
/*
* open_clientfd - open connection to server at <hostname, port>
* and return a socket descriptor ready for reading and writing.
* Returns -1 and sets errno on Unix error.
* Returns -2 and sets h_errno on DNS (gethostbyname) error.
*/
/* $begin open_clientfd */
int open_clientfd(char *hostname, int port)
{
int clientfd;
struct hostent *hp;
struct sockaddr_in serveraddr;
 
if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1; /* check errno for cause of error */
 
/* Fill in the server's IP address and port */
if ((hp = gethostbyname(hostname)) == NULL)
return -2; /* check h_errno for cause of error */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)hp->h_addr_list[0],
(char *)&serveraddr.sin_addr.s_addr, hp->h_length);
serveraddr.sin_port = htons(port);
 
/* Establish a connection with the server */
if (connect(clientfd, (SA *) &serveraddr, sizeof(serveraddr)) < 0)
return -1;
return clientfd;
}
/* $end open_clientfd */
 
/*
* open_listenfd - open and return a listening socket on port
* Returns -1 and sets errno on Unix error.
*/
/* $begin open_listenfd */
int open_listenfd(int port)
{
int listenfd, optval=1;
struct sockaddr_in serveraddr;
/* Create a socket descriptor */
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
/* Eliminates "Address already in use" error from bind. */
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int)) < 0)
return -1;
 
/* Listenfd will be an endpoint for all requests to port
on any IP address for this host */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if (bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr)) < 0)
return -1;
 
/* Make it a listening socket ready to accept connection requests */
if (listen(listenfd, LISTENQ) < 0)
return -1;
return listenfd;
}
/* $end open_listenfd */
 
/******************************************
* Wrappers for the client/server helper routines
******************************************/
int Open_clientfd(char *hostname, int port)
{
int rc;
 
if ((rc = open_clientfd(hostname, port)) < 0) {
if (rc == -1) {
unix_error("Open_clientfd Unix error");
return -1;
} else {
dns_error("Open_clientfd DNS error");
return -1;
}
}
return rc;
}
 
int Open_listenfd(int port)
{
int rc;
 
if ((rc = open_listenfd(port)) < 0) {
unix_error("Open_listenfd error");
return -1;
}
return rc;
}
/* $end csapp.c */
 
 
 
 
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/csapp.h
0,0 → 1,168
/* $begin csapp.h */
#ifndef __CSAPP_H__
#define __CSAPP_H__
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <setjmp.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <math.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
 
/* Default file permissions are DEF_MODE & ~DEF_UMASK */
/* $begin createmasks */
#define DEF_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
#define DEF_UMASK S_IWGRP|S_IWOTH
/* $end createmasks */
 
/* Simplifies calls to bind(), connect(), and accept() */
/* $begin sockaddrdef */
typedef struct sockaddr SA;
/* $end sockaddrdef */
 
/* Persistent state for the robust I/O (Rio) package */
/* $begin rio_t */
#define RIO_BUFSIZE 8192
typedef struct {
int rio_fd; /* descriptor for this internal buf */
int rio_cnt; /* unread bytes in internal buf */
char *rio_bufptr; /* next unread byte in internal buf */
char rio_buf[RIO_BUFSIZE]; /* internal buffer */
} rio_t;
/* $end rio_t */
 
/* External variables */
extern int h_errno; /* defined by BIND for DNS errors */
extern char **environ; /* defined by libc */
 
/* Misc constants */
#define MAXLINE 8192 /* max text line length */
#define MAXBUF 8192 /* max I/O buffer size */
#define LISTENQ 1024 /* second argument to listen() */
 
/* Our own error-handling functions */
void unix_error(char *msg);
void posix_error(int code, char *msg);
void dns_error(char *msg);
void app_error(char *msg);
 
/* Process control wrappers */
pid_t Fork(void);
void Execve(const char *filename, char *const argv[], char *const envp[]);
pid_t Wait(int *status);
pid_t Waitpid(pid_t pid, int *iptr, int options);
void Kill(pid_t pid, int signum);
unsigned int Sleep(unsigned int secs);
void Pause(void);
unsigned int Alarm(unsigned int seconds);
void Setpgid(pid_t pid, pid_t pgid);
pid_t Getpgrp();
 
/* Signal wrappers */
typedef void handler_t(int);
handler_t *Signal(int signum, handler_t *handler);
void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
void Sigemptyset(sigset_t *set);
void Sigfillset(sigset_t *set);
void Sigaddset(sigset_t *set, int signum);
void Sigdelset(sigset_t *set, int signum);
int Sigismember(const sigset_t *set, int signum);
 
/* Unix I/O wrappers */
int Open(const char *pathname, int flags, mode_t mode);
ssize_t Read(int fd, void *buf, size_t count);
ssize_t Write(int fd, const void *buf, size_t count);
off_t Lseek(int fildes, off_t offset, int whence);
void Close(int fd);
int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
int Dup2(int fd1, int fd2);
void Stat(const char *filename, struct stat *buf);
void Fstat(int fd, struct stat *buf) ;
 
/* Memory mapping wrappers */
void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
void Munmap(void *start, size_t length);
 
/* Standard I/O wrappers */
void Fclose(FILE *fp);
FILE *Fdopen(int fd, const char *type);
char *Fgets(char *ptr, int n, FILE *stream);
FILE *Fopen(const char *filename, const char *mode);
void Fputs(const char *ptr, FILE *stream);
size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
 
/* Dynamic storage allocation wrappers */
void *Malloc(size_t size);
void *Realloc(void *ptr, size_t size);
void *Calloc(size_t nmemb, size_t size);
void Free(void *ptr);
 
/* Sockets interface wrappers */
int Socket(int domain, int type, int protocol);
void Setsockopt(int s, int level, int optname, const void *optval, int optlen);
void Bind(int sockfd, struct sockaddr *my_addr, int addrlen);
void Listen(int s, int backlog);
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
 
/* DNS wrappers */
struct hostent *Gethostbyname(const char *name);
struct hostent *Gethostbyaddr(const char *addr, int len, int type);
 
/* Pthreads thread control wrappers */
void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp,
void * (*routine)(void *), void *argp);
void Pthread_join(pthread_t tid, void **thread_return);
void Pthread_cancel(pthread_t tid);
void Pthread_detach(pthread_t tid);
void Pthread_exit(void *retval);
pthread_t Pthread_self(void);
void Pthread_once(pthread_once_t *once_control, void (*init_function)());
 
/* POSIX semaphore wrappers */
void Sem_init(sem_t *sem, int pshared, unsigned int value);
void P(sem_t *sem);
void V(sem_t *sem);
 
/* Rio (Robust I/O) package */
ssize_t rio_readn(int fd, void *usrbuf, size_t n);
ssize_t rio_writen(int fd, void *usrbuf, size_t n);
void rio_readinitb(rio_t *rp, int fd);
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
 
/* Wrappers for Rio package */
ssize_t Rio_readn(int fd, void *usrbuf, size_t n);
void Rio_writen(int fd, void *usrbuf, size_t n);
void Rio_readinitb(rio_t *rp, int fd);
ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n);
ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
 
/* Client/server helper functions */
int open_clientfd(char *hostname, int portno);
int open_listenfd(int portno);
 
/* Wrappers for client/server helper functions */
int Open_clientfd(char *hostname, int port);
int Open_listenfd(int port);
 
#endif /* __CSAPP_H__ */
/* $end csapp.h */
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/id.txt
0,0 → 1,0
klee482
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/list.c
0,0 → 1,532
#include "list.h"
#include <assert.h>
 
/* Our doubly linked lists have two header elements: the "head"
just before the first element and the "tail" just after the
last element. The `prev' link of the front header is null, as
is the `next' link of the back header. Their other two links
point toward each other via the interior elements of the list.
 
An empty list looks like this:
 
+------+ +------+
<---| head |<--->| tail |--->
+------+ +------+
 
A list with two elements in it looks like this:
 
+------+ +-------+ +-------+ +------+
<---| head |<--->| 1 |<--->| 2 |<--->| tail |<--->
+------+ +-------+ +-------+ +------+
 
The symmetry of this arrangement eliminates lots of special
cases in list processing. For example, take a look at
list_remove(): it takes only two pointer assignments and no
conditionals. That's a lot simpler than the code would be
without header elements.
 
(Because only one of the pointers in each header element is used,
we could in fact combine them into a single header element
without sacrificing this simplicity. But using two separate
elements allows us to do a little bit of checking on some
operations, which can be valuable.) */
 
static bool is_sorted (struct list_elem *a, struct list_elem *b,
list_less_func *less, void *aux);
 
/* Returns true if ELEM is a head, false otherwise. */
static inline bool
is_head (struct list_elem *elem)
{
return elem != NULL && elem->prev == NULL && elem->next != NULL;
}
 
/* Returns true if ELEM is an interior element,
false otherwise. */
static inline bool
is_interior (struct list_elem *elem)
{
return elem != NULL && elem->prev != NULL && elem->next != NULL;
}
 
/* Returns true if ELEM is a tail, false otherwise. */
static inline bool
is_tail (struct list_elem *elem)
{
return elem != NULL && elem->prev != NULL && elem->next == NULL;
}
 
/* Initializes LIST as an empty list. */
void
list_init (struct list *list)
{
assert (list != NULL);
list->head.prev = NULL;
list->head.next = &list->tail;
list->tail.prev = &list->head;
list->tail.next = NULL;
}
 
/* Returns the beginning of LIST. */
struct list_elem *
list_begin (struct list *list)
{
assert (list != NULL);
return list->head.next;
}
 
/* Returns the element after ELEM in its list. If ELEM is the
last element in its list, returns the list tail. Results are
undefined if ELEM is itself a list tail. */
struct list_elem *
list_next (struct list_elem *elem)
{
assert (is_head (elem) || is_interior (elem));
return elem->next;
}
 
/* Returns LIST's tail.
 
list_end() is often used in iterating through a list from
front to back. See the big comment at the top of list.h for
an example. */
struct list_elem *
list_end (struct list *list)
{
assert (list != NULL);
return &list->tail;
}
 
/* Returns the LIST's reverse beginning, for iterating through
LIST in reverse order, from back to front. */
struct list_elem *
list_rbegin (struct list *list)
{
assert (list != NULL);
return list->tail.prev;
}
 
/* Returns the element before ELEM in its list. If ELEM is the
first element in its list, returns the list head. Results are
undefined if ELEM is itself a list head. */
struct list_elem *
list_prev (struct list_elem *elem)
{
assert (is_interior (elem) || is_tail (elem));
return elem->prev;
}
 
/* Returns LIST's head.
 
list_rend() is often used in iterating through a list in
reverse order, from back to front. Here's typical usage,
following the example from the top of list.h:
 
for (e = list_rbegin (&foo_list); e != list_rend (&foo_list);
e = list_prev (e))
{
struct foo *f = list_entry (e, struct foo, elem);
...do something with f...
}
*/
struct list_elem *
list_rend (struct list *list)
{
assert (list != NULL);
return &list->head;
}
 
/* Return's LIST's head.
 
list_head() can be used for an alternate style of iterating
through a list, e.g.:
 
e = list_head (&list);
while ((e = list_next (e)) != list_end (&list))
{
...
}
*/
struct list_elem *
list_head (struct list *list)
{
assert (list != NULL);
return &list->head;
}
 
/* Return's LIST's tail. */
struct list_elem *
list_tail (struct list *list)
{
assert (list != NULL);
return &list->tail;
}
 
/* Inserts ELEM just before BEFORE, which may be either an
interior element or a tail. The latter case is equivalent to
list_push_back(). */
void
list_insert (struct list_elem *before, struct list_elem *elem)
{
assert (is_interior (before) || is_tail (before));
assert (elem != NULL);
 
elem->prev = before->prev;
elem->next = before;
before->prev->next = elem;
before->prev = elem;
}
 
/* Removes elements FIRST though LAST (exclusive) from their
current list, then inserts them just before BEFORE, which may
be either an interior element or a tail. */
void
list_splice (struct list_elem *before,
struct list_elem *first, struct list_elem *last)
{
assert (is_interior (before) || is_tail (before));
if (first == last)
return;
last = list_prev (last);
 
assert (is_interior (first));
assert (is_interior (last));
 
/* Cleanly remove FIRST...LAST from its current list. */
first->prev->next = last->next;
last->next->prev = first->prev;
 
/* Splice FIRST...LAST into new list. */
first->prev = before->prev;
last->next = before;
before->prev->next = first;
before->prev = last;
}
 
/* Inserts ELEM at the beginning of LIST, so that it becomes the
front in LIST. */
void
list_push_front (struct list *list, struct list_elem *elem)
{
list_insert (list_begin (list), elem);
}
 
/* Inserts ELEM at the end of LIST, so that it becomes the
back in LIST. */
void
list_push_back (struct list *list, struct list_elem *elem)
{
list_insert (list_end (list), elem);
}
 
/* Removes ELEM from its list and returns the element that
followed it. Undefined behavior if ELEM is not in a list.
 
It's not safe to treat ELEM as an element in a list after
removing it. In particular, using list_next() or list_prev()
on ELEM after removal yields undefined behavior. This means
that a naive loop to remove the elements in a list will fail:
 
** DON'T DO THIS **
for (e = list_begin (&list); e != list_end (&list); e = list_next (e))
{
...do something with e...
list_remove (e);
}
** DON'T DO THIS **
 
Here is one correct way to iterate and remove elements from a
list:
 
for (e = list_begin (&list); e != list_end (&list); e = list_remove (e))
{
...do something with e...
}
 
If you need to free() elements of the list then you need to be
more conservative. Here's an alternate strategy that works
even in that case:
 
while (!list_empty (&list))
{
struct list_elem *e = list_pop_front (&list);
...do something with e...
}
*/
struct list_elem *
list_remove (struct list_elem *elem)
{
assert (is_interior (elem));
elem->prev->next = elem->next;
elem->next->prev = elem->prev;
return elem->next;
}
 
/* Removes the front element from LIST and returns it.
Undefined behavior if LIST is empty before removal. */
struct list_elem *
list_pop_front (struct list *list)
{
struct list_elem *front = list_front (list);
list_remove (front);
return front;
}
 
/* Removes the back element from LIST and returns it.
Undefined behavior if LIST is empty before removal. */
struct list_elem *
list_pop_back (struct list *list)
{
struct list_elem *back = list_back (list);
list_remove (back);
return back;
}
 
/* Returns the front element in LIST.
Undefined behavior if LIST is empty. */
struct list_elem *
list_front (struct list *list)
{
assert (!list_empty (list));
return list->head.next;
}
 
/* Returns the back element in LIST.
Undefined behavior if LIST is empty. */
struct list_elem *
list_back (struct list *list)
{
assert (!list_empty (list));
return list->tail.prev;
}
 
/* Returns the number of elements in LIST.
Runs in O(n) in the number of elements. */
size_t
list_size (struct list *list)
{
struct list_elem *e;
size_t cnt = 0;
 
for (e = list_begin (list); e != list_end (list); e = list_next (e))
cnt++;
return cnt;
}
 
/* Returns true if LIST is empty, false otherwise. */
bool
list_empty (struct list *list)
{
return list_begin (list) == list_end (list);
}
 
/* Swaps the `struct list_elem *'s that A and B point to. */
static void
swap (struct list_elem **a, struct list_elem **b)
{
struct list_elem *t = *a;
*a = *b;
*b = t;
}
 
/* Reverses the order of LIST. */
void
list_reverse (struct list *list)
{
if (!list_empty (list))
{
struct list_elem *e;
 
for (e = list_begin (list); e != list_end (list); e = e->prev)
swap (&e->prev, &e->next);
swap (&list->head.next, &list->tail.prev);
swap (&list->head.next->prev, &list->tail.prev->next);
}
}
 
/* Returns true only if the list elements A through B (exclusive)
are in order according to LESS given auxiliary data AUX. */
static bool
is_sorted (struct list_elem *a, struct list_elem *b,
list_less_func *less, void *aux)
{
if (a != b)
while ((a = list_next (a)) != b)
if (less (a, list_prev (a), aux))
return false;
return true;
}
 
/* Finds a run, starting at A and ending not after B, of list
elements that are in nondecreasing order according to LESS
given auxiliary data AUX. Returns the (exclusive) end of the
run.
A through B (exclusive) must form a non-empty range. */
static struct list_elem *
find_end_of_run (struct list_elem *a, struct list_elem *b,
list_less_func *less, void *aux)
{
assert (a != NULL);
assert (b != NULL);
assert (less != NULL);
assert (a != b);
do
{
a = list_next (a);
}
while (a != b && !less (a, list_prev (a), aux));
return a;
}
 
/* Merges A0 through A1B0 (exclusive) with A1B0 through B1
(exclusive) to form a combined range also ending at B1
(exclusive). Both input ranges must be nonempty and sorted in
nondecreasing order according to LESS given auxiliary data
AUX. The output range will be sorted the same way. */
static void
inplace_merge (struct list_elem *a0, struct list_elem *a1b0,
struct list_elem *b1,
list_less_func *less, void *aux)
{
assert (a0 != NULL);
assert (a1b0 != NULL);
assert (b1 != NULL);
assert (less != NULL);
assert (is_sorted (a0, a1b0, less, aux));
assert (is_sorted (a1b0, b1, less, aux));
 
while (a0 != a1b0 && a1b0 != b1)
if (!less (a1b0, a0, aux))
a0 = list_next (a0);
else
{
a1b0 = list_next (a1b0);
list_splice (a0, list_prev (a1b0), a1b0);
}
}
 
/* Sorts LIST according to LESS given auxiliary data AUX, using a
natural iterative merge sort that runs in O(n lg n) time and
O(1) space in the number of elements in LIST. */
void
list_sort (struct list *list, list_less_func *less, void *aux)
{
size_t output_run_cnt; /* Number of runs output in current pass. */
 
assert (list != NULL);
assert (less != NULL);
 
/* Pass over the list repeatedly, merging adjacent runs of
nondecreasing elements, until only one run is left. */
do
{
struct list_elem *a0; /* Start of first run. */
struct list_elem *a1b0; /* End of first run, start of second. */
struct list_elem *b1; /* End of second run. */
 
output_run_cnt = 0;
for (a0 = list_begin (list); a0 != list_end (list); a0 = b1)
{
/* Each iteration produces one output run. */
output_run_cnt++;
 
/* Locate two adjacent runs of nondecreasing elements
A0...A1B0 and A1B0...B1. */
a1b0 = find_end_of_run (a0, list_end (list), less, aux);
if (a1b0 == list_end (list))
break;
b1 = find_end_of_run (a1b0, list_end (list), less, aux);
 
/* Merge the runs. */
inplace_merge (a0, a1b0, b1, less, aux);
}
}
while (output_run_cnt > 1);
 
assert (is_sorted (list_begin (list), list_end (list), less, aux));
}
 
/* Inserts ELEM in the proper position in LIST, which must be
sorted according to LESS given auxiliary data AUX.
Runs in O(n) average case in the number of elements in LIST. */
void
list_insert_ordered (struct list *list, struct list_elem *elem,
list_less_func *less, void *aux)
{
struct list_elem *e;
 
assert (list != NULL);
assert (elem != NULL);
assert (less != NULL);
 
for (e = list_begin (list); e != list_end (list); e = list_next (e))
if (less (elem, e, aux))
break;
return list_insert (e, elem);
}
 
/* Iterates through LIST and removes all but the first in each
set of adjacent elements that are equal according to LESS
given auxiliary data AUX. If DUPLICATES is non-null, then the
elements from LIST are appended to DUPLICATES. */
void
list_unique (struct list *list, struct list *duplicates,
list_less_func *less, void *aux)
{
struct list_elem *elem, *next;
 
assert (list != NULL);
assert (less != NULL);
if (list_empty (list))
return;
 
elem = list_begin (list);
while ((next = list_next (elem)) != list_end (list))
if (!less (elem, next, aux) && !less (next, elem, aux))
{
list_remove (next);
if (duplicates != NULL)
list_push_back (duplicates, next);
}
else
elem = next;
}
 
/* Returns the element in LIST with the largest value according
to LESS given auxiliary data AUX. If there is more than one
maximum, returns the one that appears earlier in the list. If
the list is empty, returns its tail. */
struct list_elem *
list_max (struct list *list, list_less_func *less, void *aux)
{
struct list_elem *max = list_begin (list);
if (max != list_end (list))
{
struct list_elem *e;
for (e = list_next (max); e != list_end (list); e = list_next (e))
if (less (max, e, aux))
max = e;
}
return max;
}
 
/* Returns the element in LIST with the smallest value according
to LESS given auxiliary data AUX. If there is more than one
minimum, returns the one that appears earlier in the list. If
the list is empty, returns its tail. */
struct list_elem *
list_min (struct list *list, list_less_func *less, void *aux)
{
struct list_elem *min = list_begin (list);
if (min != list_end (list))
{
struct list_elem *e;
for (e = list_next (min); e != list_end (list); e = list_next (e))
if (less (e, min, aux))
min = e;
}
return min;
}
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/list.h
0,0 → 1,170
#ifndef __LIST_H
#define __LIST_H
/* This code is taken from the Pintos education OS.
* For copyright information, see www.pintos-os.org */
 
/* Doubly linked list.
 
This implementation of a doubly linked list does not require
use of dynamically allocated memory. Instead, each structure
that is a potential list element must embed a struct list_elem
member. All of the list functions operate on these `struct
list_elem's. The list_entry macro allows conversion from a
struct list_elem back to a structure object that contains it.
 
For example, suppose there is a needed for a list of `struct
foo'. `struct foo' should contain a `struct list_elem'
member, like so:
 
struct foo
{
struct list_elem elem;
int bar;
...other members...
};
 
Then a list of `struct foo' can be be declared and initialized
like so:
 
struct list foo_list;
 
list_init (&foo_list);
 
Iteration is a typical situation where it is necessary to
convert from a struct list_elem back to its enclosing
structure. Here's an example using foo_list:
 
struct list_elem *e;
 
for (e = list_begin (&foo_list); e != list_end (&foo_list);
e = list_next (e))
{
struct foo *f = list_entry (e, struct foo, elem);
...do something with f...
}
 
You can find real examples of list usage throughout the
source; for example, malloc.c, palloc.c, and thread.c in the
threads directory all use lists.
 
The interface for this list is inspired by the list<> template
in the C++ STL. If you're familiar with list<>, you should
find this easy to use. However, it should be emphasized that
these lists do *no* type checking and can't do much other
correctness checking. If you screw up, it will bite you.
 
Glossary of list terms:
 
- "front": The first element in a list. Undefined in an
empty list. Returned by list_front().
 
- "back": The last element in a list. Undefined in an empty
list. Returned by list_back().
 
- "tail": The element figuratively just after the last
element of a list. Well defined even in an empty list.
Returned by list_end(). Used as the end sentinel for an
iteration from front to back.
 
- "beginning": In a non-empty list, the front. In an empty
list, the tail. Returned by list_begin(). Used as the
starting point for an iteration from front to back.
 
- "head": The element figuratively just before the first
element of a list. Well defined even in an empty list.
Returned by list_rend(). Used as the end sentinel for an
iteration from back to front.
 
- "reverse beginning": In a non-empty list, the back. In an
empty list, the head. Returned by list_rbegin(). Used as
the starting point for an iteration from back to front.
 
- "interior element": An element that is not the head or
tail, that is, a real list element. An empty list does
not have any interior elements.
*/
 
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
 
/* List element. */
struct list_elem
{
struct list_elem *prev; /* Previous list element. */
struct list_elem *next; /* Next list element. */
};
 
/* List. */
struct list
{
struct list_elem head; /* List head. */
struct list_elem tail; /* List tail. */
};
 
/* Converts pointer to list element LIST_ELEM into a pointer to
the structure that LIST_ELEM is embedded inside. Supply the
name of the outer structure STRUCT and the member name MEMBER
of the list element. See the big comment at the top of the
file for an example. */
#define list_entry(LIST_ELEM, STRUCT, MEMBER) \
((STRUCT *) ((uint8_t *) &(LIST_ELEM)->next \
- offsetof (STRUCT, MEMBER.next)))
 
void list_init (struct list *);
 
/* List traversal. */
struct list_elem *list_begin (struct list *);
struct list_elem *list_next (struct list_elem *);
struct list_elem *list_end (struct list *);
 
struct list_elem *list_rbegin (struct list *);
struct list_elem *list_prev (struct list_elem *);
struct list_elem *list_rend (struct list *);
 
struct list_elem *list_head (struct list *);
struct list_elem *list_tail (struct list *);
 
/* List insertion. */
void list_insert (struct list_elem *, struct list_elem *);
void list_splice (struct list_elem *before,
struct list_elem *first, struct list_elem *last);
void list_push_front (struct list *, struct list_elem *);
void list_push_back (struct list *, struct list_elem *);
 
/* List removal. */
struct list_elem *list_remove (struct list_elem *);
struct list_elem *list_pop_front (struct list *);
struct list_elem *list_pop_back (struct list *);
 
/* List elements. */
struct list_elem *list_front (struct list *);
struct list_elem *list_back (struct list *);
 
/* List properties. */
size_t list_size (struct list *);
bool list_empty (struct list *);
 
/* Miscellaneous. */
void list_reverse (struct list *);
/* Compares the value of two list elements A and B, given
auxiliary data AUX. Returns true if A is less than B, or
false if A is greater than or equal to B. */
typedef bool list_less_func (const struct list_elem *a,
const struct list_elem *b,
void *aux);
 
/* Operations on lists with ordered elements. */
void list_sort (struct list *,
list_less_func *, void *aux);
void list_insert_ordered (struct list *, struct list_elem *,
list_less_func *, void *aux);
void list_unique (struct list *, struct list *duplicates,
list_less_func *, void *aux);
 
/* Max and min. */
struct list_elem *list_max (struct list *, list_less_func *, void *aux);
struct list_elem *list_min (struct list *, list_less_func *, void *aux);
 
#endif /* list.h */
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/sysstatd
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/sysstatd
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/sysstatd.c
0,0 → 1,582
 
#include "csapp.h"
#include "threadpool_exec.h"
#include "list.h"
 
#define THREAD_POOL_SIZE 10
 
// Struct for passing data to threads in the thread pool
struct parse_struct {
int connfd;
char *rootdir;
};
 
void * runloop(void *arg);
void allocanon(void);
void freeanon(void);
void parse_request(struct parse_struct *p);
void read_requesthdrs(rio_t *rp, char *close_connection);
int parse_uri(char *uri, char *filename, char *cgiargs, char *rootdir);
void serve_file(int fd, char *filename, int filesize);
void serve_json(int fd, char *data);
void check_callback(char *data, char *cgiargs);
void get_filetype(char *filename, char *filetype);
void get_loadavg(char *ret_json);
void get_meminfo(char *ret_json);
void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg);
int Open_listenfd_6(int port);
 
static pthread_mutex_t last_activity_mutex;
static time_t last_activity;
static pthread_mutex_t mem_list_mutex;
static struct list mem_list;
 
struct mem_elem {
struct list_elem elem;
void * ptr;
};
 
int main(int argc, char **argv)
{
int listenfd, connfd;
int port = 0, c;
struct sockaddr_in clientaddr;
socklen_t clientlen = sizeof(clientaddr);
char *relayhost = NULL, *rootdir = NULL;
char *default_dir = ".";
 
// Check arguments passed into program
while ((c = getopt(argc, argv, "p:r:R:")) != -1) {
switch (c) {
case 'p':
port = atoi(optarg);
break;
case 'r':
relayhost = optarg;
break;
case 'R':
rootdir = optarg;
break;
default:
break;
}
}
 
if (port == 0 && relayhost == NULL) {
fprintf(stderr, "usage: -p <port> -r <relayhost:port> -R <root directory path>\n");
exit(1);
}
 
// If rootdir is not specified, use current directory
if (rootdir == NULL) {
rootdir = default_dir;
}
 
// Create the thread pool to process client requests
struct thread_pool * t_pool = thread_pool_new(THREAD_POOL_SIZE);
 
// Initialize static variables and mutex for such variables
list_init(&mem_list);
pthread_mutex_init(&last_activity_mutex, NULL);
pthread_mutex_init(&mem_list_mutex, NULL);
 
// Open a listening port if it is specified
if (port != 0) {
listenfd = Open_listenfd_6(port);
 
while (1) {
connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
struct parse_struct p;
p.connfd = connfd;
p.rootdir = rootdir;
thread_pool_submit(t_pool, (thread_pool_callable_func_t) parse_request, &p);
}
 
} else { // Connect to the relay server
char *c, host[MAXLINE], buf[MAXLINE];
int p;
 
// Parse the hostname and port
c = strtok(relayhost, ":");
strcpy(host, c);
c = strtok(NULL, ":");
p = atoi(c);
 
 
while (1) {
printf("Connecting to relay server\n");
 
// Initialize the last activity time
pthread_mutex_lock(&last_activity_mutex);
last_activity = time(NULL);
pthread_mutex_unlock(&last_activity_mutex);
 
// Establish TCP connection to relay server
listenfd = Open_clientfd(host, p);
if (listenfd == -1) {
printf("Relay open error\n");
exit(1);
}
 
// Send relay identifier
strcpy(buf, "group244\r\n");
Rio_writen(listenfd, buf, strlen(buf));
 
// Handle HTML requests
struct parse_struct ps;
ps.connfd = listenfd;
ps.rootdir = rootdir;
thread_pool_submit(t_pool, (thread_pool_callable_func_t) parse_request, &ps);
 
// Reconnect if there has been no activity for 300 seconds
while(1) {
time_t cur_time = time(NULL);
pthread_mutex_lock(&last_activity_mutex);
if (difftime(cur_time, last_activity) > 300) {
pthread_mutex_unlock(&last_activity_mutex);
break;
} else {
pthread_mutex_unlock(&last_activity_mutex);
sleep(1);
}
}
}
}
}
 
/*
* parse_request - handle one HTTP request/response transaction
*/
void parse_request(struct parse_struct *p)
{
struct parse_struct *p_data = p;
int fd = p_data->connfd;
int parse_ret;
struct stat sbuf;
char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE], data[MAXLINE];
char filename[MAXLINE], cgiargs[MAXLINE];
char close_connection = 0;
rio_t rio;
 
while (1) {
/* Read request line and headers */
Rio_readinitb(&rio, fd);
// Make sure that EOF is not returned for the socket
if (Rio_readlineb(&rio, buf, MAXLINE) > 0) {
 
// Save current time (activity)
pthread_mutex_lock(&last_activity_mutex);
last_activity = time(NULL);
pthread_mutex_unlock(&last_activity_mutex);
 
// Parse received data
sscanf(buf, "%s %s %s", method, uri, version);
if (strcasecmp(method, "GET")) {
clienterror(fd, method, "501", "Not Implemented", "Sysstatd does not implement this method");
continue;
}
 
// Check the headers, we're only looking for Connection:close here
read_requesthdrs(&rio, &close_connection);
if (close_connection == -1) {
Close(fd);
break;
}
 
/* Parse URI from GET request */
parse_ret = parse_uri(uri, filename, cgiargs, p_data->rootdir);
if (parse_ret == 0) { // Return file
if (stat(filename, &sbuf) < 0) {
clienterror(fd, filename, "404", "Not found", "Sysstatd couldn't find this file");
continue;
}
 
if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
clienterror(fd, filename, "403", "Forbidden", "Sysstatd couldn't read the file");
continue;
}
serve_file(fd, filename, sbuf.st_size);
} else if (parse_ret == 1) { // Return /loadavg
get_loadavg(data);
check_callback(data, cgiargs);
serve_json(fd, data);
} else if (parse_ret == 2) { // Return /meminfo
get_meminfo(data);
check_callback(data, cgiargs);
serve_json(fd, data);
} else if (parse_ret == 3) { // Execute /runloop
pthread_t thr;
pthread_create(&thr, NULL, runloop, NULL);
} else if (parse_ret == 4) { // Execute /allocanon
printf("Allocanon\n");
allocanon();
} else if (parse_ret == 5) { // Execute /freeanon
printf("Freeanon\n");
freeanon();
} else {
clienterror(fd, uri, "404", "Not found", "Sysstatd does not implement this URL");
}
 
// Close the connection if HTTP 1.0 is used or close is specified in the header
if (!strcmp(version, "HTTP/1.0") || close_connection) {
Close(fd);
break;
}
} else {
Close(fd);
break;
}
}
}
 
/*
* runloop - spins for 15 seconds then returns
*/
void * runloop(void *arg) {
time_t t1 = time(NULL);
time_t t2;
do {
t2 = time(NULL);
} while (difftime(t2,t1) < 15);
return NULL;
}
 
/*
* allocanon - allocates 64MB in anonymous virtual memory
*/
void allocanon() {
// Get the address mapping for a 64MB
void * new_map = mmap(NULL, 67108864, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (new_map == MAP_FAILED) {
printf("Allocanon failed\n");
return;
} else {
printf("%p\n", new_map);
}
 
// Do something with the newly allocated memory
memset(new_map, 0, 67108864);
 
// Save address in list for later removal
struct mem_elem *m = malloc(sizeof(struct mem_elem));
m->ptr = new_map;
pthread_mutex_lock(&mem_list_mutex);
list_push_back(&mem_list, &m->elem);
pthread_mutex_unlock(&mem_list_mutex);
}
 
/*
* freeanon - frees a block of anonymous virtual memory previously allocated
*/
void freeanon() {
// Remove the most recently allocated memory block
pthread_mutex_lock(&mem_list_mutex);
if (list_size(&mem_list)) {
struct list_elem *e = list_pop_back(&mem_list);
struct mem_elem *m = list_entry(e, struct mem_elem, elem);
munmap(m->ptr, 67108864);
free(m);
}
pthread_mutex_unlock(&mem_list_mutex);
}
 
/*
* read_requesthdrs - read and parse HTTP request headers
*/
void read_requesthdrs(rio_t *rp, char *close_connection)
{
char buf[MAXLINE];
 
do {
if (Rio_readlineb(rp, buf, MAXLINE) > 0) {
// Check if the header contains a request to close connection
if (!strcmp(buf, "Connection: close\r\n"))
*close_connection = 1;
// printf("%s", buf);
} else {
*close_connection = -1;
return;
}
} while (strcmp(buf, "\r\n"));
 
return;
}
 
/*
* parse_uri - parse URI into filename and CGI args
* return 0 if file, 1 if loadavg, 2 if meminfo,
* 3 if runloop, 4 if allocanon, 5 if freeanon
* return -1 if uri is not supported
*/
int parse_uri(char *uri, char *filename, char *cgiargs, char *rootdir)
{
char *ptr;
 
// Save cgiargs if they exist
if (!strstr(uri, "?")) {
strcpy(cgiargs, "");
} else {
ptr = index(uri, '?');
if (ptr) {
strcpy(cgiargs, ptr+1);
*ptr = '\0';
}
else
strcpy(cgiargs, "");
}
 
// Check uri for specific commands
if (!strncmp(uri, "/files", 6)) {
strcpy(filename, rootdir);
strcat(filename, uri+6);
 
// Ensure that all "/../" in the filename is replaced with "////"
char *s = strstr(filename, "/../");
while (s) {
strncpy(s, "////", 4);
s = strstr(filename, "/../");
}
// printf("%s\n", filename);
return 0;
} else if (!strcmp(uri, "/loadavg")) {
return 1;
} else if (!strcmp(uri, "/meminfo")) {
return 2;
} else if (!strcmp(uri, "/runloop")) {
return 3;
} else if (!strcmp(uri, "/allocanon")) {
return 4;
} else if (!strcmp(uri, "/freeanon")) {
return 5;
} else {
return -1;
}
}
 
/*
* serve_json - returns JSON data to the client
*/
void serve_json(int fd, char *data) {
char buf[MAXBUF];
 
/* Send response headers to client */
sprintf(buf, "HTTP/1.1 200 OK\r\n");
sprintf(buf, "%sServer: Sysstatd Web Server\r\n", buf);
sprintf(buf, "%sContent-length: %d\r\n", buf, (int)strlen(data));
sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, "application/json");
Rio_writen(fd, buf, strlen(buf));
 
/* Send json data to client */
Rio_writen(fd, data, strlen(data));
}
 
/*
* get_loadavg - returns /proc/loadavg in JSON format
*/
void get_loadavg(char *ret_json) {
FILE *f;
char line[MAXLINE], load1[10], load2[10], load3[10];
char threads[20], total_threads[20], active_threads[20];
memset(active_threads, 0, 20);
memset(total_threads, 0, 20);
 
// Read data from /proc/loadavg
f = Fopen("/proc/loadavg", "rt");
Fgets(line, MAXLINE, f);
Fclose(f);
 
// Format data into JSON format
sscanf(line, "%s %s %s %s", load1, load2, load3, threads);
int i = strcspn(threads, "/");
strncpy(active_threads, threads, i);
strcpy(total_threads, threads+i+1);
 
sprintf(ret_json, "{\"total_threads\": \"%s\", \"loadavg\": [\"%s\", \"%s\", \"%s\"], \"running_threads\": \"%s\"}",
total_threads, load1, load2, load3, active_threads);
}
 
/*
* get_meminfo - returns /proc/meminfo in JSON format
*/
void get_meminfo(char *ret_json) {
FILE *f;
char line[MAXLINE], s1[MAXLINE], s2[MAXLINE], buf[MAXLINE];
 
strcpy(ret_json, "{");
 
// Read data and convert to JSON format
f = Fopen("/proc/meminfo", "rt");
while (Fgets(line, MAXLINE, f) != NULL) {
sscanf(line, "%s %s", s1, s2);
strcpy(buf, "\"");
strncat(buf, s1, strlen(s1)-1);
strcat(buf, "\": \"");
strcat(buf, s2);
strcat(buf, "\", ");
 
strcat(ret_json, buf);
}
Fclose(f);
 
strcpy(ret_json+strlen(ret_json)-2, "}");
}
 
/*
* serve_file - copy a file back to the client
*/
void serve_file(int fd, char *filename, int filesize)
{
int srcfd;
char *srcp, filetype[MAXLINE], buf[MAXBUF];
 
/* Send response headers to client */
get_filetype(filename, filetype);
sprintf(buf, "HTTP/1.1 200 OK\r\n");
sprintf(buf, "%sServer: Sysstatd Web Server\r\n", buf);
sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);
Rio_writen(fd, buf, strlen(buf));
 
/* Send response body to client */
srcfd = Open(filename, O_RDONLY, 0);
srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
Close(srcfd);
Rio_writen(fd, srcp, filesize);
Munmap(srcp, filesize);
}
 
/*
* check_callback - check to see if a callback is specified in cgiargs
*/
void check_callback(char *data, char *cgiargs)
{
char *p, buf[MAXLINE];
 
// If cgiargs is empty, return
if (!strcmp(cgiargs, ""))
return;
 
p = strtok(cgiargs, "&");
while (p != NULL) {
if (!strncmp(p, "callback=", 9)) {
strcpy(buf, p+9);
strcat(buf, "(");
strcat(buf, data);
strcat(buf, ")");
 
strcpy(data, buf);
}
p = strtok(NULL, "&");
}
}
 
/*
* get_filetype - derive file type from file name
*/
void get_filetype(char *filename, char *filetype)
{
if (strstr(filename, ".html"))
strcpy(filetype, "text/html");
else if (strstr(filename, ".gif"))
strcpy(filetype, "image/gif");
else if (strstr(filename, ".jpg"))
strcpy(filetype, "image/jpeg");
else if (strstr(filename, ".js"))
strcpy(filetype, "application/javascript");
else if (strstr(filename, ".css"))
strcpy(filetype, "text/css");
else
strcpy(filetype, "text/plain");
}
 
/*
* clienterror - returns an error message to the client
*/
void clienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg)
{
char buf[MAXLINE], body[MAXBUF];
 
/* Build the HTTP response body */
sprintf(body, "<html><title>Sysstatd Error</title>");
sprintf(body, "%s<body bgcolor=""ffffff"">\r\n", body);
sprintf(body, "%s%s: %s\r\n", body, errnum, shortmsg);
sprintf(body, "%s<p>%s: %s\r\n", body, longmsg, cause);
sprintf(body, "%s<hr><em>The Sysstatd Web server</em>\r\n", body);
 
/* Print the HTTP response */
sprintf(buf, "HTTP/1.1 %s %s\r\n", errnum, shortmsg);
Rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Content-type: text/html\r\n");
Rio_writen(fd, buf, strlen(buf));
sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body));
Rio_writen(fd, buf, strlen(buf));
Rio_writen(fd, body, strlen(body));
}
 
/*
* Open_listenfd_6 - opens and returns a listening socket on the specified port.
* will attempt to open an ipv6 socket over an ipv4 socket.
*/
int Open_listenfd_6(int port) {
char p[10];
sprintf(p, "%d", port);
 
// Initialize stuffs
struct addrinfo *ai;
struct addrinfo hints;
memset (&hints, '\0', sizeof (hints));
 
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
hints.ai_socktype = SOCK_STREAM;
int e = getaddrinfo(NULL, p, &hints, &ai);
if (e != 0) {
fprintf(stderr, "Error at getaddrinfo()\n");
exit(1);
}
 
int nfds = 0;
struct addrinfo *runp = ai;
 
// Loop for ai_family == 10 (AF_INET6) for an ipv6 socket. Choose the first
// socket in the list otherwise
int inet_6 = -1, i;
while (runp != NULL) {
if (runp->ai_family == 10)
inet_6 = nfds;
++nfds;
runp = runp->ai_next;
}
if (inet_6 > 0) {
runp = ai;
for (i = 0; i < inet_6; i++) {
runp = runp->ai_next;
}
} else {
runp = ai;
}
 
// Create, bind, and listen on the specified socket
int listenfd;
listenfd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);
if (listenfd == -1) {
fprintf(stderr, "Error at socket()\n");
exit(1);
}
int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 
if (bind(listenfd, runp->ai_addr, runp->ai_addrlen) != 0) {
fprintf(stderr, "Error at bind()\n");
close(listenfd);
exit(1);
} else {
if (listen(listenfd, SOMAXCONN) != 0) {
fprintf(stderr, "Error at listen()\n");
exit(1);
}
}
freeaddrinfo (ai);
 
return listenfd;
}
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/sysstatwebservice-handout.pdf
0,0 → 1,1902
%PDF-1.4
5 0 obj
<< /S /GoTo /D (section.1) >>
endobj
8 0 obj
(Introduction)
endobj
9 0 obj
<< /S /GoTo /D (section.2) >>
endobj
12 0 obj
(Functionality)
endobj
13 0 obj
<< /S /GoTo /D (subsection.2.1) >>
endobj
16 0 obj
(System Status Web Service)
endobj
17 0 obj
<< /S /GoTo /D (subsection.2.2) >>
endobj
20 0 obj
(Serving Files)
endobj
21 0 obj
<< /S /GoTo /D (subsection.2.3) >>
endobj
24 0 obj
(Synthetic Load Requests)
endobj
25 0 obj
<< /S /GoTo /D (subsection.2.4) >>
endobj
28 0 obj
(Multiple Client Support)
endobj
29 0 obj
<< /S /GoTo /D (subsection.2.5) >>
endobj
32 0 obj
(Robustness)
endobj
33 0 obj
<< /S /GoTo /D (subsection.2.6) >>
endobj
36 0 obj
(Protocol Independence)
endobj
37 0 obj
<< /S /GoTo /D (subsection.2.7) >>
endobj
40 0 obj
(Relay Server)
endobj
41 0 obj
<< /S /GoTo /D (subsection.2.8) >>
endobj
44 0 obj
(Widgets)
endobj
45 0 obj
<< /S /GoTo /D (subsection.2.9) >>
endobj
48 0 obj
(Minimum Requirements)
endobj
49 0 obj
<< /S /GoTo /D (subsection.2.10) >>
endobj
52 0 obj
(Choice of Port Numbers and Relay Server Prefixes)
endobj
53 0 obj
<< /S /GoTo /D (section.3) >>
endobj
56 0 obj
(Strategy)
endobj
57 0 obj
<< /S /GoTo /D (section.4) >>
endobj
60 0 obj
(Grading)
endobj
61 0 obj
<< /S /GoTo /D (subsection.4.1) >>
endobj
64 0 obj
(Coding Style)
endobj
65 0 obj
<< /S /GoTo /D (subsection.4.2) >>
endobj
68 0 obj
(Submission)
endobj
69 0 obj
<< /S /GoTo /D (subsection.4.3) >>
endobj
72 0 obj
(Online Demonstration and Grade Breakdown)
endobj
73 0 obj
<< /S /GoTo /D (subsection.4.4) >>
endobj
76 0 obj
(Extra Credit)
endobj
77 0 obj
<< /S /GoTo /D [78 0 R /Fit ] >>
endobj
80 0 obj <<
/Length 2354
/Filter /FlateDecode
>>
stream
xÚ­YëoÛ8ÿž¿Âȇ«Ä IQ¯ÅÒmî¶è>®öápÈæƒ"+±¶¶¤ÕÃiþû›á mɕ»Y´È“#r8œùq^¹^ž]ÝøáLá›Pϖ³HÏ"S'³åêÖ{»ðµ2sHï&Ýlh¤¥Òó8ÐÆûµ¹P±Wýžg} ègN?¿ií/×9MÚç¶íÒnE³ÿ^$ÚËïi²È›]‘å°Ü\Ü-ߟ½[ž©™„?eEòcø2˜eÛ³?Înïälu&gïϤð“8˜=ÁD
•$z¶=3aì&›³ÅÙ¿÷|æÀh>ätm¯͔Iì¯/c!‰íõèYôÒ.’‘Â;‚XÄ*ñá\ÿSµJŸ/”RÞ%ïË3(É¥^I½eõÈ@~Ö4ƒ½-¶ÀÅîùSßæ+«Ê0›»SçZ‰0Œ#{ør]ðöúØ(YZŽù­ª’Gy¤=}Í<ª¶5Û®ëWyÙµ‚•j‹„VA%ÈÙÜÄ"
+–o™ÂŠïª¬Ú´`pßWÞÓºÈÖôù¡j¶4!h@™ûmÕâ­Uà=«|óLT´ÿÄDBZÕ|,9`õ
+Ÿß=or\ª–ˆ×š¸„{xùçt ¿-RE@¶×°²aš²7è7]1ïÖt¿t•³EEäÍEd¼—¼Jͯò¦/í‹L7E÷ü‚giA¢CPb¤¥I6(£è.ösND ¬$Рš|˜¶Øe뇔¨`¶"#
+½3$’åÄæóRÞÊ/bÏ¥z¹i`±r3æ´t,ÕL0#sÂà7)58NAzÁ€ÌÛä@…¦ï7¼ot+åÕyÓmÇst8e™[í·“`qþÛ²F\¸Ð‰Ê¸RBÑìVߍ½u â9bÀ~+€p¾yñ bqZ@Pî[•NGQùH¤Q¢Øwƒ * 0Æ[¾vÌ|ql5g‰Ì&Æ ‰)ý°õqHÖ?µ3`óã¨îï7E»Î[bɬ>eÿy(Ò«vÚÇðÕ#Mڏ”GϬ®šÎ>4ørÿL_È@ø„^tCÄ]‘¿ZM5Ԕ–‰5˜ƒR„«)mFBE¾âlԌ¸é(º ‚2
+”‘%,Ý+©Ûã’­B%˜> UÑíӇ¢Ä@ÅAq˜#¼_üò3#P1i¥pº¥|$>`×<9<ÄÉzŸO’ÆÛº*WcHþèó¶k÷ç±od¹ÉÓ¶;z-ÕfS=a ²¯zòçyk3¹Y ’(
+ ß@ŽCâÜPâ¶yr~r¨·ŒEù¾"7—P@çÄίíkÌR‰ IRóLtª[¡ë±i™ÚÒB*.€ðñæ-QÀ‡|ʂª¢ûBÖ@±÷?ì֍D˜Ê¦@ØIIéçUiÞ=ȒfŸ^ñ’Ï
+‡ˆ8ò~| c°£€7øp‡ÖӍñ3erP‹s·†S[{%œ·Ïe—~¦±Íq ò>Ý¥‹¬)êIѸ*æ:RSÍ©/ŒÔÅÁ!÷o—nlPsE¿ÿ¦¥MÛsª
+¥s°§x,Ýå©Ì‹c:m Wt9ÿ’ºùÀÄo´±Çm„(éݸê‹ÛY—£>Õ ZۗqAç¹.ÀÿÝ¡åÍïmUÖJƒ~ 쑁‘ûˆ>¤PpiŒÊÔ·ÛÐ1œ8NyzƒÕ"°vËð
+oöšþA–—"‘Ø W¯Ã„öZÀôTm¾åŽ^窠{nûÿSÐïujß$ÿ§àµó¬»Nä«Þý;àeڇX¥”k8ð¸h)ÞÒj^òœ°—ïÀÆ¡‡½;l¥ØA…îÝC"z`àCdPÒu, ’Õ&O‚¸ˆéœ[÷%'`&{Y™…ñ+ÅRº¬õçj—oï],¸üCŠ!òº}–endstream
+endobj
+78 0 obj <<
+/Type /Page
+/Contents 80 0 R
+/Resources 79 0 R
+/MediaBox [0 0 612 792]
+/Parent 109 0 R
+/Annots [ 89 0 R 90 0 R 91 0 R 95 0 R 99 0 R ]
+>> endobj
+89 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 0]
+/Rect [363.9986 558.5216 371.9687 568.8706]
+/Subtype /Link
+/A << /S /GoTo /D (cite.fielding:acmtit2002) >>
+>> endobj
+90 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 0]
+/Rect [375.5617 558.6412 383.5318 569.0499]
+/Subtype /Link
+/A << /S /GoTo /D (cite.restful) >>
+>> endobj
+91 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 0]
+/Rect [186.2145 431.9742 194.1846 442.2036]
+/Subtype /Link
+/A << /S /GoTo /D (cite.rfc2616) >>
+>> endobj
+95 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 0]
+/Rect [209.4311 329.6253 217.4013 340.0341]
+/Subtype /Link
+/A << /S /GoTo /D (cite.json) >>
+>> endobj
+99 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [361.2472 159.7745 484.0759 173.8475]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2.2)>>
+>> endobj
+81 0 obj <<
+/D [78 0 R /XYZ 72 744.9066 null]
+>> endobj
+85 0 obj <<
+/D [78 0 R /XYZ 72 720 null]
+>> endobj
+6 0 obj <<
+/D [78 0 R /XYZ 72 663.3806 null]
+>> endobj
+10 0 obj <<
+/D [78 0 R /XYZ 72 522.2678 null]
+>> endobj
+14 0 obj <<
+/D [78 0 R /XYZ 72 411.4484 null]
+>> endobj
+79 0 obj <<
+/Font << /F36 84 0 R /F37 88 0 R /F41 94 0 R /F30 98 0 R /F29 102 0 R /F26 105 0 R /F43 108 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+116 0 obj <<
+/Length 2722
+/Filter /FlateDecode
+>>
+stream
+xÚ¥Y_oÜ6÷§Xø%2à¥ùG¢¤ÜË5EshѤ½ÄAQ$yàJ\¯­´]qíúÛwÈj%G¹؀Èáp8ÎüfÈ}q{qóRé•H™Jµ\ÝnW¹\å)tyQ®në÷É÷o•éÕZf<yiÚ[’ yµ.2™&¿¯D‘ôŸlåp,ÃÏ?¤T·;‹áqœq5ö~»*eb7Øyk÷Me=½úxûÓÅ·bÅáO•TÁ2ųUµ¿øãâýG¾ª/øê§ ÎTYd«èp&ÊR®ö©.b§½x{ñßQέ§’^Äí VfÙ¸}.×ÐðÛèO-¨›Jž„}Zw:v^Á›—©˜MÌY–¦),ä§}úî dVä)0ð,åxÆqžâÓyBi&‹¢ ‰Û%Ù+ó\Ç¥ëiŸÚH©ŒeZçgíÿ¥Ë
+­¿b¬Qâz*2˜l®R%™RsùÝњz¸|~µ’óäRäéåõÕZûvۛÚÜßÁ lcµ–:G kpÄ4͊ áý%gœsžvÔåÇØ;žº®éî¾°‰ÐLs©WºÈ™/þv›D‰ë©È%›HP€€‘oÙ&—‹.Á9K¥Š¾t÷·.¾%HÐܙ™È• &†¶VZ°\{[KÁ4¨%ðs”Úªï(F?p.-DÀÓ
+u=e½át8ôGÇ(óiN…¤Š©¼a'’Aî—¤¤À…ÙµiA§…0†é
+¡³EãîQ
+ž"Æwž¡¤Þ=CGö4Vþ;2Å­‚žÏ†(Ä«Cσ³{pô4•  Úèj¢²gŠmðkŽØ>u!æãz Лʔ•ZDx¾Ù~íÜÖ#çlçàM ›ÔYò2¸žÖ°C(‹º*ı.“f‹ã¸a‡)Kšˆ¬dY¦‹™&7M}gÝÍ¡=݁ܛOÚÞ±9¾±~oöÈ>-«;Š›©`”¹o†ÆٚTÄx>ë˜%ñàPãñð霁!
+¬£©ýƒ“º¯ ñ΂ôþAʌ o9šȎâgXRÊ ³`Vé“E®Èªÿ¯9¥–L<'1ÑßT.“ÅoðãœAçùßÂȄm°¦R©€,úôˆû
+±€}…œX8ÜãÁbkµˆ=ކp6fð9Êô$ ÍZD=‘ˆf a½á´õËyâŸ>àx–¼Ȁ¼†¨QHÌÀÚZ3¸%$`;·o¯Á–Ôäˆá\‹€ƒÿ+V)í7önöÍÞ2¿·§¨n"àכֿ٠m·˜d^™€•ª€¡Ý±‡‚T9e … _ÌÐ0UÕÔ`g@UØí#퟇~ !=ôˆÍ3ÈMäí`QØɒ0N2ŽœŽí’Eë>šaLOÞLC’±ë˜´ª™iXH[š§r0ŒÍþ½ùfêÅ0*ªœU¡Oó#¸¹b°–zš'U̓Á5*û3ÔØzóõߧÍï¼Æä€þ›%-JºŒbî,uhøÁ†³Ä!9jvCS†ÚQ
+FN òp…ž\Dœ*žãpjž¶W ®Åà”M5ŒUëÓ
+*ú£*|ÂR' 9£FŠw"UäT{ÁT>ÅÔ鈍–îÑ»+âí¬­œ
+~B~ð JæӂÛù•3 õÀ˜Dóü‚ aJßtŽÈ
+”³ù.ž½oM+?¶”+~ÛYªAÎYPñԃÕ
+X±(œ¤éîì´2òCK–>{ºÌ’ï}ç)–Àrâ¯r\ZR~Ý5`€ž?üˆCѧ/OA³yG„ òƒ$•dtvhÔÆB~_OZ’¹¡õ¿HÑÓTA€œ†ýá­(Þuÿúå`âb¡¢wÜm߶ýÃX{s€iG€™º¾V ‚zž7[†OVˆr,§®íûÃVi¸ñ#H’»i¯/ÞâÊP–Q|VIožpÓÄ©¨{Ø ô1!–ÓxŽŒ†f‡¦#¢÷¯ì@e¸Æ”j¨ì쬄ö+ z<|1ñz‹ú=ìZå$*
+dB¸`Ÿ]¾xxŸÑ´rvÆþv ùŸB€ Ò÷èÛb‚Û8ñ¡ ï¡0²!~ƒàµàæÃKÀ†*:‹€£$–XЈÈc"bKº¿±>ÁN@BÆ­«Aä$›•ôà‰Ø}°ÍݎŒ­¦œA]€MÆÎÀ¥T a2†i°›Ýi¿±T‡…j| (S?y¼|ŸS
+jd$D^Ç`š½[Éw`²¾2]ß-¾‘¾JfÄ»·à`á ôÙO¡½íÇ|é»tlúŒPžØã—sÄ1)f  ·{ßûc»‹j,¸*œèþ¸ïüA÷¾9ºJTQb|Úá"¼¸g„÷ô€±K³B»!±´©ùàÆTŸïï”üCZRPæO`åـ#pÁ8`+d`ˆa€ä½¿x×ؾoHШQ«ï~}úò˜ò’q. ~?Èóâ›Gë‰Ä…wÇTHS¨qáPT¾þåõï¯~y÷ußZHR¸ÇøÜ
+”˝ïGÒr
+8ÖU³¥C95âg%÷÷¸Á½Iê´ô¯HLq?ÆQüàaLnFÿÃðûÂ5^–3~ç£÷ßãë×~&J0.D¼åIä‘eü‘! *ø¼È#¤¾ìžØ{ÿr4pô°W½oÎJ= $“‚Çç9ÖÝba¥œyž|_JAºŒº
+‘ª GÁ
+¨I‰ã5ä´sÊ®'¿_²üÁœˆendstream
+endobj
+115 0 obj <<
+/Type /Page
+/Contents 116 0 R
+/Resources 114 0 R
+/MediaBox [0 0 612 792]
+/Parent 109 0 R
+/Annots [ 118 0 R 119 0 R ]
+>> endobj
+118 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [338.2543 625.4705 540.9963 639.5436]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://cs3214.cs.vt.edu:9011/loadavg)>>
+>> endobj
+119 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [94.2326 611.0247 302.0912 625.0978]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://cs3214.cs.vt.edu:9011/meminfo)>>
+>> endobj
+117 0 obj <<
+/D [115 0 R /XYZ 72 738.929 null]
+>> endobj
+18 0 obj <<
+/D [115 0 R /XYZ 72 572.1298 null]
+>> endobj
+22 0 obj <<
+/D [115 0 R /XYZ 72 377.3775 null]
+>> endobj
+120 0 obj <<
+/D [115 0 R /XYZ 72 248.4192 null]
+>> endobj
+121 0 obj <<
+/D [115 0 R /XYZ 72 168.9671 null]
+>> endobj
+114 0 obj <<
+/Font << /F36 84 0 R /F41 94 0 R /F30 98 0 R /F37 88 0 R /F29 102 0 R /F26 105 0 R /F43 108 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+124 0 obj <<
+/Length 2527
+/Filter /FlateDecode
+>>
+stream
+¥zââOƒ.M–;Ñwð1}%}²ëÉɵ~îǯnžk´"™P¢\ñÚÈÊM¾~ËU`2©p4¯OWcÐyˆtÃi
+ukÐàqÌ"Æ
+ÊÂÙ՟8Z+f]ñ¼îxܕD¢­ñ¢˜jȹ/w
+Áå7]7úØ0Éâ0ùYft…’õž9Ù¿vz)$‹øûhì€Â‹Ð›fí¥ïq‡RBdš@}óÍá‡ï Ùbù{24€„W^ë£KÝHFGƒ‰~¨Ð¹Áiž]隚Nÿ}‡‹àpvº,àôšö™…¯Ã€¸¬ž‚õßn€`uV2—;
+Wwú;'Wö`JCϒOŒ•ïŽˆäî#Ä·ß~ËW°cB_Áòætq+_ÝX” *–r~`ìSí0”Wp ÍTPe±°#j„…Wª£º(§Èg@”}WšË`×ÓoßÿÌ\»ê?•LW^zÍåÇyêœ@¦d ðhI„d²M¤lÙѾ±
+ôYÍTq©‚o±Ÿçj±çtÐÑЗò€’µ'ˆ)ÑÈwæNÀ´9R:D,G¶«„øæpxOÐ:1à*s3ÍÝÏõvßÈËsH`WÝY莵k‹,!){ ¤N|öb¹d¡]OÓ³´HëS:ÒqJG<z ~ùOœ¬°—ÏD27NHãM„,F»™b°“ÃÎ|·1û…f^q«ÎÆÜg¤®PFp}áÐ^‡“7fa‘ ‰ÎÅ",r©vàí
+îA¸¡ÜòZ# 3¡3>ˆVófã…ÆÎàðuiûÙp§O>Ë'ºè{G ºՄ$‚‹W½p½³·
+wƒˆ/ñôRq¢ é×§Ø¼cSÕQ¤*Ñlèåà»_3K;–g—
+Û=’¡#o6•(ݶÛïT•Ç.æ
+Œ ±}%”¿arÿ
+â†:qΈK3’Ü)¬¨†¾Õu_0ž-˜+ßLÖ4{8}ë43˺ÏÜË«¶pÊ­w"JjÊxU°®mR™t‰çnu߸+¹òYDMY!VÏЗ}C רã·äԍȚ¿=9ÁŸ¬…PK§ˆÜWãÌ_Bì‰ÞPvõ‚Õßú'òÕñÊñ:=ÕDQÌ}€ d±®j¸ÓŽ)]!ºlð=ôüÕc’–«„ƒäSÓ½¦2„焉>г`ÉI릞‰†îñ”`AÇ¢:ù6£û4ãòáhÊ7Ÿ?æJ¡B‘Cpþ¹2τE_~Ñ]²ó/º)´H*G‹åIXÄY¶+’0òèE‹T„E¥H§ ‘J€£
+!?*ºÍò‹–Õýº§ùª7#BW?àÛõ“8b®Äû%ô‹ø.ÔD ,»öL´ô
+4«`¹,KéñO†™ÌüëßO MЖǠÆü Ý=üvf¨ú_áÃö/X§ï«²0ÏÀ[<Ý眀QZø÷*)§$1Säa*2ÄÍÌe/yµøù„ãO»ÕÓÞendstream
+endobj
+123 0 obj <<
+/Type /Page
+/Contents 124 0 R
+/Resources 122 0 R
+/MediaBox [0 0 612 792]
+/Parent 109 0 R
+/Annots [ 127 0 R ]
+>> endobj
+127 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[1 0 0]
+/Rect [311.985 349.7717 318.4607 365.0371]
+/Subtype /Link
+/A << /S /GoTo /D (Hfootnote.1) >>
+>> endobj
+125 0 obj <<
+/D [123 0 R /XYZ 72 738.929 null]
+>> endobj
+126 0 obj <<
+/D [123 0 R /XYZ 72 619.2439 null]
+>> endobj
+26 0 obj <<
+/D [123 0 R /XYZ 72 449.3403 null]
+>> endobj
+30 0 obj <<
+/D [123 0 R /XYZ 72 224.2019 null]
+>> endobj
+128 0 obj <<
+/D [123 0 R /XYZ 89.9328 103.968 null]
+>> endobj
+122 0 obj <<
+/Font << /F36 84 0 R /F41 94 0 R /F37 88 0 R /F43 108 0 R /F29 102 0 R /F26 105 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+131 0 obj <<
+/Length 2820
+/Filter /FlateDecode
+>>
+stream
+Ö0&ÉIï¡óšÁ™Å& 6/üu´! ê#šU4i`¿ìËq±ÐÝînƋz@•Û-‹f ]YɨRXg‹‡‚=Ç+ео*KjËf[:;„¾3ÒašæÜù¹nh™D{e€š)cfUeÃDÛСµ‘yã@öŠlŒƒÛãql@Ÿ{àY?ڝ­m.K­mSn~jÙu˜°^Úpx®7öD+冎”™7Šc')Ž}¬8²6–9¬8rPqäLŠ;뇊Ö؋ëLZ/è){ðêÆ*»báÒ ±´(P´(|IøníP?5·½ÃØumïdhëöH%AÇnN—P$³i˜[á͒¦ã@>Š‚Î{8¤ºÚÛÜ0âÔAwèâuº¾f›×ÊÀ?&èÊ|o<”®ڦ‰a×pՌ1ÁǛ9>=üóϟ˜7@´ƒÅ3Õ¸·Ã/ïê×±–íÁôX¾eUÙÎ1:°2H,Ô©.™·Á™2ˆ/؜3lÐã,àXÇ„¼Ü4yV”Y¬yR°o+ümÀ’ ̒›W†6¼ÎC¼9™˜6Müà‹iA@u¨!Œ¢â)Þá˜C¦ârÐ[C wõîeñ.RèÒÅW1"RAé¸K,A,æÌ7€m9q‘˜O€ÁbKpÉ-úC,ž]®ᱠƑYµÌniږýL“@ëñ¾PÁKW/DKZëàl{‡ßˆí¨'‘Åv‹.ªáY1‹=ð0ðú=78–’4º•ÌJe%2"®!.ˆÃæñ¾¤ëk+~V*ê>MƒB¯ðÂ]ÙÁö6eõÌ/tÛÐáå<üº^µ|;ÛÃe?ÚíÍӑÑ
+ß5ÃØó5Ðj
+} ßØ8ŽWÃλƒH¼Žâ úÎÐL$~ƒÄÆ>ÕMÃ8š¤|k'„èÒKs׊©Ë³DwëÍ;BÒø¶%s¿˜–:Zpþ¦Ž‹ú܎œ 'cOíᄖ5y|D¯è¹£nõÂy¾™ï ŽnÎò³JüiɊqyQ®à˜dEwT” =­|¸R_…+ô•r–rÿ<æþºäp /`[£çØ6+B“lVÝ]?"ôO#£»Ð²¸‚ùYZ¤p…BUD „ÿ°–µ
+!“ÈW³qþiÉåj‚:Œjà>t寣]QEV–ÎyŸ’3ј–Ù¶†=²’p…@K“ë\s0èÅaNúUY„™˜Ýà‚&F|°Gxb¸yueyÀ,j`°ü÷•û>åD!)jq5LÌQȒ—çh ÆÍá†dWk !"¼«*yoÀQf¯ˆŠXSœ5ìÙôHÒdÝiÁ‰¢R«(ŠÄ‹ž¬C%êf×¢ÃÇäñ‹®Ó
+SÈ´¶_’­cð'=ݔGû›¢1-
+ó8oâÑØL¨
+
+Ò/ú_÷O5Ž$½˜'–žÍ¥l$’¾ß"Òì7©w¶”͈Äo%Pdœú•bâ_Û³UrŠ)wʃëfüÂä3Ö|LËr'¸RŠ•².ìnPÍ;[ºÑL¨fË9Ì·„ äG½X..V°GMŕ-ªF’™ÙÉïÓñ„x‘bŸž•M'ŸÆl|GªËXèoט©øRçv,kÌvdÑ«¡äá=/ÆŒSÎKŠª±/É)§¢Ô¿¢ë̈́i”x’Œ4LͶ`ÔåÐp¸«OXE)R:¿UõnIõ9¤êaxàµxÀ(ü€f8¥—š2»+ë† ŠLi‚Sö02óXÊXHßÆ£T—)¯O"Ÿ×'Z 䉣xË/å­|óÒì‰K±T< §—" ‹Li|(àÉÕP€ c„ôûȏ5:*Bëâ÷à
+ƒÌ&½þ‹Í\Ü{ùÁ
+ÐSè”'V³ Õa–͵¢EX¤QJ¯\‹ƒÈ8LubhÖ3t:¥-HwmÝPM/Ã'‡Šq…ù%co`z·€ñçš~«Þ±|¶LÉáèÔŒ#[_Ê8äpíúû<É+HÞqō4ôÞ ÓI½ÈNâ/â/|Ë%q®ýot’7&*ð…02zwÍßÃÍ>HÔô×dðŽÀ_ªãP‡~Çã@}ñÈà Uhùå+Ã_¾b>ŠòX8¯ þ€ƒß¿„ü}?UìðùÂޟª!<¹ÐnÇ×aëPé)Å3<&* ¿(²,e ¡3#CþÏl`Oxa,Ha¢KD‹D#ҙ€¨‘VZæ¿Åû”za¥,̳,›Æ}- ¾’ZDŽ»Œ€Ä\AFü­=ÙãÆ#šäÍì'W¹lÿ§áWendstream
+endobj
+130 0 obj <<
+/Type /Page
+/Contents 131 0 R
+/Resources 129 0 R
+/MediaBox [0 0 612 792]
+/Parent 109 0 R
+/Annots [ 133 0 R 134 0 R ]
+>> endobj
+133 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [122.228 293.5234 469.0274 306.1021]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://www.akkadia.org/drepper/userapi-ipv6.html)>>
+>> endobj
+134 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[1 0 0]
+/Rect [168.1504 136.305 174.6261 148.2707]
+/Subtype /Link
+/A << /S /GoTo /D (Hfootnote.2) >>
+>> endobj
+132 0 obj <<
+/D [130 0 R /XYZ 72 738.929 null]
+>> endobj
+34 0 obj <<
+/D [130 0 R /XYZ 72 714.0224 null]
+>> endobj
+135 0 obj <<
+/D [130 0 R /XYZ 89.9328 130.1183 null]
+>> endobj
+129 0 obj <<
+/Font << /F36 84 0 R /F37 88 0 R /F41 94 0 R /F29 102 0 R /F26 105 0 R /F43 108 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+138 0 obj <<
+/Length 2881
+/Filter /FlateDecode
+>>
+stream
+xڅYY“ܶ~ß_1oæTíPoê)¶b'r)Š¢]Ǖ²ü€á`w͐cÜñþûô+J©­ZF£Ñèãæ‡û›W?ÅÙF'aœdÑæþa“G›<®*ÊÍýá·àÍ]éd»‹RüdN'nEJGÛ]‘FIð¡Ûê"hÿk+Çc)vüùEñýÑr§î{g܁{¿nË(°{îÜÙî©®,°'Ûßï¾ùñþFoüiR).Â4Vé¦:ßüqóÛïjs¸Q›ŸoT—Eº¹BG…º,£Íù&É
+UÝܯªÑ)Ü®OÒÄ}¹Œ’—*s
+—žyÀ%Û+7á„HKl0$¸–¿{Ëߺ©]̓ݶAÅÖãY¦GþÂM˜¦Á•s^ 茱Ýâ7#eä'(0D'9[àøtžÀև¼Èt¶(èùçuBm©ë'ìƒNŽ©°±+¥,á3›x!q€-{ÜÛÝÚ8â£,õ“һ£ (z&Û³çB¯v2»åï¹s³ipÿæ7¦Câ>‹ÿc°¢Þ4_¬Åžrp¿æ¯’U„i¥ç–;J`>=WÅ£™Ðï0
+‘>CYÐ3§ËÑÀ
+*ÆÚ9VGÓA´S5 èx7ì{Lt«/m1¡~]N¥ËhõBà‹X áªúÒcò9YÑÏh
+åTäñ 6Ihµ¹ÿÿޗä³à(àxéZÔ©ºðˆaò/ßqŸ=<“%ª15ã|N…WìVðì9âÞÓ@ï4$«Òç^´¢¾aøÃYÈ"ÿŸ_Eé"½`w,À©@b™ªö©p·êñ¹/¬úðɅö0àK ÔÑm瘡T©ZŠBÜsq£¤%ªÂz~g…9¥¥OF´_<¾vЧû1œåa‚-H"˜–¾”‹óN /ñjœo3±Â=wê"aºú£Ìï«áà †s!ã%€bÅJ
+­¤Ñtªþ½MDÔ2rtîòúÕ«—v~3^±/Tó,ŒôqxÓ¦¥Ì£¥ÊàíA“~åÈõuÌá=÷䪊H­ ’ÎwsoûN8e†\žÆk”i Ã©çRÎ
+ß]±E©M%ãÝ|^GnùmúÄÜ®eô᛽tö¡þóÕ©5óô¸žó£PEQ6&}~+éj+5ÇETiJñÈÒ?_·ùn”¶n{Še‰éèJžÌVö«u–µIØ·6“©0Îc¿|96ÎÃ&¼ \.V3ô4?çOä·´—aTªd §Þ·”% í³X¡~ßÒ2–€0ý/¶•%a¡ _m;ªÓù­m-¡£ÔïozßƵääPŸËŚŽ©FF[Þx!ð‡xŸQ…%ÕÒ«8”£T3·¯ø+[)Ê0/²XÔ:6úÛÛ(ãìîÙoY¼¯©–Ë£‡¤@øëû;n4æ,$Î|zâyñTArƧ
+>P@B*Î^ø& ‚6ˆ›L—h¼¶ŽoˆÐñ÷5¾
+‹º3GšGªFÁãp'‡;àï˜ÆãzKæâ*–WS "zpÎçoß@uû[ï¢vA玑™_xºúL;È齑€2+¹ç/^˜V_%ââœ3r†µÍqÿàª=Џ%¨Œà†9lÓӓa8(¨C;ÈÏPƒÉåDðV¹G dVÎR<ˆðð x]y1þ*Jò°
+„ÀÜC bLâ®!JËü×XÝÓ@¯¬”‡Ežç#ߗ’@PVz]µˆHâGjLEïÛ'KW þ÷vö[¯ü$û?´ø+cendstream
+endobj
+137 0 obj <<
+/Type /Page
+/Contents 138 0 R
+/Resources 136 0 R
+/MediaBox [0 0 612 792]
+/Parent 109 0 R
+/Annots [ 140 0 R ]
+>> endobj
+140 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [215.5278 219.7999 375.6021 233.873]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://cs3214.cs.vt.edu:9051/)>>
+>> endobj
+139 0 obj <<
+/D [137 0 R /XYZ 72 738.929 null]
+>> endobj
+38 0 obj <<
+/D [137 0 R /XYZ 72 714.0224 null]
+>> endobj
+136 0 obj <<
+/Font << /F36 84 0 R /F37 88 0 R /F41 94 0 R /F29 102 0 R /F26 105 0 R /F43 108 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+143 0 obj <<
+/Length 2319
+/Filter /FlateDecode
+>>
+stream
+xڝk“Û6î»…¿Ež[kE½O—¤é]2mºÍº“»i;SZ¢-^ôp%Êîþû(ÛezÓÉl‚ âM¿Þ.ҥˆý(NÃåv¿ÌÂeÃ2È7Ëmù³÷æ1
+í]©hmJ80êIŽu í*Ú<;g!V¶%aa[÷„;Ê^6
+8 þœŽï€*
+½JžA¥ô¡µzÃʜ;†Æ&‚‘H@jTȖ«¯,Œ£6•#egL˔’‡OÝø‰(è¶Ò¨gJSrCbx*̯”Å¡—ÇJä(̼R-O´Kò¨;Y·îåÑd=Õt=ÞϼnÿŒO#‹J·jܝµ¸Ô©„ûõ_\[xý
+„´àœu’Äx³'ÂËzèÒmQ%“³Åóµæ²(Ô0<£žZ€.æÔ%‹`=#Ãÿ>ªË"d9ÚÁc§mÊ#|Ғyä8öüEÈWï_ýç ~— …Ÿ¦9‰þ/VÓn$jC¶üAزJ,¨¯„ŽÀ¯qõy
+KnænXs|y_ ØübðOÆWåørqÒj5Üë¶Tø•ijpGšb=àld
+Z ÿ\bïéòKK,œ,5ݼ0J˜\Jg´ƒ* k¹«QZPôÄÎy€( vlÄ’²ƒÆôX'¹ðj%Ý~ѵÃX¢™8PÕ¥ý҉Ù;1VëØ]“`[Tq»êÎ̬›Ó}
+iu´ †(*ã7TâÆËÐ%(
+í`z[Ú¡s„ü’eAÊã0€f
+‡n]×æ.ƒ è¢>·Æ›ž
+DðXjjBba=*ø¯-˜91òÚÎ\³¾x%Ïz¸QÊü-ýeŠ‹€süMÕQ^]õ›² @ÆfGÓgÂS•² ? \l=ô
+ëêêÿ©$#
+`(v2p1á¸*9)
+ ôA5<0 `7à  ˜‡í*HCž^Àñq
+îéÂNõQ‚³BR+:J<
+1„è’»Q’2¿"¸_ÐѪ–íyž‚w„>hÃGlO³ÌXä` |¶ŽqyKÅú%›ù8³Úe±7›àïlÿ¤[ř» ¦[–Z+Õ._Ÿ¡["ãÜQ`Äâ:0ÄFø¬ …í ‡~ ’þÄ\ř/ò djªg(f“ ²“øŒ ,öƒ$ÌùäÛWß|óñ݇ŸßÎIɄŸEN%Ÿ$2ìڄ8S=Rí ÅÖQ"rzc].haè\WŸð!³¾1ܐ­mø]£ ±ª†}¨˜>j|JHçÎQHú”zìöNÙ¯)0;òP\sÄTÀø…3#Ì3?@èõg^…‹ÃsˆIûIìeà›\¦`€C(¹
+¡„žxF!ëÕ$4 Ì²L É o@Ú9jFžª@ápƒm¨ãÙL·~9z"ô¤Ó Áu&ü²Îܵ7¾å1I¿ àG5ã¯5Š¼·'Õ΍oro\Q%!ÉÄP“~´ÝÓþ‚w´‹¹D±—Ø©ÖJ÷È¡"‚Žc0q·
+A —èh™AzÅ
+ýPL½ÿ%•u1#)óó,Ë&º/9£tãtÌ"Ž®(r?‡q)>t'åj^à%wW¿›óÏÛX2endstream
+endobj
+142 0 obj <<
+/Type /Page
+/Contents 143 0 R
+/Resources 141 0 R
+/MediaBox [0 0 612 792]
+/Parent 109 0 R
+/Annots [ 145 0 R 146 0 R 147 0 R 148 0 R ]
+>> endobj
+145 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [71.0037 544.831 317.3454 558.9041]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://cs3214.cs.vt.edu:9011/files/index.html)>>
+>> endobj
+146 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[1 0 0]
+/Rect [125.5903 504.6736 142.5268 515.3335]
+/Subtype /Link
+/A << /S /GoTo /D (subsection.4.3) >>
+>> endobj
+147 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[1 0 0]
+/Rect [524.0598 428.0364 540.9963 442.1094]
+/Subtype /Link
+/A << /S /GoTo /D (subsection.2.1) >>
+>> endobj
+148 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[1 0 0]
+/Rect [364.7858 413.5905 381.7223 427.6636]
+/Subtype /Link
+/A << /S /GoTo /D (subsection.2.4) >>
+>> endobj
+144 0 obj <<
+/D [142 0 R /XYZ 72 738.929 null]
+>> endobj
+42 0 obj <<
+/D [142 0 R /XYZ 72 714.0224 null]
+>> endobj
+46 0 obj <<
+/D [142 0 R /XYZ 72 487.4474 null]
+>> endobj
+50 0 obj <<
+/D [142 0 R /XYZ 72 331.3581 null]
+>> endobj
+141 0 obj <<
+/Font << /F36 84 0 R /F37 88 0 R /F41 94 0 R /F29 102 0 R /F26 105 0 R /F43 108 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+151 0 obj <<
+/Length 2222
+/Filter /FlateDecode
+>>
+stream
+xڍ]sãÆíÝ¿BoGϜî¿Ú—öœ^r™6qcw:\(r%±G‘*w)òë ,°”dËiÇã€ÅîâX~x¾ûæ£ÊBÇJgrñ¼^är‘k@“¢\<7¿DOJ
+}¿”i}¬ºŽ ™y¿,R©£Çñ^ÑðoS;ZKégI?Ÿ¥TÏ[Cˆ=Yë*×öÏûRFfEȓmm€]ßÿúüÃÝ_žïÄ"?áEREœª$]Ô»»ÿÜýòk²hî’ÅwI¬Ê"]IbQ–r±»ÓYîîéîïó9K8hyy҇ ¾ˆË4ÕOdœd ú֍•3›ÓýREúG‹p9T
+m÷ù‚âÀ†«{1íÞÊ/­CÎëh5 _0qÐ͇1‘«ÃÐ6ÌqrÌ;ø  xÑ\èL`ž6”øéåÖ87ï¹*DjÚ ¥=%Èéãþ†{ŠòÍXí®:ÙdÍ ‡oŒÃÛ~=|NÒþ-¬§¾FÏs4ôցn†ÁSÛ×xšÒìN(Ð3+^š,©`E?»©síÒmƒ½‘`¥”wlÎ+tIà[ÚjÍDÈ 2ZÂ|ÝÂ` »õ¬Ã˺”SøV»¶k«±ýÍÐ>´¦5ÝÁÛðcë¶árfÁŠ
+±c©ÑhqÙh¤,ãThèÜþø#˜M*¼Mo4¦T1'ã«óTœÈB3S=Ýÿœv–ÚîMÝB_•5©ƒ-¶ÚP‡Yª¦ ­äuq©-4fã¡”½ ¤-zk´D¥ë€ÊAç†zèh)¸2H Á å½yæÅåcꪧ%0@€¶FßöþÞn¿žºß댍ÛÌeïf3*Ÿ·ÔÏfÍ)‡î–:´€¾ôñ3ÍÆ
+#¨©|J\M&œ«{ˆTºýV!×i8œlÎìÎCêÍ^@Ï;)}Ãg ¶0*û¹Ì#­c 10bÕöÌG)*_ŒLDóŠ ý@øž¢Ê„sŠ"Ì㐀y‰Ù¨ÿáá²[1ϕ‘G(÷û²ù‡ ˆt¢Â¨³‘¸·Ês£˜µø•6JΖª÷jò¯ úæ'n9|ô<ÎÁ"s7¤¾ŒÛ4ˣ9Ìc£JCZ«Ô †PÆ£<Ò||¥‚Ä8Ià
+ÞÀ´®ìörÒ½ Ö[&óµÂûx’æ³-1¯ßj8^Ì}‰êÅpõ?¼š¼ßUƒþžwœ¿~à{·ˆ¡ ¥´#¼çahæ¾øäNy뵜ÄI^ŠË·ÛH-ÙÒD2ß¼÷:ö•ý‘Åç%, x zO©Ú?dD¼#</T@¤³÷†e©‡`€ßØ*©“©$t2u.T£F%¢f¨§9Ö}ð%ø„‡¡r;l=쁌!›Š³è¸DA¨Þ_z¹ÿÍ؇G GɡꦗïïùSÕËÆ|4yе«q~¿5ôÒ½ôÁ
+³ C:tŒ=‡¨#õÔU#á•sdJB)½ËˆFB„òr~7ÌH(ÿŒÄ†sUH4«¨ÊPÕÕÅÃü†±xž)Â&/é€"|ë(ÂG ,%ª,ÏjÂ
+U¾Ë͏ ”xû4„y¯¾É«
+¼ìJ$Å˜k60øoZHô|N©$.L"ŸR0Ù$‰ P\ö\(+vÜw1ý~¨ü…øᦏÍ
+Ð?Õ6>¸Ø4Ó[¥T"N„<<åÄ#ËE—yžÑ˜*â\äáAñ3$_dpšÉ¼)<0 ÐóÙÅJBYJïÿ&F‰7åq‘çùÌ÷ú$8(+ƒ¬‚Ðꂣˆ x¤0ǏÃÁà71þ8ûþâ.gý/xNêpendstream
+endobj
+150 0 obj <<
+/Type /Page
+/Contents 151 0 R
+/Resources 149 0 R
+/MediaBox [0 0 612 792]
+/Parent 153 0 R
+>> endobj
+152 0 obj <<
+/D [150 0 R /XYZ 72 738.929 null]
+>> endobj
+54 0 obj <<
+/D [150 0 R /XYZ 72 667.806 null]
+>> endobj
+58 0 obj <<
+/D [150 0 R /XYZ 72 249.0424 null]
+>> endobj
+62 0 obj <<
+/D [150 0 R /XYZ 72 205.7979 null]
+>> endobj
+149 0 obj <<
+/Font << /F36 84 0 R /F37 88 0 R /F41 94 0 R /F29 102 0 R /F26 105 0 R /F43 108 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+156 0 obj <<
+/Length 2269
+/Filter /FlateDecode
+>>
+stream
+xÚ­X[¯Û6~?¿ÂoG"…¤îٗm’“ì)š6›¸mÈmk£‹£‹÷×ï g(˧
+˃õ›ï6wr%à'J~ⅾWy}÷õî·?Ī¸«ï„ç§I¸:Ã@x2MÕª¾ ¢Äª»wÿœä¸ ȝKzi¯/½4 §ë 剼~Þ6E9”mÓ{k7
+Í+êI
+XŽ²¸&âcêÒ߈•5"¸PC¯{»*eYENÅE¼ò¬¤»hxlù=l•Okx֕=—ìbì¦wíTDZò,×fó&ǧÖÍ{ta¤òvl˜‰ÂR Þ×B<ôÃ
+›BQ*ë¶äÚEp°ÜEn¼”Ú<1€ Äò{õ° DÜElVV6d`ÑB¤­|änyCv&LLýÓ^gŠ67Ï~åÏó¶˜$öÃ¥2UFl_Û*¿ )×üÙÿYöÑ~ÍJzÑ̒j*)ÂKv}ƒâÄ <LÌÿª ÕÛùí¿\o=Yþ…ÿB…PÛoax­Y&„êt OH©¸n%´F¥+x>ÆqdJ[ ½øú¿¼ŽGŸí9˜ê`jiˆ F3*š 𕧤¼ÿì CG.œ{IÇÓº¿JAQêóÉ"¶"ñÈF^ñ3ï+ ŸÍþŠæŒÿŒHendstream
+endobj
+155 0 obj <<
+/Type /Page
+/Contents 156 0 R
+/Resources 154 0 R
+/MediaBox [0 0 612 792]
+/Parent 153 0 R
+>> endobj
+157 0 obj <<
+/D [155 0 R /XYZ 72 738.929 null]
+>> endobj
+66 0 obj <<
+/D [155 0 R /XYZ 72 666.0277 null]
+>> endobj
+70 0 obj <<
+/D [155 0 R /XYZ 72 339.7685 null]
+>> endobj
+154 0 obj <<
+/Font << /F36 84 0 R /F41 94 0 R /F37 88 0 R /F30 98 0 R /F29 102 0 R /F26 105 0 R /F43 108 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+160 0 obj <<
+/Length 1045
+/Filter /FlateDecode
+>>
+stream
+Á’Ï}æIúØÌ´i?ô†«Gè];ðerï@±ñ·/ûÂiM˜€2O”w~~õ¸Xnýã´ߔߔþtŸ$iò¹O|ûu®ë¦ÁŸȦGR’S×ޗÐúXF„ð²HΉb Éc¿Ó…ÕžÓ‹—íÆê¢(_ýëb¯^`ú[ٓwKtµuҟr˜ F(ccwÌñ ÏEòx e$e©E„úÝ1 kÚ1 ãŒÖ$G‚Ã3@™¿ŽEÍN|)%Yš¦‡sÿG $}eìÉ(“úÞ¼ë͋ö›:;ú•á ü r®#¨endstream
+endobj
+159 0 obj <<
+/Type /Page
+/Contents 160 0 R
+/Resources 158 0 R
+/MediaBox [0 0 612 792]
+/Parent 153 0 R
+/Annots [ 163 0 R 164 0 R 165 0 R ]
+>> endobj
+163 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [311.9171 562.6223 402.5921 576.7492]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://json.org/)>>
+>> endobj
+164 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [419.9432 526.5078 540.9963 540.5808]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://www.w3.org/Protocols/rfc2616/rfc2616.html)>>
+>> endobj
+165 0 obj <<
+/Type /Annot
+/Border[0 0 1]/H/I/C[0 1 1]
+/Rect [90.7964 514.0286 260.0641 526.135]
+/Subtype/Link/A<</Type/Action/S/URI/URI(http://www.w3.org/Protocols/rfc2616/rfc2616.html)>>
+>> endobj
+161 0 obj <<
+/D [159 0 R /XYZ 72 738.929 null]
+>> endobj
+74 0 obj <<
+/D [159 0 R /XYZ 72 714.0224 null]
+>> endobj
+162 0 obj <<
+/D [159 0 R /XYZ 72 588.3489 null]
+>> endobj
+113 0 obj <<
+/D [159 0 R /XYZ 72 588.3489 null]
+>> endobj
+112 0 obj <<
+/D [159 0 R /XYZ 72 563.6186 null]
+>> endobj
+110 0 obj <<
+/D [159 0 R /XYZ 72 515.0248 null]
+>> endobj
+111 0 obj <<
+/D [159 0 R /XYZ 72 476.9436 null]
+>> endobj
+158 0 obj <<
+/Font << /F36 84 0 R /F37 88 0 R /F43 108 0 R /F29 102 0 R /F26 105 0 R >>
+/ProcSet [ /PDF /Text ]
+>> endobj
+166 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 1/dotaccent/fi/fl/fraction/hungarumlaut/Lslash/lslash/ogonek/ring 10/.notdef 11/breve/minus 13/.notdef 14/Zcaron/zcaron/caron/dotlessi/dotlessj/ff/ffi/ffl/notequal/infinity/lessequal/greaterequal/partialdiff/summation/product/pi/grave/quotesingle/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde 127/.notdef 128/Euro/integral/quotesinglbase/florin/quotedblbase/ellipsis/dagger/daggerdbl/circumflex/perthousand/Scaron/guilsinglleft/OE/Omega/radical/approxequal 144/.notdef 147/quotedblleft/quotedblright/bullet/endash/emdash/tilde/trademark/scaron/guilsinglright/oe/Delta/lozenge/Ydieresis 160/.notdef 161/exclamdown/cent/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]
+>> endobj
+107 0 obj <<
+/Length1 1620
+/Length2 13891
+/Length3 532
+/Length 14741
+/Filter /FlateDecode
+>>
+stream
+NÐàÁƒ»»»{€à$¸w6ù¾3çž[g÷×ÔìªÞµ×+Ï+ÏzW­j
+ho´;)±È»íÄ<H44R®  ;ØÉQèè‚,Ò ''€C@@‰ åäìã
+ú8 G>9—6jÕ8õ¦Gn Tš½Ô~bmú&øÖî³øËùuOq¬Ϟ®7tžOâOÅÐ_€¹NÛÉÇ´ÂfRŠšq¢ûÙïbAiƀ—]g{J]ääŽô['—+ÂÅC•gAõ½3Z€EZC<nFV]á¯Ú䣇{º¡ñёáÞ+Øþ=b¦œxD!OTژ —b1íŠUÍOnSZcØH=c;ÂAÖ/âÙTEàŸíUÎ×ôâv‡B²Eq’ÒbžHØû)B˜wÈ}!(ù,´ðÁʌ×í÷›½Èrüfÿ}^êoé_+Å ‘M¶#»˜Mk:øï£ö»žãûŽí¦ìÓõ»X=^Õ˜8\êìëÃúUýùÒZ>aKÔçM‚£Ý6qt4…
+‰ôa›ü^Ò2¬ªVf¦4àŒFbØH]óTÝ\0O
+ëßÿÛNò=¬ýښ œ#ïÄOZÄ ÀÅp»¥3Ê
+Z&V.¼ ê Ç|B
+-Ý®”.ûv(yI°û«à*ONìiobÝ]WÆhËE§l'íƈÁ‹‘-çíǯÉÔÃK}ûoß̓‡¢ Âåúá¹J¢#£
+càõŒ¾*w8³ßÓx8šŒÙ1ï"„Óæšâ|¹@”qc¬ÛӚ¾s€åÞ£HQl‰ë~ÇÆjˆ@7ىûwžÆOnDTK34‡-ZøŠaP=ƒ6æa[ «u¦&Éj^1Å–›É¤†l7±Õî˜ñöušÀϬ„¯áŽÈèkxå¡Ð\þ‡Ü3Ý^AQ?¾A_­8LX+­„Ú³{fÜ-ÜîÏWŸÜlXÉ׳lÿ\çê½qö”©™¹ÞQT³…¡»q<ÞΧYØÛhüSETò“Ž™!ˆÁÑ}ŠÏ›ŒŸÖŠøýˆÇ;ïFä,mן
+Ú:?Ÿ°RŸÆ#ÌÀLw|–] hóp©¡ÙNVœ–ºª˜ÿݪÄÖôæ+hEíKˆ
+Jñª ÷^@Ò[)½7Î*ʁ’pçsÞÎDg&µ«æ5G,¶ ôRã#o·<¢.ÏPÔé'ümÄéþV±QwX—\>$¡5ÀÏFžÇ]¤!ú$^ ¹ÜÑ-RZ§ž̬Vÿ5’˜íž.pÁ®¾\]ʞ/Uh1H)šPC_ݲݾòÈ ÊÛ}jj‚úޕë'¸mÎ$wKÝ´:‹[ÎS±O±š`»ÞäCÔš›o´[ì4@
+Ü{óéâ;9v*£P¨A—͹*ÖIƒÞk"[8QÏeæ4nƒ"¡ùöë^˜kfÛF϶`’t
+MwD.ص.Ã]öÑïg$³šu|l#IÓ>UZÜNUý7XŠ‰Ý"l3¿Ø+ÆJ_£ÔÔ!ù¼
+순4‹W"í4Ò¶†ÔҟqãreI~v«xa?E³|ß·ùÂD #És y ]EJc¿t–ÞÎÉõâ™u$¦îšÃÏĘÙ#k"N¦_g*S9°—”­žc‡U®èæ_‹çúŒí¿¶i7KR9ä֝èMÓÜDÆüDn#¶[ÆGU\¬qÆÞ¸=‘OýÄñ¸W2ü9ìåñìQsœjáŽê.?pÆnk¶Ä„}ú°Â&P<›ÆÙ*ºî®PCкì;l¸!¾õÖÂ@%yÞò`ÑK§M­°3"•ù¤,-­wê+ûÉqÝ؍¶Öf‡
+CÀ?[bð+­§#n–MÁÉÂ<bÊ û¨œ%ÿЉPcý6þ³S–‚–”mc SÐ̟_‰Ê26<Œoq¨[1‹JÙÆÂS”ì¾ê5H ¡
+âç3ʄSìu©–ØkQý|0"ôà¼Ñ‹‘úì{aÌ·ôŦˆ½Ãl¿Ý0¯º“c}³i'Í ñ¬[„ûsØ´Jc+ˆŠéP a߯×pÛ3Åê ø5
+dœÑ„Ý>x
+•Jg
+ÌèÎXÚ2Ûz¾ûàÖ m¬E³~ÌÏCÇù)†¶µFMèqJ)Ö$…B‡"˜GÔßü5Dˆ§âFYiΕw>/‰D!"TƄð)Šñì÷UòÞk±ËÛöA#ýÁª˜¬Ò¦œ}iø]↥b±×Š”2)Á¯…âe ×åȋ_îWoöùþꆴò.r®&d^þ$s;´(ó”?FuBXÔMå¬ëԜ!mmý&^­Zn´¨¸0*ZC
+@2×ì̟7.7âÆÎFZ<®Ö@à^ӛ²¦˜?
+ŠÄÙ*ŠúŠmž3t—t‘ü\gÐÃòµº¡¦?E݈§ê¬ˆø[ù´Ùõ&Põܐ2ˆKPzGßîMþš+š Ñ£ÅrúcÊPH„é[Û/WW<ÌÒ<€‹Ý7é ò°ß1¦’—í/¡¨lãÎq+™-ŠWïÝÐØ°o-š¯ˆ†ˆ…Ä뼟ö©öå®ÂôðÞÎH“DP‘ó4—¨ý}‰ÀWSRQ7æ)µ™ž¾…å'¬Ft õdPÑ)L‡f÷Ìîqûnß럖[ËEkŒ³ð>ÈË Ê&⏪’®}Œ¿ý!R¦¨Ò¸É|2þüHÄyÈìDôŽ†[UÛ­(i8LÈ]+ûÈ
+º2ݺïšé/^®ζšo+C1;À$÷Û½†Ïééâ?÷ÂïÑBG” /®×È8ý¹n)Ṏ́Éäfß9šT®æo'gëÈû+O¶Cè4Ã1–¡Ê笅çFßbé‹×mgldr
+ýl®äÃë(JxØÖhGýô ‹å§D“^;žÛ#1d;7Š"]¥GŸ6ö{§C6²ÛŠ¸Îáf¾db gMFìhÇÞ'¬ 9}ƒ—4/}ò>â‘Ð;Áå«ó菐Í_RpN‘Ÿö(À*$+‡l Ÿ•'‰²#(×kqbɝ§G-›a Á“œ‡åGžÅeˆH¼ëÇ%^©‰[ô™ @\öTûY>ì­x2Õþ£V†o²ìoâÇtX/2†ñМºÚ¾té¦
+-;΄6¤Õ˜7ÏY/¡Mœ­Ít¤a‚ÎSúʼnÈã­E„ɟÔ})š5¾1ó}îJ‹QxôùJѵç©nR@þ¨Dƒ%ñ=0l³G*<«?EÒ©|ëgÚ\Ë[õp]Ê^:ðÒÐfýJ=jÖô†ŒçµÎÿ´Ó_l›ô6ï`ó×6vÀP_ã:í‘‚9¹æÍAú>þ[Ef¦ìy±nƒa¹!3Nã½ù-¬2?OªvM¢©ßéìx>£ˆ…¬Ø¡ZÖô\?Uk„XüA¦Þ5ðQÞIPü²n
+!ŒcºIO„ÞNÃsέ·×€íúRÞIÿƒ’oÂÇtš/Kn¥u›Ök¡˜¯'ÝJbD?ê&ëÑktœ<ٍæI×ê÷Uߕñ½*ï,Àë¤6è î„!u—çEh¾Ø;¨ÔíGGS'Ñ4t¢T„®Ÿ‚KLØíCÙ‹"œëÌ}“¢D5UZU…n”ý¤ºQ7]¦Ìt6Ëo>ŒM“0}÷ <u“ì~+úŸµiÿ\|ŽÌ ¨‚Z>i…<,N@lŸéÊU1{áŒV»ê²7à‡—M¦B™¡žð]˜¯sµßZ<Á ÷=ûɗ}/È5”ót|t7 y_öú,\~xÛ] ),nÈ¢Ë5­­:Ѫˆ¢jÚcõìþ<4l%Ô é¯â´H‰MÏ8Ùp×n39wÿA'¥´ñÞm›ƒ(N“Ðùû›–¨OB$²7tb…ÀȈ+0l~èـOŸsÉp€J½5£ªÐ¶1߬›Ñ;öømмAÞØ%W:[¹e Jð93Õò†”ƒg6'|Z£7­.pO )ÒùþÐNJ\;̄ ˜'~?&
+9DÂãqDwõroQqòÓ=„„S|ƤXùuv®yÀÅ üª>û_ÖwÞÏÍÕ±)¡ÉMñÑÓ­ÃDA˲DsN™¿àç¿~pu‚-YÓ¤Åû¤LæáK³ QŸ#ï÷úM(sJ¦ei~!RãLÑû›ŸÊ-Òvq:U7ŠÞÛ(±Tµ…ðco jPŸ4ù7¹±Y?'µ2\ÞvÜÆÏú‚äò<>ŐŸïÄUðA; zeÀà£!g–"×U“Ei¢YÃ~Öéµôrý†Ç<WÿužP|ÁX,KÂt/Óçۗ¯g-†˜‹{¿pST!Î6Pøҙbçâ‹ÒÁöÛQ»ðQËQÕªÃLkJ …{r3“ø÷q1A基XçëÓj%Ü|@,ùšK\J¡ðvï­ÃÏèïÒ£SÉÀQ)±z …† ¬¿%Á.¼¤唢qqú>c°«Óœäuù·Zæ„Qê¨Zˆ’
+ê‚ÕË%ۊÚú<©~
+ŒÔzj´Ÿyàoù2^₄fùmÆÐ_©×=F‹.ùûMœá“Sƒ™^¼ÏõWÏen¸Ì-TÓôBüsgý~0ôLÈp_š!˜îŸŠáY骒—z/c,ëÿWˆ~#„•ï3¦#Sb½ÁAúN€÷®6¨>iŒκXòŒ%yO—fc?ø÷+9W™!¼à£Hêö½ z^–Mª{=¤†¶¿Øîö3UÏ*‚%Í ‰äk3R( ÒʇsÌüï‚bIm†,Dà×KÖãô;ôyèåOÐ[gZÙç¼Ã]Ɲì¹_ÚΑM«LHx?¿
+.ck~^_º†t³¤
+瑲š Á?ùr $ß2Öz¡}hÜR²v͸Ä)Â;YKÃý¤òYýþ1‡¡ÂKÒÈËëîr"cDsÉÁÐ7ÞÄ;ΐ¼Ks?#¦Ëïª÷­™cîâG©ECy)äˆwÓe¦ë!LæNÈÊWMϹÌDÜÌÒªZïý1%NوÂ"o9z½^µÔ’Áob¬ÄËؽð”âÞW™´«=#¥^ *ë`ù%Šžˆ¯B¦CŸéí4œÔC8Äãjîà‘ÛMÑî ¨`/æ²{¬EI?zêpW¡Í°;bÏp{ßx¯Xp÷ö9ÔT!âÄYlÉÅ1‰D6ô›a)Çj~/À‹Ù˜þVå”x#p7€&£å9âù¾¬ÔɁË*‚Û©öâEéM\vqI*Cã›ñ¥‰ðÝe[ƒ=ÿ W)çnL°ÉÇ)X½P=tÿë¦ãòmÈý§À•†!n†½›¾~¢ž»šô#q)Œ”¾]v‚¤üMÁÓ¶œ–{Á›Pš£o¯%tÀˆG£,.¯w5ôˆ1˜`8koê“dº¹úSN«½ô1zÌé}õÓƱŸãìÔO4+ßOôøHZ«ŒRÝGFؒÖÊñdKÁJñ±Cª:ðRÀÔ°;¨`ž}Gð^ƒõŒnšT ’ð’Ͳ³ #ÿ2g¹a?g„y»SXs„ dʚ€öÆ*¦w£”‡äaɀÞ~%ëÓ­<› B*ëôúYý ûRt¬K͉€@ï7@Fvɛøڲԁ¦˜ïà2Ô$Ñ»¾æ>X6ŽîC¯ËSQ쒝îè¬C×/m,c0
+—³#65¡‘Ý“þ[’!S¶m-åÑ?ÉXî´àì›së^kõ2ãÇÓ ìE¡Ñsøoªgû0±½$•ë›å*ìÜ ZÖéoPuæ6Ê¿¡µb.r'kï;õ%Ï@yëU0Ž0Q}ו¦Y¨£(~ŠØ¥¥ Hõí@yݕAԍjH}Wø–J8¢_<ÂøÂÆhÌ6¨nÊàc•ØïɃ˜Ng_Á®ÊzÝwœ£¬Ç‚òƒIBìfò™ˆ-&Ës¤`ýÚÃoø¥<n§hº¾NдLÇTlèJ8³£§U#¤;³ítÛþ`L)‘ˆ1֕]Œ˜é†å–üF§¤@+HàômZÎU»ì–šþq>—ÆyÐÀ MËfî~òðËîWÅ%ÓkÁþ싵EGÒçè"Í¡7Ø+èQ~_vû8­v† =t0`Èäîõߝì’hm^c,1,ŸH\ °ä—Mok¥ìúcL2"
+Æ$©ÒKý<Ýìa4)‚›¨34³íávDáEÉ$Ûø쨇2?þ™Ã2¥“Y*0àÌz„¤é£–âäV­y#µM)ä ª6SU÷Úv׏¯Ä/’DŠÙíº.¬¡‡ÛØ/äÔ{%æVtà´_i´=/£ÇÌêBRåFrëøn9üRm ÏUfv&ƒ¤Û…D´Eø%ÿû©3ù)¤ï]Z¿twìŽí¢ëš¡ 5Ü0
+Þ¶ƒÐ)*vLƒ‘ç%,Sâv’:+>åvw”~_îÉ|QΙiK=ÔØKrLÝ
+~BíÔÖ b?3µÏœè8òó[ݨòêÎÞÚÞ¯ÜA¬‡0ýÛ]4UËS¡½¡P+vvÆ´žCr‡“|ª,çJS?-'EoR7{æãFò!¨yÆ"6Qf9Ó´{&n~ ×0RáZ¸ÚFÛúªTd‚(¢¾>Y,`‘BèÔÅW_WúŒ³¼Q*3p=/[²ž9#·ô4g¾×é™®ì(7÷I¬É¢KÇú3is$Ùùw£æèŸácž]éžs#ff†§WI® Òêêfž{©»-^±à™Å¦"D Rh›>!CýÀå{iœhڏìmØW'
+M†t4_`´¼¸œ
+1éÐïE…IÒPYÐWÑT:¦ñüt!í=â·õØîÛáGán©jhï ñÆrAd#7äbR_-îL "JämµŸ_•7/¥“©­Ä½Wò¨YÐ;—ðõ¹/ÆLó ÔùKºäòêô ¢¢D~HykFMN‚Özaôè­9MÃC{£¤+™)ž6„tß5h:’w¦{ö_¨0tæùžÃ˜ý' x¨©|PIÚR?G @)ژô¨äŒ˜}ŒÚÒÍŒ²\ç¦kz3U½RƒáC\‚rdi¶—ÎŧæŒø~|5Æm5K3}¶•ƒÑ\´“kµŸpKUX–vvÊ~»¯än.ù”Úö#ûåCR–0£EƬ>î×(³Ž#:œOLä~šíÐ Ýz™ú
+·§Ü*Tg÷mxß)ùM3óO³¨=ÄOô…Ø–ÑŸ%ڐFmQSàäÛµ«º??ð9zÌlJ4¿Û²þ2¬‘`Oq'(¼+jâ1Úš€*o¼Ÿ®wùwsÅ11‰< eîÉš—Ù£K~´ìd˜óú‡A
+8PK²
+ÐKIûÑñ ùÚGUc|hÚê[lØãt\†tԞ ‡Ä-vºù_ò.ׅf·ç»(7-Ns?íSKn^ü°zœ[´¡ÞùKâcpŽ¼$‹pv’r@:ˆóÈÒqG²/ YàÛa­9Y´AêУØË=cÎÙ4óf9 Tîxœ{(™œîªR©c1ʒe´ °¦ßéê:ëã`I–©áf!ÿÕ{NeTµ¶.G39ÏT‹{ö‹q|rÍûA}±³k¾í(lS÷ðž´³eþ¶3™º)$"©&3Åí“kñOµ°òàáÅë-ì΁dëÏÍksâ@BÑ&˟SKêÉA2ŸguÃ3FÞWUk'á"cݎq5¤NÅp'jŽtk¨dŒk1‘˜E,ԎXu˜p¶N¹Ø1½oê Í«ºÕÂ¨ŸÌw.㢕
+=B¾èΓæw
+̓i’¥óÉD4ZÊ#mÞ h¸ƒžZô»Ód+*Z’9gÄ^áâñ»¡»“ltˆYt›±Ï6“å<Äå|Ф£)Ö0^…ºis¥»‘&>7¬F ûäÀñ:d9:ùòÙpbwä6õi{2‘›¡†zêÄG™ÚŽ,_8êl“möÿæƒôÿþŸ°°]ݝ€®vHÿ ®Tïendstream
+endobj
+108 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 166 0 R
+/FirstChar 39
+/LastChar 121
+/Widths 167 0 R
+/BaseFont /NWAZDR+URWPalladioL-Ital
+/FontDescriptor 106 0 R
+>> endobj
+106 0 obj <<
+/Ascent 722
+/CapHeight 693
+/Descent -261
+/FontName /NWAZDR+URWPalladioL-Ital
+/ItalicAngle -9.5
+/StemV 78
+/XHeight 482
+/FontBBox [-170 -305 1010 941]
+/Flags 4
+/CharSet (/quoteright/comma/hyphen/period/zero/one/two/five/A/C/E/I/J/M/N/O/R/S/T/a/b/c/d/e/f/g/h/i/l/m/n/o/p/q/r/s/t/u/v/w/y)
+/FontFile 107 0 R
+>> endobj
+167 0 obj
+[278 0 0 0 0 250 333 250 0 500 500 500 0 0 500 0 0 0 0 0 0 0 0 0 0 0 722 0 667 0 611 0 0 0 333 333 0 0 944 778 778 0 0 667 556 611 0 0 0 0 0 0 0 0 0 0 0 0 444 463 407 500 389 278 500 500 278 0 0 278 778 556 444 500 463 389 389 333 556 500 722 0 500 ]
+endobj
+104 0 obj <<
+/Length1 753
+/Length2 1148
+/Length3 532
+/Length 1711
+/Filter /FlateDecode
+>>
+stream
+ÉMr!¹7äE¢’*àˆÊC áCä!_µ6 …¢"¢E0" X¢Z¬P¿ EÁ¡¬3ßП3¿æ›{þܵ÷>k¯³övXAv£°±8 C%n;ä‚©QÞr'‚E0S‚`hSûÈÏ)xäíïéçOò 8€`L¨!\ž8;ÏùŠ!,&
+¨L à,&Dc,–(Ü…ÏQ³7Ä
+Ã"Ìv'@`#, H€¹J ÎêY‡r0àó&̖
+ߦd°HŒ‹N¸Hg€Kdc(_Ø0‡@ŒÄð^0®ä¿!j>y˜”Ϗd
+féqþ”e
+¾â<&J%°P16,Bç—n†ßH£ÂlD*˜Ÿ]'aòåòa@zBÄaˆfÓ ‹8L¾ž‹Ã({¾ܶ9 ÄèÍqá4ªëÜ4çRt&‚JbÂ’ÎÖÎaè_÷F„ÈÁ’;‰á…øyû·u^«P”…±_²7`ŠDLß ‘ÁN (–XŽë%º£˜¿pKRf‡éåˆ
+Ïç0ÙYŸëläϯ
+
+Âä;ÝðÕsó ã} ?OàC&¥þ[!K*Á¨dnapoÞb‚; Ãr˜EèïÃX‰…š¿Õ(C˵µ¦.FAÜúÜÈo.Þn¶H¿›gįú!"Ùåþ¹XCÊúƒaÓáå)S6âM»aú=ɹE½ÓòíêlbŸ«¨ŠŸ„vé£ ¿ÓôŒÿB6¢ußï¨9WÑV2vu´ŒîóxÁÀŠw.m‘¿Tœáí¦âoÜ·÷œ£çŠ¨EEÉ5™^ût)‹ç›èn¦+÷™5¸þø k’ZÊ͎LǏ?é^»e‰º×{+ÚÕ{‡×'àó˜YÙá®^˳Ë_hœ2œR×h=5Ž¹EhO º€éÚ`ŸßûÃàÒ]çK”îi={;ÊR—μú2賛ʮGñ-õ×ÚwÙ[æE—wç¬î˜4é¼<Mw0¼oz£Mñʤ²ã©µîÁ!¯G&ãÉWuîÁž¶âŸ‹›’·d–&(Ö迸®óÉóx¸Ã{ƒ0/<x¢
+±Öڝöð[”%–/´C4ú‡ŒW¿ &iÏâiV¿NU¤öw®Ú1’óÃ(ÕÞz™ùÓELALÔ»¼
+Ã*–o#ÿنÀ‡ÏGÈÎèû}ëRmg¶Ë¦Ùת[)¥'$Ÿ²ìÖ(§·« “
+œ_ Ø9&6~åk¦«yÉxiscâÈFSUHǙŒ‹Ef«ô±öïǜ
+çK®ß<%ô¿™—ö‰¶²°òånÍ{ô‡OM¶äUš'îh"¯s¼kÒ »]$îõ^‰êˆmO¢;Ví®eEL9Õd #îå\¹Efܘv]™ñ}֋ÐwGkÎô+ìwª7A¦ô&ғEYgѓҭ‰Ùú¡cµ_¦ß鴘±QkšüË‹35<Îæ2z{Åë­A i_}{ö^Yã'}¾\Tý,î¤ØAÿñ…‰H3W½tµ-[h8Z_ØSjŸ£5蒎v{žDœÜÆú?=þ£6ûf~&Uý¼ÞÓ·â´6Æݖ,¶¹XùñÕ¤àB°»_G P=þmñYrWr¼Õ_ÎÝQÈls”%£C)Ñ6½‡ ÕÍ+èKÚèíiK³šJì/QÖZ^Pxf¤Íxt۝uÜVcÕ‹ŠóµäÈñWê‹ÒWܨ›±f¬|Úö ¯©—ï?2W×ÊÖœ•OÌtËÆò³Ê?k­Ru5¤ì³*:gt›z<ùó¤×þÎáõ ÀÎ_T[^,¶|ôóZaÀe¿ßÑÑM¤ËíÅUéOCS­)­µB×/«ãÜ®,¸qðÓܪMšÚló¶Û
+¡Ð“:?[—²KݓÏ÷¿g»úBuÆôþb „ǵZ’ÝÿM¹sFÈ·EVGöø0XwPš‘ÆÔsIƒœ~¢è®é¤OÍÇ×ï½w«À@Ú¦_{=¬®žáõÝș‘Àa“jqEÕÊõvSË{©i;…6³Ogï¹ÛPÒgïrÀñ{Ç°ÑÜɜ}Œ:A“™Ú’¤ß¿œWšò×°NêGSâö›Ž©zâzÊʯå{9ˆ/7a4¯ÑmÚlž—glx¼µ2!}O;×CVy»7)‚ô~„ÿüO°ø0S$ÁLQáwKÜ¥Mendstream
+endobj
+105 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 168 0 R
+/FirstChar 49
+/LastChar 58
+/Widths 169 0 R
+/BaseFont /SWYHOM+CMR6
+/FontDescriptor 103 0 R
+>> endobj
+103 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -194
+/FontName /SWYHOM+CMR6
+/ItalicAngle 0
+/StemV 83
+/XHeight 431
+/FontBBox [-20 -250 1193 750]
+/Flags 4
+/CharSet (/one/colon)
+/FontFile 104 0 R
+>> endobj
+169 0 obj
+[611 0 0 0 0 0 0 0 0 352 ]
+endobj
+168 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 49/one 50/.notdef 58/colon 59/.notdef]
+>> endobj
+101 0 obj <<
+/Length1 853
+/Length2 2413
+/Length3 532
+/Length 3019
+/Filter /FlateDecode
+>>
+stream
+xÚíRy<”í¶/#k
+ ƒ©þJ€XA¬A
+ôÀ!Ðï–L‰î$@ígëãýgË$S˜¦¹6å¦I,‰ˆ÷° ;jAbN™^þ¶~7òÁã-Єïò߃ú[MÀáýÿI ¼}¨ 0'aA2ñwªøӛ9ˆÅù~ïšRÑxFèE¸ŠLågG1ÂùXKã ¸£ñðG$bwŒï‡(Ê츃¾Þ់ýѳDãˆT[o€ýEþáafDdœàS‚ÁàL"óüysùm–!CÂ∩
+ÍvW©é‘ù ðbÒqêýi´»5i.¾‰ÆK¯i¨†f¸Í3š# wòpä_[{‘o[ž6³CßÝ*Ú9ÎÀbÈ?&D˜²:•÷Qü"¨M¨;ÆyWÖcÊ´ì÷|ë4?IÇYÑ՞|ͦùFQ2'š¯œaD.xôsôZí®Ë¹¹“`«ýõf'UŒÓå2-ÔjìB§üÁÊÍü—~>ÁYÜZ|–°iO¯¹¾‚²·©Ë½”] ²M]3ÙàigÂÉ=1yzè>ÄVñºq : ïÒm™ŒÆŃ=ZN­gJµìú-ßÉ«Bëf#H–sÒÎìú¬ã¤[GOø£À¯&ñhMŠì\^XÊ{¾!ٗY7/äåhï_¡3ºY+3uäj
+X,콬ñÖ`©ú¸¶¸>cmëeâáÇ
+–»Ëَ–‡ úÛÓü‹ò—_¶°µE»V (Ԁ"îó#"…²ñ/oµFA`5vdq;0¹å–Æו?ô ÒÁY,VaÍUƒoû%Œ íó™ÆÇšÙ»™ýr»Ÿ˜ҟ¥Ò°ƒÊ·Ÿl"%^½÷©4‹KܾEŸå: r(nÛEþیæ s—‘
+TåaáÁ
+ÚÞ Uþzê>èdAØC…Wק"FÄ®<OƬsò³ wñ–êV}â*Š?2õsë¼¾ e5‡xw°+vÙcýgz^]ò©•óÕÍoÌ/û%r{(ñž¹Q€v'¾zš }[sÙ<\ô‹ƒ‹F¿ŽŠULJ tÝ¥ùƺǬþbØÅNö»ZZç;óù}?dtï8ájÅq}¨d=.b&ؤ ¶\ü”‹?”e˜ Ç5s¾„ëüÿž6t¿^b=$½IùTP,…ݏ‹Bqè0/ò‚Ê·œxØøx1Ú¤®xXÉÒõ©¶(oŒGêAò‡~œÌýš¾HbÁçðtxN®õHiyµ+-s( seý­ýܜé¡,—%í¤µiÒâÓsæ‚óZø¾+¬j.ô#
+½Oï†wwÚu7ˆt:¿Zš[ZU;«h{É+W“úh’6¸rGΎêªýh!`Pûd`{ST!!·_ûÚY/GŒ²Áy‹m”©ºeûä¶ÔEÝ»
+„ýÅ×}Göûaùö²ž¯Äû’%]Í®¶’Æ1Rçr%³`²Œ©¤t½Rêax©Qm`¿h«ãZSòÒå-ي/çBtk)Î.¨Ëû­/xñFäëK
+…Nßd§%ÕVÔþ ÓbÙ¼®ÞPÊ£OÄϔçS-ZåæÆAUke×ǁÁ…oî¸ö!•û{Nl:¬n]à.Š–,3w¸%Q*°y¦Ñ
+W»YŽÊn™ÃN¦p>;k
+ºëÌ^á JˆTE¤^¸·ís¿‰€Œtü‰®¡Î O»þGvŽϤ;}’
+ ‘›M,bÍMqB¤Ð­5)³½p’mž¿#”rzw*½;ˆ6cUÏë?¢íòÎÖ}X-ÐBÃúc‹ðÖë#çÃhÝ¢y†ógD ˆ× „"ø¯÷AX‡Ksd ¶šÉ=ßÌVjZŒ®(¼Ÿ áÜ¿¼nw]eÙ ­c+g¸çw)$Qa¯jD,Ô¿mòXÊoïÛXN8·‘›Ždwõ­mˆ¤¹¼Aòó)Œ¾‹‡ûÝ®ï¬5¹š2X19!Ñû?Èÿþ'0xM¦’hòYÈ?*å2†endstream
+endobj
+102 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 170 0 R
+/FirstChar 58
+/LastChar 118
+/Widths 171 0 R
+/BaseFont /CLKWBA+CMMI6
+/FontDescriptor 100 0 R
+>> endobj
+100 0 obj <<
+/Ascent 694
+/CapHeight 683
+/Descent -194
+/FontName /CLKWBA+CMMI6
+/ItalicAngle -14.04
+/StemV 85
+/XHeight 431
+/FontBBox [11 -250 1241 750]
+/Flags 4
+/CharSet (/period/R/e/i/n/o/s/v)
+/FontFile 101 0 R
+>> endobj
+171 0 obj
+[380 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 922 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 589 0 0 0 446 0 0 0 0 770 612 0 0 0 584 0 0 625 ]
+endobj
+170 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 58/period 59/.notdef 82/R 83/.notdef 101/e 102/.notdef 105/i 106/.notdef 110/n/o 112/.notdef 115/s 116/.notdef 118/v 119/.notdef]
+>> endobj
+97 0 obj <<
+/Length1 797
+/Length2 957
+/Length3 532
+/Length 1519
+/Filter /FlateDecode
+>>
+stream
+xÚíR}4Ty.Úèöq*«!ÑoÉR23—†h«¤ˆšjötͽÃeæ^ݹ4ã³ÏÕNƒjª-ŠS«Èäô…c1G(‘6}(•Õj}Ô©´uÚ՟»íÙ{ÿ¹ïó>¿ç÷Üç}­¿òÙóQ2ó$ ÚfîÀÝWsÌæBÖÖî†Ð8Ix 4æ
+`ð£BÌ\gW®+ϲîd¤ŠÂCÃh`ë>wˆä ørŒÂ%|: “3DD¤Çhðe2°j脬¡l†ŠKh‚…âÄräEHIà<£Q‘[Ñ¥`L[Æä\ÀXDIB¦(&…8’¹ cœü¦F‹{FÉdD>$?œÒg}DŽËT¤<2ŠÆ(àK¢EŒ¦®ÅFÌùb(%Ýõ¢.á¡2 Øà Ø\GÞHWxâJ õÃiI"26Œc:Ú
+ß°N€È+ÀÍßîÃ\‡›~NЫU‘à~b×ð§šI‰Â•`—Í堑y?~‰G]¶Œ(N„ž@(
+“§ƒâ°¬íq¨±Zô0æ¬F#‹º£4(Ӝҏ\-ßV7¿50dۘ"Í»É-MËC4mûRÿÈóTï)Ú$7VÈø5™ú†6¤øRô3TÙ^¾7+a©w>ümJ®Å[Ý8/뎱/|~ÑÛ¹L”¿ª?¸Ø³Ý$«H®`M­Ê+ÏᅤÌ)©)ŒPœïhÉ¡®ÆӄݒLiŒúöô”ö$±±yYvlÇz+Ýeι§>/úä…^ gíÃÜ©t€m¥UUx°p‹[wõ®þŠ£à kwaçáÛ¾ó;Vh§Ø6î\ñ$'\¯û‚ˆԋ-õú·Ÿ æ¥4YXéÅÖÈ+7.ü•}ÛJÑ{)ž} %÷Üè§Ül_|_ëÒs¯[@ÐoŽ5,ºX{¤kÏõ<>¸j|=a…Ê>.}°vƒ^O¦ì$r!cK’wa<5¯)íŒ[˜X¤¡oЦ[ˆ´u°ÈÌüŠ^Úݗâ§&Üø@ÿ ü'$2 ¡hRŽPПÁD—endstream
+endobj
+98 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 172 0 R
+/FirstChar 15
+/LastChar 103
+/Widths 173 0 R
+/BaseFont /USIUBQ+CMSY10
+/FontDescriptor 96 0 R
+>> endobj
+96 0 obj <<
+/Ascent 750
+/CapHeight 683
+/Descent -194
+/FontName /USIUBQ+CMSY10
+/ItalicAngle -14.035
+/StemV 85
+/XHeight 431
+/FontBBox [-29 -960 1116 775]
+/Flags 4
+/CharSet (/bullet/braceleft/braceright)
+/FontFile 97 0 R
+>> endobj
+173 0 obj
+[500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 500 ]
+endobj
+172 0 obj <<
+/Type /Encoding
+/Differences [ 0 /.notdef 15/bullet 16/.notdef 102/braceleft/braceright 104/.notdef]
+>> endobj
+93 0 obj <<
+/Length1 1612
+/Length2 15319
+/Length3 532
+/Length 16179
+/Filter /FlateDecode
+>>
+stream
+xÚíyUp]˒¥d1Ëb֑3333333333333³ÅÌÌ,Y8¾÷u÷ëxÓó3Ý_³#vĮ̬•+seÕù8IJ
+, ÿ"ðÇnló7![{›?V|Àdm ìÍl²Ê
+
+-þÀüÁþ«;ÿ¬ðŸª×³µµtû{·ÍßQÿÁÁÌÑÁÈҘšŽþONÇ?¹M̬¡iþ1kcí?ì†N¶ÿîs6²ÿ»A¤Í Ùz†6֖nC#chiÇ?)¤ÿw*Sÿωü? ñÿˆÀÿ#òþ÷ÄýWþÓ!þïžç…v²´”Ö³ú3ÿ¸`n€$à¯;ÆRÏþ ׳2³tû/6ük ŠÑ?HþpÄõþ4ƒÏÚä ´Ô´ÿ0š9›¹ʚ9˜Œõ,ÿtêo»’µ¡‘½¥™µÑEÿn&€ŠŽ–ö_|Š¦fÖµžé.#kÃ%ÿG¤¿©Ó((È
+«(Püëúw”ìíÝlÿû·R¤l ÿcñ?¿+ÀƒêÏ ¤¢g`0ÿIÈJGçõ_dû†îŸk)=G{3W€ÆŸ’iéþ.üßÞ®´þFÈÚÀÆð¯YQpÔ³6ü3^ÿaøËmàdoÿGÕ¿OüŸ‚ÿ}ý÷ ¹@¯.Ùpš§f¤9Ö¢ç O
+²ï“~’˜‹I[@vû…l󽙜8 ?†Á¡ÃØD½I:⦮' 3ºëڐU åê[ÑR¿ÄqZ4Ã(>_XºîÃNNKŸ_ç£å”¨ÂLԘ†fÖ)o"ó-Ò Ø@¢8Óå–ou—ý*@;mpš“‚̾–9XiMuӓÄö«L.jߘeR(JVH5sçmI2Svu¤rië¨fݲٗ§i㣖ç@…†JKh²2fDžõŒ3ðF”¶¶¼8ىffBÒd<{îQ}Ëg¶Ý‹àBµ™D8„e8©åu)¨‹2ºEÏd´ûµ¿9Š!¯]½ †‘ƒÆìºÒývK,ð–ŽØt¹~¢Ý'æ/ ajƒ]raÒuì¾Åg #­)ê*öÈðp0w­`)C£ØMƒ"è´ZÆ΢ ¶YkB½NÎÐä—æ_0I”“§ÄmhÜ¢‹ñ]þÆÏÞCV7ÈEX@êÞрÉ' «““I¤¤C•Ì¥
+Žù*¶žû*«7SƒL©‰'YÿaÕ“Häö”=éFl]ÉPùFåy†<ìû¾]Å('N5§¢&ß(}øý
+Eí lB·÷ò·×jÈT+mÖ+@;4l£=àØÊÒä’j…gÁlèÜ%­jÝú‘èçNÝÓ¸§0‰ôUmBõV àÚH¶«ô"à»в3¨LÜð¸Ã0gKHR©nuæx-oÔPô+Ïejȉõ ;aÖG(Ñ#uqY"¤ã ÖfOÔªô‡Ø fsUÝÒ؊rÌÃÜ!¥Ônóû+®ëásÔÃiíë«]äWEr‡Wã{ò;Ӆ¦‘Ýž-œ^ZIµžŒÀ¾¿ÿh›YÑ{þ\@•VÄ7–É¥ÛP4ýσœøÙ
+ßiíÆè>ívôó¤:r¥Ùß2’¾ß+Äz5ꐯ3³›?º·`W¬/><Œ©Ö€Ë!™ƒé0û@Ñ|›¨‹”Ī¶Á4bXäºô>-uyʌè_^b&ݓ*´ÏC<-\­¶Ð6Š¨ÄXc¿QÄ Õ²ª[¤‰Gø´R›)í7èŸZè:¶æÿHÝPPÅ)3¨gë£ÿ¥ü##Xâ1ô,6иvªß‹2Ǎ‚Þ¦ämš³ñÕºžåå2Q“øJè^E#
+ĵ(ó"ǐã‹àf>¤ÆçX½rš#ÞîïŒê~ÈéÎ7³\ŽÃ‹3S‹™iʧÂÇq­8|ªÒ/Q_]kΆƒýX]x»ôt“<Oç®—|Ì) ¦©¤‰hb\][Û÷0W6Ivøµê‰-΅NÙdÅÒ.SÙýUøy{W˜oÞy^t[‰ùZ×ßFÃX¶Õwא_=Ÿ‡ÔIkٞL‡C#¢ÛNå ŒH—üØæ]I–ük1¶gæk„¿Þj·,ö þzè1ý+XtH-ªÃØeÿZµ¼¢?§x-¢H[¥›ârZþ¹K͜¿%Y–Lëéý½%û$ï[¥úÓt–n¤¿+2ú3§Äb]f¿ãÜbʸÅØYjLØCŽï;Üá}1Âx_­.”›uÆMGu˜DJ|‹ñ`Éñ„»ìՒZ‘,mÂ'£ ¼·ìo
+ŒU¹¼ë|VC‡ÐÍñ&òõ¸9â#°Igì~EW?Û~À†mG:Úmû2Àµ y§Í6}¦bØAÄ7èká:ŠÊ'‚¼U!Q6–!ˆ¤ŸÓ×NB/P¯ÚW÷+ÍâéÈ¡wŚÃ.Fù>ç՗gWF‘ñbTÓs¯¸³*ÍGöš¼À”ƒDƒó{Ú^2º1Å3fÕ՛ªBð—Æ«škЩ¯µ6†qðèí¤9ùók'ÊïõJ§^ãa%Fx¼ôŠu,¯šÄ³~Ï¥±A yq¡>ñž°µè\Ièfʱ wö
+ÎÞ7}¼³Æ•©ô.C’†`°‚Mºº¶lrÄy K˜â¤`p[oÍWÙ®RÎÏõӛGZIE` >决 âTrëx|¯ÞU=hüLUìÞë&ƒ&ÿÞ[‘.ãÈÁYÒįj*8ÏÐы_ËnÚnÆèå¡ãeßÝj3ˆtï…Ó8È2‹¶ ¤‹(VËó:Çjo~ö
+`ŸI±ÚT^ˆü ¦–Zÿó1MÔѽý­Ѽ×`¯õ*/{ êHké§~Ìóa,ZŸïDЮ¬Á¹U"‰ÑÇ-*ëæ ñoÇèLO±©Õñ´ÁZ€ ŠÀAa¼/;üY‰šÊ ¤(ÏÁéÁùEÞ°OóÝe¬nð›Æš›‘ÿµN]Œ¥9%º–ð°Ö¾ãOOùxôqUN´‘Ë5öÅRñi›H9²ì`øØzµÏ­:œÖa¥BŽ×WGDLgÁæ;E¤Á²ÔöÌf%æ Ä„A߇ºñ’¯ ‚j⮂$pá- úÓدjµû¬*b£ƒÃøû0 i,¼ê€ È%Ñy¸Ô¾ùJ¨«ÂJº0Rñ–¶R{£׿è•Ì»`?'`u©ÆWÙÔh ¢ò°æ÷ÒÔ÷qA­‘&шeäómÀì¸dÇ{¥Gv]ïu^9œu> «,&]g8¸qé¯@ÊÔ
+…ÄÃ]Д bßçÚ7<Ê!P2 &c-,)Á>ÿ×
+û¬½¡~hÖ#âÔÁ-'…|Í@*‹{ j[S{¼äý*L“É7~gÆÎËüØâ¥NjwQƒC+fŸx>\`‹œ: Ôr›PñžÑhԜДDa¬<Á£+Çå‚÷X 50üäžàæfo„@(Ìæ5ß„–·¸Ø\»i‡(Ñã+÷o–hÃàR`9î‘õ å˜@å­Ò`ÉI±3¨^íé®ÞÔ¼Ò~h™0ùsw¯v`®à&V/rYÐ/O&€;ŽFcúw¬ðYAÒÉGë¿´µYSQ¦ø4őcñ†4‚ÝN+V
+•f­‹Àˆ1(`*ÃüŒ¢n!QVúsŸÙ¡¹$éŽj¨kœa`Ý] !ñxU<úLt—œÕÁW:i$ýµŠáàÁ lsœV°ÒC’bÃUJ›3¤ÊG?‹¿ã¼?žäÉÇJ•×„ký£>¬†Ù0™ýGƒúìcá&͈ã°ô‡qrӂ?!åzqÏô~s¼àé¥i%{Åü wÍÏN‹»ŽùÀxgL»…lÇ8x¦Uõdo+WÆQ£Z¯1Š«ûGá°ÊUó‰c%tÑ õ±dCËÀB)ðbé>(¥ÔѸîgOî9>üQÉçÔï ‚À±s
+Éjo(wm‘ê-›m6K¶Jÿ#ç,:¦HjƒTÇ!ੂÙc¸Ï€Ëú÷÷ÜØé´ó²îHCd¾høñÜñºÄÐc>
+IMU|¾"B¦õyñ ¦AÄ>“þ KfXÖ!ä,§¢"ƒW¨©T} ÿÃöL*ˆzrÚw?¯§°›SZ’÷ôÊ·gÀbˆoȧ‰!·d§9ÕҀ¤×ÝL‡MñT/–blôÁBãJeÐuÒF6ÎP™V𑾛5!J,± YÞ¡›DÔwsö oO¯i±ò¨l·¨oˆ4C~);î Š†N_qCñ…V Oz
+øTX{0ôbɛPº¸B6¥­Oö™ðuo©LÈ7ún뙕6”-ÈIƒ ±bÞ+–QFC´òdé×âAÐ_Ƴ«b”À‘âÃj$¾
+ ë$âtëµêàº4ÖÙd 65R0ž7õAiW¢;œÉ:s“°ì~×%ŠœZp …êaí)†gEkQ‘‚ƒbúþ°*¿rÿx2^r¯R‘ m×ã[å¯þ1ˆ³Küªª©õ[ŽfìyÇÑ2ñX›Ln|2IøÑLJvÎ L÷œîck¾ç¹>ž`l^ñò~í´ødP£ôÍË+®‚ü‘“ÌÝM͹¥ì}øF?¡ÅåªUvD›=jé’pÅh6’ÄuvxNñXªžú‡KuOf\ 7$BfRtlp»,‡ô¦zûiÂ+S<(4ô:b©a¿˜áõŽ'Ê-ëWvÐÂGªzà—B {mÿ"²÷j½5£îB*\™¿;ØÙYÁé|*¢{UGqWSVá=Ɋö5+ÑêZL…$.':º%ÛBN˜}3¸/¢rõo†·©ïVó¬ÌÓޏŠ¸Wœ“¶Œ±»_R³•Âñî
+‰ñW‚ 5Þ¡eGÍN[±îfN+M–¿÷Êmá
+ÞÎÔNû…²ÏŒ²M„Z!ô®•“€ð9+ͬT—h0¨óOålÖڂ`_³qø‰h_¿QÊÜ:ɪ[µZý Xwü&êúKÀ£¿&ù·9¿±z<lÄw͉HýSQ
+§åKNè!¾ˆâàôõùÈð·;î¸Ì-°d?ÎÁB:‹Wg̱ñÝ>ûPX–꘷(P”I¦æBbs¤c)Ki+äú¬ð(ÝJD#2»'m; f\FÑ š‚«|Ó߃væ×$‰ÓtÏH<©;¸§ó9Št¤¦Q/Ô·)(9œ^¨P±™).~S:Œ/AY #RŒåt¨8Ô 4lû®8ԗªq±ÓuC:«õ¹ÃØ?!hä7tñä7ìè6@ÔÓ:¨m>à¹À‰ðkìʧ—çBæ Ä[Â
+̊‘¸]zvüÎK÷5Iç'€Í‰Ø%þñIؽ
+¿Ew."Ù0¥ ‚ÓÄùÀ¹¨©ƒ#º*~$4ÿ@Güž³Ù<åǸŠӚ¼ˆÊ*Ճ:Þ2mœ˜LÍ0•LíÈÈë| ‰½"]YÐÜccÔ-ó9ŠŒÕÛAÊÆõÒ#^ƒÔ.”‡z„º“Ó‘ëýb«E JqÜür”òƒ•&ÀG\R‚3¿Yl—ˆ¦¦ennš·EÄ#äu¦X"9ÒËtý˜­׊Ù‰„ì~˜2MÈ'ŸØ]L­w£3"é¶Õ­Ÿ©Ç_´
+Èæ"¹Ú–ío `ÎÊþúõ¤+`ÛÎSõÔø©¢×\êZðo u-; xOÐëþÕ¦5èŒó 3 €ÞÏu·k°ÐÛgšS«¤*ü^¡J(yg2¶ÞQ±)*(P•M2³I°# û¼'â;"ɶáé23T×(:Qbë:àzANLXé+Žµ1€´s&ÈÖ-D$(Uæb*WHÑú»r-t2 CÙøށfbľ²ÓšXBÀR´÷)dødFÒhºgG±jÈhŏÜÚHÚ-M$çt5ŸŠßènz]×.
+cÙÔDֆð×.–ˆžî
+,ÀCcI©VŸwÅ6?oØà~ðBø³â+Wì¢Aû§¯$gÕYÒFæ[¥ÖqøòZjyÕµ5}ÛÀŒÅw™pà˜w†6r‹{%`Á¬Â¤˜NU3Õˆ€æŒëFÐÅd”ÐU4M+
+
+꽡•ªÓãª_²<·u[(. Òb©Έl0¢²ð°†Ó¹ØE5¾ Jµ6®aJYõ­“)ÂS94ÆqWöTgã=‹È@¶ó”ð:–«n|—ýόÚ¹¨‰€Ooj8(Lühø³ˆUܖOBq>”¸ˆ eL^ïk[$?[À©a¶¨‘æ&*·üC¡êü-E•ÞÖäú]‚58{ðÆT?J€Â@Ü$˜l,È)éã–rs±–)þ'3'¼žõ‹NÖ[ ‘Æ{@\.ÙóLõð÷ıE‘çÓShÅCÛÃð$óJìqØÕ©@ûCñ¨x£:÷ ±`¸é¦/õf& 4:±,Ü&»ÍYɺ‚›œ“tò³ö5IZ]f=ü1/¨©„‚³ØQRtòv6f>\Qðãaî»[/±-dõC«™j­”] ¨Â|èx@|œöÞ,(ƒZ;1­"ØÐD¯Rçq5õ—‚qceתSbԉؠǤ.t-Aý\«'NH¯aŠUnj†)Vv{Tžô›æÄßùF¥7kLÖVa$üÕøü:—?š‡øIæ
+êåMH–1磅(uYG Y(‹U—–Ü/Ãë– ò W|†BtÆjc\7æu‹ÚlÓE³5ƒ¡ü°ŸÝ£ëûHL6T/Èß'~bô ø7²¶I}{Ô痀è™ÎeÛ®}ÞˆAŽÞ‰§éš_îyX´¯;§œ¦²-%0^dG|5æÆ·ÕÌÖ¦RWÚ¹Hî~~VB„•ãÓ©>-éå?!œ»o™+‹6²L ÖÈS ‚àÉsú¬X]EJèØÁË?68À
+w¶Q¸€iõ`
+J¹šãYѾ‹64£küo)¨c’–âX„Öt2¶•çÝߔys»c“5)5<Pw”H4â‡^P,…
+”Z£ô\ +ùhp§”ƒÙèb9Œ½„•(Ä4Ÿ©Î’ååH‡0ð×QW‡üÁÁt5ƒHLhBa`Ô=ãD†gP@Å èÞJŽ<åÜ?R0ù1µÈi¼ùÕ_·5?ªfì¤NcNEàøâ%„ÂÎRMΟTä˜õþڋÏ
+زø˞/”õAšÏÛÜ
+יˆ;,†ˆ¿††³}´ßþ÷ÔH®W!
+<Á c$cVŒòèþd*†pÂù©Ñ±€,p-¯rșàÖn)•31}bß … ‘Ìêw-T=ÿEfÊò"¹ŸÉ–º4©p†”÷»¦zë jw¼™¯hW¥Óe3ʗ۶¿ä‡àn˜H”á&+ d'Œ¶AAI'\øíÞøË ®¸”)RxÍõ‚—²žæˆS˜Â®&D°£Ëk°Ìs,@ÌS2O¯†~e=ãG†‡#ifð€sœ‚p‚ÅJʳÓxI<´â-té_•ß†M%¹/b3#ºJˆ¢¶ÂGMåÖv1„óq“–5Éq÷T*:6Ÿ +kãáèHQ
+g!úŒ)UtÂg¯ó²÷(>ĎcEHÚõª{ˆ¸Oêò½…b ø¥X)ÑÝáׂŠÞÿd©Y§z´F¥)HWI Ý–šT¯
+`g_§qä¯v¯î€÷(8ôíE9ðÓÇ:Ðç3˜AZËÃÅ¢À)À+ڏŽ .õ2@9*#݂¾¾5̝pV`Ì,ûá€%øÞ[¸p›ƒÍD8ÓKµ8)lÞÀ5gQ|½ÍJ­Ÿù!_4û夯nXßXx²—úE¿;)¿×xBç(î@^™ØÄá¡Yë҂ì¡" q㦮t½ùˆénƛ%'¶_f ¦¬X3cM[àkæß^U:$¡oį{u
+]¦vº|zÜ5f»ÔÌ+ºK×PH©…ÁÈ¥bÍl¹ÐGžwGyg•¼¶SY)…VPµ|Ú,æ_cÅ|þl zäzÁˆïS€_,©«Ø‹f¹#H.äåE¼H$‚LvC–Úëӂdf¿;Ö-Ô jö0ßNsþ¬G7zæµoç#¥ ÙïMhÖî8¦¬‡ñ]óÊàQØ>^òg‰[žÐï Õæ*[œß>é¶8Ž$ñZÐ'‰‹µ‚|šCõ$™0Eæ*{àŽ*Úßâxñ\³jñjx9u"_‡É$.Û+k}bx‡[øǤ^Mè“póÏ‡<]ßò5=÷Cä}Ï
++ÉÃҌ'\Q~ «Ë„Yßi>Æ\ï߸ üÞX¯ é-B܂mC˜›ÑI>aô´îÒù¨0—`JçG®ªøî­ÀY(l— AÓ]²#È.Ö÷Â3+²Œüo8âڙU·;ÈnT^“Ä°¿.`œ±(»>4 ×ßµ1”,D{.§/%>‡šˆ´¸ÊX¿©t²L£–x
+w
+&w{¶¥i®]vØÐ'‹Œ8q\]‚ö=¯ÇJâÚýæ]¿ìÉ" gÊíc¼;xî}Ìt‘$?K‘ÍâKÉ
+ŸlgÀléçAœ½tp§?VU '°‹èN*h 2Ù “˜³Nîí0·EýÈ{kùd)ù»L,>zP")ó:„_6صÀªª¢ähŠ.*Á àKnÒÍVΣïÍfRéúNùÌW†^Âu=úé¿TI«›poSAèó¶]¯@
+Åê‹`]•Õ…l
+[Ë=ǺmÖ½Þ ̑!b2Ô[ٌ·4;ŽŒÁ‘ë"­èÔÙ%*UVÑâa)%˗òá—G“;±^˜˜äŠ6*öï\6>ë8‚E-Y›=mÆ%ñN*Nºô’ü‘y<SàÁuhù9ÕΪÜû­Uy¯‘V§-oz»_״ݛIwr¥A[„b€ªÄ«fÖËø"lD0ך0‰“Ǭ $|Uù¬#|Rée`á›U»¶ÍðÅ;p#¬×µQ]”'Ú£€ywoü;·åot5kî £çᶻÊ_RñK7 {)Î7?Vé¡<Lg£l˜·*´O—òßážG)dƒ«_E–÷Ÿ?Ï »&µËBó%}bb6Ò@ Èšš¯ßqîbj»fcõ¾«m‚—: û£×â~N燐µÞµ›ˆ­¨F
+?âw_ÖÞ¢ùåH«xñ³,BáÌEÊeVáY‚ÈÖ½Ó5Zœí—{w©9?ºj-,zR'՞fššî2‘fÀ†Äqƒˆ¼È—‡Qt§3±LY̙MègÍV¬ÜR“’§µ¯|fÕ ¿# ‘‹‡F®Ó*hâ—á\?`<Ãhi›×/cšo‚Œ¾måʤ•>•çU§‚Gs‚ì¨ôEÝQî°SNš‚.íßGÝ$_ªi1›ÊJ¡åüiÔg{y´ïaíMHP ÷å¢ý¦5ÿ—ÕYŠ:XM 6
+n‘ݨĥš ˜ÏÂ(«??sõÉ»EAô” ræÁ\äp¢ÛV”'kŸ–q1Z›\d@¥¦ÎÊû–Bß2œÏ$;Àš…EÐþwÙîºîR.{«T6h\ϟ3z-ø°A›×ã{Jm£|@qQ!ª+éžÝ±!âsyöûÂÀ܄þ"Ñ"H~8æŽo%Œm6ü·Œ@þò%ÿ;HRÙÎ “)8¦¹ËӉæFÊrçBéãoÜ̜ Z%+½
+b",þ^LEeÚ÷êŽã»S5Ý?ž(%{ÒxÐô՗’³´³†ö=£œTð« U"Ÿ 0U 2^yƒµõÞºŸtsÒPñ.l†¤W€„¡õö9Ká½Ä¨ÓK~ãiq
+žwA™¡Ý÷y¢]¯X€žX҈KĮͭ¨ŒóÆ1…°S^n0«Í¼©Øzõ‘W%»q~R6'o]!9dt£ã’%k{„ë犡úSÜ"aN—µô߀NÆÎSD˜—œQc
+,û$–5rð úAH¸w v¦ó·ESàpn»dh´T|G®æW]UûJ_4.z³á6†­ÌÏ,î—k—yØNV€ÕçDÛG¿öæ•õ[ñ:Ž)ÑÐ7P„Û<QɉfŠ©@ÊZZɓ:é•"í+ƒˆý\ÚlPÔ!·ºv&.¥+•__w@5â±ëq֐"àÖ ÔælY¨ÅáGF> dÌ` Mš6ö€ö¿Ì×Õ¸yõk7Úìð=¢aYÏ
+Kç‡eð¨àY)QL“s>ØÆÂà@¶`/&èÃ# ['±@õ|$ЇH&#Þ¨èkF:$,Pß“e¸¯­žü oÄÍ@ûrx¸MS–*׃Ž9F¶a#nqw Rwj….‘m“ëáí¬ížøÁ%VIˆÅì/q'eÌð{ƒ¾Ÿm#ï®÷XT_¡­aQ,ײËዏìƒ_!wÚÝMé‡ù±ŒŽ\%/Ù2:·uÄb—–ñ¸YØ,Bí™kÍ~ïÑ £ý¨U€yÅJ–0~«÷ŠLΩû¼»Pj‹JAl ¿¥§¶éSð·î˹¨_'\+.ыµ0o6D?F
+“rÇ62“ a…ý`…XÒP¨cŠ"´t‚7g]%‚š?­ªîOK€™4w²× \z]•¯Lñoª2l6äÏ [dëºAtQ¡ð½È??'« Ÿmύ¥‘c/ï¬!`•Çt=)B ;I;Q[æ.<pÖQ:
+%Fµl²¾¢Ò&®BT|}ŸÛò—œï;E”$ N{Â×QV2Ž‡¾0 —¤xÑ΄žHºèÈúZ3§Pg83}LxùùBXGãs»bœ.N¶»X)ƒÐ³iË+)bW‰Æê¸ùÍ±lSÈáՁ1¥êÔC ;ã¹ÄåÙþsÜ܂?éÒ×lJNa®·h0ÖWAóf³çѧd›¶„Î,š]_ñm…mKi§¿?]o9ÅÒcØqƈæ\´£Šª;úÉRX¦
+H`¹ë‹Ü}ÿŠ#õm`Þ¾ãi¦Uƒº›Nýž{95Ië‚wù¥Ò»šØ> .…èjùðîpŽÊµ²‡ä±‡¤à¬F­”õ'Ӛ•Ýã˜l2åo,Å»ìÚO—ˆ/b͐óWãÇ|äçXwçÞniĽpº©7HdåU«[ƜeµÉ•dñ¾Ƥ½ñOLb|-ÍÈYVƒg³ÅZ<‘éFð&U–lÚ+$ë´ W5¿©Á{P=9LïöXæ×ÝÜZI+W>~÷ÂMä[–IôÕ+˜ûH,ypÌkGÀ+Uo#»ÔØr
+"8ϙ™4÷ œâÛ –š0üßB 2؜jàgıVRÙÈÖªïÞDËo^¢^`x1¼ÆêJJaíhQ/kW7I'VŒŽ á—("ïÌBÑÆîäìë›ZU'>ƒi_Y—ð«“™A¡Aԍ•p^4žU;#O¸q›Œ¾·ÏU.5„«Ö2•8ŸþwN°Ó Ÿ©ͽҊ2Ø9Ê`{ÉÕ ò6+æ –{¯Çä³@+R%›?é&njÒØOšŽì¤¬š^[Þ_WC5ˆéﱅ×ëmb@4\žû¶»
+ÏjÑùîcUU¼‹Á2ƒµÃ@ œMêÃ~kíMí'ǀo·”Ìš¤>þvÒÎñ–÷šˆ'ÅLµàeƒ™Q³3`'ËéYf¿ÑëùÙ³|q1vµÔ.ôLIŸf–ìÏè•Û ˜­í Qª„ˌœpOUgó'Ñ×øF©ÞåÔφ“ üÛ^ŠªyhäȆß}ÃðÑsÅG2íóþÿÿOXéÙ;ÚXéÙ[@ÿ/Ã^Bendstream
+endobj
+94 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 166 0 R
+/FirstChar 34
+/LastChar 121
+/Widths 174 0 R
+/BaseFont /SSPFWS+NimbusMonL-Regu
+/FontDescriptor 92 0 R
+>> endobj
+92 0 obj <<
+/Ascent 625
+/CapHeight 557
+/Descent -147
+/FontName /SSPFWS+NimbusMonL-Regu
+/ItalicAngle 0
+/StemV 41
+/XHeight 426
+/FontBBox [-12 -237 650 811]
+/Flags 4
+/CharSet (/quotedbl/ampersand/parenleft/parenright/asterisk/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/equal/question/at/A/D/E/F/I/M/N/R/S/T/U/W/bracketleft/backslash/bracketright/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y)
+/FontFile 93 0 R
+>> endobj
+174 0 obj
+[600 0 0 0 600 0 600 600 600 0 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 0 0 600 0 600 600 600 0 0 600 600 600 0 0 600 0 0 0 600 600 0 0 0 600 600 600 600 0 600 0 0 0 600 600 600 0 0 0 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 ]
+endobj
+87 0 obj <<
+/Length1 1614
+/Length2 18822
+/Length3 532
+/Length 19709
+/Filter /FlateDecode
+>>
+stream
+xÚ¬ºcte]·-ÛvRIŶm³bíØfŶmÛ¶m'•TlÛüò¼G·{~ÝïüØ­­9ÐG£Ï¹öZ»mÒ
+SêcÐ;‘Pj NÏÈŽŸÉÇF†‡znÀûöq©³c I¹]ÀàÉ"|í³qù5•‹V6Rƒ_¶åDñìÝ7‹d/•0kÈÛMNyü…ä3„K(·:+r½<Hˆ™æsM³ Q=«Vª·Ã?ÓeãKӜ¾øÀ{¾!7KÂ
+j |&&mèˆN">
+Äö¿áµ«ŸBæwžJ`>K§˜ÊRõ—Kç2K\Tsu5ÕGwàÅå¥@G¡f‚ø©¸£3oßnÆøÖ¦|ÍÛŽ‹w>ùaEk ¾Û<Z>r™²8d£ÔY5¶°42¨§m£¿•“h¿Ho+z•z¶Òý´dî“~œZ“§V†¡RU[Mƨo0È=DdmÕÂaZ—½õ"ŸÉãå-v'.TÚ3Çà"Y`ëF[]N­Ž‡×ø3H„pZïíùf55fhx6 ͐[PÙÍ(²XÖVài’$3Dé‡Ê$s"z`¦œP7ò4RKø6ä9‚"»ŒÉ‘»kÿ´ÞŸ#§µ4³ÌXE[´°7MÒ ­]ˆ$¥»¸´´ø]NgΘÜÎü´+hØÌ<›D`0€”|éð‚¤†ócÕx¬©ZÃ5}åZstÏ[«ZªËujÒ
+ɾÿÆýGµ‘ö¼ó]é¦HùÜbª‡Õ‚^#…âõÝ;ÿw}Á–6N¾¢ß>m±<Ǭ=„Ѧ}º£5©ðh¯uE67Åth*Ì}d4MáÅÑ[_T©ž¢n­"Z–R ÊP3ÇzºQ7IH¸!ú½YÒl}ÎäòxW©Æa¥}ÿÅ Ý|¡†Ç2wfܦ„‹Ûڬᭆtu—öhûè.tiç,eê:èMQJìÍlO´RŒÃ8#—Ñ›nŠÃ·©e×Eöì¬ä2·‹²ßˆ¤Æ,łÀžb׆¿Í‚gvÎVTÃÆ}–¡mýØzÒŠ®ßÇÜ®ô‘¹ õ«½¾pÏÌÄÊ|DÚÉ[×'åˆü,§¤eá
+6ÄAÞJ"ìÎ%VJçì>{6Wm)݂‰^fEt½ýƒâäoz´ ]Ï–ã`?¶z´F‚|K®ÜSÄ<Ie– ‰…ç~>ƼÀó\è½›Ú®’ #6FŸ‡ÝÉÎ~®Â–¡DNIšm³û×9¾â_®Ö¸JE³Õ¥mP/½ƒ/t¹VßѤÆPî¦6mÎÉ`.Ÿ3¾†AZce§É× ³æß ¤a z«+rzf£¢‚Í‘uªL5—ã
+ܪ¨X^~GB˜ttRh±X‘©ŸÝfª€kvÍe~ªšZ«Ül´†ß€Ï×d†hNdm§]ÉïÏïÐXRŸ¿¬cÙÀ6ò[‘éTÇêZ7™j5
+!·Ù÷oZ£
+ :­´´éÙ¤÷M¸jp'ÊÙ±™ÇT2ž“gƒ3E€óx¥GsëÏes
+AÌ©™§ž/íhÚó?Ýû‰ÁʈW£zGErá’âµ!õ€¨ O…i‘Wù#…év箍½(<£ñHtdïÙAZ”Õ #jÕÜûjyJ~á¨ï¯sŠX Í0;/\VIžæö-í'2p؈F±9ãât¡zþ ût{ŸÞÀÌÙ¶o
+Ö0 毂¬:é7¶7Ì}dѹ5×nÁ#Ñ[#7Và¨Ð~úÇçÐa…Èz½/üßmš«`Ø|]
+^vLåFp˜¤ùž‹ê[6«Ï¯.ù =O"Ï÷‘Â<ÚE»½‹Lt-»›ŠÍh˜‹Ef\Ï`ÿþ5#WÛ"DøǚFçç4·o &]$6ѝväTLÌÒ-ƙ*&ÒÉ6°0›=4ô…Aaõ aæ9¡²æädF‡êM­_N …—VWçÓ^/·@¥!uË­n–¼ÓÑÄóþ¶g1µ ,ù<5ܝÔN3) ñÈτävžRnÍö«gé„0µË¾ö,­0ÀlBuVöâ'$i€EÅ9HáZ%œý¨‚‡/ÞŒÇ [º23I!Ì£'MÄ?¤áG‘Úáô¤'ÖfÀƛ[z¹´ýTT´ìj9Á{(ž1Š¾Ë§Ac…¾Uî¿zS2x|S7ÍúUx£„
+y/KõŽ¢cï2’îM<3ÈjZuчEÉfû_πc‰Xזä10VªË!rÔA¾O¾ßr0YɑŽ@\•=ÀŸaߎî¦8WÿŒj†ŠWß·DƒÀ0ÝÉTiL_¹³G[rm]‡tˆ9£óÜÛÍ'H}vâN9¾š$̤©|¿µ$ò’Ñ>roåÈ«jˆ”] yMìs2ﱂ/§S͕Z§,ü2'Ïw8 "pׅ/x[Ϙ‰Ozöø¼µ>]BVÏoÿ9¶ýeÏ»·yû@I1Ewóʈe5Ün!ˆ¤yß­¿ý©M ~²mÖ\Ñ®#¬qÈ÷ [ó‘ù€‰¾fD_²þ¶}臾”¦À{|WÞ>N.­ö9­•ÍNÓ;\ÒâXÎ%çåwì|þ„í` ÿ¬ÈɶÜóhÿ
+½u§
+©UþB2RЭá+NòÜåål¶K´Ù!ï“ÀN )Ę"J±¢ï_èdËB¼ç *9‚ùÒB«¥†Bè:Ks œãªO67 ûú$ˆd©]—M¢ik6Ê@êšN£“,¤¤YÂvÜpz­ÃÎ,pZiðóLƒpˆàª¯,&÷æÁU”¡Ö‹ ÎÕoL6„sŽ¶POlþ u
+£jCÐ]²¼¿š*?çä0\„¼Ã4‡­Ô·B»;üËKEÿÍÀ@%Eâ–^(+¥° CÕVѤ¾”W¦½¿AÊzÁ­P>»þÎ.¨6nãsp§^TY"<>ü”[½ œ«?Qnæ#MgW¸â–úN)èGŸŸ2ïNƒˆ”&Fcǵ‘0„øô5·5yÑf¡&Eþá‚:ç/ ~GÛûJ˘-q~‰‘”ˆœ€xHå™åµíã=B£䕡¤Ûƒ¼Rݱ„:êz«?Uï~$ø̓&ì`•Øù+YؖKfÙ؇`/ÜÀT]~¿ð®çæ$º8SìpŠ€fè:MÇ=Æ] À–ÐL»‡Q·Ð\w‡8'çR‘çõքƒµ)[%¬œžUÈît-âY׊-ÿÖ@âç¯4ÉNè_;Ü)ú7``g°ðQÄùùÃóùif;b?ïð³môò=ŽüvWÏك‡šÎ_÷ŸØÈp7$²âµKP“½ªP„Z1ll“úûÙFìAÂa
+=Jc5¨J.£„²w×þºÆ²œÅí/BCÜÀ'æ›Ðþ.íÓ#ÐRB¿Ti׳…ªKKooÞgP
+
+õ1:s´6XeÇ-ÍÙpSŒëã³_ú–¦6M²ÇÁ
+ýF†½˜ˆããÕhêœáh¼‡í¸ÔcÔª„?«¤jÔ.%ÄE {ÚgP‹ø6 ˜ïuÔǏ·î|vÒ?žwºð?%9F@QóV*r¤¯ Æ@¾CeGËóÀ܄µµ¸Õ· æÊ»år¦Ï±Æh‡ûÉ4¸Ž¾ŠD¤nØ Ô3"&Éq°Xø•59:)¡{I Ë`8ÍïbÆwÂu?c®ï´K4ÿºQŠ>6øÂ,G‚â±uH#°Ë¤
+§=n® Ç¡¼ÅRÀ‡¨ŒÚ…ðlÆëÎ*_É×6ùᩋð_érµ d|°»jZ“†‰G¤}Y׈^’~۟ÈSBªÚÜÕLº‰ÁvJ³{Q¸@3I;!(ãºGá–EfÛ²=ÈE…ŒO¨rô7>©œÎw?eï¿lhà=O8¤îÛ#P'_sn÷ìm™7t}®Iåß(€¦Y'[ê*qÕv„ …cT ™(Ãæ&uKt™Í‹ºªþXdԑe8ñ>Û8ÁþhSj÷VjôÊð7ð’vôpúô‹¡72Œâ æv5ê8š~T阠ˆ‹³È—'Þâ=x
+l$;ÐBeóÿ<ÂÐ=•Õx‰”}s5ӄY$[uØ;T3ØsiÜg&án)­=C«ÓšÏ\æ±òU#}—Ÿ[~½šëô9:¢™i—F
+›Õ
+Úæg ¤ï9.àåAƒ^r5@Ôîoÿ­PÃÅOÀÌ ®i6¹«´¡³_Haî€'idsrn8ˆY’’Úêù™‘o8Ưäï:ªàÆ|„ç„Öˆõ1b½hÉ-IRú£'†9¤Ï$˜]óú¦xAJþ.2µ‚òò|H˜žYU챞'”°„6ëÿ<M
+ ¤·7È)hIó ÖóhŒ¹+U®U@‡š_E„©¬Q.Âgû‹ÀðÒ¼õ‹1ÃÂ#ócÀ ªN©¡
+O\Åܒ$K5A³/Å\Z³æâT=±).T_N‹aô,’/³LÓ[³U§@S
+|¸Bl¸É²þÆ%cE¹ ènu°³÷Ñ 2²<å­la1´ú‡¹[”ä½4ZÆSIý&¢t©Š\PD@kµnƒ\y‚£RB•È΀ÒéŒqÕZ{tæPië„ÓM°%'2 oª]w¥FÑÃB«pR=žÜƒ"¶NbIߧkº¶¯2›JÇËð¡ÐÊuLѸ6ÒóÑy`|)wðˆß°yŽŸø­šKÜOs›ìSî:„éÉìzæw°¦ ŽŸÿ°ÑŸ4ßq-E‡>z¢#65ŒŸìo½t¸Ußi‡!K)wÿê° nïkžŽaT×Þâ`iÅ̊_¢‹Z#ßæ4¬\9
+Ž,ŸôNÜqºÓ+Ì+â[íuìüùã/ŠPÌNJz݊ —9(d½ÐÉ3*h@n±jNæ<·…¼Fªrk“áIJâ9z:
+…» }ÞgRBbù
+R7ç›Ûü\7P`d±Wl×ûµX”(;³èáÊÙ]šÔ½ÛM±×çÞÓå ¸blä\îTƒg‰³#<KLäì’fô§8ëÛ¤7¦7]…³þàìŒ×2ÃÐàstvå ¾kz°|6ªÌ§HL{µÖ+Ê֘ÛW„Z0 yhÃun ]z<uõ°•K‘ÞBBa<JƱ½7ßÀ«@$Šž̖/áï ¸På»®w”²EC²O1æåçÁL&Ŷ,¢E; mú‘óьþ~OòÉïӏ%–‡îI–%È,abQõè ŸçkÉ}ýp+Ôoràõ¡ñ-tjìqsý%9ÄuÐÑ5
+õÛBuçLJ“¡éðÔCegBdϔˆCbøJ_h΅ ”ç‚i[“#.Xð¢¼à<žMG
+„âuhÒJ¼vfÇÁËg…á’53¸¾Ì÷÷*\²Ál{4ÝÄÊhv÷þtÊôêX´#‘`®e͆…N×V“{}ŠG?Çqô¥®oI
+B»°£ ŽÑ68»üéí
+{ÆD òˆ˜º‚`³è3–"°ÓžS8÷4óе^ùÌ`‰RV“ÍÁ
+ÑEž®CÌéðòaÌáï6[©?¬ùU›¶d…Ví˪aYÀM S뗣æŠ/YZÞsk#^Ìãúö*‡­N¨ ہ%üa†ñÚV«]׬í@èà5£Êï¾n|°öÚ%5:gÄÖÏF]´n—Eö¼n÷ìkÀú¯ý‘x?ޟywÍælò„‰lI%ð{ÇÐ>UOiU¨€æH­…fMñ?ðq(ížF‹Å~w)”£#ù±°f@5[™úÈ7Ën-Ð? Xù«V{]ip¬5겧ÊsŽ·Žéõû¿SÙK#4ÔæÞ2œtÉjŸBK–’Ò›È¨Ñý
+ðÊb*‰s¥‰
+jìS† ²t¼ìÞO¾Í¹÷'¼­ì*ӛiFôÜ¬ÊJðlg8¦‹&ne ÊÐ|A‡OŠ‡w‰féõÀo[z•ý¯ôžÐÉv ZVÎ œè䡀 ƒejõŸãüÑÔÔ§­2µ;^âQOßÚô¼
+àp¯O…<;·ïlRù­Seôzµ±ØwI&É_Â"’ÉÝ2'(3éÃ8ž!ÔìO§á3ü¸®¹ÝÈ•,然 úÉxµZ¦M(10oS8AŽ¶yÞOڐòwGxQçPà‰-2`8ŽÔ½ §lx]UKž¼§×86Ì84€(è ÊÖ&6о€ #y*ÐáaÑê7ˆˆ£eEA3ßB!P3¿Ç{
+µÿŽú÷ó߃/„1ۏ:Bθ+´º?|sÔ{5{ðŒR]l>½å«XŒKFÙ>y ìãc‚»RêIIلOòHþ–®ÖQVâa֔J˨—Ï©‹SˆtîU~3æÌì\Û¶€ÓK€¶§þ“çªÕmù£æ°ü“+ ï"œJ•ß¬¯ÿۖ¡¦HͽؗŽ¦·—ÍbjóVABÓ¡|³k½7ÃͲU.`6\ïÍä¥x Û'd,¬•›Åg-LÐڋ.2b…ÌTÄ~2jp[þ~]%w¹ÄúÏ?HÉÊîßVo…u…©®AíÃÙÀFžž ¹ª…¯G Ї;KT$È:±¯Îüꪲàn‡gw™Ê—üª ]‡´y1<e@ßúK¥Úހ£[8]Áº²›ÜÉaß߬ޯ1ìjÈžÝP ¹¥ Ž9£7qæµB°†‡ãäŒÕY}¬|ÿG|ڃ‚vÓûiÝö燗֝Þ
+{ œ#¥ü29?à§w+¬VÍ媂ý•»ÓæÖ@|˜äMö%D_îA7f6'5!–OG}hg“Ti]³j?–Á8€|Vœb1']”±õ7¨>Šüœ‚Œþ&*uäkäþÜWA›Ð&ŠÁµœmÏ`vˆwlDß/¢–ßg<u .=Ýÿ¡#ݶ³ƒ­±.Íê/.®D½,d”ëǗHKÐÀÇäFÁ¬LM\LЇþGìhÚ^³PN˙=ÅÐÛðÁ[[Cƒè¦…U|ú¤ÛŽ?~ð(²„l~Byqº%·¯
+(@$7+bî$è¥ EØv¬–δŠ‡Ó\:¼·¬zãån5Ìޛ/~àË^íãN{œ•çâïðÛ&Ii€Ù—¦ºõôîZ±êe6ºÓ1OžÐ1sŒJ?ùy(ŽF¾_KvÂx«Ãù®+Š–ïċ.LsvÒÌRM=mܼÞI1LFý
+-$…`Ž"ÂI¨p[<2!Wèbí>{?¡“r‚—GjjjËA%ÞL ~¢iô^¢µÃ¤UØ1vt òÊôi)`&1聽Ñta\Ú·{¸½(0‘%Ò w§ÖV˘ávO8Ç×UJâÖ$ fbTà˜0ÌC3nKs²gd7I™}\ˆ,-Æ Ý!ª9ÿ~;î[< dÏîkÇ=uT$îc;†ôzŸ¡e>ØÐ_ƒ·Ú+L§?NÁÉZéK; E¯øp©ŸÏiÍ;÷†G?”›£0~¯/kh+ºg±ã¿}?Ô=V³q(Å2¶s”3¦*-@''í™WG?•œÉ¬'„ ë7иñN=¯–”|<Ž£Òѣɟ ÝŠÏë—jûµ9àt£.'Â=~Ž©¦Âé6Ùù4QÙp—¿ëºîs)½mn
+ƹ¯ ¯ÙüHvkŸã.xG¢GXªö°7ʌqw.Ȋð>­m0k>+\œÀŸÐ{1éیþÓ߇Ã.œ1e^êíM慳*ûÓ,=åÔ©ósñŽ¹´0x@à­ò˜ûL,º<¦&GN•¾BœÕ´Òoö÷kÀÅð®
+u‹+U1À’w@_C.ýÝ3îDŒûV©šwl+` ¹;cÏÎ:ÊO¶ñ;[UÅeð™.~fä½K¤i¾»^íä'è±bëœh’rý‘Éðn^±ãqþ¹Ái6¡šö¥mb†µSöT
+œèÓõBs´Õ¦ú:¨mxš$H!y^Ç8?ž½vÞÎż R8# &°^n줵b“-LŸ¥.K…,«o{À5•ÔagðJç¬ÓimŒút0€Î R¿q›ð󈇫sáxefÔò¼ag™:+µád>Í\á&ž>á‡8¹ÿèœ)ŒøYÖLèx4„¹ ]57äêΨ05W”*G_¼P.*æ] êKª/+ØzØ BŒÑ፾ڕzZ‘ “á2ŠÌâÓÐlÇ×% ’â(ß! y7GU‡©ˆA§˜"˜é!&ðSç¦ Ù•¤èÜBY¶Êç 6óM½DÿŠ¿ðä±|.ppÜ*ÀË·Ö›û?Ü Ýž¬þÎ{^3›…_ÀxŽ°™é/Ýk§µS?
+ÅÆFŠÍõ¯j( ‡tÄõÏ!纕ě1ÂÛ¡i[O1þ“ë‹Xí#•D]´Á›=2#pý6<ÈÏn(ŽGUm¼ØÖOv°Ré!pƒ2Å6âŽýEmyk߸Ïß:ŒëøI[ØÔ­ý¥·jãIßäøiðA™P _¾p2¯Q§6Ü~qyÒJ)d:Ò2ƒÃè´q'n-»GK¦k±â¹¥d²´sI.\ƒ¯#¨!`q+ÜK
+¸ÑʽKe„a8çã#CBT8Lœ¤
+×Æû[ˆ_£Í­.`~¤Óäëøõà\Ž2¸¿ày'”“€#°†"{aôµ1ЄXóC‚¢‰#Œ‹^Çù™­O‘³z½Wf Žv©<8ÓS|ç.ìã<³o5ñ½ˆW¦äì9À3¾O½±ê§dôVïô³™J…+j'o¾ 
+Æðõ_Š»Ä/ûbC¬þQ/r­Àv~àf4þs&Œ¬ž
+8 iD­è­¥q‚.>¹eø¿bc*¯Üäèô$<4J[%ß{d;
+¤ïg;TeKŽ(2™Ã µgy)í“׍¿ë.§O9®Øu•â €­Í7¥ä¸[…¨Á•=7Õ ¹
+üéJøcôL×=¡¡°$ùÂÞáÁÊNáp(5ù3Tüîð®Q[⢞Rð$àT½Š®¾
+FìƆ÷(7¬8‰ýrN·Š’a¡!~Pk[ºƒÔƌìnÓN=Æwý™#n#ºm¨¯0k;Ã÷ºë@†SÉÓ­´7
+à>ˆ¾!sÝÚèWÄñPo:ñu[„Äw•¿–R^[Ù•"bº3†‚ñ‹¶ÂwïbâÎæ%MîV[Úºc%»¹ß¯Š^+žZ‘p.åAÚu*Ï?¾óž5!ߥ¦Í0Ö6!!nw.ÎÑHËôœø9șÁ{Cç|ÔÙE×OuaŸ^(/¹§µ•¢Æ­šZݟíB¹AÖ*%{Ï„áDÌÛ¨ÃýîÙÚnK˜oðõ·Tå—x2
+¸Ç‹Ëî[É{¸®¥@Pc»u,oÏ͸Õk
+ôF]Ɖ– ã²YÁLìB²³§4á¼ ä Ò¸øïÅÌý’ù:.óúWüdøÜûzùøÁöèõÿÁñ¤_è癉mÖ«£>£ê(\WMv”–KY¥Ñ݋á3ɳiÀ¯ê$æS¹ïÕBÕ,
+`Vü%¾®:j¬ì¿¯¸‹ìƒfb–ržáÏØgËAd)ú¨À`ÿüÃö°83
+5ÚyږŸqþLµ±ŒvÎ¥yÿˆÖèwÒwuòŠü„!µw`E4ㄩù›Ç¾ÐÐ0D`/ûsëy ÿL÷ùmǽœH€Sñ
+¶¸SÀÝ,84ïSi–›ßçOEóx¤µxÛˁk¦eD¸,(ˆÑ«Y3¨Ï½•ß çø©¢MÌóòãÉ^ΝÝjEVŠóލîn¢äísíÌ=1èy¤ºËÆo1L±¿=oêZIÄB”m’ÿÊÄ©÷lB.‘Ì a…¥ÚÎÍ»ÏÞÄve-]‡A÷}BgZˆ6öÿ®?ZµÛOtˆ¦IbâXpŸËYàwoD¶¶WBʼ«ªf€UƗi™hô*TØôfža.S
+0ÔQ†juã
+*iñX)Ì&‚X/0S¸ñ„¿&ˆI©g‹åN}ÿÌyìÀ7B™€érDã(=<s™ìsÒé!&.Kû‘ªzHÅ/Éû×åY¤¦j‡
+“Êè«HÂs°W®`À×ååü"Hi÷@ãùC îEj>V†KÉ#
+ì%vìى’º~}uÈA>2ŸtWýcý­®õÝÃ$0ùUC’u}“jp°âs9ÈBßC6ÛšUv…ÏìÞ9ÝuvJQ”Sy\* N”cʤbDÈí=;%!ˎäðí°z9÷ÞsV“ïá!‹BúæµM &Æ€¥^¹ÀÚ_îØ{Hë:«Ý½i¿e Úrñú<Œ³ïßòª©.í°PjA{ƒuʦIŠÓÔuÇ×½¬úoÌ6û¦ùQ1êXÏî—Ø®ïào‚¹Úö·íØџÏS8zýé¡zÛ*¾µf–¸WŽ=–p
+6Â1(ŸW§f‰‚R¥¹aþ W®K§CíZ·<o-®GvüÄ=?_èV` áøâi"¥žèãُêQLB¯j>ǚ¬9%¦™Ö¯Kwîstœ0vØxEb‹”ÊþI™ý×1ÊÛÔ¦”g°¸BPÏÖêúF<£ã!þ½0YiÂJx‰sX玅IÑŸW踐¶©Žô¢'mŠNA]™¥×Ú#TÓq5
+©mÇUF—TAË¿ö£‚Üœ6åçݍc¢1áí-—«Ç°0ܑ®ï0ÒäUëyÍ;¼5éå7z+hUYAàɀã«PÓ
+,‹I`†6ïïÖýìÈ’”EøDûnˆ«™“ÔmÙÎF°lº Fýd&.7pïÇÿ×¾yõ³Á0|­=[µƒ „Ú5ÚÆæ¶GÕ¨DÌ ö(jV£Š’FkD‘T­Ú31jÕÞ#µU¹•ç>y?Á{öüžÿ¸Žÿ×ÁÅËÿ˜]ý©70:IûÆ~ú¿‚%®ÓŽµxŸ>NÚ«ZKd%÷Íd“9 £E»Ý’ƒ¾;ûa•‰coš¾,é âiˆ‡”ÍÏ$S|ûGŽÍIæ–hŸè,Ų£u±enœ„)-'Èâ—ZØvÝøůì‡áJwÇÀ4;µGÍëfï_òüä7„ñ<Ò-)J[·Tþ:(A‰!›dºº9Åê£"ßaðU #C ]ľó‚Ÿuzõ±Ãž”Óý$O\œ˜Ë…Ԛ}âP‹¼Y$•âöEà(©o"‰§¿Ø~’×ßÆØUR{š,*JlíÇ5îÔvõÒ@NWîò@ÕS–~BíIâºÇM/`Ý1ÙCÄHÎzw”$-õ°´Ï+æ}j%kñ9juł|³e{T&êóùg‘€¼@7ß'9|=û¯õ*=5ÅÆkCaìY×Ç߈–Vä/7Œ'œ¦:h}S˜•Q3kÜ,4!VÌV½ Š Ø!OnF…¡¸Æ7éÂ<Êo­:օ®¹ø*ÔFì€Ê è9©ïߢÄQ_SZBÞ"'¥üåëE1œ}柂¤:¡á]qžÐÎ}Y™Ñ;nù9?%µ¬K¯!2ût$2
+¡®ÏHoÌ{—SϦ:æneӍíõKʬ’SfC­ØÇ.*ë&ðý¹÷¸]ž5»ý[Ø法‡¶»=[Óþ¢ÊÑuö`!.NXÝIv—öl«qèU®Ð½†cÁ ¯ÇËß ºª—Æ›rå>@™»š"¦¿¨‹jÅ©^
+YYª¯¼µ~ù(ÖiïM Gj5·™Ùñ˜!Å7ÓLTÑe«ô¬Ûàˆü1‹ožºý6E’ÔÂAMuyî›YB̩ힸ1Qh^²ð
+žÇ£Òƒ•â/icÝøóÃF¿¾¨Xµ;Ïÿ˜h¹ü÷í(͙þz¹sæõåÄÄgɨàƒA9Tãõƒr\Á©V·›%|gù”‰QÒN¼F“>èhÅÍî V6ölãà*/žÉû=îiÀ:²Ä…d:ψG͓ ßڙ»ÒÝwë{>$—C_tØÅû›uuô ƒW[¾tۇö¬P‡àPâyeÆRþ®°l»¿5³ÛîáUC”ì1הÜF:æ5Vè…5´¿x¢®ÝùÌ8_²`g+
+#×@O.¨çE‰œ,]2;ò¯µ”Ú’M
+î˜-y§”ÂHθ¬Êíc)¶é{ã4Yð܁
+s¬ÒKUyÚm‹vç‹ã«‰ÎÞûڃ‡/ØÉ·ÛkF/Jý}Ð+8çµÃ§0Îðï7¼¯Û”«úJÓjŠ>;ݱ.A‚VÿàI½ðµê"²ÞYÙ]g›n§èØ8½ö¡X#²{ô±Ôñí¤Tß2is!úå/çìh‹ËR£D°jU_Ò¢z'ulIÕ(V2iŒ
+¸`ۛ•bÍNá"§7ÖMñ¢tɟ²™ÒòÎõƒ’Ž^ß4D$öÅóöÃEt‹ã+” ´l[0Ý*:+`Nº27"…õŒOáÿ9¦ÿþ+n~®Á¡þ®Á¾LÿV‰X$endstream
+endobj
+88 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 166 0 R
+/FirstChar 2
+/LastChar 121
+/Widths 175 0 R
+/BaseFont /KOWNPI+URWPalladioL-Bold
+/FontDescriptor 86 0 R
+>> endobj
+86 0 obj <<
+/Ascent 708
+/CapHeight 672
+/Descent -266
+/FontName /KOWNPI+URWPalladioL-Bold
+/ItalicAngle 0
+/StemV 123
+/XHeight 471
+/FontBBox [-152 -301 1000 935]
+/Flags 4
+/CharSet (/fi/period/zero/one/two/three/four/five/six/seven/eight/nine/colon/B/C/D/E/F/G/I/L/M/N/O/P/R/S/W/a/b/c/d/e/f/g/h/i/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y)
+/FontFile 87 0 R
+>> endobj
+175 0 obj
+[611 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 250 0 500 500 500 500 500 500 500 500 500 500 250 0 0 0 0 0 0 0 667 722 833 611 556 833 0 389 0 0 611 1000 833 833 611 0 722 611 0 0 0 1000 0 0 0 0 0 0 0 0 0 500 611 444 611 500 389 556 611 333 0 611 333 889 611 556 611 611 389 444 333 611 556 833 500 556 ]
+endobj
+83 0 obj <<
+/Length1 1616
+/Length2 23802
+/Length3 532
+/Length 24704
+/Filter /FlateDecode
+>>
+stream
+xÚ¬´UT][´%JpwÎÆÝÝ!¸»»³±»»»»w‡ÁÝÝ!¸kpËË9·nÝj·ê«^}¬ÖÖ°>ú}ÎIA¢¤Ê b21—Ù»0°02óÔU4•ŒmmÍ€ 91௛ž‚BÔÉÜز3v1çhš›ÄÌM¬¬x
+@3Í@¦®ÿŒôoì/Ìߨ‹1ÐÞàbîáòO/s€ÐÙÁÖØóoï¿`NÀi¸:í-ÿ‹=ÀÉÜÒØÉÌÖÜÙù/Ì_ì¶ó_sþ—él=ÿ­ý›õ?9]œÍm-áYXÿö4uùÛÛhÏôÏQ‘¶·X˜ÿÃoæêðŸ17s§Dýϙ¡ùKÂØ doë 03·€gR¹üm  þ¿S™ñÿÈÿ$þ"ðÿyÿÿ‰ûß5ú_.ñÿßûüß¡%\mmŒíÌÿ-üçüóÈØÿoÙÆv@[ÏÿSþÏÔ4ÿ’ÿGiã¿«±·ü+3#ó8Î@s3% ‹©ÀÂØöïžþõ«Û›™;ÙíÍÿêùï* ,ÌÌÿ-¦f4µ±ÿgñÿ2·7ûïÜÿJô/s&IeeMºÿýMý7Oé¯ö.jž©ýQäAfÿÓøåÛ7À›…“ÀÀÊÍö÷ʱ²xØÙ|ÿÿbù/[ÞØÅ èÐý;63Ë¿Ãÿï¿,ýÿ#no
+]¿·;ÓôäZ'@‹äëFR~7ù—Ñ(n&°Ouyt=5vu60ðúO;Ò fID5"õ%A<ãìD_ÏXÆbøïYëbFíç9À.Ö³“•¹ÄkP;BRó4`¿hÉÞÈ[·Fg`E ˆjümÖh鿍_¦¼8*ŠíO³¼Õ‘˜UÒúc,rÅQ«æƒÁ±ò¨F—iÈGcғA;}'[·¶W»Ä¦}{~Ý)ÓEx7‹Õ/½`¡À7éxÄ­I1
+·¿žˆÏ%Ž3«A@«
+ñJ.]§ç÷t­©ÁÁHqæTåªH3a ÂŒþuv_·%¹Ýþ–ƒU™œá
+o6®èJ63û¶›] J¾±M}h€uÒ¦²‚? ûd¾×Rm¯ùR$?~”<J¢]xQgVgtÇFx–KQj±fÊñÕìΑ&N@%‰‚·ˆñºäPln®úòíúþú†'éÌO·B–ü†¥ÅŽ‹b®ZS“ñí¹p¿s¾–Mª;~ 'ïRCôB>3Üý+øU›iÖTÀµ"Œ]go~Æ3qAäpb÷ô7ž¤,›0IÕ=ÈÞ® 8AŒü\cÈO¨pzâ°Ãž½_’ÈQ‘MáôáODy]38äN!xǃ$‡ÓÀõ9²öX[”U½°1Žžñ½:½Í5¼l1ç;HáÐ6h[»œÓ”ù&¶{‡օ.ê Àl¯#:«œ%ĽE-%¢®ynbv樼Í"†|¬qˆ)œ ldíÞS£§ÔM¢¼A„ÒDÅü¶T‚æ¥Ê×BŽ>_}³©(Ö<½PÛ±1EòÖ±ºPÙ`wlÞúæáïk½:ÛÀÃ^‰ôpå[BÚùñÓäS#ùŸÆP³Ã†O”¬‡Â]göüš(ãå
+ ?‰O„Ëï5Œ?‡¢©®2:±y Èw!¦ÍÛ=U•¶Ñ"_Ù¿H¿EɔRT÷oY¢3«ÑÈ®ÞЈ)º¬k„¶&Zۏä
+NMµ¯rÉFŽ|IyUJ5J|£7¼MT} ¥±("Hô£¾±Êŀ«»WpE7>†a…å “¹†ÙŽº9“‹ÛF¤\È
+Ìüƒ/Tq% ™¿µ¶ŒÙqþN^©õ€‡¶ÒR’ÇU3g^nB"çsìœ(næÅëû>ªN´¢DÀy`ó¬dîbV š{Fâ;k#€Ý»¡
+˜³^ÝϬÈÖ¸*jò<†U³눫H±O6„¡ùnèò²ê•M
+NÕÝSŸïÑÞóã%UµvKƧM¿Ño¯Šßçöoý™bTH¡°{/ð"¹|™™À±nD½ƒ1Ÿ8Dÿ†¶
+S \ª”dŠŒ 瘝i…„"l
+bÙµ(ÊÆ'@òŽì,*Iþq~²¥0ݐ‡-—Ô^I‹֗ŠÙP-¢ƒc"¶æyÿ–ŽEg?oŒ,¼,¦t+BT]i¢Š©Q}Ú¨-ÈA'/A5ÚÇýL½±bE “.Ðe“üXÑ¿>Cÿk·¢ `æUÍYëä[ü5¹Jæhd¬6õXŠþ˜ò.aç¡1ôu<#·)„$Q‰·¬NbØýG$ٔVäBú<‡a¦]ˆ­ÍWS"Ã#4)U+®9N?nÓ'5ùçšúYCÊ-–g ®Sâ~h—èXÔu~Øá*á3\rÊ{¥Ðþ‚}ÑÃÕaTÀ÷gˆ¤ Û1œŒLÖpГ†/KsD«ñó A7SýÍ¡ t”Â:Æ3v¼À)¦¶1ÔÜ{;ð½Ñti‡´XîJ ¿z¬ô2\(yÞ±ì¸ùˆR>sA6–ï¶Ùº$ªõé“¸É BMÚÊÃk¿d¶@LN!­ĈØIÓøi°ÎŸ[…OŽ½õ~FŸ,ó
+j,~ÛVHR҈7YõÇr-û±¨´øUg>^-ÚÝ 56Ÿ/¡¯UÄìŽ
+æõW9ê/1Çûz‰C¿»¢À#V9e®ÌÀ…âZÜû\bz›` ïބ1[þ¾?ӃP
+…ôë]ž_5=„¬¿è…'œX&»})©È0ÏHíêj8×%YñŽtÍK“K(¡¬ØØë"¾þ¸Áœ´ûs0|±MmÁì½\Ž–÷’§ð;–NâžAû¶æ…*ŒBN‚ë:ŸèºÒ¸Hx…²y2‚“¶Úkñ”ďiQÖY‡>»X˼^óIGLŠÚ~u›E
+ö-Œ“é Ô¨[¹hï$KUw®fvN«5$Õ¦…lê#žôbÛw(=„¹G]oÃáO_“$m[¡a¬dԊ¯oÇ
+‚ùA/Órlª°ZÇƼ…ƒvò …(ºMö1ý~ÁÖË ‚ª»o÷Ø»˜.ý;ÇlyÈXêMíö´4°®Æ[F÷76TRÜüEŠØ¥hWºº<ìÃ7°"ü³+0¾àɤ´à3³—ËÀý\NÂݒ\4OÓÿ—ÃÔÐ]9j. Êó’`˜ &É^ý6oKõŸg_‚2ë9vlºgbmã 0ïÚyÖbëÇ÷~"q|ˆ$𠔓-QœƒvS(G/‰ä=µ$üØÝË ©íáÁçkqø¾í*´›GŸë¡æÏC%*Œàj¸Šoá*fEºTq´û®Ã§â¡øS^xM½š3Š~“ˆe|r<¿bèýSËZO!íUðÒ»_“Ø6¾Ê^ËÒ)hB¶çƃ,ˆ/•Ä ÜŸ¹øG
+±?ByzÈN‚ ׅ³»æbø/|91cò[Ó+ï3@Pc…„­Ó†xŸÚ±º†6í¿Eފ0`Lnb,^¬}0.Êä<ùx¾ž‹ò<¤»-ÂÛå)EԐ+eTÌÔê
+ß(`„øÉ%‘Ã$q_`Ðýz´¯‹>Й@Êù¼­êRV®JÃõå3§°3,«ê•Ä!¯úgÖOk0¢×T}˜ *c¨PÓÙVnÃ<[²TÐÓfbÜHtðâ旦é³õKq«Ç
+¹OÖNCF"N;ícÔ®áH.Hsä^è¹Å†qæùàËÁ¶Y——îU
+|‚ J0Ëla·+}Žt5ºgtTØ´I|"þVT¶‹²ý¹™¿@c]"‘ª¾«¸Å“¸BÝ4ñr´W=(ÚjRöm{yt_o®>GogžFÊO”'2§Ê-1S•k2þˆ®d Ú–hßH —Þ·ô|.þŒš®ý‰>„¬û
+óäñ6I\“¾ü°Ûډ­2º}\–m,ž-,ì.*/ºû§ÍEzH`3™ózù°4ä4ÉS̬ƒ|lßaƒ"M,@8‘¯ÞÏAø›Ùùnl4Õ6o4eÇÐyês}Nxà>铙©/sÑ Îüçw_ɯ¢£hï‘×a¨bK„cQ “$
+þ‘½_Ws>R
+>;Dàøˆ,ëDÙÕ×@W3ˆÏLœ#3'Û*²É<V¼£ó(ú¡½«ƒ!7KŒT­¡CËʕ~¿;“Ó¹mœ!73àÓ¡ì¯s ¿LSÍþ2§å‰þ£ùç…»Îý% ÇßÊÈh] Õ¦‰J´Oí³ 0Ú¿j‰†Š˜@a=ÝÎ>
+^J;ÅCÑ៍"e0ý6EËÞÐGUÊÒþóX s¤rIä"‡ ÿS¹>*Ö5:…Ó š?ËûÎÍïš<šDåÃç+: ûêŠÃ¬Én$ CWy웞ÇL¨û‚Û¶…€Ã|u ŸðîpÊ{xÖ¶oşËRp=õ¼9êÇ?”ø îjdcêë'$­ï+”F- ¤†ÊŸâÙß.anrP|äÚå~X« ¾5åîÍŒCBÜ2
+‘"W÷ä|HKwx=nxê#à
+,íaÜà JOšÒ©ˆó©ÔR—e(¥;ÙÊ=˜$‡âwšª"ºëÑN¶»xavUùl;N÷.#½F|õô+%
+–›Õê¶#e,tz3ÜWcQãr.[¯ÌÁ!ñàöØræoB¿ú}ƒžÕ8&_Â/èâ*Â2*8™S/•ø£ä½ô†›˜ nX›G%ŸñþD¬yFïG(Ue4wF<zˆCnt[
+yNöãSU½ªÞ×2š0-wz¥¨gEÆØ\ç°öÈÊH?©×3íKÁÀᖱßS.JN=_oöV&±£L1ºLOVkèa·ðûà˜TM#éý6x5ö´¾9“A†Þb,
+™"f…{íÚ i4®«!Ú¿ü”ü™ lÓßóê/úäÅ×ÜPÓ->‚{Ìüs¥ëßñ[†…³lÝ%Ü2glçÂðXyŸ’©òSêåpT  ÿÃo’5ѣŻÌtfìçP¬ûŒB3ò´Ì\é”1Øú¤î.!$B»w§ß¸MÖfîãsŒ:]Ïͳx‘æØhûÝM7W=ì°Œ+¢›³—¡Yí&ƒ ž> ƒ5Že½y´"[yâÖnMžh?WÅáâ±o¡ùRtmNœ—/¬×Fû³ÚËž€zðW¡õ!ݗÜ±åà|M:µæµÀƵõ ñH+5gn+`0.w1•—|ª%ÌÏø”š‘{ÊóP£™çá3ãXÓ®ÛPmNÙß ÓQ“û^N®H´¨eõŒ‘üd¦ÔOæ0›ç 1i¢£@¡Æ~'ex}„£.·i uÉLx–€½öb&?jÀÿ4sÆc¾4ÐQk ÇÒÇù&à #þÙb®}\šaÔî•
+ øº*¼w…3NÂi1¡æ Õ¯¢ø;돬ϔ2Gû›x©¥[eÐ
+Ù"ŒEw@ÿÐ~ù¾zWûP(QéÁÐf¶¢6h1èsŠ\Yþ™¶{C¸±8¬Èaè=R¼<‚"té_˜P·6ÿhò‹ÕIZÔ<w—Ɓ‡eL +NE„ÅE©õeòE½ï—m* ð§ò¡C7†¿dNféù?ÅHíÅÓ`“R}…÷S‡ú»©È{$õ˜(gàÝú*x»ö
+pdÔh6:8ɧ|Òxe÷]¦—"s{…Üò‚,`!)¿œþ ³¸%ÿüÄ©0ëRžâS‰æÐØ!z¨?-¼Ô«gꓩ->3hã m>q €ÿ®½pˆ³«|ϛŽðhUÕÄ#^Âéo<=Ktqƒº•ėtP;ֹߪ[‰¦þ]D&íΡÅ2"Óýá#¸|5LQ¿ ¦Ø³Ù¡b_¸4£ÐLðèüLz¹éŽ=è¨P4œ]"å³2k´ê™îv_ï¾ô:Ø?d9¼DCÁšBÖvì]ÿØ^yãSÒwrB
+A°&«åûÍ{Ùè„þ7¶ÒÇÝÙõ­ºÂèwÑCŸðHÙr¹kµqvtrn —yŸÙë©hª¸;2[
+ïS¯Ü}j5ˆb‹³-*/žÈF ŽêÉ[ˆ†kïVª†X’»SáêfaM
+Ð~w?ó¨·üeÏPaܺYñA$ ù•´Ûý‚¬ÆÈazH XÀTHH¹•ümIk£*/iêopÞ0Œ¬±ïÕVÜXJû§±ê kÊ]nÊÐ»Â…Ò  h(ö¶'„† ¢ŠWj œŽj/V|ùslÌ×é /ðNdŠýÕG•ÑZnB¹¯r8»%iSûd3Ý®‡Ì·/xíç‘.MÔ7æÄnì]²XŠ[l¤Eõ¯ƒ=Ö&ëVV•n¦wõ ‘ŽE;—‹/ óõ"•¬ôº)s]@Z¼Ž‚ðZ‡¾è!˜¼£C¶ÿÐ6ʸÊCM~ª-þ€@E««êÊ£}UÈR]¶à)û<åÈRʱ-‹ 9vµ5iYˆVèbÍ™˜ðoo)%—?³\¿ôõJÊÝNEÔ,gßKÑ;ÎÆ7\Rß߬¶v´b_ø€ÉÂòXx-ô¦žçû[³Þ§†¯­gÍ?(æ„ôqu=`èËl™ÛkXHÄ=íTJbåïœ7Σßï>Q³˜W=¯Á®(ÊæÂÙ
+Ðåèãe0žXÜ V騘§ËÖ ~ÅX?Ë°lð|:UnÎ)}ÍfTŒÎùQ²´ÍsàüËüWٗEý± ’¯BŒg4‡Ÿ.¢ÊÚ߈ǩ´KOé²È,õœ¹îE§«è׍™H›MfNΕ4°zð”Õ· ,iÚXÔY%ü–àM‹bo¶2Á(Ry¹hhùDp¶×­L| íMT‰§¯Åˆî×ԉ&Æ,Mí .ÏI¬»Èì™2
+ÆͶ½)©RÃËk‚¶wÛá ´[ý†¹ ™({¥Ñ|'Cë$¼Ê ¹"8Þ¸ÞɈŒ®†(¦Ó1/K;̶/•àÞ2Cßh %Æ<ÜÓj‘«Þƒ #F_ÓHˎcÈ6Ž€ɤҾóx»É΢ 
+¾Q_›tȃê[ÝÈÑi§4˜­¯Î² R¡’´Û>¨Ka–ÈÉÐ/(DÑD•¿\Øº€9ÇR)´µÒ[ ·´Å¹GŠS‘×jÊÀ…q
+$0oðfoPë^“å®=àK?±(å·vÀžÑÃ~“o1Æþ=ÕÒÛ¤Oñ¼Þ
+¥š$„š
+Í%H¸[mK,ÏuӉ“&ܧøž(¬2²ªDÎVõe؍ŸXÂÖd‹ŒBC%6¶Ò"­3CÏÒMCªe©‘4Fú–Ér Q¨19‹g‰8';í¾h/óŠ®À2xøu/!ÓÑÍ@oz.Ÿë˜ö
+¾àr[ݜF§ø†ØbӃ™ÖO`ë2'g‘£¿»#l~Cò<ûEö|W7p“vۄÓé¤à¢_&
+½eî$Ýèuüü$2jy<ç]pž7
+w¨Î_h„›»†-àó7‚Ÿn §Ü!ø˜ÒŽƒeajKÝ®­óaiw~÷BníÓÓ©·n‡=³["a]Õ#c'&™òŠeØØÀª‘e\eöIÏLû¸ñŒMÿ
+À]eÿ-uò–X=–?Ѓ</­åÍQ¾Åxy3L3YōààÖqˆ—4õ†ñ<àžtT&€¤¯ã¶‚Û~»‚±e—.§j|;#V0€P@þvóÜûõ,ùÉ= °•Lqh2y±Ó FÜÙ§“-)Œ%[ó«<˜J‚CóâÁ[Ʋ́J@ÏHídÊ«Íî鋮“Lä(¸£öyZZ—ç·_I«ß;
+o ˜…Ø¿£ÝÕm9˨‡¦HØá²ú˶T´ÿt<Rì+ üA¹å¦ÔŊoƒ“ôäÀ¥·Í_ºå(.ýfæøšº ¬9ž%Þèýáé玏ë‡H½Ÿ‚yŒ˜"³ˆ¯Œæç}î!Fôʎ$½g¾‰ È»8w²Ï
+›ĀÝËoã©Œ†‰©"ª‰Óã[ĘX]4ð² "ÚwçRè9β]‹¦L0Yoü4'VǦfëy™¸S3Eڅ~
+Uל'gpùB{gx?P±$0ÚR®¥Ùi š.ڗ ˆšŽeøE®Z‹6EW˜R(vÞ¦l¿­uŠ#¤ãŠ9Pó÷[‹’v¹ïw^0½C¦ïJz`×Á\ÍH¦·Å]lE‘½ÂÙ䤨ÉQ«ëyðr<€rÕ°$EC~sŠ)W—iÜbԉ\¤èý¨vºxÜÑ0Ý[‰  ]jÊBé­HíÓ J÷XÉ ÙÐ
+úÍmTÓKóƒ} ÿÇñÙ]cÿæxêyéÖM €ÕÊÇú €Èý+Jg?¼*öË="F(O݂ãIÔzðm1•ÔÐg²q—ƒ˜Oɪò%DßegË£÷Ùsô-wŸEß RŒ§ý
+âôÝâ|W³*Š1•È+y±ƒkúÉJI 9ž¯¢+å¶!wÜ¡mL5Š)RSÖq=Z‹½#À6O¤$ꊡYö
+€ _†+#žMp¼9BÃP¶iœ¥—b?(7ëë] ëOòÅX¥òÈÜyyù‡Ug`œ£R¦:98ðöÎ/Cfg.µü¶º éScûw.hÿˆë…Þ¬º½î£Ù„9:%;Ȗ]ä;›IcZMyõ„è;J²Š –ÖxFQ9gµýq…`£V ¡X‡dëwè^äõÇ4]¡g=š! ‹š°nÁpµwwÚèP ”û…Ýy£¤—Ow(§õBŠP¨(;ؗ+º“oQ8–2¹Úc.e!ɋ"Ø暞 RVÈi+˜G|Ùëh÷¶†¤`#ª<Ñ26®ÐÚѕNøCê áÝþë•15TŽ²n'ÖV]ƒrv臽×&*;{ ª†Ïþ2gø ¦MMîŸ ­ï) ¦ågûêÛbû€Ë3²„W‚£÷“wR™ƒrִΨÖù¨ãÞkÉ×G_Að’y/^œóQí"p‚õÝãñ?¬z¦&NI¢påْ¾:>ÝN§ê×ë= RÕðGîþ–yL&ŗÇûõä_FòoîcqXO¸%iãñR*p·¦Ó¿³OÝUŸ¸´Ø¶å'æí0…dì*ϼ},9 ŽFþ±‡>Ɂ—_æ 9ÊAsÒÅJÖRüh"ÞîÕç¾ÁDãQÉE« æ±`ÀVøíýlªol——–_¼G‰Œð4Žà"–7žAL|Ý&ÛƒùË)€Q«‡³>wîŠ+‘PEhûQPRŽ3)
+º çí5×nU£ÚµRñ-;ÿÖxóº#(zéèÄ}ï·ÒYg‰Þ/bð£Öîá×gãQ+'gS"©€oç‚r?x¾3Y³3Õ}‡ޕ¿N¡ånCGŽxF 㡽ÒKד©kêÆýâý¤{6¥ r›‹PŸÄŽUl6ο“ÙCZ¦µg¢wÍA“š!—Ïe¢[ˆ ~(§Ð[#^5Œ¤Ó6~T*ÉJ»ÒóÅÚmj¯ t0}>üaIû®)ûA÷¤Î!É¿ʺ¡}P†ÿ¸VÿÖ%ÝþF½F™ñýÀ:bˆ!—f©Ê·ŸÿOe2À»p¿;¼TëA‹%wy2’µ¬îmÃՅzÙNb÷Ä ï$!Æ5 1ŽÍ6<Ô¤í6À¾1««z³ÊVBMÓ¤žÓ0?JÔNÀ¾]ŠñN¬FÔÿ‰Ë™ÆSŒ 
+,n©í5[wÙE›¸96Ž1‘*‹áò&:Ë«*Åú ƒzΧ쳑Eüڎ-?5Ô¾ÀÖ—x°A6iÙÚ&ÿ/P#|þŠƒÍŒpo,¹»am/%ÝmQܺ³b£ev–l¬óö1Ÿ—Ê“¤zoҊ+ã»WLóÚ¢¨ŠÊÁÆ
+6
+ܪüõMµšÅË,3Ÿœ$AÖÎ{Ï°ÍËhV~[<úì.Qz!ò%U ®8˜oϑjw07‚„Ôo*Œ¯-‘85©{„ï÷ÚîS¼ptüé1FÊ£‘ÞOÓØ,¤»ù@UÝÂÆ0)H±‚.æ’ìøÑëp<­P/Ô©æV8¬”Qð‹šËÁðAi s‘Ã>wŽò<þÐ[<f Ӛ­f„­—%üF¦ÄÐ ‹¡e@\/G`­¿Þ›=Ã{ö8ò¸€¶ÿÕ‘ –ß}ƒö:Çù.uõp9lµ"hÛÛªý2“ÕðxÏ«ß4‘ÜfÑáî˜äÁ­¹Äzt‹tB†Ê>$“?­¾lì$4ë8?2éÎþ¼¸›Ðó‘^DŠ÷¹‹íMC€Ò[ “G˜Ԅ"ãQà³·—èkèÔ¦bc%G֕ŒeƒWqM¸$CÐõçgs}füìm¡³&nԑފ.z¦2‰¢ÅçE%È3K«‚)—å¸a¡n€løúØM•T¦
+ü͌ЄHÂ%½”‡s„×y9ëy¦Ղý•sXYØAЅΖ{’þ3c<å×œhl† Ƈ’¤&Q— {bË)þ‡kQé&}+ï„ ÊW»R©ÒSµà£}Â+äjÔš pn'¦¥ÀîìíÀ÷FÄ߇b\;—£Û8”½È;w!7q–ËêïQðÎǾΌõ֌B
+¯²eíG‹<Ñ짠¤!&ÇnSEÂѬëð‡rxµwÚá{•@8vîðņA;‡a´ÌàG “U3¦eãõGTììíÍ*sìKÇ{”K<ƒIñæ{ôR¾Ö®HÙhÿI5*ЍHšèj57| yĜÌî\aÃ>“ãÙùל³Ì§|1ߗ"¦pÜ¥ÏTRÌ+`/.†‡åڅ*ºÉO…MæC‡b
+Z†Â±l×4ì˸cü!v‚/î·Hé^ÙjVOïn]øċ€ÔHQ…´ß]'ø[wgϯ ¤µþ>†œ·_2bJ¬Ù Ö#˜³ÂþÜO ”™¦f‹ðªÖ9¶ÍKG‡'])ßrÌãÓ}Öu¶@èoùC 8ìçÏp Çrúù ^ó>­¶yš€Ér»3üÙ¯7Ãûû×qTÿO›ð%>¸sÿ賐†1p4KyÌÁ;‚ÐPµ;,4q5
+ø0'y¡nÔÎÎضº†/D'óË
+x(y+nø
+Ûç©ObA%ãm» qoøŽHÂøkK
+ã{_w=Dng~Gó¼Eºf ë¥a|†5}ƅ×*4a·…Y¾¶`I;[-®ùùcÏ»uÚõcilmk¥kº¨úV^r73 ˆ»çѝ$‚¯1€s‡`Hj„{óµú+` r!jµ†cµ.DIîD— *ÜëGì/¥èá5Ç¥ kçBääÔ.DAŠe©Æþ?£s2¿Û
+2±ÕêÒÃG‘p…Ö3hréåDÔ,<™¼/Khž×æsSûn’ÞÖ§So¢S¨‚+…CG…ÏßùÝSÄto.jî&z|·Ð–áP!_ZÌÏÝ)³¨ÁZ™±tQžƒ4!gõiæ”Í>uÒ΋gLÂʒ¡Õôk¿ý(l®¸ÐSBxK9ýh³
+ÔÈHŽ‹½o’„¿ÝQTø™˜v»Kˆ´´Üò¨þœ)Y @ SŒî2BwPÞ¢ ÇAæ¬Æá˜zU—¤|ÅrO6$¿ÖÿVb,„Ã*qÃå %ù³q¼„»%< ö©oüJ ©(ËþLŸðÍ^P5¬°*´1fïóÛÁ&ø²O=¥BÎNã4РðG€ˆ·NOä|¿r” ƒ³„0„*ƒÕR´Ïë‡ë¯Z‚›ôôG¬Êu"íWm½ìæ>žd´B.³őzøeŸïñã)ô0’†MÚL.úØâÍç‰3!WVÅöå‡|¥Ù˾äÕC Šc
+;§š$l8y¡:6ælÛðÒº²ûf-ËRì+M€t›?ðΑý±8a;[¬’–-²ÂMù]M X\ÿ‚Ê<x§'å¦Ó졁åc’í|’ÚA]0E¸^±ÐÝÖŒ½0ÏÀ(SÒÁ`
+ÁÜÊ͹÷6c¾êE_'}Ø ý>ç¡õÉé–J1Àn‚+1Ò3ÈNÈm<v.ðß©«\È\ñ
+õ.ø“Ô0ön“CԂÞR’8¡C†Zÿ=˜·þšjÖ™Ï ¤%¦‚ªá³Æ*o{lñòT^:Í>S3âÍ[Âëå¶ °îé?ݳ ¦7‚y¿j”«
+Ô&8|©SŠÿ2Ì(£äˆÂÞ÷! õÿ-ýó‡Ë²ÕQ§Ect}áƒqC(@ûî叀DG¹ÿ.V¤Wg5È{MZ•z¥:åà(ôj¿¥8“–ѹÃì]+Ñ5_ڌjŒÆ3 ÑËꨖÉò§…Åæ§êñŽ%ˆÂÌK ­ëmNÏ#<õœHA¸q(ª!v®m{@8@ˆHsY¿’`‹m²Ê…‘ª‚«-§$+vìºmQqæµÜŠEÁ620cÁçnIì(¢Ò/-zusÊâ%)SÕG²ƒLqýüÆ-Û2)‘ŽŠªU<úÿk¿û"q…›mk«mÃlvÓfÛ¶&cÒfÛ¶­ÍÆfnnjóþ3&ÛxîwxÞÝß=à¼>'%³sìGD¤wª+Õ¶ËÚ㳯1.»Ô8J>ÇgTdÓQQÈþø[ð,&"õX8Ô?t®•VØä"¥¼÷ÉÂXòù´Ç_B€ôŸ3̈—W3¶ë*JâZڊ)FÔ0¢cäh-û·úXS¹ØØI½æOjÞÔ  ±À]“»•SGÀx§fÿ#¥ñèöˆšÕXÁd)øN÷9TðÃ@ íM%F¥q ±tN3IH5pX`'‚HÃ7™¶âŠ¬CÎ#~Tð+î>{Lm×ç.?.^š\‡¤ *̃Ñ8S>>…Ù8@&%s²wzMÕ¤¾­pCbæ´¸+_j0~ŕTˆO.ÀêyÓ¶®¤°h2ƒ{"d*Q
+~ƒ×@}eh^Ñ!π-_1-;á7¢üÀL¡S̙[72àÛ㛠Fߦ@058Žð'3ãZì¹î5‡Þ—•™¸òcÀ0-ÿ¿eÂáÖ6% ðGÝ  bºUfGœÉt¹‘E×#nÛ<£‚Ʀ„hzî#òâa”¶“ÖLzíŒ “ÚÄ‚\ÈÖ¹å$÷,/Œñ–SZ“aíÝñ™Õi¥9>´†­ù<õw¤éAAó)N3àl£Í÷ÆKºó’àM'èÕw‹r”eÙ¬3:ûƒ‚÷}R¤ƒd™¥uÊaAQ¯xXƒ1j‡ý’Wq¤%L ƒˆcV
+ æéq+þ’rö‰ÀB’#BÈË\<q°E[Dg̸yûû#£úÃù)½
+£Èë‡hœ©`m³þŠ‡‹ô÷—=Zeʊx¼s^þ>p:.1YS†¥PGÕàcý®W
+…»V—i.C ¢Ýîi–Ý(Gýú«Ô”Dé2`ŸÒÏÚXˆÆ!õ¼'Ú¤/=ìùX2 K*WnЗah¼m´­U3ŸÁ›Ä­%jK\Dà¯Lç}—ZkeðÝýØ1Ëä)»èJgÿï­Tëî8fgJy—-—'˙4ŽOñ¤=%O¢ê1‹¨ï[¢‡fˆQ˜¹‚v¯¬%φˆÓ`®DÈ»BéwöŽ<:XÞ£au—ÑâaŒîsҀž%1ÎóÄáâU?6^RöʾI%s„o•“¿I3Î¥À4×)V…2œ¯KvÂ]çí B?²E2M"úçqßú#Ü“Pl:²è¹êo
+Sûû-]n¢ãFu:Ò¼ë$u–‹‹îJXàD Íý\[†Â×{¥%4ÓbhC(Q‡Ç¢$‡ÐJ“/¤•ŠSšc­µƒ®Ïù·ÎŠŸÔ'C—^VªÃÃ~ý)Ýéûñ¥Bf7¬sE.â†Ý¤ ìäÙ<e™^éßÌt³×Ñ­°ßŠTÉæ
+o^e©eEoÇõnv¦ë$Wu].y½Á ¹ïhä7ëvwñ’²ØŸàÅJ,£%±Éâo˜°´&°éß[ÃI1ù©½ú“4¬ ¾ã˜ºMæp¦÷Ÿ¹d8ôZU»|?~wei+~?_üOcú‘¼úTmB˜d¿j†U6'^Þâcöôûn#ÿàB&éW§Ñn•0Ö/"]Ve¬ëƒ¸™ñq–2&ç]–ؘß2'ð¿­]XhpYiý]Œ
+ö#PÂÂќƒžßÆ»³ÆÅÉØP±ôï"eV У+¸0*àW@SžælÊøà5’©zϐ/R—E<zñ¿[ñÊjnI<yØ)†drôÓR*ÅwggÐF
+€…&üFWЬ‚^Eل:^à {¾)T-'¹ÝŠ=5‡}þ|ÜþʵQF
+8·FpC«z"—Ιà¯êé'ˆoÕ¶@΢;Ðnl]£Èµ»H\2ǚ×'G­Ö
+qnw5‹W¨„×øJֈޘ_ƒ*ˆ/uÈEËvTIœŒ¬Úuï.8(QBä wtÿ}>.Žä™‰W?
+y¿‰9‚–œ‘>×­_~¥6f…ží2§$)(aVªn¹ã–ßϲ8?6ÜF÷Wö’[o6eX7vu
+/\׎aË|±NðNG¯"c^hè3șnÚÊ×dH=¤jùÖf~c?ñ–jA§Û{—¹`br:ʸ]6zhÝ°Ì$FàP™%,F„­Ì„#’Ï5v9øš®»iù¶u§Ñ‡°ÿB‡–xï•™ýIJÍ[#ûˆ
+®–Z¸aÌô¥åjïõ4¿8êÌ"
+|˔¨R'uƒì7m&š^G§‹³•b/©}D´¥*ª3ŽQMõÌñü›Îâþ¤l΄B‘šjy~vë]¶¶ìágÖÁžÛ©Ͼ‹-?.›†öÚUß×s=~­÷ÒzÄ+ZÅrwsöƒ+ó;揄žNr#ò"âj•nP³`ÅMËS˜4—U§y"ëž´ s7ó¶£çùFK”8¥4þÅX×î¥Â'ÆZ}ÈP Jì‚ÖÁÞÃn‰Æ²ª‹»¤ü]‘¼ÊC`ƒM(Ò9j×¢þ›øu|-)"4|—âí0îo":S2TÅá Ǭ©œw2‰Z[eý‰Q /öRŒñö”T*¨æ™.ÅZÒ·©-‘c1Ý·„É.y¡ý»orÑۜÀ`y*¼‡H¶•"F¿aèßÄsèü‡
+3õ¾ok †]0÷H¶ã;l"Yèˆxâ¤ÿàÍo{Êüþ¸‹O‡ÍàüxFÅÄt ZByý„M> +ïý¼‡C~«ÚèCŒ øÃWø^\¸±ÂKoL¾„Þ,eôhÛbVÖ@² ÝF˜äÚË l;UŠkŒ¯ó_:^Ù-TaD¼Ö 4:ۜRt¼óIe»:qø²"vق×®<ëì<¾U×M7QôºsÍfP™W;Ÿƒ¼ä²+~SÿîÐ8 ;²›Ko¡¬æòÊl¡ôÃs"=Cçƒà™ÃIìŪ"
+uÜ všUw<EE¾¾3)QÝÃQ«? K¤Áæê»ùü eÏò½[5.¿Ó’6ƒÒ*aµ®GT¡—/
+]ã%¯ñü0SuŒå•~͂Ìvþ"`íKéÀÑÅ*́#gN"xí€- Œ’ˉÔè¥oA"–¿O_
+‹PóôðÚÚG^(gӚ8Þç=ƅ“
+残ê8¯
+ˆp€Róð‚i‰V>ñ4¤¾(š²*¿µnGg“R‹údˆ!ÍÄe_£ÎL)ò¿"Hzõ=lEhŠåôÇú 2>ˑÞáJzÉQ±S¨SÞQÊ<`XjžCFL„@§õÎŽKdØTÁ¾†<]zP á]ûÕ ž}±,.Cވ=Ú`µøÂ:0dº®Daçæ
+:°Eáné¸>žÛU{ì‹Õž¶B
+ÿp‚;ΒÐD¨~\fý;5±•AÏ”…
+L¶’ŽàÁ°ÿ‚ö‚ÿ K3Ww°£™«=Úÿ5ÆÞ{endstream
+endobj
+84 0 obj <<
+/Type /Font
+/Subtype /Type1
+/Encoding 166 0 R
+/FirstChar 2
+/LastChar 150
+/Widths 176 0 R
+/BaseFont /GZQQJW+URWPalladioL-Roma
+/FontDescriptor 82 0 R
+>> endobj
+82 0 obj <<
+/Ascent 715
+/CapHeight 680
+/Descent -282
+/FontName /GZQQJW+URWPalladioL-Roma
+/ItalicAngle 0
+/StemV 84
+/XHeight 469
+/FontBBox [-166 -283 1021 943]
+/Flags 4
+/CharSet (/fi/fl/exclam/quoteright/parenleft/parenright/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/equal/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/R/S/T/U/V/W/X/Y/bracketleft/bracketright/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/quotedblleft/quotedblright/endash)
+/FontFile 83 0 R
+>> endobj
+176 0 obj
+[605 608 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 278 0 0 0 0 0 278 333 333 0 606 250 333 250 606 500 500 500 500 500 500 500 500 500 500 250 250 0 606 0 0 747 778 611 709 774 611 556 763 832 337 333 726 611 946 831 786 604 0 668 525 613 778 722 1000 667 667 0 333 0 333 0 0 278 500 553 444 611 479 333 556 582 291 234 556 291 883 582 546 601 560 395 424 326 603 565 834 516 556 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 500 0 500 ]
+endobj
+109 0 obj <<
+/Type /Pages
+/Count 6
+/Parent 177 0 R
+/Kids [78 0 R 115 0 R 123 0 R 130 0 R 137 0 R 142 0 R]
+>> endobj
+153 0 obj <<
+/Type /Pages
+/Count 3
+/Parent 177 0 R
+/Kids [150 0 R 155 0 R 159 0 R]
+>> endobj
+177 0 obj <<
+/Type /Pages
+/Count 9
+/Kids [109 0 R 153 0 R]
+>> endobj
+178 0 obj <<
+/Type /Outlines
+/First 7 0 R
+/Last 59 0 R
+/Count 4
+>> endobj
+75 0 obj <<
+/Title 76 0 R
+/A 73 0 R
+/Parent 59 0 R
+/Prev 71 0 R
+>> endobj
+71 0 obj <<
+/Title 72 0 R
+/A 69 0 R
+/Parent 59 0 R
+/Prev 67 0 R
+/Next 75 0 R
+>> endobj
+67 0 obj <<
+/Title 68 0 R
+/A 65 0 R
+/Parent 59 0 R
+/Prev 63 0 R
+/Next 71 0 R
+>> endobj
+63 0 obj <<
+/Title 64 0 R
+/A 61 0 R
+/Parent 59 0 R
+/Next 67 0 R
+>> endobj
+59 0 obj <<
+/Title 60 0 R
+/A 57 0 R
+/Parent 178 0 R
+/Prev 55 0 R
+/First 63 0 R
+/Last 75 0 R
+/Count -4
+>> endobj
+55 0 obj <<
+/Title 56 0 R
+/A 53 0 R
+/Parent 178 0 R
+/Prev 11 0 R
+/Next 59 0 R
+>> endobj
+51 0 obj <<
+/Title 52 0 R
+/A 49 0 R
+/Parent 11 0 R
+/Prev 47 0 R
+>> endobj
+47 0 obj <<
+/Title 48 0 R
+/A 45 0 R
+/Parent 11 0 R
+/Prev 43 0 R
+/Next 51 0 R
+>> endobj
+43 0 obj <<
+/Title 44 0 R
+/A 41 0 R
+/Parent 11 0 R
+/Prev 39 0 R
+/Next 47 0 R
+>> endobj
+39 0 obj <<
+/Title 40 0 R
+/A 37 0 R
+/Parent 11 0 R
+/Prev 35 0 R
+/Next 43 0 R
+>> endobj
+35 0 obj <<
+/Title 36 0 R
+/A 33 0 R
+/Parent 11 0 R
+/Prev 31 0 R
+/Next 39 0 R
+>> endobj
+31 0 obj <<
+/Title 32 0 R
+/A 29 0 R
+/Parent 11 0 R
+/Prev 27 0 R
+/Next 35 0 R
+>> endobj
+27 0 obj <<
+/Title 28 0 R
+/A 25 0 R
+/Parent 11 0 R
+/Prev 23 0 R
+/Next 31 0 R
+>> endobj
+23 0 obj <<
+/Title 24 0 R
+/A 21 0 R
+/Parent 11 0 R
+/Prev 19 0 R
+/Next 27 0 R
+>> endobj
+19 0 obj <<
+/Title 20 0 R
+/A 17 0 R
+/Parent 11 0 R
+/Prev 15 0 R
+/Next 23 0 R
+>> endobj
+15 0 obj <<
+/Title 16 0 R
+/A 13 0 R
+/Parent 11 0 R
+/Next 19 0 R
+>> endobj
+11 0 obj <<
+/Title 12 0 R
+/A 9 0 R
+/Parent 178 0 R
+/Prev 7 0 R
+/Next 55 0 R
+/First 15 0 R
+/Last 51 0 R
+/Count -10
+>> endobj
+7 0 obj <<
+/Title 8 0 R
+/A 5 0 R
+/Parent 178 0 R
+/Next 11 0 R
+>> endobj
+179 0 obj <<
+/Names [(Doc-Start) 85 0 R (Hfootnote.1) 128 0 R (Hfootnote.2) 135 0 R (Item.1) 120 0 R (Item.2) 121 0 R (Item.3) 126 0 R (cite.fielding:acmtit2002) 110 0 R (cite.json) 113 0 R (cite.restful) 111 0 R (cite.rfc2616) 112 0 R (page.1) 81 0 R (page.2) 117 0 R (page.3) 125 0 R (page.4) 132 0 R (page.5) 139 0 R (page.6) 144 0 R (page.7) 152 0 R (page.8) 157 0 R (page.9) 161 0 R (section*.1) 162 0 R (section.1) 6 0 R (section.2) 10 0 R (section.3) 54 0 R (section.4) 58 0 R (subsection.2.1) 14 0 R (subsection.2.10) 50 0 R (subsection.2.2) 18 0 R (subsection.2.3) 22 0 R (subsection.2.4) 26 0 R (subsection.2.5) 30 0 R (subsection.2.6) 34 0 R (subsection.2.7) 38 0 R (subsection.2.8) 42 0 R (subsection.2.9) 46 0 R (subsection.4.1) 62 0 R (subsection.4.2) 66 0 R (subsection.4.3) 70 0 R (subsection.4.4) 74 0 R]
+/Limits [(Doc-Start) (subsection.4.4)]
+>> endobj
+180 0 obj <<
+/Kids [179 0 R]
+>> endobj
+181 0 obj <<
+/Dests 180 0 R
+>> endobj
+182 0 obj <<
+/Type /Catalog
+/Pages 177 0 R
+/Outlines 178 0 R
+/Names 181 0 R
+/PageMode /UseOutlines
+/OpenAction 77 0 R
+>> endobj
+183 0 obj <<
+/Author()/Title()/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfeTeX-1.21a)/Keywords()
+/CreationDate (D:20121105090203-05'00')
+/PTEX.Fullbanner (This is pdfeTeX, Version 3.141592-1.21a-2.2 (Web2C 7.5.4) kpathsea version 3.5.4)
+>> endobj
+xref
+0 184
+0000000001 65535 f
+0000000002 00000 f
+0000000003 00000 f
+0000000004 00000 f
+0000000000 00000 f
+0000000009 00000 n
+0000005163 00000 n
+0000123185 00000 n
+0000000054 00000 n
+0000000084 00000 n
+0000005218 00000 n
+0000123061 00000 n
+0000000129 00000 n
+0000000161 00000 n
+0000005274 00000 n
+0000122987 00000 n
+0000000212 00000 n
+0000000256 00000 n
+0000008849 00000 n
+0000122900 00000 n
+0000000307 00000 n
+0000000339 00000 n
+0000008906 00000 n
+0000122813 00000 n
+0000000390 00000 n
+0000000432 00000 n
+0000012236 00000 n
+0000122726 00000 n
+0000000483 00000 n
+0000000525 00000 n
+0000012293 00000 n
+0000122639 00000 n
+0000000576 00000 n
+0000000605 00000 n
+0000015999 00000 n
+0000122552 00000 n
+0000000656 00000 n
+0000000696 00000 n
+0000019583 00000 n
+0000122465 00000 n
+0000000747 00000 n
+0000000778 00000 n
+0000023064 00000 n
+0000122378 00000 n
+0000000829 00000 n
+0000000855 00000 n
+0000023121 00000 n
+0000122291 00000 n
+0000000906 00000 n
+0000000945 00000 n
+0000023178 00000 n
+0000122217 00000 n
+0000000997 00000 n
+0000001064 00000 n
+0000025840 00000 n
+0000122129 00000 n
+0000001110 00000 n
+0000001137 00000 n
+0000025896 00000 n
+0000122017 00000 n
+0000001183 00000 n
+0000001209 00000 n
+0000025953 00000 n
+0000121943 00000 n
+0000001260 00000 n
+0000001291 00000 n
+0000028662 00000 n
+0000121856 00000 n
+0000001342 00000 n
+0000001371 00000 n
+0000028719 00000 n
+0000121769 00000 n
+0000001422 00000 n
+0000001481 00000 n
+0000030818 00000 n
+0000121695 00000 n
+0000001532 00000 n
+0000001563 00000 n
+0000004046 00000 n
+0000005330 00000 n
+0000001613 00000 n
+0000005056 00000 n
+0000120336 00000 n
+0000095341 00000 n
+0000120166 00000 n
+0000005112 00000 n
+0000094624 00000 n
+0000074624 00000 n
+0000094454 00000 n
+0000004202 00000 n
+0000004372 00000 n
+0000004530 00000 n
+0000073842 00000 n
+0000057373 00000 n
+0000073673 00000 n
+0000004688 00000 n
+0000056817 00000 n
+0000055020 00000 n
+0000056657 00000 n
+0000004843 00000 n
+0000054447 00000 n
+0000051147 00000 n
+0000054286 00000 n
+0000050795 00000 n
+0000048805 00000 n
+0000050636 00000 n
+0000048211 00000 n
+0000033175 00000 n
+0000048038 00000 n
+0000121343 00000 n
+0000031049 00000 n
+0000031107 00000 n
+0000030991 00000 n
+0000030933 00000 n
+0000009079 00000 n
+0000008277 00000 n
+0000005475 00000 n
+0000008792 00000 n
+0000008417 00000 n
+0000008605 00000 n
+0000008963 00000 n
+0000009021 00000 n
+0000012412 00000 n
+0000011832 00000 n
+0000009225 00000 n
+0000012121 00000 n
+0000012178 00000 n
+0000011964 00000 n
+0000012350 00000 n
+0000016119 00000 n
+0000015446 00000 n
+0000012546 00000 n
+0000015942 00000 n
+0000015586 00000 n
+0000015785 00000 n
+0000016056 00000 n
+0000019640 00000 n
+0000019214 00000 n
+0000016253 00000 n
+0000019526 00000 n
+0000019346 00000 n
+0000023235 00000 n
+0000022173 00000 n
+0000019774 00000 n
+0000023007 00000 n
+0000022329 00000 n
+0000022524 00000 n
+0000022685 00000 n
+0000022846 00000 n
+0000026010 00000 n
+0000025671 00000 n
+0000023369 00000 n
+0000025783 00000 n
+0000121459 00000 n
+0000028776 00000 n
+0000028493 00000 n
+0000026144 00000 n
+0000028605 00000 n
+0000031165 00000 n
+0000030047 00000 n
+0000028922 00000 n
+0000030761 00000 n
+0000030875 00000 n
+0000030195 00000 n
+0000030363 00000 n
+0000030563 00000 n
+0000031287 00000 n
+0000048537 00000 n
+0000051043 00000 n
+0000050999 00000 n
+0000054825 00000 n
+0000054667 00000 n
+0000057249 00000 n
+0000057045 00000 n
+0000074302 00000 n
+0000094975 00000 n
+0000120862 00000 n
+0000121552 00000 n
+0000121621 00000 n
+0000123257 00000 n
+0000124128 00000 n
+0000124167 00000 n
+0000124205 00000 n
+0000124334 00000 n
+trailer
+<<
+/Size 184
+/Root 182 0 R
+/Info 183 0 R
+/ID [<F276A63ADFB7E867814B00A85D15DDF2> <F276A63ADFB7E867814B00A85D15DDF2>]
+>>
+startxref
+124597
+%%EOF
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/threadpool_exec.c
0,0 → 1,101
#include "threadpool_exec.h"
#include "list.h"
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
 
struct future {
struct list_elem elem;
thread_pool_callable_func_t callable;
void * callable_data;
};
 
struct thread_pool {
pthread_mutex_t mutex_lock;
pthread_cond_t condition_var;
struct list future_list;
bool shutting_down;
int thread_list_length;
pthread_t * thread_list;
};
 
static void * thread_func(void * arg) {
struct thread_pool *t_pool = arg;
pthread_mutex_lock(&t_pool->mutex_lock);
while(1) {
// Get lock and wait for signal while there are no jobs queued
while (list_size(&t_pool->future_list) == 0) {
pthread_cond_wait(&t_pool->condition_var,&t_pool->mutex_lock);
if (t_pool->shutting_down) {
pthread_mutex_unlock(&t_pool->mutex_lock);
return NULL;
}
}
// Retreive and remove the first future in the list
struct list_elem *e = list_pop_front(&t_pool->future_list);
pthread_mutex_unlock(&t_pool->mutex_lock);
struct future *f_entry = list_entry(e, struct future, elem);
 
f_entry->callable(f_entry->callable_data);
free(f_entry);
 
pthread_mutex_lock(&t_pool->mutex_lock);
if (t_pool->shutting_down)
return NULL;
}
}
 
/* Create a new thread pool with n threads. */
struct thread_pool * thread_pool_new(int nthreads) {
// Allocate a new thread pool structure
struct thread_pool *t_pool = malloc(sizeof(struct thread_pool));
 
// Initialize the thread pool variables
pthread_mutex_init(&t_pool->mutex_lock,NULL);
pthread_cond_init(&t_pool->condition_var,NULL);
list_init(&t_pool->future_list);
t_pool->shutting_down = false;
t_pool->thread_list_length = nthreads;
 
// Allocate and start each thread in the thread pool
t_pool->thread_list = malloc(nthreads * sizeof(pthread_t));
int i;
for (i = 0; i < nthreads; i++)
pthread_create(t_pool->thread_list + i, NULL, thread_func, t_pool);
 
return t_pool;
}
 
/* Shutdown this thread pool. May or may not execute already queued tasks. */
void thread_pool_shutdown(struct thread_pool * t_pool) {
// Set the shutdown flag and notify all worker threads
pthread_mutex_lock(&t_pool->mutex_lock);
t_pool->shutting_down = true;
pthread_cond_broadcast(&t_pool->condition_var);
pthread_mutex_unlock(&t_pool->mutex_lock);
 
// Wait for all worker threads to join before returning
int i;
for (i = 0; i < t_pool->thread_list_length; i++)
pthread_join(t_pool->thread_list[i],NULL);
 
free(t_pool->thread_list);
free(t_pool);
}
 
/* Submit a callable to thread pool and return future.
* The returned future can be used in future_get() and future_free() */
void thread_pool_submit(struct thread_pool * t_pool,
thread_pool_callable_func_t callable, void * callable_data) {
// Allocate and initialize the new future
struct future *f_entry = malloc(sizeof(struct future));
f_entry->callable = callable;
f_entry->callable_data = callable_data;
 
// Get the lock on the thread pool and enqueue the future to the end of the work queue
pthread_mutex_lock(&t_pool->mutex_lock);
list_push_back(&t_pool->future_list,&f_entry->elem);
// Notify one worker thread to process the future
pthread_cond_signal(&t_pool->condition_var);
pthread_mutex_unlock(&t_pool->mutex_lock);
}
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/threadpool_exec.h
0,0 → 1,16
/* Create a new thread pool with n threads. */
struct thread_pool * thread_pool_new(int nthreads);
 
/* Shutdown this thread pool. May or may not execute already queued tasks. */
void thread_pool_shutdown(struct thread_pool *);
 
/* A function pointer representing a 'callable' */
typedef void (* thread_pool_callable_func_t) (void * data);
 
/* Submit a callable to thread pool and return future.
* The returned future can be used in future_get() and future_free()
*/
void thread_pool_submit(
struct thread_pool *,
thread_pool_callable_func_t callable,
void * callable_data);
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/webfiles/excanvas.js
0,0 → 1,1415
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
 
 
// Known Issues:
//
// * Patterns only support repeat.
// * Radial gradient are not implemented. The VML version of these look very
// different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
// width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
// Quirks mode will draw the canvas using border-box. Either change your
// doctype to HTML5
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
// or use Box Sizing Behavior from WebFX
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Non uniform scaling does not correctly scale strokes.
// * Optimize. There is always room for speed improvements.
 
// Only add this code if we do not already have a canvas implementation
if (!document.createElement('canvas').getContext) {
 
(function() {
 
// alias some functions to make (compiled) code shorter
var m = Math;
var mr = m.round;
var ms = m.sin;
var mc = m.cos;
var abs = m.abs;
var sqrt = m.sqrt;
 
// this is used for sub pixel precision
var Z = 10;
var Z2 = Z / 2;
 
/**
* This funtion is assigned to the <canvas> elements as element.getContext().
* @this {HTMLElement}
* @return {CanvasRenderingContext2D_}
*/
function getContext() {
return this.context_ ||
(this.context_ = new CanvasRenderingContext2D_(this));
}
 
var slice = Array.prototype.slice;
 
/**
* Binds a function to an object. The returned function will always use the
* passed in {@code obj} as {@code this}.
*
* Example:
*
* g = bind(f, obj, a, b)
* g(c, d) // will do f.call(obj, a, b, c, d)
*
* @param {Function} f The function to bind the object to
* @param {Object} obj The object that should act as this when the function
* is called
* @param {*} var_args Rest arguments that will be used as the initial
* arguments when the function is called
* @return {Function} A new function that has bound this
*/
function bind(f, obj, var_args) {
var a = slice.call(arguments, 2);
return function() {
return f.apply(obj, a.concat(slice.call(arguments)));
};
}
 
function encodeHtmlAttribute(s) {
return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
}
 
function addNamespacesAndStylesheet(doc) {
// create xmlns
if (!doc.namespaces['g_vml_']) {
doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
'#default#VML');
 
}
if (!doc.namespaces['g_o_']) {
doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
'#default#VML');
}
 
// Setup default CSS. Only add one style sheet per document
if (!doc.styleSheets['ex_canvas_']) {
var ss = doc.createStyleSheet();
ss.owningElement.id = 'ex_canvas_';
ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
// default size is 300x150 in Gecko and Opera
'text-align:left;width:300px;height:150px}';
}
}
 
// Add namespaces and stylesheet at startup.
addNamespacesAndStylesheet(document);
 
var G_vmlCanvasManager_ = {
init: function(opt_doc) {
if (/MSIE/.test(navigator.userAgent) && !window.opera) {
var doc = opt_doc || document;
// Create a dummy element so that IE will allow canvas elements to be
// recognized.
doc.createElement('canvas');
doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
}
},
 
init_: function(doc) {
// find all canvas elements
var els = doc.getElementsByTagName('canvas');
for (var i = 0; i < els.length; i++) {
this.initElement(els[i]);
}
},
 
/**
* Public initializes a canvas element so that it can be used as canvas
* element from now on. This is called automatically before the page is
* loaded but if you are creating elements using createElement you need to
* make sure this is called on the element.
* @param {HTMLElement} el The canvas element to initialize.
* @return {HTMLElement} the element that was created.
*/
initElement: function(el) {
if (!el.getContext) {
el.getContext = getContext;
 
// Add namespaces and stylesheet to document of the element.
addNamespacesAndStylesheet(el.ownerDocument);
 
// Remove fallback content. There is no way to hide text nodes so we
// just remove all childNodes. We could hide all elements and remove
// text nodes but who really cares about the fallback content.
el.innerHTML = '';
 
// do not use inline function because that will leak memory
el.attachEvent('onpropertychange', onPropertyChange);
el.attachEvent('onresize', onResize);
 
var attrs = el.attributes;
if (attrs.width && attrs.width.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setWidth_(attrs.width.nodeValue);
el.style.width = attrs.width.nodeValue + 'px';
} else {
el.width = el.clientWidth;
}
if (attrs.height && attrs.height.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setHeight_(attrs.height.nodeValue);
el.style.height = attrs.height.nodeValue + 'px';
} else {
el.height = el.clientHeight;
}
//el.getContext().setCoordsize_()
}
return el;
}
};
 
function onPropertyChange(e) {
var el = e.srcElement;
 
switch (e.propertyName) {
case 'width':
el.getContext().clearRect();
el.style.width = el.attributes.width.nodeValue + 'px';
// In IE8 this does not trigger onresize.
el.firstChild.style.width = el.clientWidth + 'px';
break;
case 'height':
el.getContext().clearRect();
el.style.height = el.attributes.height.nodeValue + 'px';
el.firstChild.style.height = el.clientHeight + 'px';
break;
}
}
 
function onResize(e) {
var el = e.srcElement;
if (el.firstChild) {
el.firstChild.style.width = el.clientWidth + 'px';
el.firstChild.style.height = el.clientHeight + 'px';
}
}
 
G_vmlCanvasManager_.init();
 
// precompute "00" to "FF"
var decToHex = [];
for (var i = 0; i < 16; i++) {
for (var j = 0; j < 16; j++) {
decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
}
}
 
function createMatrixIdentity() {
return [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]
];
}
 
function matrixMultiply(m1, m2) {
var result = createMatrixIdentity();
 
for (var x = 0; x < 3; x++) {
for (var y = 0; y < 3; y++) {
var sum = 0;
 
for (var z = 0; z < 3; z++) {
sum += m1[x][z] * m2[z][y];
}
 
result[x][y] = sum;
}
}
return result;
}
 
function copyState(o1, o2) {
o2.fillStyle = o1.fillStyle;
o2.lineCap = o1.lineCap;
o2.lineJoin = o1.lineJoin;
o2.lineWidth = o1.lineWidth;
o2.miterLimit = o1.miterLimit;
o2.shadowBlur = o1.shadowBlur;
o2.shadowColor = o1.shadowColor;
o2.shadowOffsetX = o1.shadowOffsetX;
o2.shadowOffsetY = o1.shadowOffsetY;
o2.strokeStyle = o1.strokeStyle;
o2.globalAlpha = o1.globalAlpha;
o2.font = o1.font;
o2.textAlign = o1.textAlign;
o2.textBaseline = o1.textBaseline;
o2.arcScaleX_ = o1.arcScaleX_;
o2.arcScaleY_ = o1.arcScaleY_;
o2.lineScale_ = o1.lineScale_;
}
 
var colorData = {
aliceblue: '#F0F8FF',
antiquewhite: '#FAEBD7',
aquamarine: '#7FFFD4',
azure: '#F0FFFF',
beige: '#F5F5DC',
bisque: '#FFE4C4',
black: '#000000',
blanchedalmond: '#FFEBCD',
blueviolet: '#8A2BE2',
brown: '#A52A2A',
burlywood: '#DEB887',
cadetblue: '#5F9EA0',
chartreuse: '#7FFF00',
chocolate: '#D2691E',
coral: '#FF7F50',
cornflowerblue: '#6495ED',
cornsilk: '#FFF8DC',
crimson: '#DC143C',
cyan: '#00FFFF',
darkblue: '#00008B',
darkcyan: '#008B8B',
darkgoldenrod: '#B8860B',
darkgray: '#A9A9A9',
darkgreen: '#006400',
darkgrey: '#A9A9A9',
darkkhaki: '#BDB76B',
darkmagenta: '#8B008B',
darkolivegreen: '#556B2F',
darkorange: '#FF8C00',
darkorchid: '#9932CC',
darkred: '#8B0000',
darksalmon: '#E9967A',
darkseagreen: '#8FBC8F',
darkslateblue: '#483D8B',
darkslategray: '#2F4F4F',
darkslategrey: '#2F4F4F',
darkturquoise: '#00CED1',
darkviolet: '#9400D3',
deeppink: '#FF1493',
deepskyblue: '#00BFFF',
dimgray: '#696969',
dimgrey: '#696969',
dodgerblue: '#1E90FF',
firebrick: '#B22222',
floralwhite: '#FFFAF0',
forestgreen: '#228B22',
gainsboro: '#DCDCDC',
ghostwhite: '#F8F8FF',
gold: '#FFD700',
goldenrod: '#DAA520',
grey: '#808080',
greenyellow: '#ADFF2F',
honeydew: '#F0FFF0',
hotpink: '#FF69B4',
indianred: '#CD5C5C',
indigo: '#4B0082',
ivory: '#FFFFF0',
khaki: '#F0E68C',
lavender: '#E6E6FA',
lavenderblush: '#FFF0F5',
lawngreen: '#7CFC00',
lemonchiffon: '#FFFACD',
lightblue: '#ADD8E6',
lightcoral: '#F08080',
lightcyan: '#E0FFFF',
lightgoldenrodyellow: '#FAFAD2',
lightgreen: '#90EE90',
lightgrey: '#D3D3D3',
lightpink: '#FFB6C1',
lightsalmon: '#FFA07A',
lightseagreen: '#20B2AA',
lightskyblue: '#87CEFA',
lightslategray: '#778899',
lightslategrey: '#778899',
lightsteelblue: '#B0C4DE',
lightyellow: '#FFFFE0',
limegreen: '#32CD32',
linen: '#FAF0E6',
magenta: '#FF00FF',
mediumaquamarine: '#66CDAA',
mediumblue: '#0000CD',
mediumorchid: '#BA55D3',
mediumpurple: '#9370DB',
mediumseagreen: '#3CB371',
mediumslateblue: '#7B68EE',
mediumspringgreen: '#00FA9A',
mediumturquoise: '#48D1CC',
mediumvioletred: '#C71585',
midnightblue: '#191970',
mintcream: '#F5FFFA',
mistyrose: '#FFE4E1',
moccasin: '#FFE4B5',
navajowhite: '#FFDEAD',
oldlace: '#FDF5E6',
olivedrab: '#6B8E23',
orange: '#FFA500',
orangered: '#FF4500',
orchid: '#DA70D6',
palegoldenrod: '#EEE8AA',
palegreen: '#98FB98',
paleturquoise: '#AFEEEE',
palevioletred: '#DB7093',
papayawhip: '#FFEFD5',
peachpuff: '#FFDAB9',
peru: '#CD853F',
pink: '#FFC0CB',
plum: '#DDA0DD',
powderblue: '#B0E0E6',
rosybrown: '#BC8F8F',
royalblue: '#4169E1',
saddlebrown: '#8B4513',
salmon: '#FA8072',
sandybrown: '#F4A460',
seagreen: '#2E8B57',
seashell: '#FFF5EE',
sienna: '#A0522D',
skyblue: '#87CEEB',
slateblue: '#6A5ACD',
slategray: '#708090',
slategrey: '#708090',
snow: '#FFFAFA',
springgreen: '#00FF7F',
steelblue: '#4682B4',
tan: '#D2B48C',
thistle: '#D8BFD8',
tomato: '#FF6347',
turquoise: '#40E0D0',
violet: '#EE82EE',
wheat: '#F5DEB3',
whitesmoke: '#F5F5F5',
yellowgreen: '#9ACD32'
};
 
 
function getRgbHslContent(styleString) {
var start = styleString.indexOf('(', 3);
var end = styleString.indexOf(')', start + 1);
var parts = styleString.substring(start + 1, end).split(',');
// add alpha if needed
if (parts.length == 4 && styleString.substr(3, 1) == 'a') {
alpha = Number(parts[3]);
} else {
parts[3] = 1;
}
return parts;
}
 
function percent(s) {
return parseFloat(s) / 100;
}
 
function clamp(v, min, max) {
return Math.min(max, Math.max(min, v));
}
 
function hslToRgb(parts){
var r, g, b;
h = parseFloat(parts[0]) / 360 % 360;
if (h < 0)
h++;
s = clamp(percent(parts[1]), 0, 1);
l = clamp(percent(parts[2]), 0, 1);
if (s == 0) {
r = g = b = l; // achromatic
} else {
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hueToRgb(p, q, h + 1 / 3);
g = hueToRgb(p, q, h);
b = hueToRgb(p, q, h - 1 / 3);
}
 
return '#' + decToHex[Math.floor(r * 255)] +
decToHex[Math.floor(g * 255)] +
decToHex[Math.floor(b * 255)];
}
 
function hueToRgb(m1, m2, h) {
if (h < 0)
h++;
if (h > 1)
h--;
 
if (6 * h < 1)
return m1 + (m2 - m1) * 6 * h;
else if (2 * h < 1)
return m2;
else if (3 * h < 2)
return m1 + (m2 - m1) * (2 / 3 - h) * 6;
else
return m1;
}
 
function processStyle(styleString) {
var str, alpha = 1;
 
styleString = String(styleString);
if (styleString.charAt(0) == '#') {
str = styleString;
} else if (/^rgb/.test(styleString)) {
var parts = getRgbHslContent(styleString);
var str = '#', n;
for (var i = 0; i < 3; i++) {
if (parts[i].indexOf('%') != -1) {
n = Math.floor(percent(parts[i]) * 255);
} else {
n = Number(parts[i]);
}
str += decToHex[clamp(n, 0, 255)];
}
alpha = parts[3];
} else if (/^hsl/.test(styleString)) {
var parts = getRgbHslContent(styleString);
str = hslToRgb(parts);
alpha = parts[3];
} else {
str = colorData[styleString] || styleString;
}
return {color: str, alpha: alpha};
}
 
var DEFAULT_STYLE = {
style: 'normal',
variant: 'normal',
weight: 'normal',
size: 10,
family: 'sans-serif'
};
 
// Internal text style cache
var fontStyleCache = {};
 
function processFontStyle(styleString) {
if (fontStyleCache[styleString]) {
return fontStyleCache[styleString];
}
 
var el = document.createElement('div');
var style = el.style;
try {
style.font = styleString;
} catch (ex) {
// Ignore failures to set to invalid font.
}
 
return fontStyleCache[styleString] = {
style: style.fontStyle || DEFAULT_STYLE.style,
variant: style.fontVariant || DEFAULT_STYLE.variant,
weight: style.fontWeight || DEFAULT_STYLE.weight,
size: style.fontSize || DEFAULT_STYLE.size,
family: style.fontFamily || DEFAULT_STYLE.family
};
}
 
function getComputedStyle(style, element) {
var computedStyle = {};
 
for (var p in style) {
computedStyle[p] = style[p];
}
 
// Compute the size
var canvasFontSize = parseFloat(element.currentStyle.fontSize),
fontSize = parseFloat(style.size);
 
if (typeof style.size == 'number') {
computedStyle.size = style.size;
} else if (style.size.indexOf('px') != -1) {
computedStyle.size = fontSize;
} else if (style.size.indexOf('em') != -1) {
computedStyle.size = canvasFontSize * fontSize;
} else if(style.size.indexOf('%') != -1) {
computedStyle.size = (canvasFontSize / 100) * fontSize;
} else if (style.size.indexOf('pt') != -1) {
computedStyle.size = canvasFontSize * (4/3) * fontSize;
} else {
computedStyle.size = canvasFontSize;
}
 
// Different scaling between normal text and VML text. This was found using
// trial and error to get the same size as non VML text.
computedStyle.size *= 0.981;
 
return computedStyle;
}
 
function buildStyle(style) {
return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
style.size + 'px ' + style.family;
}
 
function processLineCap(lineCap) {
switch (lineCap) {
case 'butt':
return 'flat';
case 'round':
return 'round';
case 'square':
default:
return 'square';
}
}
 
/**
* This class implements CanvasRenderingContext2D interface as described by
* the WHATWG.
* @param {HTMLElement} surfaceElement The element that the 2D context should
* be associated with
*/
function CanvasRenderingContext2D_(surfaceElement) {
this.m_ = createMatrixIdentity();
 
this.mStack_ = [];
this.aStack_ = [];
this.currentPath_ = [];
 
// Canvas context properties
this.strokeStyle = '#000';
this.fillStyle = '#000';
 
this.lineWidth = 1;
this.lineJoin = 'miter';
this.lineCap = 'butt';
this.miterLimit = Z * 1;
this.globalAlpha = 1;
this.font = '10px sans-serif';
this.textAlign = 'left';
this.textBaseline = 'alphabetic';
this.canvas = surfaceElement;
 
var el = surfaceElement.ownerDocument.createElement('div');
el.style.width = surfaceElement.clientWidth + 'px';
el.style.height = surfaceElement.clientHeight + 'px';
el.style.overflow = 'hidden';
el.style.position = 'absolute';
surfaceElement.appendChild(el);
 
this.element_ = el;
this.arcScaleX_ = 1;
this.arcScaleY_ = 1;
this.lineScale_ = 1;
}
 
var contextPrototype = CanvasRenderingContext2D_.prototype;
contextPrototype.clearRect = function() {
if (this.textMeasureEl_) {
this.textMeasureEl_.removeNode(true);
this.textMeasureEl_ = null;
}
this.element_.innerHTML = '';
};
 
contextPrototype.beginPath = function() {
// TODO: Branch current matrix so that save/restore has no effect
// as per safari docs.
this.currentPath_ = [];
};
 
contextPrototype.moveTo = function(aX, aY) {
var p = this.getCoords_(aX, aY);
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
this.currentX_ = p.x;
this.currentY_ = p.y;
};
 
contextPrototype.lineTo = function(aX, aY) {
var p = this.getCoords_(aX, aY);
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
 
this.currentX_ = p.x;
this.currentY_ = p.y;
};
 
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
aCP2x, aCP2y,
aX, aY) {
var p = this.getCoords_(aX, aY);
var cp1 = this.getCoords_(aCP1x, aCP1y);
var cp2 = this.getCoords_(aCP2x, aCP2y);
bezierCurveTo(this, cp1, cp2, p);
};
 
// Helper function that takes the already fixed cordinates.
function bezierCurveTo(self, cp1, cp2, p) {
self.currentPath_.push({
type: 'bezierCurveTo',
cp1x: cp1.x,
cp1y: cp1.y,
cp2x: cp2.x,
cp2y: cp2.y,
x: p.x,
y: p.y
});
self.currentX_ = p.x;
self.currentY_ = p.y;
}
 
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
// the following is lifted almost directly from
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
 
var cp = this.getCoords_(aCPx, aCPy);
var p = this.getCoords_(aX, aY);
 
var cp1 = {
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
};
var cp2 = {
x: cp1.x + (p.x - this.currentX_) / 3.0,
y: cp1.y + (p.y - this.currentY_) / 3.0
};
 
bezierCurveTo(this, cp1, cp2, p);
};
 
contextPrototype.arc = function(aX, aY, aRadius,
aStartAngle, aEndAngle, aClockwise) {
aRadius *= Z;
var arcType = aClockwise ? 'at' : 'wa';
 
var xStart = aX + mc(aStartAngle) * aRadius - Z2;
var yStart = aY + ms(aStartAngle) * aRadius - Z2;
 
var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
 
// IE won't render arches drawn counter clockwise if xStart == xEnd.
if (xStart == xEnd && !aClockwise) {
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
// that can be represented in binary
}
 
var p = this.getCoords_(aX, aY);
var pStart = this.getCoords_(xStart, yStart);
var pEnd = this.getCoords_(xEnd, yEnd);
 
this.currentPath_.push({type: arcType,
x: p.x,
y: p.y,
radius: aRadius,
xStart: pStart.x,
yStart: pStart.y,
xEnd: pEnd.x,
yEnd: pEnd.y});
 
};
 
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
};
 
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
var oldPath = this.currentPath_;
this.beginPath();
 
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.stroke();
 
this.currentPath_ = oldPath;
};
 
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
var oldPath = this.currentPath_;
this.beginPath();
 
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.fill();
 
this.currentPath_ = oldPath;
};
 
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
var gradient = new CanvasGradient_('gradient');
gradient.x0_ = aX0;
gradient.y0_ = aY0;
gradient.x1_ = aX1;
gradient.y1_ = aY1;
return gradient;
};
 
contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
aX1, aY1, aR1) {
var gradient = new CanvasGradient_('gradientradial');
gradient.x0_ = aX0;
gradient.y0_ = aY0;
gradient.r0_ = aR0;
gradient.x1_ = aX1;
gradient.y1_ = aY1;
gradient.r1_ = aR1;
return gradient;
};
 
contextPrototype.drawImage = function(image, var_args) {
var dx, dy, dw, dh, sx, sy, sw, sh;
 
// to find the original width we overide the width and height
var oldRuntimeWidth = image.runtimeStyle.width;
var oldRuntimeHeight = image.runtimeStyle.height;
image.runtimeStyle.width = 'auto';
image.runtimeStyle.height = 'auto';
 
// get the original size
var w = image.width;
var h = image.height;
 
// and remove overides
image.runtimeStyle.width = oldRuntimeWidth;
image.runtimeStyle.height = oldRuntimeHeight;
 
if (arguments.length == 3) {
dx = arguments[1];
dy = arguments[2];
sx = sy = 0;
sw = dw = w;
sh = dh = h;
} else if (arguments.length == 5) {
dx = arguments[1];
dy = arguments[2];
dw = arguments[3];
dh = arguments[4];
sx = sy = 0;
sw = w;
sh = h;
} else if (arguments.length == 9) {
sx = arguments[1];
sy = arguments[2];
sw = arguments[3];
sh = arguments[4];
dx = arguments[5];
dy = arguments[6];
dw = arguments[7];
dh = arguments[8];
} else {
throw Error('Invalid number of arguments');
}
 
var d = this.getCoords_(dx, dy);
 
var w2 = sw / 2;
var h2 = sh / 2;
 
var vmlStr = [];
 
var W = 10;
var H = 10;
 
// For some reason that I've now forgotten, using divs didn't work
vmlStr.push(' <g_vml_:group',
' coordsize="', Z * W, ',', Z * H, '"',
' coordorigin="0,0"' ,
' style="width:', W, 'px;height:', H, 'px;position:absolute;');
 
// If filters are necessary (rotation exists), create them
// filters are bog-slow, so only create them if abbsolutely necessary
// The following check doesn't account for skews (which don't exist
// in the canvas spec (yet) anyway.
 
if (this.m_[0][0] != 1 || this.m_[0][1] ||
this.m_[1][1] != 1 || this.m_[1][0]) {
var filter = [];
 
// Note the 12/21 reversal
filter.push('M11=', this.m_[0][0], ',',
'M12=', this.m_[1][0], ',',
'M21=', this.m_[0][1], ',',
'M22=', this.m_[1][1], ',',
'Dx=', mr(d.x / Z), ',',
'Dy=', mr(d.y / Z), '');
 
// Bounding box calculation (need to minimize displayed area so that
// filters don't waste time on unused pixels.
var max = d;
var c2 = this.getCoords_(dx + dw, dy);
var c3 = this.getCoords_(dx, dy + dh);
var c4 = this.getCoords_(dx + dw, dy + dh);
 
max.x = m.max(max.x, c2.x, c3.x, c4.x);
max.y = m.max(max.y, c2.y, c3.y, c4.y);
 
vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
filter.join(''), ", sizingmethod='clip');");
 
} else {
vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
}
 
vmlStr.push(' ">' ,
'<g_vml_:image src="', image.src, '"',
' style="width:', Z * dw, 'px;',
' height:', Z * dh, 'px"',
' cropleft="', sx / w, '"',
' croptop="', sy / h, '"',
' cropright="', (w - sx - sw) / w, '"',
' cropbottom="', (h - sy - sh) / h, '"',
' />',
'</g_vml_:group>');
 
this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
};
 
contextPrototype.stroke = function(aFill) {
var lineStr = [];
var lineOpen = false;
 
var W = 10;
var H = 10;
 
lineStr.push('<g_vml_:shape',
' filled="', !!aFill, '"',
' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
' coordorigin="0,0"',
' coordsize="', Z * W, ',', Z * H, '"',
' stroked="', !aFill, '"',
' path="');
 
var newSeq = false;
var min = {x: null, y: null};
var max = {x: null, y: null};
 
for (var i = 0; i < this.currentPath_.length; i++) {
var p = this.currentPath_[i];
var c;
 
switch (p.type) {
case 'moveTo':
c = p;
lineStr.push(' m ', mr(p.x), ',', mr(p.y));
break;
case 'lineTo':
lineStr.push(' l ', mr(p.x), ',', mr(p.y));
break;
case 'close':
lineStr.push(' x ');
p = null;
break;
case 'bezierCurveTo':
lineStr.push(' c ',
mr(p.cp1x), ',', mr(p.cp1y), ',',
mr(p.cp2x), ',', mr(p.cp2y), ',',
mr(p.x), ',', mr(p.y));
break;
case 'at':
case 'wa':
lineStr.push(' ', p.type, ' ',
mr(p.x - this.arcScaleX_ * p.radius), ',',
mr(p.y - this.arcScaleY_ * p.radius), ' ',
mr(p.x + this.arcScaleX_ * p.radius), ',',
mr(p.y + this.arcScaleY_ * p.radius), ' ',
mr(p.xStart), ',', mr(p.yStart), ' ',
mr(p.xEnd), ',', mr(p.yEnd));
break;
}
 
 
// TODO: Following is broken for curves due to
// move to proper paths.
 
// Figure out dimensions so we can do gradient fills
// properly
if (p) {
if (min.x == null || p.x < min.x) {
min.x = p.x;
}
if (max.x == null || p.x > max.x) {
max.x = p.x;
}
if (min.y == null || p.y < min.y) {
min.y = p.y;
}
if (max.y == null || p.y > max.y) {
max.y = p.y;
}
}
}
lineStr.push(' ">');
 
if (!aFill) {
appendStroke(this, lineStr);
} else {
appendFill(this, lineStr, min, max);
}
 
lineStr.push('</g_vml_:shape>');
 
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
};
 
function appendStroke(ctx, lineStr) {
var a = processStyle(ctx.strokeStyle);
var color = a.color;
var opacity = a.alpha * ctx.globalAlpha;
var lineWidth = ctx.lineScale_ * ctx.lineWidth;
 
// VML cannot correctly render a line if the width is less than 1px.
// In that case, we dilute the color to make the line look thinner.
if (lineWidth < 1) {
opacity *= lineWidth;
}
 
lineStr.push(
'<g_vml_:stroke',
' opacity="', opacity, '"',
' joinstyle="', ctx.lineJoin, '"',
' miterlimit="', ctx.miterLimit, '"',
' endcap="', processLineCap(ctx.lineCap), '"',
' weight="', lineWidth, 'px"',
' color="', color, '" />'
);
}
 
function appendFill(ctx, lineStr, min, max) {
var fillStyle = ctx.fillStyle;
var arcScaleX = ctx.arcScaleX_;
var arcScaleY = ctx.arcScaleY_;
var width = max.x - min.x;
var height = max.y - min.y;
if (fillStyle instanceof CanvasGradient_) {
// TODO: Gradients transformed with the transformation matrix.
var angle = 0;
var focus = {x: 0, y: 0};
 
// additional offset
var shift = 0;
// scale factor for offset
var expansion = 1;
 
if (fillStyle.type_ == 'gradient') {
var x0 = fillStyle.x0_ / arcScaleX;
var y0 = fillStyle.y0_ / arcScaleY;
var x1 = fillStyle.x1_ / arcScaleX;
var y1 = fillStyle.y1_ / arcScaleY;
var p0 = ctx.getCoords_(x0, y0);
var p1 = ctx.getCoords_(x1, y1);
var dx = p1.x - p0.x;
var dy = p1.y - p0.y;
angle = Math.atan2(dx, dy) * 180 / Math.PI;
 
// The angle should be a non-negative number.
if (angle < 0) {
angle += 360;
}
 
// Very small angles produce an unexpected result because they are
// converted to a scientific notation string.
if (angle < 1e-6) {
angle = 0;
}
} else {
var p0 = ctx.getCoords_(fillStyle.x0_, fillStyle.y0_);
focus = {
x: (p0.x - min.x) / width,
y: (p0.y - min.y) / height
};
 
width /= arcScaleX * Z;
height /= arcScaleY * Z;
var dimension = m.max(width, height);
shift = 2 * fillStyle.r0_ / dimension;
expansion = 2 * fillStyle.r1_ / dimension - shift;
}
 
// We need to sort the color stops in ascending order by offset,
// otherwise IE won't interpret it correctly.
var stops = fillStyle.colors_;
stops.sort(function(cs1, cs2) {
return cs1.offset - cs2.offset;
});
 
var length = stops.length;
var color1 = stops[0].color;
var color2 = stops[length - 1].color;
var opacity1 = stops[0].alpha * ctx.globalAlpha;
var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
 
var colors = [];
for (var i = 0; i < length; i++) {
var stop = stops[i];
colors.push(stop.offset * expansion + shift + ' ' + stop.color);
}
 
// When colors attribute is used, the meanings of opacity and o:opacity2
// are reversed.
lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
' method="none" focus="100%"',
' color="', color1, '"',
' color2="', color2, '"',
' colors="', colors.join(','), '"',
' opacity="', opacity2, '"',
' g_o_:opacity2="', opacity1, '"',
' angle="', angle, '"',
' focusposition="', focus.x, ',', focus.y, '" />');
} else if (fillStyle instanceof CanvasPattern_) {
if (width && height) {
var deltaLeft = -min.x;
var deltaTop = -min.y;
lineStr.push('<g_vml_:fill',
' position="',
deltaLeft / width * arcScaleX * arcScaleX, ',',
deltaTop / height * arcScaleY * arcScaleY, '"',
' type="tile"',
// TODO: Figure out the correct size to fit the scale.
//' size="', w, 'px ', h, 'px"',
' src="', fillStyle.src_, '" />');
}
} else {
var a = processStyle(ctx.fillStyle);
var color = a.color;
var opacity = a.alpha * ctx.globalAlpha;
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
'" />');
}
}
 
contextPrototype.fill = function() {
this.stroke(true);
};
 
contextPrototype.closePath = function() {
this.currentPath_.push({type: 'close'});
};
 
/**
* @private
*/
contextPrototype.getCoords_ = function(aX, aY) {
var m = this.m_;
return {
x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
};
};
 
contextPrototype.save = function() {
var o = {};
copyState(this, o);
this.aStack_.push(o);
this.mStack_.push(this.m_);
this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
};
 
contextPrototype.restore = function() {
if (this.aStack_.length) {
copyState(this.aStack_.pop(), this);
this.m_ = this.mStack_.pop();
}
};
 
function matrixIsFinite(m) {
return isFinite(m[0][0]) && isFinite(m[0][1]) &&
isFinite(m[1][0]) && isFinite(m[1][1]) &&
isFinite(m[2][0]) && isFinite(m[2][1]);
}
 
function setM(ctx, m, updateLineScale) {
if (!matrixIsFinite(m)) {
return;
}
ctx.m_ = m;
 
if (updateLineScale) {
// Get the line scale.
// Determinant of this.m_ means how much the area is enlarged by the
// transformation. So its square root can be used as a scale factor
// for width.
var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
ctx.lineScale_ = sqrt(abs(det));
}
}
 
contextPrototype.translate = function(aX, aY) {
var m1 = [
[1, 0, 0],
[0, 1, 0],
[aX, aY, 1]
];
 
setM(this, matrixMultiply(m1, this.m_), false);
};
 
contextPrototype.rotate = function(aRot) {
var c = mc(aRot);
var s = ms(aRot);
 
var m1 = [
[c, s, 0],
[-s, c, 0],
[0, 0, 1]
];
 
setM(this, matrixMultiply(m1, this.m_), false);
};
 
contextPrototype.scale = function(aX, aY) {
this.arcScaleX_ *= aX;
this.arcScaleY_ *= aY;
var m1 = [
[aX, 0, 0],
[0, aY, 0],
[0, 0, 1]
];
 
setM(this, matrixMultiply(m1, this.m_), true);
};
 
contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
var m1 = [
[m11, m12, 0],
[m21, m22, 0],
[dx, dy, 1]
];
 
setM(this, matrixMultiply(m1, this.m_), true);
};
 
contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
var m = [
[m11, m12, 0],
[m21, m22, 0],
[dx, dy, 1]
];
 
setM(this, m, true);
};
 
/**
* The text drawing function.
* The maxWidth argument isn't taken in account, since no browser supports
* it yet.
*/
contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
var m = this.m_,
delta = 1000,
left = 0,
right = delta,
offset = {x: 0, y: 0},
lineStr = [];
 
var fontStyle = getComputedStyle(processFontStyle(this.font),
this.element_);
 
var fontStyleString = buildStyle(fontStyle);
 
var elementStyle = this.element_.currentStyle;
var textAlign = this.textAlign.toLowerCase();
switch (textAlign) {
case 'left':
case 'center':
case 'right':
break;
case 'end':
textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
break;
case 'start':
textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
break;
default:
textAlign = 'left';
}
 
// 1.75 is an arbitrary number, as there is no info about the text baseline
switch (this.textBaseline) {
case 'hanging':
case 'top':
offset.y = fontStyle.size / 1.75;
break;
case 'middle':
break;
default:
case null:
case 'alphabetic':
case 'ideographic':
case 'bottom':
offset.y = -fontStyle.size / 2.25;
break;
}
 
switch(textAlign) {
case 'right':
left = delta;
right = 0.05;
break;
case 'center':
left = right = delta / 2;
break;
}
 
var d = this.getCoords_(x + offset.x, y + offset.y);
 
lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
' coordsize="100 100" coordorigin="0 0"',
' filled="', !stroke, '" stroked="', !!stroke,
'" style="position:absolute;width:1px;height:1px;">');
 
if (stroke) {
appendStroke(this, lineStr);
} else {
// TODO: Fix the min and max params.
appendFill(this, lineStr, {x: -left, y: 0},
{x: right, y: fontStyle.size});
}
 
var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
 
var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);
 
lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
' offset="', skewOffset, '" origin="', left ,' 0" />',
'<g_vml_:path textpathok="true" />',
'<g_vml_:textpath on="true" string="',
encodeHtmlAttribute(text),
'" style="v-text-align:', textAlign,
';font:', encodeHtmlAttribute(fontStyleString),
'" /></g_vml_:line>');
 
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
};
 
contextPrototype.fillText = function(text, x, y, maxWidth) {
this.drawText_(text, x, y, maxWidth, false);
};
 
contextPrototype.strokeText = function(text, x, y, maxWidth) {
this.drawText_(text, x, y, maxWidth, true);
};
 
contextPrototype.measureText = function(text) {
if (!this.textMeasureEl_) {
var s = '<span style="position:absolute;' +
'top:-20000px;left:0;padding:0;margin:0;border:none;' +
'white-space:pre;"></span>';
this.element_.insertAdjacentHTML('beforeEnd', s);
this.textMeasureEl_ = this.element_.lastChild;
}
var doc = this.element_.ownerDocument;
this.textMeasureEl_.innerHTML = '';
this.textMeasureEl_.style.font = this.font;
// Don't use innerHTML or innerText because they allow markup/whitespace.
this.textMeasureEl_.appendChild(doc.createTextNode(text));
return {width: this.textMeasureEl_.offsetWidth};
};
 
/******** STUBS ********/
contextPrototype.clip = function() {
// TODO: Implement
};
 
contextPrototype.arcTo = function() {
// TODO: Implement
};
 
contextPrototype.createPattern = function(image, repetition) {
return new CanvasPattern_(image, repetition);
};
 
// Gradient / Pattern Stubs
function CanvasGradient_(aType) {
this.type_ = aType;
this.x0_ = 0;
this.y0_ = 0;
this.r0_ = 0;
this.x1_ = 0;
this.y1_ = 0;
this.r1_ = 0;
this.colors_ = [];
}
 
CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
aColor = processStyle(aColor);
this.colors_.push({offset: aOffset,
color: aColor.color,
alpha: aColor.alpha});
};
 
function CanvasPattern_(image, repetition) {
assertImageIsValid(image);
switch (repetition) {
case 'repeat':
case null:
case '':
this.repetition_ = 'repeat';
break
case 'repeat-x':
case 'repeat-y':
case 'no-repeat':
this.repetition_ = repetition;
break;
default:
throwException('SYNTAX_ERR');
}
 
this.src_ = image.src;
this.width_ = image.width;
this.height_ = image.height;
}
 
function throwException(s) {
throw new DOMException_(s);
}
 
function assertImageIsValid(img) {
if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
throwException('TYPE_MISMATCH_ERR');
}
if (img.readyState != 'complete') {
throwException('INVALID_STATE_ERR');
}
}
 
function DOMException_(s) {
this.code = this[s];
this.message = s +': DOM Exception ' + this.code;
}
var p = DOMException_.prototype = new Error;
p.INDEX_SIZE_ERR = 1;
p.DOMSTRING_SIZE_ERR = 2;
p.HIERARCHY_REQUEST_ERR = 3;
p.WRONG_DOCUMENT_ERR = 4;
p.INVALID_CHARACTER_ERR = 5;
p.NO_DATA_ALLOWED_ERR = 6;
p.NO_MODIFICATION_ALLOWED_ERR = 7;
p.NOT_FOUND_ERR = 8;
p.NOT_SUPPORTED_ERR = 9;
p.INUSE_ATTRIBUTE_ERR = 10;
p.INVALID_STATE_ERR = 11;
p.SYNTAX_ERR = 12;
p.INVALID_MODIFICATION_ERR = 13;
p.NAMESPACE_ERR = 14;
p.INVALID_ACCESS_ERR = 15;
p.VALIDATION_ERR = 16;
p.TYPE_MISMATCH_ERR = 17;
 
// set up externs
G_vmlCanvasManager = G_vmlCanvasManager_;
CanvasRenderingContext2D = CanvasRenderingContext2D_;
CanvasGradient = CanvasGradient_;
CanvasPattern = CanvasPattern_;
DOMException = DOMException_;
})();
 
} // if
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/webfiles/index.html
0,0 → 1,80
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
 
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
 
<title>Sysstat Widgets Demo</title>
 
<!--
The widgets are <div> and <span> elements with classes memstat
and loadavg, respectively.
Change the 'url' attribute to point to your web service.
-->
<script language="javascript" type="text/javascript" src="sysstatwidgets.js">
</script>
<script type="text/javascript">
function send(url, rselector) {
var $ = jQuerySysStatWidget;
$.get(url, function (response) {
$(rselector).html(response);
});
}
</script>
</head>
 
<body>
<p>This page display two widgets that display the physical memory
usage and the overall CPU load average of the machine that runs your
web service. Examine the HTML to see how these 'widgets' are embedded
into the page. </p>
<p>
<script>var count = 0;</script>
<a href="#" onclick="javascript:send('/runloop', '#responsemsg');">Click here</a> to run a 15 second loop on this machine (which will result in an increase in the load average).
<span id="responsemsg"></span>
</p>
 
<p>
<a href="#" onclick="javascript:send('/allocanon', '#responsemsg2');">Click here</a> to force allocation of 64MB of physical
memory used as application (anonymous) memory.
<span id="responsemsg2"></span>
</p>
 
<p>
<a href="#" onclick="javascript:send('/freeanon', '#responsemsg3');">Click here</a> to force deallocation of last
chunk of allocated physical memory.
<span id="responsemsg3"></span>
</p>
 
<table>
<tr>
<th>Memory</th>
 
<th>CPU Load Average</th>
</tr>
 
<tr>
<td>
<div id="meminfo" url="http://ec2-107-20-99-126.compute-1.amazonaws.com:80" update="1000"
style="margin-top:20px; margin-left:20px; width:180px; height:400px;">
</div>
</td>
 
<td>
<div id="loadavg" url="http://ec2-107-20-99-126.compute-1.amazonaws.com:80" update="1000"
style="margin-top:20px; margin-left:20px; width:600px; height:400px;">
Loading, please wait...
</div>
</td>
</tr>
</table>
 
<p>A text-only version of the load average widget:
<span class="loadavg-text" url="http://ec2-107-20-99-126.compute-1.amazonaws.com:80" update="1000"
style="font-weight: bold">
</span>
</p>
</body>
</html>
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/webfiles/jquery.jqplot.js
0,0 → 1,4026
/**
* Title: jqPlot Charts
*
* Pure JavaScript plotting plugin for jQuery.
*
* About: Version
*
* 0.9.6
*
* About: Copyright & License
*
* Copyright (c) 2009 Chris Leonello
* jqPlot is currently available for use in all personal or commercial projects
* under both the MIT and GPL version 2.0 licenses. This means that you can
* choose the license that best suits your project and use it accordingly.
*
* See <GPL Version 2> and <MIT License> contained within this distribution for further information.
*
* The author would appreciate an email letting him know of any substantial
* use of jqPlot. You can reach the author at: chris dot leonello at gmail
* dot com or see http://www.jqplot.com/info.php. This is, of course, not required.
*
* If you are feeling kind and generous, consider supporting the project by
* making a donation at: http://www.jqplot.com/donate.php.
*
*
* About: Introduction
*
* jqPlot requires jQuery (tested with 1.3.2 or better). jQuery 1.3.2 is included in the distribution.
* To use jqPlot include jQuery, the jqPlot jQuery plugin, the jqPlot css file and optionally
* the excanvas script for IE support in your web page:
*
* > <!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->
* > <script language="javascript" type="text/javascript" src="jquery-1.3.2.min.js"></script>
* > <script language="javascript" type="text/javascript" src="jquery.jqplot.min.js"></script>
* > <link rel="stylesheet" type="text/css" href="jquery.jqplot.css" />
*
* jqPlot can be customized by overriding the defaults of any of the objects which make
* up the plot. The general usage of jqplot is:
*
* > chart = $.jqplot('targetElemId', [dataArray,...], {optionsObject});
*
* The options available to jqplot are detailed in <jqPlot Options> in the jqPlotOptions.txt file.
*
* An actual call to $.jqplot() may look like the
* examples below:
*
* > chart = $.jqplot('chartdiv', [[[1, 2],[3,5.12],[5,13.1],[7,33.6],[9,85.9],[11,219.9]]]);
*
* or
*
* > dataArray = [34,12,43,55,77];
* > chart = $.jqplot('targetElemId', [dataArray, ...], {title:'My Plot', axes:{yaxis:{min:20, max:100}}});
*
* For more inforrmation, see <jqPlot Usage>.
*
* About: Usage
*
* See <jqPlot Usage>
*
* About: Available Options
*
* See <jqPlot Options> for a list of options available thorugh the options object (not complete yet!)
*
* About: Options Usage
*
* See <Options Tutorial>
*
* About: Changes
*
* See <Change Log>
*
*/
 
(function($) {
// make sure undefined is undefined
var undefined;
 
/**
* Class: $.jqplot
* jQuery function called by the user to create a plot.
*
* Parameters:
* target - ID of target element to render the plot into.
* data - an array of data series.
* options - user defined options object. See the individual classes for available options.
*
* Properties:
* config - object to hold configuration information for jqPlot plot object.
*
* attributes:
* enablePlugins - False to disable plugins by default. Plugins must then be explicitly
* enabled in the individual plot options. Default: true.
* This property sets the "show" property of certain plugins to true or false.
* Only plugins that can be immediately active upon loading are affected. This includes
* non-renderer plugins like cursor, dragable, highlighter, and trendline.
* defaultHeight - Default height for plots where no css height specification exists. This
* is a jqplot wide default.
* defaultWidth - Default height for plots where no css height specification exists. This
* is a jqplot wide default.
*/
 
$.jqplot = function(target, data, options) {
var _data, _options;
// check to see if only 2 arguments were specified, what is what.
if (data == null) {
throw "No data specified";
}
if (data.constructor == Array && data.length == 0 || data[0].constructor != Array) {
throw "Improper Data Array";
}
if (options == null) {
if (data instanceof Array) {
_data = data;
_options = null;
}
else if (data.constructor == Object) {
_data = null;
_options = data;
}
}
else {
_data = data;
_options = options;
}
var plot = new jqPlot();
plot.init(target, _data, _options);
plot.draw();
return plot;
};
$.jqplot.debug = 1;
$.jqplot.config = {
debug:1,
enablePlugins:true,
defaultHeight:300,
defaultWidth:400
};
$.jqplot.enablePlugins = $.jqplot.config.enablePlugins;
/**
*
* Hooks: jqPlot Pugin Hooks
*
* $.jqplot.preInitHooks - called before initialization.
* $.jqplot.postInitHooks - called after initialization.
* $.jqplot.preParseOptionsHooks - called before user options are parsed.
* $.jqplot.postParseOptionsHooks - called after user options are parsed.
* $.jqplot.preDrawHooks - called before plot draw.
* $.jqplot.postDrawHooks - called after plot draw.
* $.jqplot.preDrawSeriesHooks - called before each series is drawn.
* $.jqplot.postDrawSeriesHooks - called after each series is drawn.
* $.jqplot.preDrawLegendHooks - called before the legend is drawn.
* $.jqplot.addLegendRowHooks - called at the end of legend draw, so plugins
* can add rows to the legend table.
* $.jqplot.preSeriesInitHooks - called before series is initialized.
* $.jqplot.postSeriesInitHooks - called after series is initialized.
* $.jqplot.preParseSeriesOptionsHooks - called before series related options
* are parsed.
* $.jqplot.postParseSeriesOptionsHooks - called after series related options
* are parsed.
* $.jqplot.eventListenerHooks - called at the end of plot drawing, binds
* listeners to the event canvas which lays on top of the grid area.
* $.jqplot.preDrawSeriesShadowHooks - called before series shadows are drawn.
* $.jqplot.postDrawSeriesShadowHooks - called after series shadows are drawn.
*
*/
$.jqplot.preInitHooks = [];
$.jqplot.postInitHooks = [];
$.jqplot.preParseOptionsHooks = [];
$.jqplot.postParseOptionsHooks = [];
$.jqplot.preDrawHooks = [];
$.jqplot.postDrawHooks = [];
$.jqplot.preDrawSeriesHooks = [];
$.jqplot.postDrawSeriesHooks = [];
$.jqplot.preDrawLegendHooks = [];
$.jqplot.addLegendRowHooks = [];
$.jqplot.preSeriesInitHooks = [];
$.jqplot.postSeriesInitHooks = [];
$.jqplot.preParseSeriesOptionsHooks = [];
$.jqplot.postParseSeriesOptionsHooks = [];
$.jqplot.eventListenerHooks = [];
$.jqplot.preDrawSeriesShadowHooks = [];
$.jqplot.postDrawSeriesShadowHooks = [];
 
// A superclass holding some common properties and methods.
$.jqplot.ElemContainer = function() {
this._elem;
this._plotWidth;
this._plotHeight;
this._plotDimensions = {height:null, width:null};
};
$.jqplot.ElemContainer.prototype.getWidth = function() {
if (this._elem) {
return this._elem.outerWidth(true);
}
else {
return null;
}
};
$.jqplot.ElemContainer.prototype.getHeight = function() {
if (this._elem) {
return this._elem.outerHeight(true);
}
else {
return null;
}
};
$.jqplot.ElemContainer.prototype.getPosition = function() {
if (this._elem) {
return this._elem.position();
}
else {
return {top:null, left:null, bottom:null, right:null};
}
};
$.jqplot.ElemContainer.prototype.getTop = function() {
return this.getPosition().top;
};
$.jqplot.ElemContainer.prototype.getLeft = function() {
return this.getPosition().left;
};
$.jqplot.ElemContainer.prototype.getBottom = function() {
return this._elem.css('bottom');
};
$.jqplot.ElemContainer.prototype.getRight = function() {
return this._elem.css('right');
};
 
/**
* Class: Axis
* An individual axis object. Cannot be instantiated directly, but created
* by the Plot oject. Axis properties can be set or overriden by the
* options passed in from the user.
*
*/
function Axis(name) {
$.jqplot.ElemContainer.call(this);
// Group: Properties
//
// Axes options are specified within an axes object at the top level of the
// plot options like so:
// > {
// > axes: {
// > xaxis: {min: 5},
// > yaxis: {min: 2, max: 8, numberTicks:4},
// > x2axis: {pad: 1.5},
// > y2axis: {ticks:[22, 44, 66, 88]}
// > }
// > }
// There are 4 axes, 'xaxis', 'yaxis', 'x2axis', 'y2axis'. Any or all of
// which may be specified.
this.name = name;
this._series = [];
// prop: show
// Wether to display the axis on the graph.
this.show = false;
// prop: tickRenderer
// A class of a rendering engine for creating the ticks labels displayed on the plot,
// See <$.jqplot.AxisTickRenderer>.
this.tickRenderer = $.jqplot.AxisTickRenderer;
// prop: tickOptions
// Options that will be passed to the tickRenderer, see <$.jqplot.AxisTickRenderer> options.
this.tickOptions = {};
// prop: labelRenderer
// A class of a rendering engine for creating an axis label.
this.labelRenderer = $.jqplot.AxisLabelRenderer;
// prop: labelOptions
// Options passed to the label renderer.
this.labelOptions = {};
// prop: label
// Label for the axis
this.label = null;
// prop: showLabel
// true to show the axis label.
this.showLabel = true;
// prop: min
// minimum value of the axis (in data units, not pixels).
this.min=null;
// prop: max
// maximum value of the axis (in data units, not pixels).
this.max=null;
// prop: autoscale
// Autoscale the axis min and max values to provide sensible tick spacing.
// If axis min or max are set, autoscale will be turned off.
// The numberTicks, tickInterval and pad options do work with
// autoscale, although tickInterval has not been tested yet.
// padMin and padMax do nothing when autoscale is on.
this.autoscale = false;
// prop: pad
// Padding to extend the range above and below the data bounds.
// The data range is multiplied by this factor to determine minimum and maximum axis bounds.
// A value of 0 will be interpreted to mean no padding, and pad will be set to 1.0.
this.pad = 1.2;
// prop: padMax
// Padding to extend the range above data bounds.
// The top of the data range is multiplied by this factor to determine maximum axis bounds.
// A value of 0 will be interpreted to mean no padding, and padMax will be set to 1.0.
this.padMax = null;
// prop: padMin
// Padding to extend the range below data bounds.
// The bottom of the data range is multiplied by this factor to determine minimum axis bounds.
// A value of 0 will be interpreted to mean no padding, and padMin will be set to 1.0.
this.padMin = null;
// prop: ticks
// 1D [val, val, ...] or 2D [[val, label], [val, label], ...] array of ticks for the axis.
// If no label is specified, the value is formatted into an appropriate label.
this.ticks = [];
// prop: numberTicks
// Desired number of ticks. Default is to compute automatically.
this.numberTicks;
// prop: tickInterval
// number of units between ticks. Mutually exclusive with numberTicks.
this.tickInterval;
// prop: renderer
// A class of a rendering engine that handles tick generation,
// scaling input data to pixel grid units and drawing the axis element.
this.renderer = $.jqplot.LinearAxisRenderer;
// prop: rendererOptions
// renderer specific options. See <$.jqplot.LinearAxisRenderer> for options.
this.rendererOptions = {};
// prop: showTicks
// wether to show the ticks (both marks and labels) or not.
this.showTicks = true;
// prop: showTickMarks
// wether to show the tick marks (line crossing grid) or not.
this.showTickMarks = true;
// prop: showMinorTicks
// Wether or not to show minor ticks. This is renderer dependent.
// The default <$.jqplot.LinearAxisRenderer> does not have minor ticks.
this.showMinorTicks = true;
// prop: useSeriesColor
// Use the color of the first series associated with this axis for the
// tick marks and line bordering this axis.
this.useSeriesColor = false;
// prop: borderWidth
// width of line stroked at the border of the axis. Defaults
// to the width of the grid boarder.
this.borderWidth = null;
// prop: borderColor
// color of the border adjacent to the axis. Defaults to grid border color.
this.borderColor = null;
// minimum and maximum values on the axis.
this._dataBounds = {min:null, max:null};
// pixel position from the top left of the min value and max value on the axis.
this._offsets = {min:null, max:null};
this._ticks=[];
this._label = null;
// prop: syncTicks
// true to try and synchronize tick spacing across multiple axes so that ticks and
// grid lines line up. This has an impact on autoscaling algorithm, however.
// In general, autoscaling an individual axis will work better if it does not
// have to sync ticks.
this.syncTicks = null;
// prop: tickSpacing
// Approximate pixel spacing between ticks on graph. Used during autoscaling.
// This number will be an upper bound, actual spacing will be less.
this.tickSpacing = 75;
// Properties to hold the original values for min, max, ticks, tickInterval and numberTicks
// so they can be restored if altered by plugins.
this._min = null;
this._max = null;
this._tickInterval = null;
this._numberTicks = null;
this.__ticks = null;
}
Axis.prototype = new $.jqplot.ElemContainer();
Axis.prototype.constructor = Axis;
Axis.prototype.init = function() {
this.renderer = new this.renderer();
// set the axis name
this.tickOptions.axis = this.name;
if (this.label == null || this.label == '') {
this.showLabel = false;
}
else {
this.labelOptions.label = this.label;
}
if (this.showLabel == false) {
this.labelOptions.show = false;
}
// set the default padMax, padMin if not specified
// special check, if no padding desired, padding
// should be set to 1.0
if (this.pad == 0) {
this.pad = 1.0;
}
if (this.padMax == 0) {
this.padMax = 1.0;
}
if (this.padMin == 0) {
this.padMin = 1.0;
}
if (this.padMax == null) {
this.padMax = (this.pad-1)/2 + 1;
}
if (this.padMin == null) {
this.padMin = (this.pad-1)/2 + 1;
}
// now that padMin and padMax are correctly set, reset pad in case user has supplied
// padMin and/or padMax
this.pad = this.padMax + this.padMin - 1;
if (this.min != null || this.max != null) {
this.autoscale = false;
}
// if not set, sync ticks for y axes but not x by default.
if (this.syncTicks == null && this.name.indexOf('y') > -1) {
this.syncTicks = true;
}
else if (this.syncTicks == null){
this.syncTicks = false;
}
this.renderer.init.call(this, this.rendererOptions);
};
Axis.prototype.draw = function(ctx) {
return this.renderer.draw.call(this, ctx);
};
Axis.prototype.set = function() {
this.renderer.set.call(this);
};
Axis.prototype.pack = function(pos, offsets) {
if (this.show) {
this.renderer.pack.call(this, pos, offsets);
}
// these properties should all be available now.
if (this._min == null) {
this._min = this.min;
this._max = this.max;
this._tickInterval = this.tickInterval;
this._numberTicks = this.numberTicks;
this.__ticks = this._ticks;
}
};
// reset the axis back to original values if it has been scaled, zoomed, etc.
Axis.prototype.reset = function() {
this.renderer.reset.call(this);
};
Axis.prototype.resetScale = function() {
this.min = null;
this.max = null;
this.numberTicks = null;
this.tickInterval = null;
};
 
/**
* Class: Legend
* Legend object. Cannot be instantiated directly, but created
* by the Plot oject. Legend properties can be set or overriden by the
* options passed in from the user.
*/
function Legend(options) {
$.jqplot.ElemContainer.call(this);
// Group: Properties
// prop: show
// Wether to display the legend on the graph.
this.show = false;
// prop: location
// Placement of the legend. one of the compass directions: nw, n, ne, e, se, s, sw, w
this.location = 'ne';
// prop: xoffset
// offset from the inside edge of the plot in the x direction in pixels.
this.xoffset = 12;
// prop: yoffset
// offset from the inside edge of the plot in the y direction in pixels.
this.yoffset = 12;
// prop: border
// css spec for the border around the legend box.
this.border;
// prop: background
// css spec for the background of the legend box.
this.background;
// prop: textColor
// css color spec for the legend text.
this.textColor;
// prop: fontFamily
// css font-family spec for the legend text.
this.fontFamily;
// prop: fontSize
// css font-size spec for the legend text.
this.fontSize ;
// prop: rowSpacing
// css padding-top spec for the rows in the legend.
this.rowSpacing = '0.5em';
// renderer
// A class that will create a DOM object for the legend,
// see <$.jqplot.TableLegendRenderer>.
this.renderer = $.jqplot.TableLegendRenderer;
// prop: rendererOptions
// renderer specific options passed to the renderer.
this.rendererOptions = {};
// prop: predraw
// Wether to draw the legend before the series or not.
this.preDraw = false;
this.escapeHtml = false;
this._series = [];
$.extend(true, this, options);
}
Legend.prototype = new $.jqplot.ElemContainer();
Legend.prototype.constructor = Legend;
Legend.prototype.init = function() {
this.renderer = new this.renderer();
this.renderer.init.call(this, this.rendererOptions);
};
Legend.prototype.draw = function(offsets) {
for (var i=0; i<$.jqplot.preDrawLegendHooks.length; i++){
$.jqplot.preDrawLegendHooks[i].call(this, offsets);
}
return this.renderer.draw.call(this, offsets);
};
Legend.prototype.pack = function(offsets) {
this.renderer.pack.call(this, offsets);
};
 
/**
* Class: Title
* Plot Title object. Cannot be instantiated directly, but created
* by the Plot oject. Title properties can be set or overriden by the
* options passed in from the user.
*
* Parameters:
* text - text of the title.
*/
function Title(text) {
$.jqplot.ElemContainer.call(this);
// Group: Properties
// prop: text
// text of the title;
this.text = text;
// prop: show
// wether or not to show the title
this.show = true;
// prop: fontFamily
// css font-family spec for the text.
this.fontFamily;
// prop: fontSize
// css font-size spec for the text.
this.fontSize ;
// prop: textAlign
// css text-align spec for the text.
this.textAlign;
// prop: textColor
// css color spec for the text.
this.textColor;
// prop: renderer
// A class for creating a DOM element for the title,
// see <$.jqplot.DivTitleRenderer>.
this.renderer = $.jqplot.DivTitleRenderer;
// prop: rendererOptions
// renderer specific options passed to the renderer.
this.rendererOptions = {};
}
Title.prototype = new $.jqplot.ElemContainer();
Title.prototype.constructor = Title;
Title.prototype.init = function() {
this.renderer = new this.renderer();
this.renderer.init.call(this, this.rendererOptions);
};
Title.prototype.draw = function(width) {
return this.renderer.draw.call(this, width);
};
Title.prototype.pack = function() {
this.renderer.pack.call(this);
};
 
 
/**
* Class: Series
* An individual data series object. Cannot be instantiated directly, but created
* by the Plot oject. Series properties can be set or overriden by the
* options passed in from the user.
*/
function Series() {
$.jqplot.ElemContainer.call(this);
// Group: Properties
// Properties will be assigned from a series array at the top level of the
// options. If you had two series and wanted to change the color and line
// width of the first and set the second to use the secondary y axis with
// no shadow and supply custom labels for each:
// > {
// > series:[
// > {color: '#ff4466', lineWidth: 5, label:'good line'},
// > {yaxis: 'y2axis', shadow: false, label:'bad line'}
// > ]
// > }
// prop: show
// wether or not to draw the series.
this.show = true;
// prop: xaxis
// which x axis to use with this series, either 'xaxis' or 'x2axis'.
this.xaxis = 'xaxis';
this._xaxis;
// prop: yaxis
// which y axis to use with this series, either 'yaxis' or 'y2axis'.
this.yaxis = 'yaxis';
this._yaxis;
this.gridBorderWidth = 2.0;
// prop: renderer
// A class of a renderer which will draw the series,
// see <$.jqplot.LineRenderer>.
this.renderer = $.jqplot.LineRenderer;
// prop: rendererOptions
// Options to pass on to the renderer.
this.rendererOptions = {};
this.data = [];
this.gridData = [];
// prop: label
// Line label to use in the legend.
this.label = '';
// prop: showLabel
// true to show label for this series in the legend.
this.showLabel = true;
// prop: color
// css color spec for the series
this.color;
// prop: lineWidth
// width of the line in pixels. May have different meanings depending on renderer.
this.lineWidth = 2.5;
// prop: shadow
// wether or not to draw a shadow on the line
this.shadow = true;
// prop: shadowAngle
// Shadow angle in degrees
this.shadowAngle = 45;
// prop: shadowOffset
// Shadow offset from line in pixels
this.shadowOffset = 1.25;
// prop: shadowDepth
// Number of times shadow is stroked, each stroke offset shadowOffset from the last.
this.shadowDepth = 3;
// prop: shadowAlpha
// Alpha channel transparency of shadow. 0 = transparent.
this.shadowAlpha = '0.1';
// prop: breakOnNull
// Not implemented. wether line segments should be be broken at null value.
// False will join point on either side of line.
this.breakOnNull = false;
// prop: markerRenderer
// A class of a renderer which will draw marker (e.g. circle, square, ...) at the data points,
// see <$.jqplot.MarkerRenderer>.
this.markerRenderer = $.jqplot.MarkerRenderer;
// prop: markerOptions
// renderer specific options to pass to the markerRenderer,
// see <$.jqplot.MarkerRenderer>.
this.markerOptions = {};
// prop: showLine
// wether to actually draw the line or not. Series will still be renderered, even if no line is drawn.
this.showLine = true;
// prop: showMarker
// wether or not to show the markers at the data points.
this.showMarker = true;
// prop: index
// 0 based index of this series in the plot series array.
this.index;
// prop: fill
// true or false, wether to fill under lines or in bars.
// May not be implemented in all renderers.
this.fill = false;
// prop: fillColor
// CSS color spec to use for fill under line. Defaults to line color.
this.fillColor;
// prop: fillAlpha
// Alpha transparency to apply to the fill under the line.
// Use this to adjust alpha separate from fill color.
this.fillAlpha;
// prop: fillAndStroke
// If true will stroke the line (with color this.color) as well as fill under it.
// Applies only when fill is true.
this.fillAndStroke = false;
// prop: disableStack
// true to not stack this series with other series in the plot.
// To render properly, non-stacked series must come after any stacked series
// in the plot's data series array. So, the plot's data series array would look like:
// > [stackedSeries1, stackedSeries2, ..., nonStackedSeries1, nonStackedSeries2, ...]
// disableStack will put a gap in the stacking order of series, and subsequent
// stacked series will not fill down through the non-stacked series and will
// most likely not stack properly on top of the non-stacked series.
this.disableStack = false;
// _stack is set by the Plot if the plot is a stacked chart.
// will stack lines or bars on top of one another to build a "mountain" style chart.
// May not be implemented in all renderers.
this._stack = false;
// prop: neighborThreshold
// how close or far (in pixels) the cursor must be from a point marker to detect the point.
this.neighborThreshold = 4;
// prop: fillToZero
// true will force bar and filled series to fill toward zero on the fill Axis.
this.fillToZero = false;
// prop: fillAxis
// Either 'x' or 'y'. Which axis to fill the line toward if fillToZero is true.
// 'y' means fill up/down to 0 on the y axis for this series.
this.fillAxis = 'y';
this._stackData = [];
// _plotData accounts for stacking. If plots not stacked, _plotData and data are same. If
// stacked, _plotData is accumulation of stacking data.
this._plotData = [];
// _plotValues hold the individual x and y values that will be plotted for this series.
this._plotValues = {x:[], y:[]};
// statistics about the intervals between data points. Used for auto scaling.
this._intervals = {x:{}, y:{}};
// data from the previous series, for stacked charts.
this._prevPlotData = [];
this._prevGridData = [];
this._stackAxis = 'y';
this._primaryAxis = '_xaxis';
this.plugins = {};
}
Series.prototype = new $.jqplot.ElemContainer();
Series.prototype.constructor = Series;
Series.prototype.init = function(index, gridbw) {
// weed out any null values in the data.
this.index = index;
this.gridBorderWidth = gridbw;
var d = this.data;
for (var i=0; i<d.length; i++) {
if (! this.breakOnNull) {
if (d[i] == null || d[i][0] == null || d[i][1] == null) {
d.splice(i,1);
continue;
}
}
else {
if (d[i] == null || d[i][0] == null || d[i][1] == null) {
// TODO: figure out what to do with null values
var undefined;
}
}
}
if (!this.fillColor) {
this.fillColor = this.color;
}
if (this.fillAlpha) {
var comp = $.jqplot.normalize2rgb(this.fillColor);
var comp = $.jqplot.getColorComponents(comp);
this.fillColor = 'rgba('+comp[0]+','+comp[1]+','+comp[2]+','+this.fillAlpha+')';
}
this.renderer = new this.renderer();
this.renderer.init.call(this, this.rendererOptions);
this.markerRenderer = new this.markerRenderer();
if (!this.markerOptions.color) {
this.markerOptions.color = this.color;
}
if (this.markerOptions.show == null) {
this.markerOptions.show = this.showMarker;
}
// the markerRenderer is called within it's own scaope, don't want to overwrite series options!!
this.markerRenderer.init(this.markerOptions);
};
// data - optional data point array to draw using this series renderer
// gridData - optional grid data point array to draw using this series renderer
// stackData - array of cumulative data for stacked plots.
Series.prototype.draw = function(sctx, opts) {
var options = (opts == undefined) ? {} : opts;
// hooks get called even if series not shown
// we don't clear canvas here, it would wipe out all other series as well.
for (var j=0; j<$.jqplot.preDrawSeriesHooks.length; j++) {
$.jqplot.preDrawSeriesHooks[j].call(this, sctx, options);
}
if (this.show) {
this.renderer.setGridData.call(this);
if (!options.preventJqPlotSeriesDrawTrigger) {
$(sctx.canvas).trigger('jqplotSeriesDraw', [this.data, this.gridData]);
}
var data = [];
if (options.data) {
data = options.data;
}
else if (!this._stack) {
data = this.data;
}
else {
data = this._plotData;
}
var gridData = options.gridData || this.renderer.makeGridData.call(this, data);
this.renderer.draw.call(this, sctx, gridData, options);
}
for (var j=0; j<$.jqplot.postDrawSeriesHooks.length; j++) {
$.jqplot.postDrawSeriesHooks[j].call(this, sctx, options);
}
};
Series.prototype.drawShadow = function(sctx, opts) {
var options = (opts == undefined) ? {} : opts;
// hooks get called even if series not shown
// we don't clear canvas here, it would wipe out all other series as well.
for (var j=0; j<$.jqplot.preDrawSeriesShadowHooks.length; j++) {
$.jqplot.preDrawSeriesShadowHooks[j].call(this, sctx, options);
}
if (this.shadow) {
this.renderer.setGridData.call(this);
 
var data = [];
if (options.data) {
data = options.data;
}
else if (!this._stack) {
data = this.data;
}
else {
data = this._plotData;
}
var gridData = options.gridData || this.renderer.makeGridData.call(this, data);
this.renderer.drawShadow.call(this, sctx, gridData, options);
}
for (var j=0; j<$.jqplot.postDrawSeriesShadowHooks.length; j++) {
$.jqplot.postDrawSeriesShadowHooks[j].call(this, sctx, options);
}
};
 
 
/**
* Class: Grid
*
* Object representing the grid on which the plot is drawn. The grid in this
* context is the area bounded by the axes, the area which will contain the series.
* Note, the series are drawn on their own canvas.
* The Grid object cannot be instantiated directly, but is created by the Plot oject.
* Grid properties can be set or overriden by the options passed in from the user.
*/
function Grid() {
$.jqplot.ElemContainer.call(this);
// Group: Properties
// prop: drawGridlines
// wether to draw the gridlines on the plot.
this.drawGridlines = true;
// prop: gridLineColor
// color of the grid lines.
this.gridLineColor = '#cccccc';
// prop: gridLineWidth
// width of the grid lines.
this.gridLineWidth = 1.0;
// prop: background
// css spec for the background color.
this.background = '#fffdf6';
// prop: borderColor
// css spec for the color of the grid border.
this.borderColor = '#999999';
// prop: borderWidth
// width of the border in pixels.
this.borderWidth = 2.0;
// prop: shadow
// wether to show a shadow behind the grid.
this.shadow = true;
// prop: shadowAngle
// shadow angle in degrees
this.shadowAngle = 45;
// prop: shadowOffset
// Offset of each shadow stroke from the border in pixels
this.shadowOffset = 1.5;
// prop: shadowWidth
// width of the stoke for the shadow
this.shadowWidth = 3;
// prop: shadowDepth
// Number of times shadow is stroked, each stroke offset shadowOffset from the last.
this.shadowDepth = 3;
// prop: shadowAlpha
// Alpha channel transparency of shadow. 0 = transparent.
this.shadowAlpha = '0.07';
this._left;
this._top;
this._right;
this._bottom;
this._width;
this._height;
this._axes = [];
// prop: renderer
// Instance of a renderer which will actually render the grid,
// see <$.jqplot.CanvasGridRenderer>.
this.renderer = $.jqplot.CanvasGridRenderer;
// prop: rendererOptions
// Options to pass on to the renderer,
// see <$.jqplot.CanvasGridRenderer>.
this.rendererOptions = {};
this._offsets = {top:null, bottom:null, left:null, right:null};
}
Grid.prototype = new $.jqplot.ElemContainer();
Grid.prototype.constructor = Grid;
Grid.prototype.init = function() {
this.renderer = new this.renderer();
this.renderer.init.call(this, this.rendererOptions);
};
Grid.prototype.createElement = function(offsets) {
this._offsets = offsets;
return this.renderer.createElement.call(this);
};
Grid.prototype.draw = function() {
this.renderer.draw.call(this);
};
$.jqplot.GenericCanvas = function() {
$.jqplot.ElemContainer.call(this);
this._ctx;
};
$.jqplot.GenericCanvas.prototype = new $.jqplot.ElemContainer();
$.jqplot.GenericCanvas.prototype.constructor = $.jqplot.GenericCanvas;
$.jqplot.GenericCanvas.prototype.createElement = function(offsets, clss, plotDimensions) {
this._offsets = offsets;
var klass = 'jqplot';
if (clss != undefined) {
klass = clss;
}
var elem = document.createElement('canvas');
// if new plotDimensions supplied, use them.
if (plotDimensions != undefined) {
this._plotDimensions = plotDimensions;
}
elem.width = this._plotDimensions.width - this._offsets.left - this._offsets.right;
elem.height = this._plotDimensions.height - this._offsets.top - this._offsets.bottom;
this._elem = $(elem);
this._elem.addClass(klass);
this._elem.css({ position: 'absolute', left: this._offsets.left, top: this._offsets.top });
// borrowed from flot by Ole Laursen
if ($.browser.msie) {
window.G_vmlCanvasManager.init_(document);
}
if ($.browser.msie) {
elem = window.G_vmlCanvasManager.initElement(elem);
}
return this._elem;
};
$.jqplot.GenericCanvas.prototype.setContext = function() {
this._ctx = this._elem.get(0).getContext("2d");
return this._ctx;
};
 
/**
* Class: jqPlot
* Plot object returned by call to $.jqplot. Handles parsing user options,
* creating sub objects (Axes, legend, title, series) and rendering the plot.
*/
function jqPlot() {
// Group: Properties
// These properties are specified at the top of the options object
// like so:
// > {
// > axesDefaults:{min:0},
// > series:[{color:'#6633dd'}],
// > title: 'A Plot'
// > }
//
// prop: data
// user's data. Data should *NOT* be specified in the options object,
// but be passed in as the second argument to the $.jqplot() function.
// The data property is described here soley for reference.
// The data should be in the form of an array of 2D or 1D arrays like
// > [ [[x1, y1], [x2, y2],...], [y1, y2, ...] ].
this.data = [];
// The id of the dom element to render the plot into
this.targetId = null;
// the jquery object for the dom target.
this.target = null;
this.defaults = {
// prop: axesDefaults
// default options that will be applied to all axes.
// see <Axis> for axes options.
axesDefaults: {},
axes: {xaxis:{}, yaxis:{}, x2axis:{}, y2axis:{}, y3axis:{}, y4axis:{}, y5axis:{}, y6axis:{}, y7axis:{}, y8axis:{}, y9axis:{}},
// prop: seriesDefaults
// default options that will be applied to all series.
// see <Series> for series options.
seriesDefaults: {},
gridPadding: {top:10, right:10, bottom:23, left:10},
series:[]
};
// prop: series
// Array of series object options.
// see <Series> for series specific options.
this.series = [];
// prop: axes
// up to 4 axes are supported, each with it's own options,
// See <Axis> for axis specific options.
this.axes = {xaxis: new Axis('xaxis'), yaxis: new Axis('yaxis'), x2axis: new Axis('x2axis'), y2axis: new Axis('y2axis'), y3axis: new Axis('y3axis'), y4axis: new Axis('y4axis'), y5axis: new Axis('y5axis'), y6axis: new Axis('y6axis'), y7axis: new Axis('y7axis'), y8axis: new Axis('y8axis'), y9axis: new Axis('y9axis')};
// prop: grid
// See <Grid> for grid specific options.
this.grid = new Grid();
// prop: legend
// see <$.jqplot.TableLegendRenderer>
this.legend = new Legend();
this.baseCanvas = new $.jqplot.GenericCanvas();
this.seriesCanvas = new $.jqplot.GenericCanvas();
this.eventCanvas = new $.jqplot.GenericCanvas();
this._width = null;
this._height = null;
this._plotDimensions = {height:null, width:null};
this._gridPadding = {top:10, right:10, bottom:10, left:10};
// a shortcut for axis syncTicks options. Not implemented yet.
this.syncXTicks = true;
// a shortcut for axis syncTicks options. Not implemented yet.
this.syncYTicks = true;
// prop: seriesColors
// Ann array of CSS color specifications that will be applied, in order,
// to the series in the plot. Colors will wrap around so, if their
// are more series than colors, colors will be reused starting at the
// beginning. For pie charts, this specifies the colors of the slices.
this.seriesColors = [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc"];
// this.negativeSeriesColors = [ "#9653C4", "#1CE540", "#7BC28F", "#525A94", "#529386", "#00914A", "#967C33", "#E650A8", "#37D46A", "#1BF800", "#AD25CC"];
this.negativeSeriesColors = [ "#498991", "#C08840", "#9F9274", "#546D61", "#646C4A", "#6F6621", "#6E3F5F", "#4F64B0", "#A89050", "#C45923", "#187399"];
// prop: sortData
// false to not sort the data passed in by the user.
// Many bar, stakced and other graphs as well as many plugins depend on
// having sorted data.
this.sortData = true;
var seriesColorsIndex = 0;
// prop textColor
// css spec for the css color attribute. Default for the entire plot.
this.textColor;
// prop; fontFamily
// css spec for the font-family attribute. Default for the entire plot.
this.fontFamily;
// prop: fontSize
// css spec for the font-size attribute. Default for the entire plot.
this.fontSize;
// prop: title
// Title object. See <Title> for specific options. As a shortcut, you
// can specify the title option as just a string like: title: 'My Plot'
// and this will create a new title object with the specified text.
this.title = new Title();
// container to hold all of the merged options. Convienence for plugins.
this.options = {};
// prop: stackSeries
// true or false, creates a stack or "mountain" plot.
// Not all series renderers may implement this option.
this.stackSeries = false;
// array to hold the cumulative stacked series data.
// used to ajust the individual series data, which won't have access to other
// series data.
this._stackData = [];
// array that holds the data to be plotted. This will be the series data
// merged with the the appropriate data from _stackData according to the stackAxis.
this._plotData = [];
// Namespece to hold plugins. Generally non-renderer plugins add themselves to here.
this.plugins = {};
// Count how many times the draw method has been called while the plot is visible.
// Mostly used to test if plot has never been dran (=0), has been successfully drawn
// into a visible container once (=1) or draw more than once into a visible container.
// Can use this in tests to see if plot has been visibly drawn at least one time.
// After plot has been visibly drawn once, it generally doesn't need redrawn if its
// container is hidden and shown.
this._drawCount = 0;
// prop: drawIfHidden
// True to execute the draw method even if the plot target is hidden.
// Generally, this should be false. Most plot elements will not be sized/
// positioned correclty if renderered into a hidden container. To render into
// a hidden container, call the replot method when the container is shown.
this.drawIfHidden = false;
this.colorGenerator = $.jqplot.ColorGenerator;
// Group: methods
//
// method: init
// sets the plot target, checks data and applies user
// options to plot.
this.init = function(target, data, options) {
for (var i=0; i<$.jqplot.preInitHooks.length; i++) {
$.jqplot.preInitHooks[i].call(this, target, data, options);
}
this.targetId = '#'+target;
this.target = $('#'+target);
if (!this.target.get(0)) {
throw "No plot target specified";
}
// make sure the target is positioned by some means and set css
if (this.target.css('position') == 'static') {
this.target.css('position', 'relative');
}
if (!this.target.hasClass('jqplot-target')) {
this.target.addClass('jqplot-target');
}
// if no height or width specified, use a default.
if (!this.target.height()) {
var h;
if (options && options.height) {
h = parseInt(options.height, 10);
}
else if (this.target.attr('data-height')) {
h = parseInt(this.target.attr('data-height'), 10);
}
else {
h = parseInt($.jqplot.config.defaultHeight, 10);
}
this._height = h;
this.target.css('height', h+'px');
}
else {
this._height = this.target.height();
}
if (!this.target.width()) {
var w;
if (options && options.width) {
w = parseInt(options.width, 10);
}
else if (this.target.attr('data-width')) {
w = parseInt(this.target.attr('data-width'), 10);
}
else {
w = parseInt($.jqplot.config.defaultWidth, 10);
}
this._width = w;
this.target.css('width', w+'px');
}
else {
this._width = this.target.width();
}
this._plotDimensions.height = this._height;
this._plotDimensions.width = this._width;
this.grid._plotDimensions = this._plotDimensions;
this.title._plotDimensions = this._plotDimensions;
this.baseCanvas._plotDimensions = this._plotDimensions;
this.seriesCanvas._plotDimensions = this._plotDimensions;
this.eventCanvas._plotDimensions = this._plotDimensions;
this.legend._plotDimensions = this._plotDimensions;
if (this._height <=0 || this._width <=0 || !this._height || !this._width) {
throw "Canvas dimension not set";
}
this.data = data;
this.parseOptions(options);
if (this.textColor) {
this.target.css('color', this.textColor);
}
if (this.fontFamily) {
this.target.css('font-family', this.fontFamily);
}
if (this.fontSize) {
this.target.css('font-size', this.fontSize);
}
this.title.init();
this.legend.init();
for (var i=0; i<this.series.length; i++) {
for (var j=0; j<$.jqplot.preSeriesInitHooks.length; j++) {
$.jqplot.preSeriesInitHooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i]);
}
this.populatePlotData(this.series[i], i);
this.series[i]._plotDimensions = this._plotDimensions;
this.series[i].init(i, this.grid.borderWidth);
for (var j=0; j<$.jqplot.postSeriesInitHooks.length; j++) {
$.jqplot.postSeriesInitHooks[j].call(this.series[i], target, data, this.options.seriesDefaults, this.options.series[i]);
}
}
 
for (var name in this.axes) {
this.axes[name]._plotDimensions = this._plotDimensions;
this.axes[name].init();
}
if (this.sortData) {
sortData(this.series);
}
this.grid.init();
this.grid._axes = this.axes;
this.legend._series = this.series;
 
for (var i=0; i<$.jqplot.postInitHooks.length; i++) {
$.jqplot.postInitHooks[i].call(this, target, data, options);
}
};
// method: resetAxesScale
// Reset the specified axes min, max, numberTicks and tickInterval properties to null
// or reset these properties on all axes if no list of axes is provided.
//
// Parameters:
// axes - Boolean to reset or not reset all axes or an array or object of axis names to reset.
this.resetAxesScale = function(axes) {
var ax = (axes != undefined) ? axes : this.axes;
if (ax === true) {
ax = this.axes;
}
if (ax.constructor === Array) {
for (var i = 0; i < ax.length; i++) {
this.axes[ax[i]].resetScale();
}
}
else if (ax.constructor === Object) {
for (var name in ax) {
this.axes[name].resetScale();
}
}
};
// method: reInitialize
// reinitialize plot for replotting.
// not called directly.
this.reInitialize = function () {
// Plot should be visible and have a height and width.
// If plot doesn't have height and width for some
// reason, set it by other means. Plot must not have
// a display:none attribute, however.
if (!this.target.height()) {
var h;
if (options && options.height) {
h = parseInt(options.height, 10);
}
else if (this.target.attr('data-height')) {
h = parseInt(this.target.attr('data-height'), 10);
}
else {
h = parseInt($.jqplot.config.defaultHeight, 10);
}
this._height = h;
this.target.css('height', h+'px');
}
else {
this._height = this.target.height();
}
if (!this.target.width()) {
var w;
if (options && options.width) {
w = parseInt(options.width, 10);
}
else if (this.target.attr('data-width')) {
w = parseInt(this.target.attr('data-width'), 10);
}
else {
w = parseInt($.jqplot.config.defaultWidth, 10);
}
this._width = w;
this.target.css('width', w+'px');
}
else {
this._width = this.target.width();
}
if (this._height <=0 || this._width <=0 || !this._height || !this._width) {
throw "Target dimension not set";
}
this._plotDimensions.height = this._height;
this._plotDimensions.width = this._width;
this.grid._plotDimensions = this._plotDimensions;
this.title._plotDimensions = this._plotDimensions;
this.baseCanvas._plotDimensions = this._plotDimensions;
this.seriesCanvas._plotDimensions = this._plotDimensions;
this.eventCanvas._plotDimensions = this._plotDimensions;
this.legend._plotDimensions = this._plotDimensions;
for (var n in this.axes) {
var axis = this.axes[n];
axis._plotWidth = this._width;
axis._plotHeight = this._height;
}
this.title._plotWidth = this._width;
if (this.textColor) {
this.target.css('color', this.textColor);
}
if (this.fontFamily) {
this.target.css('font-family', this.fontFamily);
}
if (this.fontSize) {
this.target.css('font-size', this.fontSize);
}
for (var i=0; i<this.series.length; i++) {
this.populatePlotData(this.series[i], i);
this.series[i]._plotDimensions = this._plotDimensions;
//this.series[i].init(i, this.grid.borderWidth);
}
for (var name in this.axes) {
this.axes[name]._plotDimensions = this._plotDimensions;
this.axes[name]._ticks = [];
this.axes[name].renderer.init.call(this.axes[name], {});
}
if (this.sortData) {
sortData(this.series);
}
this.grid._axes = this.axes;
this.legend._series = this.series;
};
// sort the series data in increasing order.
function sortData(series) {
var d, ret;
for (var i=0; i<series.length; i++) {
d = series[i].data;
var check = true;
if (series[i]._stackAxis == 'x') {
for (var j = 0; j < d.length; j++) {
if (typeof(d[j][1]) != "number") {
check = false;
break;
}
}
if (check) {
d.sort(function(a,b) { return a[1] - b[1]; });
}
}
else {
for (var j = 0; j < d.length; j++) {
if (typeof(d[j][0]) != "number") {
check = false;
break;
}
}
if (check) {
d.sort(function(a,b) { return a[0] - b[0]; });
}
}
}
}
// populate the _stackData and _plotData arrays for the plot and the series.
this.populatePlotData = function(series, index) {
// if a stacked chart, compute the stacked data
this._plotData = [];
this._stackData = [];
series._stackData = [];
series._plotData = [];
var plotValues = {x:[], y:[]};
if (this.stackSeries && !series.disableStack) {
series._stack = true;
var sidx = series._stackAxis == 'x' ? 0 : 1;
var idx = sidx ? 0 : 1;
// push the current data into stackData
//this._stackData.push(this.series[i].data);
var temp = $.extend(true, [], series.data);
// create the data that will be plotted for this series
var plotdata = $.extend(true, [], series.data);
// for first series, nothing to add to stackData.
for (var j=0; j<index; j++) {
var cd = this.series[j].data;
for (var k=0; k<cd.length; k++) {
temp[k][0] += cd[k][0];
temp[k][1] += cd[k][1];
// only need to sum up the stack axis column of data
plotdata[k][sidx] += cd[k][sidx];
}
}
for (var i=0; i<plotdata.length; i++) {
plotValues.x.push(plotdata[i][0]);
plotValues.y.push(plotdata[i][1]);
}
this._plotData.push(plotdata);
this._stackData.push(temp);
series._stackData = temp;
series._plotData = plotdata;
series._plotValues = plotValues;
}
else {
for (var i=0; i<series.data.length; i++) {
plotValues.x.push(series.data[i][0]);
plotValues.y.push(series.data[i][1]);
}
this._stackData.push(series.data);
this.series[index]._stackData = series.data;
this._plotData.push(series.data);
series._plotData = series.data;
series._plotValues = plotValues;
}
if (index>0) {
series._prevPlotData = this.series[index-1]._plotData;
}
};
// function to safely return colors from the color array and wrap around at the end.
this.getNextSeriesColor = (function(t) {
var idx = 0;
var sc = t.seriesColors;
return function () {
if (idx < sc.length) {
return sc[idx++];
}
else {
idx = 0;
return sc[idx++];
}
};
})(this);
this.parseOptions = function(options){
for (var i=0; i<$.jqplot.preParseOptionsHooks.length; i++) {
$.jqplot.preParseOptionsHooks[i].call(this, options);
}
this.options = $.extend(true, {}, this.defaults, options);
this.stackSeries = this.options.stackSeries;
if (this.options.seriesColors) {
this.seriesColors = this.options.seriesColors;
}
var cg = new this.colorGenerator(this.seriesColors);
// this._gridPadding = this.options.gridPadding;
$.extend(true, this._gridPadding, this.options.gridPadding);
this.sortData = (this.options.sortData != null) ? this.options.sortData : this.sortData;
for (var n in this.axes) {
var axis = this.axes[n];
$.extend(true, axis, this.options.axesDefaults, this.options.axes[n]);
axis._plotWidth = this._width;
axis._plotHeight = this._height;
}
if (this.data.length == 0) {
this.data = [];
for (var i=0; i<this.options.series.length; i++) {
this.data.push(this.options.series.data);
}
}
var normalizeData = function(data) {
// return data as an array of point arrays,
// in form [[x1,y1...], [x2,y2...], ...]
var temp = [];
var i;
if (!(data[0] instanceof Array)) {
// we have a series of scalars. One line with just y values.
// turn the scalar list of data into a data array of form:
// [[1, data[0]], [2, data[1]], ...]
for (var i=0; i<data.length; i++) {
temp.push([i+1, data[i]]);
}
}
else {
// we have a properly formatted data series, copy it.
$.extend(true, temp, data);
}
return temp;
};
 
for (var i=0; i<this.data.length; i++) {
var temp = new Series();
for (var j=0; j<$.jqplot.preParseSeriesOptionsHooks.length; j++) {
$.jqplot.preParseSeriesOptionsHooks[j].call(temp, this.options.seriesDefaults, this.options.series[i]);
}
$.extend(true, temp, {seriesColors:this.seriesColors, negativeSeriesColors:this.negativeSeriesColors}, this.options.seriesDefaults, this.options.series[i]);
temp.data = normalizeData(this.data[i]);
switch (temp.xaxis) {
case 'xaxis':
temp._xaxis = this.axes.xaxis;
break;
case 'x2axis':
temp._xaxis = this.axes.x2axis;
break;
default:
break;
}
temp._yaxis = this.axes[temp.yaxis];
temp._xaxis._series.push(temp);
temp._yaxis._series.push(temp);
if (temp.show) {
temp._xaxis.show = true;
temp._yaxis.show = true;
}
 
// parse the renderer options and apply default colors if not provided
if (!temp.color && temp.show != false) {
temp.color = cg.next();
}
if (!temp.label) {
temp.label = 'Series '+ (i+1).toString();
}
// temp.rendererOptions.show = temp.show;
// $.extend(true, temp.renderer, {color:this.seriesColors[i]}, this.rendererOptions);
this.series.push(temp);
for (var j=0; j<$.jqplot.postParseSeriesOptionsHooks.length; j++) {
$.jqplot.postParseSeriesOptionsHooks[j].call(this.series[i], this.options.seriesDefaults, this.options.series[i]);
}
}
// copy the grid and title options into this object.
$.extend(true, this.grid, this.options.grid);
// if axis border properties aren't set, set default.
for (var n in this.axes) {
var axis = this.axes[n];
if (axis.borderWidth == null) {
axis.borderWidth =this.grid.borderWidth;
}
if (axis.borderColor == null) {
if (n != 'xaxis' && n != 'x2axis' && axis.useSeriesColor === true && axis.show) {
axis.borderColor = axis._series[0].color;
}
else {
axis.borderColor = this.grid.borderColor;
}
}
}
if (typeof this.options.title == 'string') {
this.title.text = this.options.title;
}
else if (typeof this.options.title == 'object') {
$.extend(true, this.title, this.options.title);
}
this.title._plotWidth = this._width;
$.extend(true, this.legend, this.options.legend);
for (var i=0; i<$.jqplot.postParseOptionsHooks.length; i++) {
$.jqplot.postParseOptionsHooks[i].call(this, options);
}
};
// method: replot
// Does a reinitialization of the plot followed by
// a redraw. Method could be used to interactively
// change plot characteristics and then replot.
//
// Parameters:
// options - Options used for replotting.
//
// Properties:
// clear - false to not clear (empty) the plot container before replotting (default: true).
// resetAxes - true to reset all axes min, max, numberTicks and tickInterval setting so axes will rescale themselves.
// optionally pass in list of axes to reset (e.g. ['xaxis', 'y2axis']) (default: false).
this.replot = function(options) {
var opts = (options != undefined) ? options : {};
var clear = (opts.clear != undefined) ? opts.clear : true;
var resetAxes = (opts.resetAxes != undefined) ? opts.resetAxes : false;
this.target.trigger('jqplotPreReplot');
if (clear) {
this.target.empty();
}
if (resetAxes) {
this.resetAxesScale(resetAxes);
}
this.reInitialize();
this.draw();
this.target.trigger('jqplotPostReplot');
};
// method: redraw
// Empties the plot target div and redraws the plot.
// This enables plot data and properties to be changed
// and then to comletely clear the plot and redraw.
// redraw *will not* reinitialize any plot elements.
// That is, axes will not be autoscaled and defaults
// will not be reapplied to any plot elements. redraw
// is used primarily with zooming.
//
// Parameters:
// clear - false to not clear (empty) the plot container before redrawing (default: true).
this.redraw = function(clear) {
clear = (clear != null) ? clear : true;
this.target.trigger('jqplotPreRedraw');
if (clear) {
this.target.empty();
}
for (var ax in this.axes) {
this.axes[ax]._ticks = [];
}
for (var i=0; i<this.series.length; i++) {
this.populatePlotData(this.series[i], i);
}
this.draw();
this.target.trigger('jqplotPostRedraw');
};
// method: draw
// Draws all elements of the plot into the container.
// Does not clear the container before drawing.
this.draw = function(){
if (this.drawIfHidden || this.target.is(':visible')) {
this.target.trigger('jqplotPreDraw');
for (var i=0; i<$.jqplot.preDrawHooks.length; i++) {
$.jqplot.preDrawHooks[i].call(this);
}
// create an underlying canvas to be used for special features.
this.target.append(this.baseCanvas.createElement({left:0, right:0, top:0, bottom:0}, 'jqplot-base-canvas'));
var bctx = this.baseCanvas.setContext();
this.target.append(this.title.draw());
this.title.pack({top:0, left:0});
for (var name in this.axes) {
this.target.append(this.axes[name].draw(bctx));
this.axes[name].set();
}
if (this.axes.yaxis.show) {
this._gridPadding.left = this.axes.yaxis.getWidth();
}
var ra = ['y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
var rapad = [0, 0, 0, 0];
var gpr = 0;
for (var n=8; n>0; n--) {
var ax = this.axes[ra[n-1]];
if (ax.show) {
rapad[n-1] = gpr;
gpr += ax.getWidth();
}
}
if (gpr > this._gridPadding.right) {
this._gridPadding.right = gpr;
}
if (this.title.show && this.axes.x2axis.show) {
this._gridPadding.top = this.title.getHeight() + this.axes.x2axis.getHeight();
}
else if (this.title.show) {
this._gridPadding.top = this.title.getHeight();
}
else if (this.axes.x2axis.show) {
this._gridPadding.top = this.axes.x2axis.getHeight();
}
if (this.axes.xaxis.show) {
this._gridPadding.bottom = this.axes.xaxis.getHeight();
}
this.axes.xaxis.pack({position:'absolute', bottom:0, left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right});
this.axes.yaxis.pack({position:'absolute', top:0, left:0, height:this._height}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
this.axes.x2axis.pack({position:'absolute', top:this.title.getHeight(), left:0, width:this._width}, {min:this._gridPadding.left, max:this._width - this._gridPadding.right});
for (var i=8; i>0; i--) {
this.axes[ra[i-1]].pack({position:'absolute', top:0, right:rapad[i-1]}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
}
// this.axes.y2axis.pack({position:'absolute', top:0, right:0}, {min:this._height - this._gridPadding.bottom, max: this._gridPadding.top});
this.target.append(this.grid.createElement(this._gridPadding));
this.grid.draw();
this.target.append(this.seriesCanvas.createElement(this._gridPadding, 'jqplot-series-canvas'));
var sctx = this.seriesCanvas.setContext();
this.target.append(this.eventCanvas.createElement(this._gridPadding, 'jqplot-event-canvas'));
var ectx = this.eventCanvas.setContext();
ectx.fillStyle = 'rgba(0,0,0,0)';
ectx.fillRect(0,0,ectx.canvas.width, ectx.canvas.height);
// bind custom event handlers to regular events.
this.bindCustomEvents();
// draw legend before series if the series needs to know the legend dimensions.
if (this.legend.preDraw) {
this.target.append(this.legend.draw());
this.legend.pack(this._gridPadding);
if (this.legend._elem) {
this.drawSeries(sctx, {legendInfo:{location:this.legend.location, width:this.legend.getWidth(), height:this.legend.getHeight(), xoffset:this.legend.xoffset, yoffset:this.legend.yoffset}});
}
else {
this.drawSeries(sctx);
}
}
else { // draw series before legend
this.drawSeries(sctx);
$(this.seriesCanvas._elem).after(this.legend.draw());
// this.target.append(this.legend.draw());
this.legend.pack(this._gridPadding);
}
// register event listeners on the overlay canvas
for (var i=0; i<$.jqplot.eventListenerHooks.length; i++) {
var h = $.jqplot.eventListenerHooks[i];
// in the handler, this will refer to the eventCanvas dom element.
// make sure there are references back into plot objects.
this.eventCanvas._elem.bind(h[0], {plot:this}, h[1]);
}
 
for (var i=0; i<$.jqplot.postDrawHooks.length; i++) {
$.jqplot.postDrawHooks[i].call(this);
}
if (this.target.is(':visible')) {
this._drawCount += 1;
}
this.target.trigger('jqplotPostDraw', [this]);
}
};
this.bindCustomEvents = function() {
this.eventCanvas._elem.bind('click', {plot:this}, this.onClick);
this.eventCanvas._elem.bind('dblclick', {plot:this}, this.onDblClick);
this.eventCanvas._elem.bind('mousedown', {plot:this}, this.onMouseDown);
this.eventCanvas._elem.bind('mouseup', {plot:this}, this.onMouseUp);
this.eventCanvas._elem.bind('mousemove', {plot:this}, this.onMouseMove);
this.eventCanvas._elem.bind('mouseenter', {plot:this}, this.onMouseEnter);
this.eventCanvas._elem.bind('mouseleave', {plot:this}, this.onMouseLeave);
};
function getEventPosition(ev) {
var plot = ev.data.plot;
// var xaxis = plot.axes.xaxis;
// var x2axis = plot.axes.x2axis;
// var yaxis = plot.axes.yaxis;
// var y2axis = plot.axes.y2axis;
var offsets = plot.eventCanvas._elem.offset();
var gridPos = {x:ev.pageX - offsets.left, y:ev.pageY - offsets.top};
// var dataPos = {x1y1:{x:null, y:null}, x1y2:{x:null, y:null}, x2y1:{x:null, y:null}, x2y2:{x:null, y:null}};
var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null};
var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
var ax = plot.axes;
for (var n=11; n>0; n--) {
var axis = an[n-1];
if (ax[axis].show) {
dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]);
}
}
 
return ({offsets:offsets, gridPos:gridPos, dataPos:dataPos});
}
function getNeighborPoint(plot, x, y) {
var ret = null;
var s, i, d0, d, j, r;
var threshold;
for (var i=0; i<plot.series.length; i++) {
s = plot.series[i];
r = s.renderer;
if (s.show) {
threshold = Math.abs(s.markerRenderer.size/2+s.neighborThreshold);
for (var j=0; j<s.gridData.length; j++) {
p = s.gridData[j];
// neighbor looks different to OHLC chart.
if (r.constructor == $.jqplot.OHLCRenderer) {
if (r.candleStick) {
var yp = s._yaxis.series_u2p;
if (x >= p[0]-r._bodyWidth/2 && x <= p[0]+r._bodyWidth/2 && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
}
}
// if an open hi low close chart
else if (!r.hlc){
var yp = s._yaxis.series_u2p;
if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][2]) && y <= yp(s.data[j][3])) {
ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
}
}
// a hi low close chart
else {
var yp = s._yaxis.series_u2p;
if (x >= p[0]-r._tickLength && x <= p[0]+r._tickLength && y >= yp(s.data[j][1]) && y <= yp(s.data[j][2])) {
ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
}
}
}
else {
d = Math.sqrt( (x-p[0]) * (x-p[0]) + (y-p[1]) * (y-p[1]) );
if (d <= threshold && (d <= d0 || d0 == null)) {
d0 = d;
ret = {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]};
}
}
}
}
}
return ret;
}
this.onClick = function(ev) {
// Event passed in is unnormalized and will have data attribute.
// Event passed out in normalized and won't have data attribute.
var positions = getEventPosition(ev);
var p = ev.data.plot;
var neighbor = getNeighborPoint(p, positions.gridPos.x, positions.gridPos.y);
ev.data.plot.eventCanvas._elem.trigger('jqplotClick', [positions.gridPos, positions.dataPos, neighbor, p]);
};
this.onDblClick = function(ev) {
// Event passed in is unnormalized and will have data attribute.
// Event passed out in normalized and won't have data attribute.
var positions = getEventPosition(ev);
var p = ev.data.plot;
var neighbor = getNeighborPoint(p, positions.gridPos.x, positions.gridPos.y);
ev.data.plot.eventCanvas._elem.trigger('jqplotDblClick', [positions.gridPos, positions.dataPos, neighbor, p]);
};
this.onMouseDown = function(ev) {
var positions = getEventPosition(ev);
var p = ev.data.plot;
var neighbor = getNeighborPoint(p, positions.gridPos.x, positions.gridPos.y);
ev.data.plot.eventCanvas._elem.trigger('jqplotMouseDown', [positions.gridPos, positions.dataPos, neighbor, p]);
};
this.onMouseUp = function(ev) {
var positions = getEventPosition(ev);
ev.data.plot.eventCanvas._elem.trigger('jqplotMouseUp', [positions.gridPos, positions.dataPos, null, ev.data.plot]);
};
this.onMouseMove = function(ev) {
var positions = getEventPosition(ev);
var p = ev.data.plot;
var neighbor = getNeighborPoint(p, positions.gridPos.x, positions.gridPos.y);
ev.data.plot.eventCanvas._elem.trigger('jqplotMouseMove', [positions.gridPos, positions.dataPos, neighbor, p]);
};
this.onMouseEnter = function(ev) {
var positions = getEventPosition(ev);
var p = ev.data.plot;
ev.data.plot.eventCanvas._elem.trigger('jqplotMouseEnter', [positions.gridPos, positions.dataPos, null, p]);
};
this.onMouseLeave = function(ev) {
var positions = getEventPosition(ev);
var p = ev.data.plot;
ev.data.plot.eventCanvas._elem.trigger('jqplotMouseLeave', [positions.gridPos, positions.dataPos, null, p]);
};
this.drawSeries = function(sctx, options){
// first clear the canvas, since we are redrawing all series.
sctx.clearRect(0,0,sctx.canvas.width, sctx.canvas.height);
// if call series drawShadow method first, in case all series shadows
// should be drawn before any series. This will ensure, like for
// stacked bar plots, that shadows don't overlap series.
for (var i=0; i<this.series.length; i++) {
this.series[i].drawShadow(sctx, options);
}
for (var i=0; i<this.series.length; i++) {
this.series[i].draw(sctx, options);
}
};
}
$.jqplot.ColorGenerator = function(colors) {
var idx = 0;
this.next = function () {
if (idx < colors.length) {
return colors[idx++];
}
else {
idx = 0;
return colors[idx++];
}
};
this.previous = function () {
if (idx > 0) {
return colors[idx--];
}
else {
idx = colors.length-1;
return colors[idx];
}
};
// get a color by index without advancing pointer.
this.get = function(i) {
return colors[i];
};
this.setColors = function(c) {
colors = c;
};
this.reset = function() {
idx = 0;
};
};
 
// convert a hex color string to rgb string.
// h - 3 or 6 character hex string, with or without leading #
// a - optional alpha
$.jqplot.hex2rgb = function(h, a) {
h = h.replace('#', '');
if (h.length == 3) {
h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2];
}
var rgb;
rgb = 'rgba('+parseInt(h.slice(0,2), 16)+', '+parseInt(h.slice(2,4), 16)+', '+parseInt(h.slice(4,6), 16);
if (a) {
rgb += ', '+a;
}
rgb += ')';
return rgb;
};
// convert an rgb color spec to a hex spec. ignore any alpha specification.
$.jqplot.rgb2hex = function(s) {
var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *(?:, *[0-9.]*)?\)/;
var m = s.match(pat);
var h = '#';
for (i=1; i<4; i++) {
var temp;
if (m[i].search(/%/) != -1) {
temp = parseInt(255*m[i]/100, 10).toString(16);
if (temp.length == 1) {
temp = '0'+temp;
}
}
else {
temp = parseInt(m[i], 10).toString(16);
if (temp.length == 1) {
temp = '0'+temp;
}
}
h += temp;
}
return h;
};
// given a css color spec, return an rgb css color spec
$.jqplot.normalize2rgb = function(s, a) {
if (s.search(/^ *rgba?\(/) != -1) {
return s;
}
else if (s.search(/^ *#?[0-9a-fA-F]?[0-9a-fA-F]/) != -1) {
return $.jqplot.hex2rgb(s, a);
}
else {
throw 'invalid color spec';
}
};
// extract the r, g, b, a color components out of a css color spec.
$.jqplot.getColorComponents = function(s) {
var rgb = $.jqplot.normalize2rgb(s);
var pat = /rgba?\( *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *, *([0-9]{1,3}\.?[0-9]*%?) *,? *([0-9.]* *)?\)/;
var m = rgb.match(pat);
var ret = [];
for (i=1; i<4; i++) {
if (m[i].search(/%/) != -1) {
ret[i-1] = parseInt(255*m[i]/100, 10);
}
else {
ret[i-1] = parseInt(m[i], 10);
}
}
ret[3] = parseFloat(m[4]) ? parseFloat(m[4]) : 1.0;
return ret;
};
// Convienence function that won't hang IE.
$.jqplot.log = function() {
if (window.console && $.jqplot.debug) {
if (arguments.length == 1) {
console.log (arguments[0]);
}
else {
console.log(arguments);
}
}
};
var log = $.jqplot.log;
 
// class: $.jqplot.AxisLabelRenderer
// Renderer to place labels on the axes.
$.jqplot.AxisLabelRenderer = function(options) {
// Group: Properties
$.jqplot.ElemContainer.call(this);
// name of the axis associated with this tick
this.axis;
// prop: show
// wether or not to show the tick (mark and label).
this.show = true;
// prop: label
// The text or html for the label.
this.label = '';
this._elem;
// prop: escapeHTML
// true to escape HTML entities in the label.
this.escapeHTML = false;
$.extend(true, this, options);
};
$.jqplot.AxisLabelRenderer.prototype = new $.jqplot.ElemContainer();
$.jqplot.AxisLabelRenderer.prototype.constructor = $.jqplot.AxisLabelRenderer;
$.jqplot.AxisLabelRenderer.prototype.init = function(options) {
$.extend(true, this, options);
};
$.jqplot.AxisLabelRenderer.prototype.draw = function() {
this._elem = $('<div style="position:absolute;" class="jqplot-'+this.axis+'-label"></div>');
if (Number(this.label)) {
this._elem.css('white-space', 'nowrap');
}
if (!this.escapeHTML) {
this._elem.html(this.label);
}
else {
this._elem.text(this.label);
}
return this._elem;
};
$.jqplot.AxisLabelRenderer.prototype.pack = function() {
};
 
// class: $.jqplot.AxisTickRenderer
// A "tick" object showing the value of a tick/gridline on the plot.
$.jqplot.AxisTickRenderer = function(options) {
// Group: Properties
$.jqplot.ElemContainer.call(this);
// prop: mark
// tick mark on the axis. One of 'inside', 'outside', 'cross', '' or null.
this.mark = 'outside';
// name of the axis associated with this tick
this.axis;
// prop: showMark
// wether or not to show the mark on the axis.
this.showMark = true;
// prop: showGridline
// wether or not to draw the gridline on the grid at this tick.
this.showGridline = true;
// prop: isMinorTick
// if this is a minor tick.
this.isMinorTick = false;
// prop: size
// Length of the tick beyond the grid in pixels.
// DEPRECATED: This has been superceeded by markSize
this.size = 4;
// prop: markSize
// Length of the tick marks in pixels. For 'cross' style, length
// will be stoked above and below axis, so total length will be twice this.
this.markSize = 6;
// prop: show
// wether or not to show the tick (mark and label).
// Setting this to false requires more testing. It is recommended
// to set showLabel and showMark to false instead.
this.show = true;
// prop: showLabel
// wether or not to show the label.
this.showLabel = true;
this.label = '';
this.value = null;
this._styles = {};
// prop: formatter
// A class of a formatter for the tick text. sprintf by default.
this.formatter = $.jqplot.DefaultTickFormatter;
// prop: formatString
// string passed to the formatter.
this.formatString = '';
// prop: fontFamily
// css spec for the font-family css attribute.
this.fontFamily;
// prop: fontSize
// css spec for the font-size css attribute.
this.fontSize;
// prop: textColor
// css spec for the color attribute.
this.textColor;
this._elem;
$.extend(true, this, options);
};
$.jqplot.AxisTickRenderer.prototype.init = function(options) {
$.extend(true, this, options);
};
$.jqplot.AxisTickRenderer.prototype = new $.jqplot.ElemContainer();
$.jqplot.AxisTickRenderer.prototype.constructor = $.jqplot.AxisTickRenderer;
$.jqplot.AxisTickRenderer.prototype.setTick = function(value, axisName, isMinor) {
this.value = value;
this.axis = axisName;
if (isMinor) {
this.isMinorTick = true;
}
return this;
};
$.jqplot.AxisTickRenderer.prototype.draw = function() {
if (!this.label) {
this.label = this.formatter(this.formatString, this.value);
}
style ='style="position:absolute;';
if (Number(this.label)) {
style +='white-space:nowrap;';
}
style += '"';
this._elem = $('<div '+style+' class="jqplot-'+this.axis+'-tick">'+this.label+'</div>');
for (var s in this._styles) {
this._elem.css(s, this._styles[s]);
}
if (this.fontFamily) {
this._elem.css('font-family', this.fontFamily);
}
if (this.fontSize) {
this._elem.css('font-size', this.fontSize);
}
if (this.textColor) {
this._elem.css('color', this.textColor);
}
return this._elem;
};
$.jqplot.DefaultTickFormatter = function (format, val) {
if (typeof val == 'number') {
if (!format) {
format = '%.1f';
}
return $.jqplot.sprintf(format, val);
}
else {
return String(val);
}
};
$.jqplot.AxisTickRenderer.prototype.pack = function() {
};
// Class: $.jqplot.CanvasGridRenderer
// The default jqPlot grid renderer, creating a grid on a canvas element.
// The renderer has no additional options beyond the <Grid> class.
$.jqplot.CanvasGridRenderer = function(){
this.shadowRenderer = new $.jqplot.ShadowRenderer();
};
// called with context of Grid object
$.jqplot.CanvasGridRenderer.prototype.init = function(options) {
this._ctx;
$.extend(true, this, options);
// set the shadow renderer options
var sopts = {lineJoin:'miter', lineCap:'round', fill:false, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.shadowWidth, closePath:false};
this.renderer.shadowRenderer.init(sopts);
};
// called with context of Grid.
$.jqplot.CanvasGridRenderer.prototype.createElement = function() {
var elem = document.createElement('canvas');
var w = this._plotDimensions.width;
var h = this._plotDimensions.height;
elem.width = w;
elem.height = h;
this._elem = $(elem);
this._elem.addClass('jqplot-grid-canvas');
this._elem.css({ position: 'absolute', left: 0, top: 0 });
if ($.browser.msie) {
window.G_vmlCanvasManager.init_(document);
}
if ($.browser.msie) {
elem = window.G_vmlCanvasManager.initElement(elem);
}
this._top = this._offsets.top;
this._bottom = h - this._offsets.bottom;
this._left = this._offsets.left;
this._right = w - this._offsets.right;
this._width = this._right - this._left;
this._height = this._bottom - this._top;
return this._elem;
};
$.jqplot.CanvasGridRenderer.prototype.draw = function() {
this._ctx = this._elem.get(0).getContext("2d");
var ctx = this._ctx;
var axes = this._axes;
// Add the grid onto the grid canvas. This is the bottom most layer.
ctx.save();
ctx.fillStyle = this.background;
ctx.fillRect(this._left, this._top, this._width, this._height);
if (this.drawGridlines) {
ctx.save();
ctx.lineJoin = 'miter';
ctx.lineCap = 'butt';
ctx.lineWidth = this.gridLineWidth;
ctx.strokeStyle = this.gridLineColor;
var b, e;
var ax = ['xaxis', 'yaxis', 'x2axis', 'y2axis'];
for (var i=4; i>0; i--) {
var name = ax[i-1];
var axis = axes[name];
var ticks = axis._ticks;
if (axis.show) {
for (var j=ticks.length; j>0; j--) {
var t = ticks[j-1];
if (t.show) {
var pos = Math.round(axis.u2p(t.value)) + 0.5;
switch (name) {
case 'xaxis':
// draw the grid line
if (t.showGridline) {
drawLine(pos, this._top, pos, this._bottom);
}
// draw the mark
if (t.showMark && t.mark) {
s = t.markSize;
m = t.mark;
var pos = Math.round(axis.u2p(t.value)) + 0.5;
switch (m) {
case 'outside':
b = this._bottom;
e = this._bottom+s;
break;
case 'inside':
b = this._bottom-s;
e = this._bottom;
break;
case 'cross':
b = this._bottom-s;
e = this._bottom+s;
break;
default:
b = this._bottom;
e = this._bottom+s;
break;
}
// draw the shadow
if (this.shadow) {
this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
}
// draw the line
drawLine(pos, b, pos, e);
}
break;
case 'yaxis':
// draw the grid line
if (t.showGridline) {
drawLine(this._right, pos, this._left, pos);
}
// draw the mark
if (t.showMark && t.mark) {
s = t.markSize;
m = t.mark;
var pos = Math.round(axis.u2p(t.value)) + 0.5;
switch (m) {
case 'outside':
b = this._left-s;
e = this._left;
break;
case 'inside':
b = this._left;
e = this._left+s;
break;
case 'cross':
b = this._left-s;
e = this._left+s;
break;
default:
b = this._left-s;
e = this._left;
break;
}
// draw the shadow
if (this.shadow) {
this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
}
drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
}
break;
case 'x2axis':
// draw the grid line
if (t.showGridline) {
drawLine(pos, this._bottom, pos, this._top);
}
// draw the mark
if (t.showMark && t.mark) {
s = t.markSize;
m = t.mark;
var pos = Math.round(axis.u2p(t.value)) + 0.5;
switch (m) {
case 'outside':
b = this._top-s;
e = this._top;
break;
case 'inside':
b = this._top;
e = this._top+s;
break;
case 'cross':
b = this._top-s;
e = this._top+s;
break;
default:
b = this._top-s;
e = this._top;
break;
}
// draw the shadow
if (this.shadow) {
this.renderer.shadowRenderer.draw(ctx, [[pos,b],[pos,e]], {lineCap:'butt', lineWidth:this.gridLineWidth, offset:this.gridLineWidth*0.75, depth:2, fill:false, closePath:false});
}
drawLine(pos, b, pos, e);
}
break;
case 'y2axis':
// draw the grid line
if (t.showGridline) {
drawLine(this._left, pos, this._right, pos);
}
// draw the mark
if (t.showMark && t.mark) {
s = t.markSize;
m = t.mark;
var pos = Math.round(axis.u2p(t.value)) + 0.5;
switch (m) {
case 'outside':
b = this._right;
e = this._right+s;
break;
case 'inside':
b = this._right-s;
e = this._right;
break;
case 'cross':
b = this._right-s;
e = this._right+s;
break;
default:
b = this._right;
e = this._right+s;
break;
}
// draw the shadow
if (this.shadow) {
this.renderer.shadowRenderer.draw(ctx, [[b, pos], [e, pos]], {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
}
drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
}
break;
default:
break;
}
}
}
}
}
// Now draw grid lines for additional y axes
ax = ['y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis'];
for (var i=7; i>0; i--) {
var axis = axes[ax[i-1]];
var ticks = axis._ticks;
if (axis.show) {
var tn = ticks[axis.numberTicks-1];
var t0 = ticks[0];
var left = axis.getLeft();
var points = [[left, tn.getTop() + tn.getHeight()/2], [left, t0.getTop() + t0.getHeight()/2 + 1.0]];
// draw the shadow
if (this.shadow) {
this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', fill:false, closePath:false});
}
// draw the line
drawLine(points[0][0], points[0][1], points[1][0], points[1][1], {lineCap:'butt', strokeStyle:axis.borderColor, lineWidth:axis.borderWidth});
// draw the tick marks
for (var j=ticks.length; j>0; j--) {
var t = ticks[j-1];
s = t.markSize;
m = t.mark;
var pos = Math.round(axis.u2p(t.value)) + 0.5;
if (t.showMark && t.mark) {
switch (m) {
case 'outside':
b = left;
e = left+s;
break;
case 'inside':
b = left-s;
e = left;
break;
case 'cross':
b = left-s;
e = left+s;
break;
default:
b = left;
e = left+s;
break;
}
points = [[b,pos], [e,pos]];
// draw the shadow
if (this.shadow) {
this.renderer.shadowRenderer.draw(ctx, points, {lineCap:'butt', lineWidth:this.gridLineWidth*1.5, offset:this.gridLineWidth*0.75, fill:false, closePath:false});
}
// draw the line
drawLine(b, pos, e, pos, {strokeStyle:axis.borderColor});
}
}
}
}
ctx.restore();
}
function drawLine(bx, by, ex, ey, opts) {
ctx.save();
opts = opts || {};
$.extend(true, ctx, opts);
ctx.beginPath();
ctx.moveTo(bx, by);
ctx.lineTo(ex, ey);
ctx.stroke();
ctx.restore();
}
if (this.shadow) {
var points = [[this._left, this._bottom], [this._right, this._bottom], [this._right, this._top]];
this.renderer.shadowRenderer.draw(ctx, points);
}
// Now draw border around grid. Use axis border definitions. start at
// upper left and go clockwise.
drawLine (this._left, this._top, this._right, this._top, {lineCap:'round', strokeStyle:axes.x2axis.borderColor, lineWidth:axes.x2axis.borderWidth});
drawLine (this._right, this._top, this._right, this._bottom, {lineCap:'round', strokeStyle:axes.y2axis.borderColor, lineWidth:axes.y2axis.borderWidth});
drawLine (this._right, this._bottom, this._left, this._bottom, {lineCap:'round', strokeStyle:axes.xaxis.borderColor, lineWidth:axes.xaxis.borderWidth});
drawLine (this._left, this._bottom, this._left, this._top, {lineCap:'round', strokeStyle:axes.yaxis.borderColor, lineWidth:axes.yaxis.borderWidth});
// ctx.lineWidth = this.borderWidth;
// ctx.strokeStyle = this.borderColor;
// ctx.strokeRect(this._left, this._top, this._width, this._height);
ctx.restore();
};
// Class: $.jqplot.DivTitleRenderer
// The default title renderer for jqPlot. This class has no options beyond the <Title> class.
$.jqplot.DivTitleRenderer = function() {
};
$.jqplot.DivTitleRenderer.prototype.init = function(options) {
$.extend(true, this, options);
};
$.jqplot.DivTitleRenderer.prototype.draw = function() {
var r = this.renderer;
if (!this.text) {
this.show = false;
this._elem = $('<div style="height:0px;width:0px;"></div>');
}
else if (this.text) {
// don't trust that a stylesheet is present, set the position.
var styletext = 'position:absolute;top:0px;left:0px;';
styletext += (this._plotWidth) ? 'width:'+this._plotWidth+'px;' : '';
styletext += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
styletext += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
styletext += (this.textAlign) ? 'text-align:'+this.textAlign+';' : 'text-align:center;';
styletext += (this.textColor) ? 'color:'+this.textColor+';' : '';
this._elem = $('<div class="jqplot-title" style="'+styletext+'">'+this.text+'</div>');
}
return this._elem;
};
$.jqplot.DivTitleRenderer.prototype.pack = function() {
// nothing to do here
};
// Class: $.jqplot.LineRenderer
// The default line renderer for jqPlot, this class has no options beyond the <Series> class.
// Draws series as a line.
$.jqplot.LineRenderer = function(){
this.shapeRenderer = new $.jqplot.ShapeRenderer();
this.shadowRenderer = new $.jqplot.ShadowRenderer();
};
// called with scope of series.
$.jqplot.LineRenderer.prototype.init = function(options) {
$.extend(true, this.renderer, options);
// set the shape renderer options
var opts = {lineJoin:'round', lineCap:'round', fill:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.fillColor, lineWidth:this.lineWidth, closePath:this.fill};
this.renderer.shapeRenderer.init(opts);
// set the shadow renderer options
// scale the shadowOffset to the width of the line.
if (this.lineWidth > 2.5) {
var shadow_offset = this.shadowOffset* (1 + (Math.atan((this.lineWidth/2.5))/0.785398163 - 1)*0.6);
// var shadow_offset = this.shadowOffset;
}
// for skinny lines, don't make such a big shadow.
else {
var shadow_offset = this.shadowOffset*Math.atan((this.lineWidth/2.5))/0.785398163;
}
var sopts = {lineJoin:'round', lineCap:'round', fill:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.lineWidth, closePath:this.fill};
this.renderer.shadowRenderer.init(sopts);
};
// Method: setGridData
// converts the user data values to grid coordinates and stores them
// in the gridData array.
// Called with scope of a series.
$.jqplot.LineRenderer.prototype.setGridData = function() {
// recalculate the grid data
var xp = this._xaxis.series_u2p;
var yp = this._yaxis.series_u2p;
var data = this._plotData;
var pdata = this._prevPlotData;
this.gridData = [];
this._prevGridData = [];
for (var i=0; i<this.data.length; i++) {
if (data[i] != null) {
this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]);
}
if (pdata[i] != null) {
this._prevGridData.push([xp.call(this._xaxis, pdata[i][0]), yp.call(this._yaxis, pdata[i][1])]);
}
}
};
// Method: makeGridData
// converts any arbitrary data values to grid coordinates and
// returns them. This method exists so that plugins can use a series'
// linerenderer to generate grid data points without overwriting the
// grid data associated with that series.
// Called with scope of a series.
$.jqplot.LineRenderer.prototype.makeGridData = function(data) {
// recalculate the grid data
var xp = this._xaxis.series_u2p;
var yp = this._yaxis.series_u2p;
var gd = [];
var pgd = [];
for (var i=0; i<data.length; i++) {
if (data[i] != null) {
gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1])]);
}
}
return gd;
};
 
// called within scope of series.
$.jqplot.LineRenderer.prototype.draw = function(ctx, gd, options) {
var i;
var opts = (options != undefined) ? options : {};
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
var fill = (opts.fill != undefined) ? opts.fill : this.fill;
var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke;
ctx.save();
if (gd.length) {
if (showLine) {
// if we fill, we'll have to add points to close the curve.
if (fill) {
if (this.fillToZero) {
// have to break line up into shapes at axis crossings
var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
var negativeColor = negativeColors.get(this.index);
var isnegative = false;
var posfs = opts.fillStyle;
// if stoking line as well as filling, get a copy of line data.
if (fillAndStroke) {
var fasgd = gd.slice(0);
}
// if not stacked, fill down to axis
if (this.index == 0 || !this._stack) {
var tempgd = [];
var pyzero = this._yaxis.series_u2p(0);
var pxzero = this._xaxis.series_u2p(0);
if (this.fillAxis == 'y') {
tempgd.push([gd[0][0], pyzero]);
for (var i=0; i<gd.length-1; i++) {
tempgd.push(gd[i]);
// do we have an axis crossing?
if (this._plotData[i][1] * this._plotData[i+1][1] < 0) {
if (this._plotData[i][1] < 0) {
isnegative = true;
opts.fillStyle = negativeColor;
}
else {
isnegative = false;
opts.fillStyle = posfs;
}
var xintercept = gd[i][0] + (gd[i+1][0] - gd[i][0]) * (pyzero-gd[i][1])/(gd[i+1][1] - gd[i][1]);
tempgd.push([xintercept, pyzero]);
// now draw this shape and shadow.
if (shadow) {
this.renderer.shadowRenderer.draw(ctx, tempgd, opts);
}
this.renderer.shapeRenderer.draw(ctx, tempgd, opts);
// now empty temp array and continue
tempgd = [[xintercept, pyzero]];
}
}
if (this._plotData[gd.length-1][1] < 0) {
isnegative = true;
opts.fillStyle = negativeColor;
}
else {
isnegative = false;
opts.fillStyle = posfs;
}
tempgd.push(gd[gd.length-1]);
tempgd.push([gd[gd.length-1][0], pyzero]);
}
// now draw this shape and shadow.
if (shadow) {
this.renderer.shadowRenderer.draw(ctx, tempgd, opts);
}
this.renderer.shapeRenderer.draw(ctx, tempgd, opts);
// var gridymin = this._yaxis.series_u2p(0);
// // IE doesn't return new length on unshift
// gd.unshift([gd[0][0], gridymin]);
// len = gd.length;
// gd.push([gd[len - 1][0], gridymin]);
}
// if stacked, fill to line below
else {
var prev = this._prevGridData;
for (var i=prev.length; i>0; i--) {
gd.push(prev[i-1]);
}
if (shadow) {
this.renderer.shadowRenderer.draw(ctx, gd, opts);
}
this.renderer.shapeRenderer.draw(ctx, gd, opts);
}
}
else {
// if stoking line as well as filling, get a copy of line data.
if (fillAndStroke) {
var fasgd = gd.slice(0);
}
// if not stacked, fill down to axis
if (this.index == 0 || !this._stack) {
// var gridymin = this._yaxis.series_u2p(this._yaxis.min) - this.gridBorderWidth / 2;
var gridymin = ctx.canvas.height;
// IE doesn't return new length on unshift
gd.unshift([gd[0][0], gridymin]);
len = gd.length;
gd.push([gd[len - 1][0], gridymin]);
}
// if stacked, fill to line below
else {
var prev = this._prevGridData;
for (var i=prev.length; i>0; i--) {
gd.push(prev[i-1]);
}
}
if (shadow) {
this.renderer.shadowRenderer.draw(ctx, gd, opts);
}
this.renderer.shapeRenderer.draw(ctx, gd, opts);
}
if (fillAndStroke) {
var fasopts = $.extend(true, {}, opts, {fill:false, closePath:false});
this.renderer.shapeRenderer.draw(ctx, fasgd, fasopts);
//////////
// TODO: figure out some way to do shadows nicely
// if (shadow) {
// this.renderer.shadowRenderer.draw(ctx, fasgd, fasopts);
// }
// now draw the markers
if (this.markerRenderer.show) {
for (i=0; i<fasgd.length; i++) {
this.markerRenderer.draw(fasgd[i][0], fasgd[i][1], ctx, opts.markerOptions);
}
}
}
}
else {
if (shadow) {
this.renderer.shadowRenderer.draw(ctx, gd, opts);
}
this.renderer.shapeRenderer.draw(ctx, gd, opts);
}
}
// now draw the markers
if (this.markerRenderer.show && !fill) {
for (i=0; i<gd.length; i++) {
this.markerRenderer.draw(gd[i][0], gd[i][1], ctx, opts.markerOptions);
}
}
}
ctx.restore();
};
$.jqplot.LineRenderer.prototype.drawShadow = function(ctx, gd, options) {
// This is a no-op, shadows drawn with lines.
};
// class: $.jqplot.LinearAxisRenderer
// The default jqPlot axis renderer, creating a numeric axis.
// The renderer has no additional options beyond the <Axis> object.
$.jqplot.LinearAxisRenderer = function() {
};
// called with scope of axis object.
$.jqplot.LinearAxisRenderer.prototype.init = function(options){
$.extend(true, this, options);
var db = this._dataBounds;
// Go through all the series attached to this axis and find
// the min/max bounds for this axis.
for (var i=0; i<this._series.length; i++) {
var s = this._series[i];
var d = s._plotData;
for (var j=0; j<d.length; j++) {
if (this.name == 'xaxis' || this.name == 'x2axis') {
if (d[j][0] < db.min || db.min == null) {
db.min = d[j][0];
}
if (d[j][0] > db.max || db.max == null) {
db.max = d[j][0];
}
}
else {
if (d[j][1] < db.min || db.min == null) {
db.min = d[j][1];
}
if (d[j][1] > db.max || db.max == null) {
db.max = d[j][1];
}
}
}
}
};
// called with scope of axis
$.jqplot.LinearAxisRenderer.prototype.draw = function(ctx) {
if (this.show) {
// populate the axis label and value properties.
// createTicks is a method on the renderer, but
// call it within the scope of the axis.
this.renderer.createTicks.call(this);
// fill a div with axes labels in the right direction.
// Need to pregenerate each axis to get it's bounds and
// position it and the labels correctly on the plot.
var dim=0;
var temp;
this._elem = $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>');
if (this.name == 'xaxis' || this.name == 'x2axis') {
this._elem.width(this._plotDimensions.width);
}
else {
this._elem.height(this._plotDimensions.height);
}
// create a _label object.
this.labelOptions.axis = this.name;
this._label = new this.labelRenderer(this.labelOptions);
if (this._label.show) {
var elem = this._label.draw(ctx);
elem.appendTo(this._elem);
}
if (this.showTicks) {
var t = this._ticks;
for (var i=0; i<t.length; i++) {
var tick = t[i];
if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
var elem = tick.draw(ctx);
elem.appendTo(this._elem);
}
}
}
}
return this._elem;
};
// called with scope of an axis
$.jqplot.LinearAxisRenderer.prototype.reset = function() {
this.min = this._min;
this.max = this._max;
this.tickInterval = this._tickInterval;
this.numberTicks = this._numberTicks;
// this._ticks = this.__ticks;
};
// called with scope of axis
$.jqplot.LinearAxisRenderer.prototype.set = function() {
var dim = 0;
var temp;
var w = 0;
var h = 0;
var lshow = (this._label == null) ? false : this._label.show;
if (this.show && this.showTicks) {
var t = this._ticks;
for (var i=0; i<t.length; i++) {
var tick = t[i];
if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {
if (this.name == 'xaxis' || this.name == 'x2axis') {
temp = tick._elem.outerHeight(true);
}
else {
temp = tick._elem.outerWidth(true);
}
if (temp > dim) {
dim = temp;
}
}
}
if (lshow) {
w = this._label._elem.outerWidth(true);
h = this._label._elem.outerHeight(true);
}
if (this.name == 'xaxis') {
dim = dim + h;
this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});
}
else if (this.name == 'x2axis') {
dim = dim + h;
this._elem.css({'height':dim+'px', left:'0px', top:'0px'});
}
else if (this.name == 'yaxis') {
dim = dim + w;
this._elem.css({'width':dim+'px', left:'0px', top:'0px'});
if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
this._label._elem.css('width', w+'px');
}
}
else {
dim = dim + w;
this._elem.css({'width':dim+'px', right:'0px', top:'0px'});
if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {
this._label._elem.css('width', w+'px');
}
}
}
};
// called with scope of axis
$.jqplot.LinearAxisRenderer.prototype.createTicks = function() {
// we're are operating on an axis here
var ticks = this._ticks;
var userTicks = this.ticks;
var name = this.name;
// databounds were set on axis initialization.
var db = this._dataBounds;
var dim, interval;
var min, max;
var pos1, pos2;
var tt, i;
// if we already have ticks, use them.
// ticks must be in order of increasing value.
if (userTicks.length) {
// ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
for (i=0; i<userTicks.length; i++){
var ut = userTicks[i];
var t = new this.tickRenderer(this.tickOptions);
if (ut.constructor == Array) {
t.value = ut[0];
t.label = ut[1];
if (!this.showTicks) {
t.showLabel = false;
t.showMark = false;
}
else if (!this.showTickMarks) {
t.showMark = false;
}
t.setTick(ut[0], this.name);
this._ticks.push(t);
}
else {
t.value = ut;
if (!this.showTicks) {
t.showLabel = false;
t.showMark = false;
}
else if (!this.showTickMarks) {
t.showMark = false;
}
t.setTick(ut, this.name);
this._ticks.push(t);
}
}
this.numberTicks = userTicks.length;
this.min = this._ticks[0].value;
this.max = this._ticks[this.numberTicks-1].value;
this.tickInterval = (this.max - this.min) / (this.numberTicks - 1);
}
// we don't have any ticks yet, let's make some!
else {
if (name == 'xaxis' || name == 'x2axis') {
dim = this._plotDimensions.width;
}
else {
dim = this._plotDimensions.height;
}
// if min, max and number of ticks specified, user can't specify interval.
if (!this.autoscale && this.min != null && this.max != null && this.numberTicks != null) {
this.tickInterval = null;
}
// if max, min, and interval specified and interval won't fit, ignore interval.
// if (this.min != null && this.max != null && this.tickInterval != null) {
// if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) {
// this.tickInterval = null;
// }
// }
min = ((this.min != null) ? this.min : db.min);
max = ((this.max != null) ? this.max : db.max);
// if min and max are same, space them out a bit
if (min == max) {
var adj = 0.05;
if (min > 0) {
adj = Math.max(Math.log(min)/Math.LN10, 0.05);
}
min -= adj;
max += adj;
}
 
var range = max - min;
var rmin, rmax;
var temp;
// autoscale. Can't autoscale if min or max is supplied.
// Will use numberTicks and tickInterval if supplied. Ticks
// across multiple axes may not line up depending on how
// bars are to be plotted.
if (this.autoscale && this.min == null && this.max == null) {
var rrange, ti, margin;
var forceMinZero = false;
var forceZeroLine = false;
var intervals = {min:null, max:null, average:null, stddev:null};
// if any series are bars, or if any are fill to zero, and if this
// is the axis to fill toward, check to see if we can start axis at zero.
for (var i=0; i<this._series.length; i++) {
var s = this._series[i];
var faname = (s.fillAxis == 'x') ? s._xaxis.name : s._yaxis.name;
// check to see if this is the fill axis
if (this.name == faname) {
var vals = s._plotValues[s.fillAxis];
var vmin = vals[0];
var vmax = vals[0];
for (var j=1; j<vals.length; j++) {
if (vals[j] < vmin) {
vmin = vals[j];
}
else if (vals[j] > vmax) {
vmax = vals[j];
}
}
var dp = (vmax - vmin) / vmax;
// is this sries a bar?
if (s.renderer.constructor == $.jqplot.BarRenderer) {
// if no negative values and could also check range.
if (vmin >= 0 && (s.fillToZero || dp > 0.1)) {
forceMinZero = true;
}
else {
forceMinZero = false;
if (s.fill && s.fillToZero && vmin < 0 && vmax > 0) {
forceZeroLine = true;
}
else {
forceZeroLine = false;
}
}
}
// if not a bar and filling, use appropriate method.
else if (s.fill) {
if (vmin >= 0 && (s.fillToZero || dp > 0.1)) {
forceMinZero = true;
}
else if (vmin < 0 && vmax > 0 && s.fillToZero) {
forceMinZero = false;
forceZeroLine = true;
}
else {
forceMinZero = false;
forceZeroLine = false;
}
}
// if not a bar and not filling, only change existing state
// if it doesn't make sense
else if (vmin < 0) {
forceMinZero = false;
}
}
}
// check if we need make axis min at 0.
if (forceMinZero) {
// compute number of ticks
this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
this.min = 0;
// what order is this range?
// what tick interval does that give us?
ti = max/(this.numberTicks-1);
temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
if (ti/temp == parseInt(ti/temp, 10)) {
ti += temp;
}
this.tickInterval = Math.ceil(ti/temp) * temp;
this.max = this.tickInterval * (this.numberTicks - 1);
}
// check if we need to make sure there is a tick at 0.
else if (forceZeroLine) {
// compute number of ticks
this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
var ntmin = Math.ceil(Math.abs(min)/range*(this.numberTicks-1));
var ntmax = this.numberTicks - 1 - ntmin;
ti = Math.max(Math.abs(min/ntmin), Math.abs(max/ntmax));
temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
this.tickInterval = Math.ceil(ti/temp) * temp;
this.max = this.tickInterval * ntmax;
this.min = -this.tickInterval * ntmin;
}
// if nothing else, do autoscaling which will try to line up ticks across axes.
else {
if (this.numberTicks == null){
if (this.tickInterval) {
this.numberTicks = 3 + Math.ceil(range / this.tickInterval);
}
else {
this.numberTicks = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);
}
}
if (this.tickInterval == null) {
// get a tick interval
ti = range/(this.numberTicks - 1);
 
if (ti < 1) {
temp = Math.pow(10, Math.abs(Math.floor(Math.log(ti)/Math.LN10)));
}
else {
temp = 1;
}
this.tickInterval = Math.ceil(ti*temp*this.pad)/temp;
}
else {
temp = 1 / this.tickInterval;
}
// try to compute a nicer, more even tick interval
// temp = Math.pow(10, Math.floor(Math.log(ti)/Math.LN10));
// this.tickInterval = Math.ceil(ti/temp) * temp;
rrange = this.tickInterval * (this.numberTicks - 1);
margin = (rrange - range)/2;
if (this.min == null) {
this.min = Math.floor(temp*(min-margin))/temp;
}
if (this.max == null) {
this.max = this.min + rrange;
}
}
}
else {
rmin = (this.min != null) ? this.min : min - range*(this.padMin - 1);
rmax = (this.max != null) ? this.max : max + range*(this.padMax - 1);
this.min = rmin;
this.max = rmax;
range = this.max - this.min;
if (this.numberTicks == null){
// if tickInterval is specified by user, we will ignore computed maximum.
// max will be equal or greater to fit even # of ticks.
if (this.tickInterval != null) {
this.numberTicks = Math.ceil((this.max - this.min)/this.tickInterval)+1;
this.max = this.min + this.tickInterval*(this.numberTicks-1);
}
else if (dim > 100) {
this.numberTicks = parseInt(3+(dim-100)/75, 10);
}
else {
this.numberTicks = 2;
}
}
if (this.tickInterval == null) {
this.tickInterval = range / (this.numberTicks-1);
}
}
 
for (var i=0; i<this.numberTicks; i++){
tt = this.min + i * this.tickInterval;
var t = new this.tickRenderer(this.tickOptions);
// var t = new $.jqplot.AxisTickRenderer(this.tickOptions);
if (!this.showTicks) {
t.showLabel = false;
t.showMark = false;
}
else if (!this.showTickMarks) {
t.showMark = false;
}
t.setTick(tt, this.name);
this._ticks.push(t);
}
}
};
// called with scope of axis
$.jqplot.LinearAxisRenderer.prototype.pack = function(pos, offsets) {
var ticks = this._ticks;
var max = this.max;
var min = this.min;
var offmax = offsets.max;
var offmin = offsets.min;
var lshow = (this._label == null) ? false : this._label.show;
for (var p in pos) {
this._elem.css(p, pos[p]);
}
this._offsets = offsets;
// pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
var pixellength = offmax - offmin;
var unitlength = max - min;
// point to unit and unit to point conversions references to Plot DOM element top left corner.
this.p2u = function(p){
return (p - offmin) * unitlength / pixellength + min;
};
this.u2p = function(u){
return (u - min) * pixellength / unitlength + offmin;
};
if (this.name == 'xaxis' || this.name == 'x2axis'){
this.series_u2p = function(u){
return (u - min) * pixellength / unitlength;
};
this.series_p2u = function(p){
return p * unitlength / pixellength + min;
};
}
else {
this.series_u2p = function(u){
return (u - max) * pixellength / unitlength;
};
this.series_p2u = function(p){
return p * unitlength / pixellength + max;
};
}
if (this.show) {
if (this.name == 'xaxis' || this.name == 'x2axis') {
for (i=0; i<ticks.length; i++) {
var t = ticks[i];
if (t.show && t.showLabel) {
var shim;
if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
// will need to adjust auto positioning based on which axis this is.
var temp = (this.name == 'xaxis') ? 1 : -1;
switch (t.labelPosition) {
case 'auto':
// position at end
if (temp * t.angle < 0) {
shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
}
// position at start
else {
shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
}
break;
case 'end':
shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
break;
case 'start':
shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
break;
case 'middle':
shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
break;
default:
shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
break;
}
}
else {
shim = -t.getWidth()/2;
}
var val = this.u2p(t.value) + shim + 'px';
t._elem.css('left', val);
t.pack();
}
}
if (lshow) {
var w = this._label._elem.outerWidth(true);
this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
if (this.name == 'xaxis') {
this._label._elem.css('bottom', '0px');
}
else {
this._label._elem.css('top', '0px');
}
this._label.pack();
}
}
else {
for (i=0; i<ticks.length; i++) {
var t = ticks[i];
if (t.show && t.showLabel) {
var shim;
if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
// will need to adjust auto positioning based on which axis this is.
var temp = (this.name == 'yaxis') ? 1 : -1;
switch (t.labelPosition) {
case 'auto':
// position at end
case 'end':
if (temp * t.angle < 0) {
shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
}
else {
shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
}
break;
case 'start':
if (t.angle > 0) {
shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
}
else {
shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
}
break;
case 'middle':
// if (t.angle > 0) {
// shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
// }
// else {
// shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
// }
shim = -t.getHeight()/2;
break;
default:
shim = -t.getHeight()/2;
break;
}
}
else {
shim = -t.getHeight()/2;
}
var val = this.u2p(t.value) + shim + 'px';
t._elem.css('top', val);
t.pack();
}
}
if (lshow) {
var h = this._label._elem.outerHeight(true);
this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
if (this.name == 'yaxis') {
this._label._elem.css('left', '0px');
}
else {
this._label._elem.css('right', '0px');
}
this._label.pack();
}
}
}
};
 
 
// class: $.jqplot.MarkerRenderer
// The default jqPlot marker renderer, rendering the points on the line.
$.jqplot.MarkerRenderer = function(options){
// Group: Properties
// prop: show
// wether or not to show the marker.
this.show = true;
// prop: style
// One of diamond, circle, square, x, plus, dash, filledDiamond, filledCircle, filledSquare
this.style = 'filledCircle';
// prop: lineWidth
// size of the line for non-filled markers.
this.lineWidth = 2;
// prop: size
// Size of the marker (diameter or circle, length of edge of square, etc.)
this.size = 9.0;
// prop: color
// color of marker. Will be set to color of series by default on init.
this.color = '#666666';
// prop: shadow
// wether or not to draw a shadow on the line
this.shadow = true;
// prop: shadowAngle
// Shadow angle in degrees
this.shadowAngle = 45;
// prop: shadowOffset
// Shadow offset from line in pixels
this.shadowOffset = 1;
// prop: shadowDepth
// Number of times shadow is stroked, each stroke offset shadowOffset from the last.
this.shadowDepth = 3;
// prop: shadowAlpha
// Alpha channel transparency of shadow. 0 = transparent.
this.shadowAlpha = '0.07';
// prop: shadowRenderer
// Renderer that will draws the shadows on the marker.
this.shadowRenderer = new $.jqplot.ShadowRenderer();
// prop: shapeRenderer
// Renderer that will draw the marker.
this.shapeRenderer = new $.jqplot.ShapeRenderer();
$.extend(true, this, options);
};
$.jqplot.MarkerRenderer.prototype.init = function(options) {
$.extend(true, this, options);
var sdopt = {angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, lineWidth:this.lineWidth, depth:this.shadowDepth, closePath:true};
if (this.style.indexOf('filled') != -1) {
sdopt.fill = true;
}
if (this.style.indexOf('ircle') != -1) {
sdopt.isarc = true;
sdopt.closePath = false;
}
this.shadowRenderer.init(sdopt);
var shopt = {fill:false, isarc:false, strokeStyle:this.color, fillStyle:this.color, lineWidth:this.lineWidth, closePath:true};
if (this.style.indexOf('filled') != -1) {
shopt.fill = true;
}
if (this.style.indexOf('ircle') != -1) {
shopt.isarc = true;
shopt.closePath = false;
}
this.shapeRenderer.init(shopt);
};
$.jqplot.MarkerRenderer.prototype.drawDiamond = function(x, y, ctx, fill, options) {
var stretch = 1.2;
var dx = this.size/2/stretch;
var dy = this.size/2*stretch;
var points = [[x-dx, y], [x, y+dy], [x+dx, y], [x, y-dy]];
if (this.shadow) {
this.shadowRenderer.draw(ctx, points);
}
this.shapeRenderer.draw(ctx, points, options);
 
ctx.restore();
};
$.jqplot.MarkerRenderer.prototype.drawPlus = function(x, y, ctx, fill, options) {
var stretch = 1.0;
var dx = this.size/2*stretch;
var dy = this.size/2*stretch;
var points1 = [[x, y-dy], [x, y+dy]];
var points2 = [[x+dx, y], [x-dx, y]];
var opts = $.extend(true, {}, this.options, {closePath:false});
if (this.shadow) {
this.shadowRenderer.draw(ctx, points1, {closePath:false});
this.shadowRenderer.draw(ctx, points2, {closePath:false});
}
this.shapeRenderer.draw(ctx, points1, opts);
this.shapeRenderer.draw(ctx, points2, opts);
 
ctx.restore();
};
$.jqplot.MarkerRenderer.prototype.drawX = function(x, y, ctx, fill, options) {
var stretch = 1.0;
var dx = this.size/2*stretch;
var dy = this.size/2*stretch;
var opts = $.extend(true, {}, this.options, {closePath:false});
var points1 = [[x-dx, y-dy], [x+dx, y+dy]];
var points2 = [[x-dx, y+dy], [x+dx, y-dy]];
if (this.shadow) {
this.shadowRenderer.draw(ctx, points1, {closePath:false});
this.shadowRenderer.draw(ctx, points2, {closePath:false});
}
this.shapeRenderer.draw(ctx, points1, opts);
this.shapeRenderer.draw(ctx, points2, opts);
 
ctx.restore();
};
$.jqplot.MarkerRenderer.prototype.drawDash = function(x, y, ctx, fill, options) {
var stretch = 1.0;
var dx = this.size/2*stretch;
var dy = this.size/2*stretch;
var points = [[x-dx, y], [x+dx, y]];
if (this.shadow) {
this.shadowRenderer.draw(ctx, points);
}
this.shapeRenderer.draw(ctx, points, options);
 
ctx.restore();
};
$.jqplot.MarkerRenderer.prototype.drawSquare = function(x, y, ctx, fill, options) {
var stretch = 1.0;
var dx = this.size/2/stretch;
var dy = this.size/2*stretch;
var points = [[x-dx, y-dy], [x-dx, y+dy], [x+dx, y+dy], [x+dx, y-dy]];
if (this.shadow) {
this.shadowRenderer.draw(ctx, points);
}
this.shapeRenderer.draw(ctx, points, options);
 
ctx.restore();
};
$.jqplot.MarkerRenderer.prototype.drawCircle = function(x, y, ctx, fill, options) {
var radius = this.size/2;
var end = 2*Math.PI;
var points = [x, y, radius, 0, end, true];
if (this.shadow) {
this.shadowRenderer.draw(ctx, points);
}
this.shapeRenderer.draw(ctx, points, options);
ctx.restore();
};
$.jqplot.MarkerRenderer.prototype.draw = function(x, y, ctx, options) {
options = options || {};
switch (this.style) {
case 'diamond':
this.drawDiamond(x,y,ctx, false, options);
break;
case 'filledDiamond':
this.drawDiamond(x,y,ctx, true, options);
break;
case 'circle':
this.drawCircle(x,y,ctx, false, options);
break;
case 'filledCircle':
this.drawCircle(x,y,ctx, true, options);
break;
case 'square':
this.drawSquare(x,y,ctx, false, options);
break;
case 'filledSquare':
this.drawSquare(x,y,ctx, true, options);
break;
case 'x':
this.drawX(x,y,ctx, true, options);
break;
case 'plus':
this.drawPlus(x,y,ctx, true, options);
break;
case 'dash':
this.drawDash(x,y,ctx, true, options);
break;
default:
this.drawDiamond(x,y,ctx, false, options);
break;
}
};
// class: $.jqplot.shadowRenderer
// The default jqPlot shadow renderer, rendering shadows behind shapes.
$.jqplot.ShadowRenderer = function(options){
// Group: Properties
// prop: angle
// Angle of the shadow in degrees. Measured counter-clockwise from the x axis.
this.angle = 45;
// prop: offset
// Pixel offset at the given shadow angle of each shadow stroke from the last stroke.
this.offset = 1;
// prop: alpha
// alpha transparency of shadow stroke.
this.alpha = 0.07;
// prop: lineWidth
// width of the shadow line stroke.
this.lineWidth = 1.5;
// prop: lineJoin
// How line segments of the shadow are joined.
this.lineJoin = 'miter';
// prop: lineCap
// how ends of the shadow line are rendered.
this.lineCap = 'round';
// prop; closePath
// whether line path segment is closed upon itself.
this.closePath = false;
// prop: fill
// whether to fill the shape.
this.fill = false;
// prop: depth
// how many times the shadow is stroked. Each stroke will be offset by offset at angle degrees.
this.depth = 3;
// prop: isarc
// wether the shadow is an arc or not.
this.isarc = false;
$.extend(true, this, options);
};
$.jqplot.ShadowRenderer.prototype.init = function(options) {
$.extend(true, this, options);
};
// function: draw
// draws an transparent black (i.e. gray) shadow.
//
// ctx - canvas drawing context
// points - array of points or [x, y, radius, start angle (rad), end angle (rad)]
$.jqplot.ShadowRenderer.prototype.draw = function(ctx, points, options) {
ctx.save();
var opts = (options != null) ? options : {};
var fill = (opts.fill != null) ? opts.fill : this.fill;
var closePath = (opts.closePath != null) ? opts.closePath : this.closePath;
var offset = (opts.offset != null) ? opts.offset : this.offset;
var alpha = (opts.alpha != null) ? opts.alpha : this.alpha;
var depth = (opts.depth != null) ? opts.depth : this.depth;
ctx.lineWidth = (opts.lineWidth != null) ? opts.lineWidth : this.lineWidth;
ctx.lineJoin = (opts.lineJoin != null) ? opts.lineJoin : this.lineJoin;
ctx.lineCap = (opts.lineCap != null) ? opts.lineCap : this.lineCap;
ctx.strokeStyle = 'rgba(0,0,0,'+alpha+')';
ctx.fillStyle = 'rgba(0,0,0,'+alpha+')';
for (var j=0; j<depth; j++) {
ctx.translate(Math.cos(this.angle*Math.PI/180)*offset, Math.sin(this.angle*Math.PI/180)*offset);
ctx.beginPath();
if (this.isarc) {
ctx.arc(points[0], points[1], points[2], points[3], points[4], true);
}
else {
ctx.moveTo(points[0][0], points[0][1]);
for (var i=1; i<points.length; i++) {
ctx.lineTo(points[i][0], points[i][1]);
}
}
if (closePath) {
ctx.closePath();
}
if (fill) {
ctx.fill();
}
else {
ctx.stroke();
}
}
ctx.restore();
};
// class: $.jqplot.shapeRenderer
// The default jqPlot shape renderer. Given a set of points will
// plot them and either stroke a line (fill = false) or fill them (fill = true).
// If a filled shape is desired, closePath = true must also be set to close
// the shape.
$.jqplot.ShapeRenderer = function(options){
this.lineWidth = 1.5;
// prop: lineJoin
// How line segments of the shadow are joined.
this.lineJoin = 'miter';
// prop: lineCap
// how ends of the shadow line are rendered.
this.lineCap = 'round';
// prop; closePath
// whether line path segment is closed upon itself.
this.closePath = false;
// prop: fill
// whether to fill the shape.
this.fill = false;
// prop: isarc
// wether the shadow is an arc or not.
this.isarc = false;
// prop: fillRect
// true to draw shape as a filled rectangle.
this.fillRect = false;
// prop: strokeRect
// true to draw shape as a stroked rectangle.
this.strokeRect = false;
// prop: clearRect
// true to cear a rectangle.
this.clearRect = false;
// prop: strokeStyle
// css color spec for the stoke style
this.strokeStyle = '#999999';
// prop: fillStyle
// css color spec for the fill style.
this.fillStyle = '#999999';
$.extend(true, this, options);
};
$.jqplot.ShapeRenderer.prototype.init = function(options) {
$.extend(true, this, options);
};
// function: draw
// draws the shape.
//
// ctx - canvas drawing context
// points - array of points for shapes or
// [x, y, width, height] for rectangles or
// [x, y, radius, start angle (rad), end angle (rad)] for circles and arcs.
$.jqplot.ShapeRenderer.prototype.draw = function(ctx, points, options) {
ctx.save();
var opts = (options != null) ? options : {};
var fill = (opts.fill != null) ? opts.fill : this.fill;
var closePath = (opts.closePath != null) ? opts.closePath : this.closePath;
var fillRect = (opts.fillRect != null) ? opts.fillRect : this.fillRect;
var strokeRect = (opts.strokeRect != null) ? opts.strokeRect : this.strokeRect;
var clearRect = (opts.clearRect != null) ? opts.clearRect : this.clearRect;
var isarc = (opts.isarc != null) ? opts.isarc : this.isarc;
ctx.lineWidth = opts.lineWidth || this.lineWidth;
ctx.lineJoin = opts.lineJoing || this.lineJoin;
ctx.lineCap = opts.lineCap || this.lineCap;
ctx.strokeStyle = (opts.strokeStyle || opts.color) || this.strokeStyle;
ctx.fillStyle = opts.fillStyle || this.fillStyle;
ctx.beginPath();
if (isarc) {
ctx.arc(points[0], points[1], points[2], points[3], points[4], true);
if (closePath) {
ctx.closePath();
}
if (fill) {
ctx.fill();
}
else {
ctx.stroke();
}
}
else if (fillRect) {
ctx.fillRect(points[0], points[1], points[2], points[3]);
}
else if (strokeRect) {
ctx.strokeRect(points[0], points[1], points[2], points[3]);
}
else if (clearRect) {
ctx.clearRect(points[0], points[1], points[2], points[3]);
}
else {
ctx.moveTo(points[0][0], points[0][1]);
for (var i=1; i<points.length; i++) {
ctx.lineTo(points[i][0], points[i][1]);
}
if (closePath) {
ctx.closePath();
}
if (fill) {
ctx.fill();
}
else {
ctx.stroke();
}
}
ctx.restore();
};
// class $.jqplot.TableLegendRenderer
// The default legend renderer for jqPlot, this class has no options beyond the <Legend> class.
$.jqplot.TableLegendRenderer = function(){
//
};
$.jqplot.TableLegendRenderer.prototype.init = function(options) {
$.extend(true, this, options);
};
$.jqplot.TableLegendRenderer.prototype.addrow = function (label, color, pad) {
var rs = (pad) ? this.rowSpacing : '0';
var tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem);
$('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+
'<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+
'</div></td>').appendTo(tr);
var elem = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>');
elem.appendTo(tr);
if (this.escapeHtml) {
elem.text(label);
}
else {
elem.html(label);
}
};
// called with scope of legend
$.jqplot.TableLegendRenderer.prototype.draw = function() {
var legend = this;
if (this.show) {
var series = this._series;
// make a table. one line label per row.
var ss = 'position:absolute;';
ss += (this.background) ? 'background:'+this.background+';' : '';
ss += (this.border) ? 'border:'+this.border+';' : '';
ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : '';
ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : '';
ss += (this.textColor) ? 'color:'+this.textColor+';' : '';
this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>');
var pad = false;
for (var i = 0; i< series.length; i++) {
s = series[i];
if (s.show && s.showLabel) {
var lt = s.label.toString();
if (lt) {
var color = s.color;
if (s._stack && !s.fill) {
color = '';
}
this.renderer.addrow.call(this, lt, color, pad);
pad = true;
}
// let plugins add more rows to legend. Used by trend line plugin.
for (var j=0; j<$.jqplot.addLegendRowHooks.length; j++) {
var item = $.jqplot.addLegendRowHooks[j].call(this, s);
if (item) {
this.renderer.addrow.call(this, item.label, item.color, pad);
pad = true;
}
}
}
}
}
return this._elem;
};
$.jqplot.TableLegendRenderer.prototype.pack = function(offsets) {
if (this.show) {
// fake a grid for positioning
var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom};
switch (this.location) {
case 'nw':
var a = grid._left + this.xoffset;
var b = grid._top + this.yoffset;
this._elem.css('left', a);
this._elem.css('top', b);
break;
case 'n':
var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
var b = grid._top + this.yoffset;
this._elem.css('left', a);
this._elem.css('top', b);
break;
case 'ne':
var a = offsets.right + this.xoffset;
var b = grid._top + this.yoffset;
this._elem.css({right:a, top:b});
break;
case 'e':
var a = offsets.right + this.xoffset;
var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
this._elem.css({right:a, top:b});
break;
case 'se':
var a = offsets.right + this.xoffset;
var b = offsets.bottom + this.yoffset;
this._elem.css({right:a, bottom:b});
break;
case 's':
var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2;
var b = offsets.bottom + this.yoffset;
this._elem.css({left:a, bottom:b});
break;
case 'sw':
var a = grid._left + this.xoffset;
var b = offsets.bottom + this.yoffset;
this._elem.css({left:a, bottom:b});
break;
case 'w':
var a = grid._left + this.xoffset;
var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2;
this._elem.css({left:a, top:b});
break;
default: // same as 'se'
var a = grid._right - this.xoffset;
var b = grid._bottom + this.yoffset;
this._elem.css({right:a, bottom:b});
break;
}
}
};
/**
* JavaScript printf/sprintf functions.
*
* This code is unrestricted: you are free to use it however you like.
*
* The functions should work as expected, performing left or right alignment,
* truncating strings, outputting numbers with a required precision etc.
*
* For complex cases, these functions follow the Perl implementations of
* (s)printf, allowing arguments to be passed out-of-order, and to set the
* precision or length of the output based on arguments instead of fixed
* numbers.
*
* See http://perldoc.perl.org/functions/sprintf.html for more information.
*
* Implemented:
* - zero and space-padding
* - right and left-alignment,
* - base X prefix (binary, octal and hex)
* - positive number prefix
* - (minimum) width
* - precision / truncation / maximum width
* - out of order arguments
*
* Not implemented (yet):
* - vector flag
* - size (bytes, words, long-words etc.)
*
* Will not implement:
* - %n or %p (no pass-by-reference in JavaScript)
*
* @version 2007.04.27
* @author Ash Searle
*/
/**
* @Modifications 2009.05.26
* @author Chris Leonello
*
* Added %p %P specifier
* Acts like %g or %G but will not add more significant digits to the output than present in the input.
* Example:
* Format: '%.3p', Input: 0.012, Output: 0.012
* Format: '%.3g', Input: 0.012, Output: 0.0120
* Format: '%.4p', Input: 12.0, Output: 12.0
* Format: '%.4g', Input: 12.0, Output: 12.00
* Format: '%.4p', Input: 4.321e-5, Output: 4.321e-5
* Format: '%.4g', Input: 4.321e-5, Output: 4.3210e-5
*/
$.jqplot.sprintf = function() {
function pad(str, len, chr, leftJustify) {
var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
return leftJustify ? str + padding : padding + str;
 
}
 
function justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace) {
var diff = minWidth - value.length;
if (diff > 0) {
var spchar = ' ';
if (htmlSpace) { spchar = '&nbsp;'; }
if (leftJustify || !zeroPad) {
value = pad(value, minWidth, spchar, leftJustify);
} else {
value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
}
}
return value;
}
 
function formatBaseX(value, base, prefix, leftJustify, minWidth, precision, zeroPad, htmlSpace) {
// Note: casts negative numbers to positive ones
var number = value >>> 0;
prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || '';
value = prefix + pad(number.toString(base), precision || 0, '0', false);
return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
}
 
function formatString(value, leftJustify, minWidth, precision, zeroPad, htmlSpace) {
if (precision != null) {
value = value.slice(0, precision);
}
return justify(value, '', leftJustify, minWidth, zeroPad, htmlSpace);
}
 
var a = arguments, i = 0, format = a[i++];
 
return format.replace($.jqplot.sprintf.regex, function(substring, valueIndex, flags, minWidth, _, precision, type) {
if (substring == '%%') { return '%'; }
 
// parse flags
var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, htmlSpace = false;
for (var j = 0; flags && j < flags.length; j++) switch (flags.charAt(j)) {
case ' ': positivePrefix = ' '; break;
case '+': positivePrefix = '+'; break;
case '-': leftJustify = true; break;
case '0': zeroPad = true; break;
case '#': prefixBaseX = true; break;
case '&': htmlSpace = true; break;
}
 
// parameters may be null, undefined, empty-string or real valued
// we want to ignore null, undefined and empty-string values
 
if (!minWidth) {
minWidth = 0;
}
else if (minWidth == '*') {
minWidth = +a[i++];
}
else if (minWidth.charAt(0) == '*') {
minWidth = +a[minWidth.slice(1, -1)];
}
else {
minWidth = +minWidth;
}
 
// Note: undocumented perl feature:
if (minWidth < 0) {
minWidth = -minWidth;
leftJustify = true;
}
 
if (!isFinite(minWidth)) {
throw new Error('$.jqplot.sprintf: (minimum-)width must be finite');
}
 
if (!precision) {
precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0);
}
else if (precision == '*') {
precision = +a[i++];
}
else if (precision.charAt(0) == '*') {
precision = +a[precision.slice(1, -1)];
}
else {
precision = +precision;
}
 
// grab value using valueIndex if required?
var value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
 
switch (type) {
case 's': {
if (value == null) {
return '';
}
return formatString(String(value), leftJustify, minWidth, precision, zeroPad, htmlSpace);
}
case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad, htmlSpace);
case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad,htmlSpace);
case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace).toUpperCase();
case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace);
case 'i':
case 'd': {
var number = parseInt(+value, 10);
if (isNaN(number)) {
return '';
}
var prefix = number < 0 ? '-' : positivePrefix;
value = prefix + pad(String(Math.abs(number)), precision, '0', false);
return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace);
}
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
{
var number = +value;
if (isNaN(number)) {
return '';
}
var prefix = number < 0 ? '-' : positivePrefix;
var method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
var textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
value = prefix + Math.abs(number)[method](precision);
return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform]();
}
case 'p':
case 'P':
{
// make sure number is a number
var number = +value;
if (isNaN(number)) {
return '';
}
var prefix = number < 0 ? '-' : positivePrefix;
 
var parts = String(Number(Math.abs(number)).toExponential()).split(/e|E/);
var sd = (parts[0].indexOf('.') != -1) ? parts[0].length - 1 : parts[0].length;
var zeros = (parts[1] < 0) ? -parts[1] - 1 : 0;
if (Math.abs(number) < 1) {
if (sd + zeros <= precision) {
value = prefix + Math.abs(number).toPrecision(sd);
}
else {
if (sd <= precision - 1) {
value = prefix + Math.abs(number).toExponential(sd-1);
}
else {
value = prefix + Math.abs(number).toExponential(precision-1);
}
}
}
else {
var prec = (sd <= precision) ? sd : precision;
value = prefix + Math.abs(number).toPrecision(prec);
}
var textTransform = ['toString', 'toUpperCase']['pP'.indexOf(type) % 2];
return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform]();
}
case 'n': return '';
default: return substring;
}
});
};
$.jqplot.sprintf.regex = /%%|%(\d+\$)?([-+#0& ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g;
 
})(jQuerySysStatWidget || jQuery);
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/webfiles/jquery.jqplot.min.css
0,0 → 1,0
.jqplot-target{position:relative;color:#666;font-family:"Trebuchet MS",Arial,Helvetica,sans-serif;font-size:1em;}.jqplot-axis{font-size:.75em;}.jqplot-xaxis{margin-top:10px;}.jqplot-x2axis{margin-bottom:10px;}.jqplot-yaxis{margin-right:10px;}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis{margin-left:10px;margin-right:10px;}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{position:absolute;}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top;}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom;}.jqplot-yaxis-tick{right:0;top:15px;text-align:right;}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left;}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute;}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute;}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute;}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;position:absolute;}table.jqplot-table-legend{background-color:rgba(255,255,255,0.6);border:1px solid #ccc;position:absolute;font-size:.75em;}td.jqplot-table-legend{vertical-align:middle;}td.jqplot-table-legend>div{border:1px solid #ccc;padding:.2em;}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:.35em;border-bottom-width:.35em;border-left-width:.6em;border-right-width:.6em;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid;}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em;}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-highlighter-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-point-label{font-size:.75em;}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center;}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em;}
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/webfiles/jquery.min.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);
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/webfiles/plugins/jqplot.barRenderer.js
0,0 → 1,334
/**
* Copyright (c) 2009 Chris Leonello
* jqPlot is currently available for use in all personal or commercial projects
* under both the MIT and GPL version 2.0 licenses. This means that you can
* choose the license that best suits your project and use it accordingly.
*
* The author would appreciate an email letting him know of any substantial
* use of jqPlot. You can reach the author at: chris dot leonello at gmail
* dot com or see http://www.jqplot.com/info.php . This is, of course,
* not required.
*
* If you are feeling kind and generous, consider supporting the project by
* making a donation at: http://www.jqplot.com/donate.php .
*
* Thanks for using jqPlot!
*
*/
(function($) {
// Class: $.jqplot.BarRenderer
// A plugin renderer for jqPlot to draw a bar plot.
// Draws series as a line.
$.jqplot.BarRenderer = function(){
$.jqplot.LineRenderer.call(this);
};
$.jqplot.BarRenderer.prototype = new $.jqplot.LineRenderer();
$.jqplot.BarRenderer.prototype.constructor = $.jqplot.BarRenderer;
// called with scope of series.
$.jqplot.BarRenderer.prototype.init = function(options) {
// Group: Properties
//
// prop: barPadding
// Number of pixels between adjacent bars at the same axis value.
this.barPadding = 8;
// prop: barMargin
// Number of pixels between groups of bars at adjacent axis values.
this.barMargin = 10;
// prop: barDirection
// 'vertical' = up and down bars, 'horizontal' = side to side bars
this.barDirection = 'vertical';
// prop: barWidth
// Width of the bar in pixels (auto by devaul). null = calculated automatically.
this.barWidth = null;
// prop: shadowOffset
// offset of the shadow from the slice and offset of
// each succesive stroke of the shadow from the last.
this.shadowOffset = 2;
// prop: shadowDepth
// number of strokes to apply to the shadow,
// each stroke offset shadowOffset from the last.
this.shadowDepth = 5;
// prop: shadowAlpha
// transparency of the shadow (0 = transparent, 1 = opaque)
this.shadowAlpha = 0.08;
$.extend(true, this, options);
// fill is still needed to properly draw the legend.
// bars have to be filled.
this.fill = true;
if (this.barDirection == 'vertical' ) {
this._primaryAxis = '_xaxis';
this._stackAxis = 'y';
this.fillAxis = 'y';
}
else {
this._primaryAxis = '_yaxis';
this._stackAxis = 'x';
this.fillAxis = 'x';
}
// set the shape renderer options
var opts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill};
this.renderer.shapeRenderer.init(opts);
// set the shadow renderer options
var sopts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill};
this.renderer.shadowRenderer.init(sopts);
};
// called with scope of series
function barPreInit(target, data, seriesDefaults, options) {
if (this.rendererOptions.barDirection == 'horizontal') {
this._stackAxis = 'x';
this._primaryAxis = '_yaxis';
}
}
$.jqplot.preSeriesInitHooks.push(barPreInit);
// needs to be called with scope of series, not renderer.
$.jqplot.BarRenderer.prototype.calcSeriesNumbers = function() {
var nvals = 0;
var nseries = 0;
var paxis = this[this._primaryAxis];
var s, series, pos;
// loop through all series on this axis
for (var i=0; i < paxis._series.length; i++) {
series = paxis._series[i];
if (series === this) {
pos = i;
}
// is the series rendered as a bar?
if (series.renderer.constructor == $.jqplot.BarRenderer) {
// gridData may not be computed yet, use data length insted
nvals += series.data.length;
nseries += 1;
}
}
return [nvals, nseries, pos];
};
 
$.jqplot.BarRenderer.prototype.setBarWidth = function() {
// need to know how many data values we have on the approprate axis and figure it out.
var i;
var nvals = 0;
var nseries = 0;
var paxis = this[this._primaryAxis];
var s, series, pos;
var temp = this.renderer.calcSeriesNumbers.call(this);
nvals = temp[0];
nseries = temp[1];
var nticks = paxis.numberTicks;
var nbins = (nticks-1)/2;
// so, now we have total number of axis values.
if (paxis.name == 'xaxis' || paxis.name == 'x2axis') {
if (this._stack) {
this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals * nseries - this.barMargin;
}
else {
this.barWidth = ((paxis._offsets.max - paxis._offsets.min)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
// this.barWidth = (paxis._offsets.max - paxis._offsets.min) / nvals - this.barPadding - this.barMargin/nseries;
}
}
else {
if (this._stack) {
this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals * nseries - this.barMargin;
}
else {
this.barWidth = ((paxis._offsets.min - paxis._offsets.max)/nbins - this.barPadding * (nseries-1) - this.barMargin*2)/nseries;
// this.barWidth = (paxis._offsets.min - paxis._offsets.max) / nvals - this.barPadding - this.barMargin/nseries;
}
}
return [nvals, nseries];
};
$.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options) {
var i;
var opts = (options != undefined) ? options : {};
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
var fill = (opts.fill != undefined) ? opts.fill : this.fill;
var xaxis = this.xaxis;
var yaxis = this.yaxis;
var xp = this._xaxis.series_u2p;
var yp = this._yaxis.series_u2p;
var pointx, pointy, nvals, nseries, pos;
if (this.barWidth == null) {
this.renderer.setBarWidth.call(this);
}
var temp = this.renderer.calcSeriesNumbers.call(this);
nvals = temp[0];
nseries = temp[1];
pos = temp[2];
if (this._stack) {
this._barNudge = 0;
}
else {
this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
}
if (showLine) {
var negativeColors = new $.jqplot.ColorGenerator(this.negativeSeriesColors);
var negativeColor = negativeColors.get(this.index);
var isnegative = false;
var posfs = opts.fillStyle;
var tempfs;
if (this.barDirection == 'vertical') {
for (var i=0; i<gridData.length; i++) {
points = [];
var base = gridData[i][0] + this._barNudge;
var ystart;
// stacked
if (this._stack && this._prevGridData.length) {
ystart = this._prevGridData[i][1];
}
// not stacked and first series in stack
else {
if (this.fillToZero) {
ystart = this._yaxis.series_u2p(0);
}
else {
ystart = ctx.canvas.height;
}
}
if (this.fillToZero && this._plotData[i][1] < 0) {
isnegative = true;
opts.fillStyle = negativeColor;
}
else {
opts.fillStyle = posfs;
isnegative = false;
}
points.push([base-this.barWidth/2, ystart]);
points.push([base-this.barWidth/2, gridData[i][1]]);
points.push([base+this.barWidth/2, gridData[i][1]]);
points.push([base+this.barWidth/2, ystart]);
// now draw the shadows if not stacked.
// for stacked plots, they are predrawn by drawShadow
if (shadow && !this._stack) {
this.renderer.shadowRenderer.draw(ctx, points, opts);
}
this.renderer.shapeRenderer.draw(ctx, points, opts);
}
}
else if (this.barDirection == 'horizontal'){
for (var i=0; i<gridData.length; i++) {
points = [];
var base = gridData[i][1] - this._barNudge;
var xstart;
if (this._stack && this._prevGridData.length) {
xstart = this._prevGridData[i][0];
}
else {
xstart = 0;
}
points.push([xstart, base+this.barWidth/2]);
points.push([gridData[i][0], base+this.barWidth/2]);
points.push([gridData[i][0], base-this.barWidth/2]);
points.push([xstart, base-this.barWidth/2]);
// now draw the shadows if not stacked.
// for stacked plots, they are predrawn by drawShadow
if (shadow && !this._stack) {
this.renderer.shadowRenderer.draw(ctx, points, opts);
}
this.renderer.shapeRenderer.draw(ctx, points, opts);
}
}
}
 
};
// for stacked plots, shadows will be pre drawn by drawShadow.
$.jqplot.BarRenderer.prototype.drawShadow = function(ctx, gridData, options) {
var i;
var opts = (options != undefined) ? options : {};
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow;
var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
var fill = (opts.fill != undefined) ? opts.fill : this.fill;
var xaxis = this.xaxis;
var yaxis = this.yaxis;
var xp = this._xaxis.series_u2p;
var yp = this._yaxis.series_u2p;
var pointx, pointy, nvals, nseries, pos;
if (this._stack && this.shadow) {
if (this.barWidth == null) {
this.renderer.setBarWidth.call(this);
}
var temp = this.renderer.calcSeriesNumbers.call(this);
nvals = temp[0];
nseries = temp[1];
pos = temp[2];
if (this._stack) {
this._barNudge = 0;
}
else {
this._barNudge = (-Math.abs(nseries/2 - 0.5) + pos) * (this.barWidth + this.barPadding);
}
if (showLine) {
if (this.barDirection == 'vertical') {
for (var i=0; i<gridData.length; i++) {
points = [];
var base = gridData[i][0] + this._barNudge;
var ystart;
if (this._stack && this._prevGridData.length) {
ystart = this._prevGridData[i][1];
}
else {
if (this.fillToZero) {
ystart = this._yaxis.series_u2p(0);
}
else {
ystart = ctx.canvas.height;
}
}
points.push([base-this.barWidth/2, ystart]);
points.push([base-this.barWidth/2, gridData[i][1]]);
points.push([base+this.barWidth/2, gridData[i][1]]);
points.push([base+this.barWidth/2, ystart]);
this.renderer.shadowRenderer.draw(ctx, points, opts);
}
}
else if (this.barDirection == 'horizontal'){
for (var i=0; i<gridData.length; i++) {
points = [];
var base = gridData[i][1] - this._barNudge;
var xstart;
if (this._stack && this._prevGridData.length) {
xstart = this._prevGridData[i][0];
}
else {
xstart = 0;
}
points.push([xstart, base+this.barWidth/2]);
points.push([gridData[i][0], base+this.barWidth/2]);
points.push([gridData[i][0], base-this.barWidth/2]);
points.push([xstart, base-this.barWidth/2]);
this.renderer.shadowRenderer.draw(ctx, points, opts);
}
}
}
}
 
};
})(jQuerySysStatWidget || jQuery);
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/webfiles/plugins/jqplot.categoryAxisRenderer.js
0,0 → 1,238
/**
* Copyright (c) 2009 Chris Leonello
* jqPlot is currently available for use in all personal or commercial projects
* under both the MIT and GPL version 2.0 licenses. This means that you can
* choose the license that best suits your project and use it accordingly.
*
* The author would appreciate an email letting him know of any substantial
* use of jqPlot. You can reach the author at: chris dot leonello at gmail
* dot com or see http://www.jqplot.com/info.php . This is, of course,
* not required.
*
* If you are feeling kind and generous, consider supporting the project by
* making a donation at: http://www.jqplot.com/donate.php .
*
* Thanks for using jqPlot!
*
*/
(function($) {
/**
* class: $.jqplot.CategoryAxisRenderer
* A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series.
* This renderer has no options beyond those supplied by the <Axis> class.
*
* To use this renderer, include the plugin in your source
* > <script type="text/javascript" language="javascript" src="plugins/jqplot.categoryAxisRenderer.js"></script>
*
* and supply the appropriate options to your plot
*
* > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}}
**/
$.jqplot.CategoryAxisRenderer = function() {
$.jqplot.LinearAxisRenderer.call(this);
};
$.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
$.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer;
$.jqplot.CategoryAxisRenderer.prototype.init = function(options){
// prop: tickRenderer
// A class of a rendering engine for creating the ticks labels displayed on the plot,
// See <$.jqplot.AxisTickRenderer>.
// this.tickRenderer = $.jqplot.AxisTickRenderer;
// this.labelRenderer = $.jqplot.AxisLabelRenderer;
$.extend(true, this, {tickOptions:{formatString:'%d'}}, options);
var db = this._dataBounds;
// Go through all the series attached to this axis and find
// the min/max bounds for this axis.
for (var i=0; i<this._series.length; i++) {
var s = this._series[i];
var d = s.data;
for (var j=0; j<d.length; j++) {
if (this.name == 'xaxis' || this.name == 'x2axis') {
if (d[j][0] < db.min || db.min == null) {
db.min = d[j][0];
}
if (d[j][0] > db.max || db.max == null) {
db.max = d[j][0];
}
}
else {
if (d[j][1] < db.min || db.min == null) {
db.min = d[j][1];
}
if (d[j][1] > db.max || db.max == null) {
db.max = d[j][1];
}
}
}
}
};
 
$.jqplot.CategoryAxisRenderer.prototype.createTicks = function() {
// we're are operating on an axis here
var ticks = this._ticks;
var userTicks = this.ticks;
var name = this.name;
// databounds were set on axis initialization.
var db = this._dataBounds;
var dim, interval;
var min, max;
var pos1, pos2;
var tt, i;
 
// if we already have ticks, use them.
if (userTicks.length) {
this.min = 0.5;
this.max = userTicks.length + 0.5;
var range = this.max - this.min;
this.numberTicks = 2*userTicks.length + 1;
for (i=0; i<userTicks.length; i++){
tt = this.min + 2 * i * range / (this.numberTicks-1);
// need a marker before and after the tick
var t = new this.tickRenderer(this.tickOptions);
t.showLabel = false;
t.showMark = true;
t.setTick(tt, this.name);
this._ticks.push(t);
var t = new this.tickRenderer(this.tickOptions);
t.label = userTicks[i];
t.showLabel = true;
t.showMark = false;
t.showGridline = false;
t.setTick(tt+0.5, this.name);
this._ticks.push(t);
}
// now add the last tick at the end
var t = new this.tickRenderer(this.tickOptions);
t.showLabel = false;
t.showMark = true;
t.setTick(tt+1, this.name);
this._ticks.push(t);
}
 
// we don't have any ticks yet, let's make some!
else {
if (name == 'xaxis' || name == 'x2axis') {
dim = this._plotDimensions.width;
}
else {
dim = this._plotDimensions.height;
}
// if min, max and number of ticks specified, user can't specify interval.
if (this.min != null && this.max != null && this.numberTicks != null) {
this.tickInterval = null;
}
// if max, min, and interval specified and interval won't fit, ignore interval.
if (this.min != null && this.max != null && this.tickInterval != null) {
if (parseInt((this.max-this.min)/this.tickInterval, 10) != (this.max-this.min)/this.tickInterval) {
this.tickInterval = null;
}
}
// find out how many categories are in the lines and collect labels
var labels = [];
var numcats = 0;
var min = 0.5;
var max, val;
for (var i=0; i<this._series.length; i++) {
var s = this._series[i];
for (var j=0; j<s.data.length; j++) {
if (this.name == 'xaxis' || this.name == 'x2axis') {
val = s.data[j][0];
}
else {
val = s.data[j][1];
}
if ($.inArray(val, labels) == -1) {
numcats += 1;
labels.push(val);
}
}
}
// keep a reference to these tick labels to use for redrawing plot (see bug #57)
this.ticks = labels;
// now bin the data values to the right lables.
for (var i=0; i<this._series.length; i++) {
var s = this._series[i];
for (var j=0; j<s.data.length; j++) {
if (this.name == 'xaxis' || this.name == 'x2axis') {
val = s.data[j][0];
}
else {
val = s.data[j][1];
}
// for category axis, force the values into category bins.
// we should have the value in the label array now.
var idx = $.inArray(val, labels)+1;
if (this.name == 'xaxis' || this.name == 'x2axis') {
s.data[j][0] = idx;
}
else {
s.data[j][1] = idx;
}
}
}
max = numcats + 0.5;
if (this.numberTicks == null) {
this.numberTicks = 2*numcats + 1;
}
 
var range = max - min;
this.min = min;
this.max = max;
var track = 0;
// todo: adjust this so more ticks displayed.
var maxVisibleTicks = parseInt(3+dim/20, 10);
var skip = parseInt(numcats/maxVisibleTicks, 10);
 
if (this.tickInterval == null) {
 
this.tickInterval = range / (this.numberTicks-1);
 
}
// if tickInterval is specified, we will ignore any computed maximum.
for (var i=0; i<this.numberTicks; i++){
tt = this.min + i * this.tickInterval;
var t = new this.tickRenderer(this.tickOptions);
// if even tick, it isn't a category, it's a divider
if (i/2 == parseInt(i/2, 10)) {
t.showLabel = false;
t.showMark = true;
}
else {
if (skip>0 && track<skip) {
t.showLabel = false;
track += 1;
}
else {
t.showLabel = true;
track = 0;
}
t.label = t.formatter(t.formatString, labels[(i-1)/2]);
t.showMark = false;
t.showGridline = false;
}
if (!this.showTicks) {
t.showLabel = false;
t.showMark = false;
}
else if (!this.showTickMarks) {
t.showMark = false;
}
t.setTick(tt, this.name);
this._ticks.push(t);
}
}
};
})(jQuerySysStatWidget || jQuery);
/Classwork/CS3214 - Computer Systems/Project 5 - Web Service/webfiles/sysstatwidgets.js
0,0 → 1,272
/*
* Widgets that plot data obtained from the sys stat web service.
*
* Supports
*
* <div id="meminfo"> </div>
* <div id="loadavg"> </div>
*
* Written by Godmar Back for CS 3214 Fall 2009
*/
(function () {
 
var jqplotbase = "/files/";
 
// loadScript taken from
// http://devblog.techhead.biz/2009/04/dynamically-load-external-javascript-in.html
// (code mirrors $.getScript)
function loadScript(src, callback) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
var loaded = false;
script.setAttribute('src', src);
script.onload = script.onreadystatechange = function() {
if (!loaded && (!this.readyState || this.readyState == 'complete'
|| this.readyState == 'loaded') ) {
loaded = true;
callback();
script.onload = script.onreadystatechange = null;
head.removeChild(script);
}
}
head.appendChild(script);
}
 
/*
* A Delayer object invokes a callback passed to the constructor
* after the following two conditions are true:
* - every function returned from a call to add() has been called
* - the ready() method has been called.
*/
var Delayer = function (cb) {
var count = 0;
var finalized = false;
 
this.add = function () {
count++;
 
return function () {
count--;
if (count == 0 && finalized)
cb();
}
}
 
this.ready = function () {
finalized = true;
if (count == 0)
cb();
}
}
 
function dowithJQuery($) {
 
function updateLoadaveragePlot(plot, divid, value, nvalues, title) {
if (plot) {
var data = plot.series[0].data;
for (var i = 0; i < data.length - 1; i++)
data[i][1] = data[i+1][1];
data[i][1] = value;
 
var ymax = 1.0;
$.each(data, function (index, el) {
if (el[1] > ymax) ymax = el[1];
});
 
plot.axes.yaxis.max = ymax;
plot.title.text = title;
plot.replot();
return plot;
}
 
var data = [value];
for (var i = 2; i < nvalues; i++)
data.push(0.0);
 
return $.jqplot(divid, [data], {
seriesDefaults:{neighborThreshold:0, showMarker: false},
series:[
{
fill: true, fillAlpha:0.8,
shadow:false, showLabel: false,
}
],
legend: {
location:'nw',
xoffset: 310,
yoffset: 100
},
axesDefaults:{
autoscale: true,
useSeriesColor: true
},
title : title,
axes: {
yaxis: {
tickOptions: {formatString:"%.1f"},
min: -0.001
},
xaxis: {
min: 1, max: nvalues,
showTicks: false
}
}
});
}
 
function showMemory(plot, divid, vallabel, axismax, title) {
 
if (plot) {
for (var i = 0; i < vallabel.length; i++)
plot.series[i].data[0][1] = vallabel[i].value;
 
plot.axes.yaxis.max = axismax;
plot.replot();
return plot;
}
 
var data = [];
for (var i = 0; i < vallabel.length; i++)
data.push([ vallabel[i].value ]);
 
var labels = [];
for (var i = 0; i < vallabel.length; i++)
labels.push({ label: vallabel[i].label });
 
return $.jqplot(divid, data, {
seriesColors: [ "#8B3A3A", "#CD5555", "#000080", "#008B00" ],
stackSeries: true,
legend: {
show: true,
location: 'nw',
// xoffset: 115
},
seriesDefaults: {
renderer: $.jqplot.BarRenderer,
rendererOptions: {
barPadding: 2,
barMargin: 10
}
},
series: labels,
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: [title]
},
yaxis: {
numberTicks: 6,
tickOptions: {
formatString: "%.0dM"
},
min: 0,
max: axismax
}
}
});
}
 
function renderWidgets($) {
$('#meminfo').each(function () {
var $div = $(this);
var url = $div.attr('url');
var updateInterval = Number($div.attr('update'));
var plot = undefined;
 
function update () {
$.getJSON(url + "/meminfo?callback=?", function (data) {
var MB = 1024;
plot = showMemory(plot, $div.attr('id'),
[
{ value: data.Cached / MB, label: "Cached" },
{ value: data.Buffers / MB, label: "Buffers" },
{ value: (data.MemTotal
- data.MemFree
- data.Cached
- data.Buffers) / MB, label: "Anonymous" },
{ value: data.MemFree / MB, label: "Free" }
],
data.MemTotal / MB, url.match(/http:\/\/(.*):\d+/)[1]
);
});
}
update ();
setInterval(update, updateInterval);
});
 
$('.loadavg-text').each(function () {
var $span = $(this);
var url = $span.attr('url');
var updateInterval = Number($span.attr('update'));
 
function update () {
$.getJSON(url + "/loadavg?callback=?", function (data) {
$span.text(
"Load Average: " + data.loadavg.join(" ")
+ " Threads: " + data.running_threads
+ "/" + data.total_threads
);
});
}
update ();
setInterval(update, updateInterval);
});
 
$('#loadavg').each(function () {
var $div = $(this);
var url = $div.attr('url');
var updateInterval = Number($div.attr('update'));
var plot = undefined;
 
function update () {
$.getJSON(url + "/loadavg?callback=?", function (data) {
plot = updateLoadaveragePlot(
plot, $div.attr('id'), Number(data.loadavg[0]),
$div.width(), // # values, 1 per pixel
url.match(/http:\/\/(.*):\d+/)[1] + ": " +
data.running_threads + "/" + data.total_threads);
});
}
update ();
setInterval(update, updateInterval);
});
};
 
var delay = new Delayer(function () {
renderWidgets($);
});
 
$('head').append('<link rel="stylesheet" type="text/css"'
+' href="' + jqplotbase + 'jquery.jqplot.min.css" />');
 
if ($.browser.msie)
$.getScript(jqplotbase + "excanvas.js", delay.add());
 
var jqplotloaded = delay.add();
$.getScript(jqplotbase + "jquery.jqplot.js", function () {
$.each([ "plugins/jqplot.barRenderer.js",
"plugins/jqplot.categoryAxisRenderer.js"
],
function (index, jsfile) {
$.getScript(jqplotbase + jsfile, delay.add());
});
 
jqplotloaded();
});
 
$(document).ready(delay.add());
delay.ready();
}
 
loadScript(
jqplotbase + 'jquery.min.js',
function() {
// rename jQuery to jQuerySysStatWidget, remove both reference
// to jQuery and $; the jqplot plug-ins were changed to attach to
// jQuerySysStatWidget instead of jQuery
jQuerySysStatWidget = jQuery.noConflict(true);
dowithJQuery(jQuerySysStatWidget);
}
);
 
}) ();