void extended_html__block_body(onion_dict *context, onion_response *res){ #line 1 #line 8 onion_response_write(res, "\n<h1>This is an extended template</h1>\n\n", 40); #line 8 { #line 8 void (*f)(onion_dict *context, onion_response *res); #line 8 f=(void*)onion_dict_get(context, "__block_body_in__"); #line 8 if (f) #line 8 f(context, res); #line 8 } #line 14 onion_response_write(res, "\n\nIf you see this, <span style=\"color: green;\">OK</span>.\n<br>\nRandom (only at test2): ", 87); #line 14 { #line 14 const char *tmp; #line 14 tmp=onion_dict_get(context, "random"); #line 14 if (tmp) #line 14 onion_response_write0(res, tmp); #line 14 } #line 19 onion_response_write(res, "\n<br>\n\nUnicode Chars: \342\202\254 \302\241 \303\241 \303\251 \303\255 \303\272 \303\263. \346\261\211\350\257\255/\346\274\242\350\252\236.\n\n", 61); #line 1 }
/// Gets the output data int oterm_out(process *o, onion_request *req, onion_response *res){ pthread_mutex_lock(&o->mutex); if (onion_request_get_query(req, "initial")){ if (o->buffer[BUFFER_SIZE-1]!=0){ // If 0 then never wrote on it. So if not, write from pos to end too, first. onion_response_write(res, &o->buffer[o->buffer_pos], BUFFER_SIZE-o->buffer_pos); } onion_response_write(res, o->buffer, o->buffer_pos); onion_response_printf(res, "\033]oterm;%d;", o->buffer_pos); onion_response_printf(res, "\033]url;https://localhost:8080/uuid/%s/;", o->uuid); pthread_mutex_unlock(&o->mutex); return OCS_PROCESSED; } int16_t p=atoi(onion_request_get_queryd(req, "pos", "0")); //o->buffer_pos; ONION_DEBUG("Wait for data at %d", p); while(p==o->buffer_pos) // We need it to be diferent, if not does not make sense to wake up pthread_cond_wait(&o->dataReady, &o->mutex); ONION_DEBUG("Data ready at %d (waiting from %d)", o->buffer_pos, p); if (o->buffer_pos<p){ onion_response_write(res, &o->buffer[p], BUFFER_SIZE-p); p=0; } onion_response_write(res, &o->buffer[p], o->buffer_pos-p); onion_response_printf(res, "\033]oterm;%d;", o->buffer_pos); pthread_mutex_unlock(&o->mutex); return OCS_PROCESSED; }
/* Return raw file if found. Security risk?! Check of filename/path required?! */ int search_file(onion_dict *context, onion_request *req, onion_response *res){ //const char* path = onion_request_get_path(req);//empty?! const char* path = onion_request_get_fullpath(req); printf("Request of %s %i.\n",path, strlen(path)); char filename[strlen(path)+8]; //sprintf(filename,"./%s",path); sprintf(filename,"./html/%s",path); //read file if( FILE *f=fopen(filename,"rb") ){ fseek(f,0,SEEK_END); long len=ftell(f); fseek(f,0,SEEK_SET); char *data=(char*)malloc(len+1); fread(data,1,len,f); fclose(f); if (context) onion_dict_add(context, "LANG", onion_request_get_language_code(req), OD_FREE_VALUE); onion_response_set_length(res, len); onion_response_write(res, data, len); if (context) onion_dict_free(context); free(data); }else{ onion_response_set_length(res, 24); onion_response_write(res, "<h1>File not found</h1>", 24); } return OCS_PROCESSED; }
/** * @short Writes all the header to the given response * @memberof onion_response_t * @ingroup response * * It writes the headers and depending on the method, return OR_SKIP_CONTENT. this is set when in head mode. Handlers * should react to this return by not trying to write more, but if they try this object will just skip those writtings. * * Explicit calling to this function is not necessary, as as soon as the user calls any write function this will * be performed. * * As soon as the headers are written, any modification on them will be just ignored. * * @returns 0 if should procced to normal data write, or OR_SKIP_CONTENT if should not write content. */ int onion_response_write_headers(onion_response * res) { if (!res->request) { ONION_ERROR ("Bad formed response. Need a request at creation. Will not write headers."); return -1; } res->flags |= OR_HEADER_SENT; // I Set at the begining so I can do normal writing. res->request->flags |= OR_HEADER_SENT; char chunked = 0; if (res->request->flags & OR_HTTP11) { onion_response_printf(res, "HTTP/1.1 %d %s\r\n", res->code, onion_response_code_description(res->code)); //ONION_DEBUG("Response header: HTTP/1.1 %d %s\n",res->code, onion_response_code_description(res->code)); if (!(res->flags & OR_LENGTH_SET) && onion_request_keep_alive(res->request)) { onion_response_write(res, CONNECTION_CHUNK_ENCODING, sizeof(CONNECTION_CHUNK_ENCODING) - 1); chunked = 1; } } else { onion_response_printf(res, "HTTP/1.0 %d %s\r\n", res->code, onion_response_code_description(res->code)); //ONION_DEBUG("Response header: HTTP/1.0 %d %s\n",res->code, onion_response_code_description(res->code)); if (res->flags & OR_LENGTH_SET) // On HTTP/1.0, i need to state it. On 1.1 it is default. onion_response_write(res, CONNECTION_KEEP_ALIVE, sizeof(CONNECTION_KEEP_ALIVE) - 1); } if (!(res->flags & OR_LENGTH_SET) && !chunked && !(res->flags & OR_CONNECTION_UPGRADE)) onion_response_write(res, CONNECTION_CLOSE, sizeof(CONNECTION_CLOSE) - 1); if (res->flags & OR_CONNECTION_UPGRADE) onion_response_write(res, CONNECTION_UPGRADE, sizeof(CONNECTION_UPGRADE) - 1); onion_dict_preorder(res->headers, write_header, res); if (res->request->session_id && (onion_dict_count(res->request->session) > 0)) // I have session with something, tell user onion_response_printf(res, "Set-Cookie: sessionid=%s; httponly; Path=/\n", res->request->session_id); onion_response_write(res, "\r\n", 2); ONION_DEBUG0("Headers written"); res->sent_bytes = -res->buffer_pos; // the header size is not counted here. It will add again so start negative. if ((res->request->flags & OR_METHODS) == OR_HEAD) { onion_response_flush(res); res->flags |= OR_SKIP_CONTENT; return OR_SKIP_CONTENT; } if (chunked) { onion_response_flush(res); res->flags |= OR_CHUNKED; } return 0; }
/** * @short Writes some data to the response. Using sprintf format strings. va_list args version * * @param args va_list of arguments * @memberof onion_response_t */ ssize_t onion_response_vprintf(onion_response *res, const char *fmt, va_list args) { char temp[512]; int l; l=vsnprintf(temp, sizeof(temp), fmt, args); if (l<0) { ONION_ERROR("Invalid vprintf fmt"); return -1; } else if (l<sizeof(temp)) { return onion_response_write(res, temp, l); } else { ssize_t s; char*buf = onion_low_scalar_malloc(l+1); if (!buf){ // this cannot happen, since onion_low_scalar_malloc // handles that error... ONION_ERROR("Could not reserve %d bytes", l+1); return -1; } vsnprintf(buf, l, fmt, args); s = onion_response_write (res, buf, l); onion_low_free (buf); return s; } }
/** * @short Helper that is called on each header, and writes the header * @memberof onion_response_t */ static void write_header(onion_response *res, const char *key, const char *value, int flags){ //ONION_DEBUG0("Response header: %s: %s",key, value); onion_response_write0(res, key); onion_response_write(res, ": ",2); onion_response_write0(res, value); onion_response_write(res, "\r\n",2); }
/* Check post values and then return template of index.html. (Or use *p for other callbacks (not implemented)) */ int checkFormularValues(void *p, onion_request *req, onion_response *res){ int ok = ((OnionServer*)p)->updateSetting(req,res); if( ok != 0){ onion_response_set_length(res, 6); onion_response_write(res, "reload", 6); }else{ onion_response_set_length(res, 2); onion_response_write(res, "Ok", 2); } return OCS_PROCESSED; }
void base_html(onion_dict *context, onion_response *res){ #line 1 #line 1 int has_context=(context!=NULL); #line 1 if (!has_context) #line 1 context=onion_dict_new(); #line 1 #line 1 base_html_blocks_init(context); onion_response_write(res, "<!DOCTYPE html>\n" "<html>\n" " <head>\n" " <title>", 43); #line 4 { #line 4 const char *tmp; #line 4 tmp=onion_dict_get(context, "title"); #line 4 if (tmp) #line 4 onion_response_write_html_safe(res, tmp); #line 4 } onion_response_write(res, "</title>\n" " </head>\n" " <body>\n" "", 28); #line 7 { #line 7 void (*f)(onion_dict *context, onion_response *res); #line 7 f=(void*)onion_dict_get(context, "__block_content__"); #line 7 if (f) #line 7 f(context, res); #line 7 } onion_response_write(res, " \n" " </body>\n" "</html>\n" "", 21); #line 10 if (!has_context) #line 10 onion_dict_free(context); #line 1 }
/** * @short Writes some data to the response. Using sprintf format strings. Max final string size: 1024 * @memberof onion_response_t */ ssize_t onion_response_printf(onion_response *res, const char *fmt, ...){ char temp[1024]; va_list ap; va_start(ap, fmt); int l=vsnprintf(temp, sizeof(temp)-1, fmt, ap); va_end(ap); return onion_response_write(res, temp, l); }
onion_connection_status wait_random(void *_, onion_request *req, onion_response *res){ int ms=105.0 + (float)((200.0 * rand()) / ((float)RAND_MAX)); ONION_INFO("Wait %.3f seconds", ms/1000.0); usleep(ms*1000); onion_response_write(res, "OK", 3); return OCS_PROCESSED; }
onion_connection_status random_timeout(void *_, onion_request * req, onion_response * res) { int ms = 2000 * (((float)RAND_MAX) / rand()); ONION_INFO("Wait %d ms", ms); usleep(ms * 1000); ONION_INFO("Done"); onion_response_write(res, "OK", 2); return OCS_PROCESSED; }
/** * @short Writes all buffered output waiting for sending. * @ingroup response * * If header has not been sent yet (delayed), it uses a temporary buffer to send it now. This * way header can use the buffer_size information to send the proper content-length, even when it * wasnt properly set by programmer. Whith this information its possib to keep alive the connection * on more cases. */ int onion_response_flush(onion_response * res) { res->sent_bytes += res->buffer_pos; res->sent_bytes_total += res->buffer_pos; if (res->buffer_pos == 0) // Not used. return 0; if (!(res->flags & OR_HEADER_SENT)) { // Automatic header write ONION_DEBUG0 ("Doing fast header hack: store current buffer, send current headers. Resend buffer."); char tmpb[sizeof(res->buffer)]; int tmpp = res->buffer_pos; memcpy(tmpb, res->buffer, res->buffer_pos); res->buffer_pos = 0; onion_response_write_headers(res); onion_response_write(res, tmpb, tmpp); return 0; } if (res->flags & OR_SKIP_CONTENT) // HEAD request return 0; ONION_DEBUG0("Flush %d bytes", res->buffer_pos); onion_request *req = res->request; ssize_t(*write) (onion_request *, const char *data, size_t len); write = req->connection.listen_point->write; ssize_t w; off_t pos = 0; //ONION_DEBUG0("Write %d bytes",res->buffer_pos); if (res->flags & OR_CHUNKED) { char tmp[16]; snprintf(tmp, sizeof(tmp), "%X\r\n", (unsigned int)res->buffer_pos); if ((w = write(req, tmp, strlen(tmp))) <= 0) { ONION_WARNING("Error writing chunk encoding length. Aborting write."); return OCS_CLOSE_CONNECTION; } ONION_DEBUG0("Write %d-%d bytes", res->buffer_pos, w); } while ((w = write(req, &res->buffer[pos], res->buffer_pos)) != res->buffer_pos) { if (w <= 0 || res->buffer_pos < 0) { ONION_ERROR("Error writing %d bytes. Maybe closed connection. Code %d. ", res->buffer_pos, w); perror(""); res->buffer_pos = 0; return OCS_CLOSE_CONNECTION; } pos += w; ONION_DEBUG0("Write %d-%d bytes", res->buffer_pos, w); res->buffer_pos -= w; } if (res->flags & OR_CHUNKED) { write(req, "\r\n", 2); } res->buffer_pos = 0; return 0; }
int php_sapi_ponion_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */ { ponion_context_t *context = (ponion_context_t*) SG(server_context); if (context) { if (onion_response_write(context->res, message, length)) return SUCCESS; } return FAILURE; } /* }}} */
/** * @short Performs the real request: set the code and write data */ int onion_handler_static_handler(onion_handler_static_data *d, onion_request *request, onion_response *res){ int length=strlen(d->data); onion_response_set_length(res, length); onion_response_set_code(res, d->code); onion_response_write_headers(res); //fprintf(stderr,"Write %d bytes\n",length); onion_response_write(res, d->data, length); return OCS_PROCESSED; }
int onion_handler_auth_pam_handler(onion_handler_auth_pam_data *d, onion_request *request, onion_response *res){ /// Use session to know if already logged in, so do not mess with PAM so often. if (onion_request_get_session(request, "pam_logged_in")) return onion_handler_handle(d->inside, request, res); const char *o=onion_request_get_header(request, "Authorization"); char *auth=NULL; char *username=NULL; char *passwd=NULL; if (o && strncmp(o,"Basic",5)==0){ //fprintf(stderr,"auth: '%s'\n",&o[6]); auth=onion_base64_decode(&o[6], NULL); username=auth; int i=0; while (auth[i]!='\0' && auth[i]!=':') i++; if (auth[i]==':'){ auth[i]='\0'; // so i have user ready passwd=&auth[i+1]; } else passwd=NULL; } // I have my data, try to authorize if (username && passwd){ int ok=authorize(d->pamname, username, passwd); if (ok){ // I save the username at the session, so it can be accessed later. onion_dict *session=onion_request_get_session_dict(request); onion_dict_lock_write(session); onion_dict_add(session, "username", username, OD_REPLACE|OD_DUP_VALUE); onion_dict_add(session, "pam_logged_in", username, OD_REPLACE|OD_DUP_VALUE); onion_dict_unlock(session); free(auth); return onion_handler_handle(d->inside, request, res); } } if (auth) free(auth); // Not authorized. Ask for it. char temp[256]; sprintf(temp, "Basic realm=\"%s\"",d->realm); onion_response_set_header(res, "WWW-Authenticate",temp); onion_response_set_code(res, HTTP_UNAUTHORIZED); onion_response_set_length(res,sizeof(RESPONSE_UNAUTHORIZED)); onion_response_write(res,RESPONSE_UNAUTHORIZED,sizeof(RESPONSE_UNAUTHORIZED)); return OCS_PROCESSED; }
/** * @short Handles a propfind * * @param path the shared path. */ onion_connection_status onion_webdav_propfind(const char *filename, onion_webdav *wd, onion_request* req, onion_response* res){ // Prepare the basepath, necesary for props. char *basepath=NULL; int pathlen=0; const char *current_path=onion_request_get_path(req); const char *fullpath=onion_request_get_fullpath(req); pathlen=(current_path-fullpath); basepath=alloca(pathlen+1); memcpy(basepath, fullpath, pathlen+1); ONION_DEBUG0("Pathbase initial <%s> %d", basepath, pathlen); while(basepath[pathlen]=='/' && pathlen>0) pathlen--; basepath[pathlen+1]=0; ONION_DEBUG0("PROPFIND; pathbase %s", basepath); int depth; { const char *depths=onion_request_get_header(req, "Depth"); if (!depths){ ONION_ERROR("Missing Depth header on webdav request"); return OCS_INTERNAL_ERROR; } if (strcmp(depths,"infinity")==0){ ONION_ERROR("Infinity depth not supported yet."); return OCS_INTERNAL_ERROR; } depth=atoi(depths); } int props=onion_webdav_parse_propfind(onion_request_get_data(req)); ONION_DEBUG("Asking for props %08X, depth %d", props, depth); onion_block *block=onion_webdav_write_propfind(basepath, filename, onion_request_get_path(req), depth, props); if (!block) // No block, resource does not exist return onion_shortcut_response("Not found", HTTP_NOT_FOUND, req, res); ONION_DEBUG0("Printing block %s", onion_block_data(block)); onion_response_set_header(res, "Content-Type", "text/xml; charset=\"utf-8\""); onion_response_set_length(res, onion_block_size(block)); onion_response_set_code(res, HTTP_MULTI_STATUS); onion_response_write_headers(res); onion_response_flush(res); onion_response_write(res, onion_block_data(block), onion_block_size(block)); onion_block_free(block); return OCS_PROCESSED; }
void external_html(onion_dict *context, onion_response *res){ #line 1 #line 1 int has_context=(context!=NULL); #line 1 if (!has_context) #line 1 context=onion_dict_new(); #line 1 #line 1 external_html_blocks_init(context); #line 2 onion_response_write(res, "This code is in an external html.\n", 34); #line 2 if (!has_context) #line 2 onion_dict_free(context); #line 1 }
/** * @short Shortcut for fast responses, like errors, with extra headers * * Prepares a fast response. You pass only the request, the text and the code, and it do the full response * object and sends the data. * * On this version you also pass a NULL terminated list of headers, in key, value pairs. */ onion_connection_status onion_shortcut_response_extra_headers(const char* response, int code, onion_request* req, onion_response *res, ... ){ unsigned int l=strlen(response); const char *key, *value; onion_response_set_length(res,l); onion_response_set_code(res,code); va_list ap; va_start(ap, res); while ( (key=va_arg(ap, const char *)) ){ value=va_arg(ap, const char *); if (key && value) onion_response_set_header(res, key, value); else break; } va_end(ap); onion_response_write_headers(res); onion_response_write(res,response,l); return OCS_PROCESSED; }
/** * @short Handles a propfind * * @param path the shared path. */ onion_connection_status onion_webdav_propfind(const char *filename, onion_webdav *wd, onion_request* req, onion_response* res){ ONION_DEBUG0("PROPFIND"); int depth; { const char *depths=onion_request_get_header(req, "Depth"); if (!depths){ ONION_ERROR("Missing Depth header on webdav request"); return OCS_INTERNAL_ERROR; } if (strcmp(depths,"infinity")==0){ ONION_ERROR("Infinity depth not supported yet."); return OCS_INTERNAL_ERROR; } depth=atoi(depths); } int props=onion_webdav_parse_propfind(onion_request_get_data(req)); ONION_DEBUG("Asking for props %08X, depth %d", props, depth); onion_block *block=onion_webdav_write_propfind(filename, onion_request_get_path(req), depth, props); if (!block) // No block, resource does not exist return onion_shortcut_response("Not found", HTTP_NOT_FOUND, req, res); ONION_DEBUG0("Printing block %s", onion_block_data(block)); onion_response_set_header(res, "Content-Type", "text/xml; charset=\"utf-8\""); onion_response_set_length(res, onion_block_size(block)); onion_response_set_code(res, HTTP_MULTI_STATUS); onion_response_write(res, onion_block_data(block), onion_block_size(block)); onion_block_free(block); return OCS_PROCESSED; }
/** * @short Default error printer. * @memberof onion_server_t * * Ugly errors, that can be reimplemented setting a handler with onion_server_set_internal_error_handler. */ static int onion_default_error(void *handler, onion_request *req, onion_response *res){ const char *msg; int l; int code; switch(req->flags&0x0F000){ case OR_INTERNAL_ERROR: msg=ERROR_500; l=sizeof(ERROR_500)-1; code=HTTP_INTERNAL_ERROR; break; case OR_NOT_IMPLEMENTED: msg=ERROR_505; l=sizeof(ERROR_505)-1; code=HTTP_NOT_IMPLEMENTED; break; case OR_FORBIDDEN: msg=ERROR_403; l=sizeof(ERROR_403)-1; code=HTTP_FORBIDDEN; break; default: msg=ERROR_404; l=sizeof(ERROR_404)-1; code=HTTP_NOT_FOUND; break; } ONION_DEBUG0("Internally managed error: %s, code %d.", msg, code); onion_response_set_code(res,code); onion_response_set_length(res, l); onion_response_write_headers(res); onion_response_write(res,msg,l); return OCS_PROCESSED; }
int write(const char *data, int len){ return onion_response_write(ptr, data, len); }
/// Writes a 0-ended string to the response. ssize_t onion_response_write0(onion_response *res, const char *data){ return onion_response_write(res, data, strlen(data)); }
void extended_html__block_body_in(onion_dict *context, onion_response *res){ #line 1 #line 10 onion_response_write(res, "\nMore text.\n", 12); #line 1 }
onion_connection_status opack_index_html(void *_, onion_request *req, onion_response *res){ char data[]={ 0x3C, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x0A, 0x20, 0x3C, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x3E, 0x0A, 0x20, 0x20, 0x3C, 0x74, 0x69, 0x74, 0x6C, 0x65, 0x3E, 0x4F, 0x6E, 0x69, 0x6F, 0x6E, 0x20, 0x54, 0x6F, 0x70, 0x3C, 0x2F, 0x74, 0x69, 0x74, 0x6C, 0x65, 0x3E, 0x0A, 0x20, 0x20, 0x3C, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x20, 0x73, 0x72, 0x63, 0x3D, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x63, 0x6F, 0x64, 0x65, 0x2E, 0x6A, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x6A, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2D, 0x31, 0x2E, 0x34, 0x2E, 0x33, 0x2E, 0x6D, 0x69, 0x6E, 0x2E, 0x6A, 0x73, 0x22, 0x3E, 0x3C, 0x2F, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3E, 0x0A, 0x3C, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0A, 0x62, 0x6F, 0x64, 0x79, 0x7B, 0x0A, 0x09, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x23, 0x66, 0x65, 0x66, 0x65, 0x66, 0x65, 0x3B, 0x0A, 0x09, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x66, 0x61, 0x6D, 0x69, 0x6C, 0x79, 0x3A, 0x20, 0x73, 0x61, 0x6E, 0x73, 0x2D, 0x73, 0x65, 0x72, 0x69, 0x66, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x68, 0x31, 0x7B, 0x0A, 0x09, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x62, 0x6C, 0x61, 0x63, 0x6B, 0x3B, 0x0A, 0x09, 0x74, 0x65, 0x78, 0x74, 0x2D, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3A, 0x20, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x7B, 0x0A, 0x09, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x3A, 0x20, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6E, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x7B, 0x0A, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x20, 0x31, 0x30, 0x30, 0x25, 0x3B, 0x0A, 0x09, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x3A, 0x20, 0x31, 0x70, 0x78, 0x20, 0x73, 0x6F, 0x6C, 0x69, 0x64, 0x20, 0x23, 0x61, 0x61, 0x61, 0x3B, 0x20, 0x0A, 0x09, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x3B, 0x0A, 0x09, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2D, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3A, 0x20, 0x35, 0x70, 0x78, 0x3B, 0x0A, 0x09, 0x2D, 0x6D, 0x6F, 0x7A, 0x2D, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2D, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x3A, 0x20, 0x35, 0x70, 0x78, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x7B, 0x0A, 0x09, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x23, 0x65, 0x65, 0x65, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x2C, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x64, 0x7B, 0x0A, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x20, 0x31, 0x30, 0x65, 0x6D, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x2E, 0x75, 0x69, 0x64, 0x7B, 0x0A, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x20, 0x31, 0x35, 0x65, 0x6D, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x65, 0x61, 0x64, 0x7B, 0x0A, 0x09, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x3A, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x3B, 0x0A, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x20, 0x31, 0x30, 0x30, 0x25, 0x3B, 0x0A, 0x7D, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x7B, 0x0A, 0x09, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, 0x3A, 0x20, 0x61, 0x75, 0x74, 0x6F, 0x3B, 0x0A, 0x09, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x3A, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x74, 0x72, 0x2E, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x64, 0x7B, 0x0A, 0x09, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x72, 0x65, 0x64, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x74, 0x72, 0x2E, 0x6E, 0x65, 0x77, 0x7B, 0x0A, 0x09, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x67, 0x72, 0x65, 0x65, 0x6E, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x74, 0x72, 0x3A, 0x68, 0x6F, 0x76, 0x65, 0x72, 0x7B, 0x0A, 0x09, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x79, 0x65, 0x6C, 0x6C, 0x6F, 0x77, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x0A, 0x3C, 0x2F, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0A, 0x20, 0x3C, 0x2F, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x3E, 0x0A, 0x3C, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x0A, 0x3C, 0x68, 0x31, 0x3E, 0x4F, 0x6E, 0x69, 0x6F, 0x6E, 0x20, 0x54, 0x6F, 0x70, 0x3C, 0x2F, 0x68, 0x31, 0x3E, 0x0A, 0x0A, 0x3C, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3D, 0x22, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x22, 0x3E, 0x0A, 0x3C, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x3E, 0x0A, 0x3C, 0x74, 0x68, 0x65, 0x61, 0x64, 0x3E, 0x0A, 0x3C, 0x74, 0x72, 0x3E, 0x3C, 0x74, 0x68, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x70, 0x69, 0x64, 0x22, 0x3E, 0x50, 0x49, 0x44, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3E, 0x43, 0x6F, 0x6D, 0x6D, 0x61, 0x6E, 0x64, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x75, 0x69, 0x64, 0x22, 0x3E, 0x55, 0x69, 0x64, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x3E, 0x50, 0x50, 0x69, 0x64, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x3E, 0x52, 0x53, 0x53, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x3E, 0x44, 0x61, 0x74, 0x61, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x68, 0x3E, 0x4C, 0x69, 0x62, 0x3C, 0x2F, 0x74, 0x68, 0x3E, 0x3C, 0x74, 0x64, 0x3E, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x0A, 0x3C, 0x2F, 0x74, 0x68, 0x65, 0x61, 0x64, 0x3E, 0x0A, 0x3C, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x0A, 0x3C, 0x2F, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x0A, 0x3C, 0x2F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x3E, 0x0A, 0x3C, 0x2F, 0x64, 0x69, 0x76, 0x3E, 0x0A, 0x0A, 0x3C, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3E, 0x0A, 0x24, 0x28, 0x64, 0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x29, 0x2E, 0x72, 0x65, 0x61, 0x64, 0x79, 0x28, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x28, 0x29, 0x7B, 0x0A, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6F, 0x70, 0x28, 0x29, 0x0A, 0x7D, 0x29, 0x0A, 0x0A, 0x2F, 0x2A, 0x2A, 0x0A, 0x20, 0x2A, 0x20, 0x40, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6F, 0x70, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x0A, 0x20, 0x2A, 0x2F, 0x0A, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6F, 0x70, 0x20, 0x3D, 0x20, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x28, 0x29, 0x7B, 0x0A, 0x09, 0x76, 0x61, 0x72, 0x20, 0x70, 0x3D, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x27, 0x29, 0x0A, 0x09, 0x76, 0x61, 0x72, 0x20, 0x58, 0x3D, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2E, 0x70, 0x61, 0x67, 0x65, 0x58, 0x4F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x0A, 0x09, 0x76, 0x61, 0x72, 0x20, 0x59, 0x3D, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2E, 0x70, 0x61, 0x67, 0x65, 0x59, 0x4F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x0A, 0x09, 0x24, 0x2E, 0x67, 0x65, 0x74, 0x28, 0x27, 0x2F, 0x70, 0x73, 0x2F, 0x27, 0x2C, 0x20, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x28, 0x6F, 0x72, 0x69, 0x67, 0x29, 0x7B, 0x0A, 0x09, 0x09, 0x6F, 0x3D, 0x6F, 0x72, 0x69, 0x67, 0x0A, 0x09, 0x09, 0x64, 0x3D, 0x24, 0x2E, 0x70, 0x61, 0x72, 0x73, 0x65, 0x4A, 0x53, 0x4F, 0x4E, 0x28, 0x6F, 0x72, 0x69, 0x67, 0x29, 0x0A, 0x09, 0x09, 0x24, 0x28, 0x27, 0x74, 0x72, 0x2E, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x64, 0x27, 0x29, 0x2E, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x28, 0x29, 0x0A, 0x09, 0x09, 0x76, 0x61, 0x72, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x73, 0x3D, 0x70, 0x2E, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x72, 0x65, 0x6E, 0x28, 0x27, 0x74, 0x72, 0x27, 0x29, 0x0A, 0x09, 0x09, 0x6C, 0x69, 0x6E, 0x65, 0x73, 0x2E, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x43, 0x6C, 0x61, 0x73, 0x73, 0x28, 0x27, 0x6E, 0x65, 0x77, 0x27, 0x2C, 0x27, 0x73, 0x6C, 0x6F, 0x77, 0x27, 0x29, 0x0A, 0x0A, 0x09, 0x09, 0x66, 0x6F, 0x72, 0x28, 0x6B, 0x20, 0x69, 0x6E, 0x20, 0x64, 0x29, 0x7B, 0x0A, 0x09, 0x09, 0x09, 0x76, 0x61, 0x72, 0x20, 0x6C, 0x3D, 0x64, 0x5B, 0x6B, 0x5D, 0x0A, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6B, 0x21, 0x3D, 0x2D, 0x31, 0x29, 0x7B, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6C, 0x69, 0x6E, 0x65, 0x73, 0x2E, 0x66, 0x69, 0x6C, 0x74, 0x65, 0x72, 0x28, 0x27, 0x23, 0x27, 0x2B, 0x6B, 0x29, 0x2E, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x29, 0x7B, 0x20, 0x2F, 0x2F, 0x20, 0x61, 0x6C, 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, 0x68, 0x65, 0x72, 0x65, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6C, 0x69, 0x6E, 0x65, 0x73, 0x3D, 0x6C, 0x69, 0x6E, 0x65, 0x73, 0x2E, 0x6E, 0x6F, 0x74, 0x28, 0x27, 0x23, 0x27, 0x2B, 0x6B, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x7D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6C, 0x73, 0x65, 0x7B, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x76, 0x61, 0x72, 0x20, 0x74, 0x72, 0x3D, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x72, 0x3E, 0x27, 0x29, 0x2E, 0x61, 0x74, 0x74, 0x72, 0x28, 0x27, 0x69, 0x64, 0x27, 0x2C, 0x6B, 0x29, 0x2E, 0x61, 0x64, 0x64, 0x43, 0x6C, 0x61, 0x73, 0x73, 0x28, 0x27, 0x6E, 0x65, 0x77, 0x27, 0x29, 0x2E, 0x66, 0x61, 0x64, 0x65, 0x49, 0x6E, 0x28, 0x27, 0x73, 0x6C, 0x6F, 0x77, 0x27, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x70, 0x69, 0x64, 0x22, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6B, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 0x4E, 0x61, 0x6D, 0x65, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x20, 0x63, 0x6C, 0x61, 0x73, 0x73, 0x3D, 0x22, 0x75, 0x69, 0x64, 0x22, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 0x55, 0x69, 0x64, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 0x50, 0x50, 0x69, 0x64, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 0x56, 0x6D, 0x52, 0x53, 0x53, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 0x56, 0x6D, 0x44, 0x61, 0x74, 0x61, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x74, 0x72, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x24, 0x28, 0x27, 0x3C, 0x74, 0x64, 0x3E, 0x27, 0x29, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x28, 0x6C, 0x5B, 0x27, 0x56, 0x6D, 0x4C, 0x69, 0x62, 0x27, 0x5D, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x70, 0x2E, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x64, 0x28, 0x74, 0x72, 0x29, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x7D, 0x0A, 0x09, 0x09, 0x09, 0x7D, 0x0A, 0x09, 0x09, 0x7D, 0x0A, 0x0A, 0x09, 0x09, 0x6C, 0x69, 0x6E, 0x65, 0x73, 0x2E, 0x61, 0x64, 0x64, 0x43, 0x6C, 0x61, 0x73, 0x73, 0x28, 0x27, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x64, 0x27, 0x29, 0x2E, 0x66, 0x61, 0x64, 0x65, 0x4F, 0x75, 0x74, 0x28, 0x27, 0x73, 0x6C, 0x6F, 0x77, 0x27, 0x29, 0x0A, 0x0A, 0x09, 0x09, 0x2F, 0x2F, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2E, 0x0A, 0x09, 0x09, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x74, 0x64, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x2E, 0x70, 0x69, 0x64, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x2B, 0x33, 0x29, 0x0A, 0x09, 0x09, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x74, 0x64, 0x2E, 0x75, 0x69, 0x64, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x2E, 0x75, 0x69, 0x64, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x29, 0x0A, 0x09, 0x09, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x2E, 0x6E, 0x61, 0x6D, 0x65, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x61, 0x64, 0x20, 0x2E, 0x6E, 0x61, 0x6D, 0x65, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x29, 0x0A, 0x09, 0x7D, 0x2C, 0x27, 0x70, 0x6C, 0x61, 0x69, 0x6E, 0x27, 0x29, 0x0A, 0x09, 0x0A, 0x09, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x53, 0x69, 0x7A, 0x65, 0x28, 0x29, 0x3B, 0x0A, 0x09, 0x24, 0x28, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x29, 0x2E, 0x72, 0x65, 0x73, 0x69, 0x7A, 0x65, 0x28, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x53, 0x69, 0x7A, 0x65, 0x29, 0x0A, 0x0A, 0x09, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2E, 0x73, 0x63, 0x72, 0x6F, 0x6C, 0x6C, 0x54, 0x6F, 0x28, 0x58, 0x2C, 0x59, 0x29, 0x0A, 0x09, 0x73, 0x65, 0x74, 0x54, 0x69, 0x6D, 0x65, 0x6F, 0x75, 0x74, 0x28, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x6F, 0x70, 0x2C, 0x32, 0x2A, 0x31, 0x30, 0x30, 0x30, 0x29, 0x0A, 0x7D, 0x0A, 0x0A, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x53, 0x69, 0x7A, 0x65, 0x20, 0x3D, 0x20, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x28, 0x29, 0x7B, 0x0A, 0x09, 0x2F, 0x2F, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x27, 0x29, 0x2E, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2E, 0x69, 0x6E, 0x6E, 0x65, 0x72, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2D, 0x31, 0x30, 0x30, 0x29, 0x3B, 0x0A, 0x09, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x62, 0x6F, 0x64, 0x79, 0x27, 0x29, 0x2E, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2E, 0x69, 0x6E, 0x6E, 0x65, 0x72, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2D, 0x24, 0x28, 0x27, 0x2E, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x43, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x61, 0x64, 0x27, 0x29, 0x2E, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x28, 0x29, 0x2D, 0x31, 0x31, 0x35, 0x29, 0x3B, 0x0A, 0x09, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x61, 0x64, 0x20, 0x2E, 0x6E, 0x61, 0x6D, 0x65, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x24, 0x28, 0x27, 0x23, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x27, 0x29, 0x2E, 0x77, 0x69, 0x64, 0x74, 0x68, 0x28, 0x29, 0x29, 0x0A, 0x0A, 0x7D, 0x0A, 0x0A, 0x3C, 0x2F, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3E, 0x0A, 0x0A, 0x3C, 0x2F, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x0A, }; onion_response_set_length(res, 2507); return onion_response_write(res, data, sizeof(data)); }
void extended_html__block_title(onion_dict *context, onion_response *res){ #line 1 #line 3 onion_response_write(res, "Extended", 8); #line 1 }
// Writes the data to the response static void onion_png_write(png_struct *p, png_bytep data, size_t l){ onion_png_data *d=(onion_png_data*)png_get_io_ptr(p); onion_response_write(d->res, (const char *)data, l); //ONION_DEBUG("Write"); }
void base_html__block_content(onion_dict *context, onion_response *res){ #line 1 onion_response_write(res, "No content", 10); #line 1 }
/** * @short This shortcut returns the given file contents. * * It sets all the compilant headers (TODO), cache and so on. * * This is the recomended way to send static files; it even can use sendfile Linux call * if suitable (TODO). * * It does no security checks, so caller must be security aware. */ onion_connection_status onion_shortcut_response_file(const char *filename, onion_request *request, onion_response *res){ int fd=open(filename,O_RDONLY|O_CLOEXEC); if (fd<0) return OCS_NOT_PROCESSED; if(O_CLOEXEC == 0) { // Good compiler know how to cut this out int flags=fcntl(fd, F_GETFD); if (flags==-1){ ONION_ERROR("Retrieving flags from file descriptor"); } flags|=FD_CLOEXEC; if (fcntl(fd, F_SETFD, flags)==-1){ ONION_ERROR("Setting O_CLOEXEC to file descriptor"); } } struct stat st; if (stat(filename, &st)!=0){ ONION_WARNING("File does not exist: %s",filename); close(fd); return OCS_NOT_PROCESSED; } if (S_ISDIR(st.st_mode)){ close(fd); return OCS_NOT_PROCESSED; } size_t length=st.st_size; char etag[64]; onion_shortcut_etag(&st, etag); const char *range=onion_request_get_header(request, "Range"); if (range){ strncat(etag,range,sizeof(etag)-1); } onion_response_set_header(res, "Etag", etag); if (range && strncmp(range,"bytes=",6)==0){ onion_response_set_code(res, HTTP_PARTIAL_CONTENT); //ONION_DEBUG("Need just a range: %s",range); char tmp[1024]; strncpy(tmp, range+6, 1024); char *start=tmp; char *end=tmp; while (*end!='-' && *end) end++; if (*end=='-'){ *end='\0'; end++; //ONION_DEBUG("Start %s, end %s",start,end); size_t ends, starts; if (*end) ends=atol(end); else ends=length; starts=atol(start); length=ends-starts+1; lseek(fd, starts, SEEK_SET); snprintf(tmp,sizeof(tmp),"bytes %d-%d/%d",(unsigned int)starts, (unsigned int)ends, (unsigned int)st.st_size); //onion_response_set_header(res, "Accept-Ranges","bytes"); onion_response_set_header(res, "Content-Range",tmp); } } onion_response_set_length(res, length); onion_response_set_header(res, "Content-Type", onion_mime_get(filename) ); ONION_DEBUG("Mime type is %s",onion_mime_get(filename)); ONION_DEBUG0("Etag %s", etag); const char *prev_etag=onion_request_get_header(request, "If-None-Match"); if (prev_etag && (strcmp(prev_etag, etag)==0)){ ONION_DEBUG0("Not modified"); onion_response_set_length(res, 0); onion_response_set_code(res, HTTP_NOT_MODIFIED); onion_response_write_headers(res); close(fd); return OCS_PROCESSED; } onion_response_write_headers(res); if ((onion_request_get_flags(request)&OR_HEAD) == OR_HEAD){ // Just head. length=0; } if (length){ #ifdef USE_SENDFILE if (request->connection.listen_point->write==(void*)onion_http_write){ // Lets have a house party! I can use sendfile! onion_response_write(res,NULL,0); ONION_DEBUG("Using sendfile"); int r=sendfile(request->connection.fd, fd, NULL, length); ONION_DEBUG("Wrote %d, should be %d (%s)", r, length, r==length ? "ok" : "nok"); if (r!=length || r<0){ ONION_ERROR("Could not send all file (%s)", strerror(errno)); close(fd); return OCS_INTERNAL_ERROR; } res->sent_bytes+=length; res->sent_bytes_total+=length; } else #endif { // Ok, no I cant, do it as always. int r=0,w; size_t tr=0; char tmp[4046]; if (length>sizeof(tmp)){ size_t max=length-sizeof(tmp); while( tr<max ){ r=read(fd,tmp,sizeof(tmp)); tr+=r; if (r<0) break; w=onion_response_write(res, tmp, r); if (w!=r){ ONION_ERROR("Wrote less than read: write %d, read %d. Quite probably closed connection.",w,r); break; } } } if (sizeof(tmp) >= (length-tr)){ r=read(fd, tmp, length-tr); w=onion_response_write(res, tmp, r); if (w!=r){ ONION_ERROR("Wrote less than read: write %d, read %d. Quite probably closed connection.",w,r); } } } } close(fd); return OCS_PROCESSED; }