From 7753459dc20ee50af0e0087eca5184fd59bcd8a5 Mon Sep 17 00:00:00 2001 From: bookug Date: Tue, 25 Jul 2017 23:19:05 +0800 Subject: [PATCH] feat: enhance the HTTP server; merge lijing's code, support a good sparql endpoint; bug in download file, and unable to visit by inputing URLs in browser directly; by lijing and zengli --- Database/Database.cpp | 8 + Main/ghttp.cpp | 494 ++++++++++++++++---- Server/LICENSE | 0 Server/README.md | 0 Server/client_http.hpp | 11 +- Server/server_http.hpp | 15 +- Server/web/PHPAPIExample.php | 37 ++ Server/web/index.html | 141 +++--- Server/web/index.js | 246 +++++++++- Server/web/view.css | 866 +++++++++++++++++++++++++++++++++++ Server/web/view.js | 1 + Util/Util.h | 7 + api/http/REST.md | 23 + api/http/cpp/TODO | 0 init.conf | 2 + makefile | 2 +- 16 files changed, 1668 insertions(+), 185 deletions(-) mode change 100755 => 100644 Server/LICENSE mode change 100755 => 100644 Server/README.md mode change 100755 => 100644 Server/client_http.hpp mode change 100755 => 100644 Server/server_http.hpp create mode 100755 Server/web/PHPAPIExample.php create mode 100755 Server/web/view.css create mode 100755 Server/web/view.js create mode 100644 api/http/REST.md create mode 100644 api/http/cpp/TODO diff --git a/Database/Database.cpp b/Database/Database.cpp index 83ee710..71d48b1 100644 --- a/Database/Database.cpp +++ b/Database/Database.cpp @@ -625,6 +625,10 @@ Database::load() id2entity_thread.join(); id2literal_thread.join(); #endif + + //TODO+BETTER: if we set string buffer using string index instead of B+Tree, then we can + //avoid to load id2entity and id2literal in ONLY_READ mode + //generate the string buffer for entity and literal, no need for predicate //NOTICE:the total string size should not exceed 20G, assume that most strings length < 500 //too many empty between entity and literal, so divide them @@ -1200,6 +1204,10 @@ Database::query(const string _query, ResultSet& _result_set, FILE* _fp) //Update else { +#ifdef ONLY_READ + //invalid query because updates are not allowed in ONLY_READ mode + return -101; +#endif success_num = 0; TripleWithObjType *update_triple = NULL; TYPE_TRIPLE_NUM update_triple_num = 0; diff --git a/Main/ghttp.cpp b/Main/ghttp.cpp index fa8fddf..919ab28 100644 --- a/Main/ghttp.cpp +++ b/Main/ghttp.cpp @@ -6,6 +6,12 @@ # Description: created by lvxin, improved by lijing =============================================================================*/ +//TODO: change json or other formats to RDF N3 format in openkg +// +//SPARQL Endpoint: log files in logs/endpoint/ +//operation.log: not used +//query.log: query string, result num, and time of answering + #include "../Server/server_http.hpp" #include "../Server/client_http.hpp" //db @@ -19,10 +25,12 @@ using namespace boost::property_tree; typedef SimpleWeb::Server HttpServer; typedef SimpleWeb::Client HttpClient; -int initialize(); +//int initialize(); +int initialize(int argc, char *argv[]); //Added for the default_resource example void default_resource_send(const HttpServer &server, const shared_ptr &response, const shared_ptr &ifs); +void download_result(const HttpServer& server, const shared_ptr& response, const shared_ptr& request, string download, string filepath); pthread_t start_thread(void *(*_function)(void*)); bool stop_thread(pthread_t _thread); @@ -39,12 +47,7 @@ pthread_t scheduler = 0; //DEBUG+TODO: why the result transfered to client has no \n \t?? //using json is a good way to avoid this problem -//TODO+BETTER: port should be optional -//1. admin.html: build/load/query/unload -//2. index.html: only query (maybe load/unload if using multiple databases) -//3. ghttp: can add or not add a db as parameter //BETTER: How about change HttpConnector into a console? -// //TODO: we need a route //JSON parser: http://www.tuicool.com/articles/yUJb6f //(or use boost spirit to generate parser when compiling) @@ -87,15 +90,17 @@ string UrlDecode(string& SRC) return (ret); } -int main() { - +int main(int argc, char *argv[]) +{ Util util; + srand(time(NULL)); while (true) { pid_t fpid = fork(); if (fpid == 0) { - int ret = initialize(); + //int ret = initialize(); + int ret = initialize(argc, argv); exit(ret); return ret; } @@ -120,16 +125,70 @@ int main() { return 0; } +bool isNum(char *str) +{ + for(int i = 0; i < strlen(str); i++) + { + int tmp = (int)(str[i]); + if(tmp < 48 || tmp > 57) + return false; + } + return true; +} -int initialize() { +int initialize(int argc, char *argv[]) +{ + cout << "enter initialize." << endl; + HttpServer server; + string db_name; + if(argc == 1) + { + server.config.port = 9000; + db_name = ""; + } + else if(argc == 2) + { + if(isNum(argv[1])) + { + server.config.port = atoi(argv[1]); + db_name = ""; + } + else + { + server.config.port = 9000; + db_name = argv[1]; + } + } + else + { + if(isNum(argv[1])) + { + server.config.port = atoi(argv[1]); + db_name = argv[2]; + } + else if(isNum(argv[2])) + { + server.config.port = atoi(argv[2]); + db_name = argv[1]; + } + else + { + cout << "wrong format of parameters, please input the server port and the database." << endl; + return 0; + } + } + cout << "server port: " << server.config.port << " database name: " << db_name << endl; + Util util; //HTTP-server at port 9000 using 1 thread + //Unless you do more heavy non-threaded processing in the resources, //1 thread is usually faster than several threads - HttpServer server; + //HttpServer server; //server.config.port=8080; - server.config.port=9000; + //server.config.port=9000; //cout<<"after server built"< response, shared_ptr request) { @@ -157,6 +216,107 @@ int initialize() { //database += ".db"; string dataset = db_path; + if(current_database != NULL) + { + string error = "Please unload your database first."; + *response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; + return 0; + } + + cout << "Import dataset to build database..." << endl; + cout << "DB_store: " << database << "\tRDF_data: " << dataset << endl; + int len = database.length(); + + current_database = new Database(database); + bool flag = current_database->build(dataset); + delete current_database; + current_database = NULL; + + if(!flag) + { + string error = "Import RDF file to database failed."; + string cmd = "rm -r " + database; + system(cmd.c_str()); + return 0; + } + + // string success = db_name + " " + db_path; + string success = "Import RDF file to database done."; + *response << "HTTP/1.1 200 OK\r\nContent-Length: " << success.length() << "\r\n\r\n" << success; + return 0; + }; +*/ + + + //GET-example for the path /load/[db_name], responds with the matched string in path + //For instance a request GET /load/db123 will receive: db123 + //server.resource["^/load/(.*)$"]["GET"]=[&server](shared_ptr response, shared_ptr request) { + + string database = db_name; + if(database != "") + { + if(database.length() > 3 && database.substr(database.length()-3, 3) == ".db") + { + cout << "Your db name to be built should not end with \".db\"." << endl; + return 0; + } + + //database += ".db"; + + if(current_database != NULL) + { + cout << "Please unload your current database first." << endl; + return 0; + } + cout << database << endl; + current_database = new Database(database); + bool flag = current_database->load(); + if (!flag) + { + cout << "Failed to load the database."< response, shared_ptr request) { + + cout<<"HTTP: this is build"<path_match[1]; + string db_path=request->path_match[2]; + if(db_name=="" || db_path=="") + { + string error = "Exactly 2 arguments required!"; + // error = db_name + " " + db_path; + *response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; + return 0; + } + + string database = db_name; + if(database.length() > 3 && database.substr(database.length()-3, 3) == ".db") + { + string error = "Your db name to be built should not end with \".db\"."; + *response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; + return 0; + } + + //database += ".db"; + string dataset = db_path; + if(current_database != NULL) { string error = "Please unload your database first."; @@ -187,25 +347,24 @@ int initialize() { return 0; }; - //GET-example for the path /load/[db_name], responds with the matched string in path - //For instance a request GET /load/db123 will receive: db123 - server.resource["^/load/(.*)$"]["GET"]=[&server](shared_ptr response, shared_ptr request) { + //GET-example for the path /?operation=load&db_name=[db_name], responds with the matched string in path + server.resource["^/%3[F|f]operation%3[D|d]load%26db_name%3[D|d](.*)$"]["GET"]=[&server](shared_ptr response, shared_ptr request) { cout<<"HTTP: this is load"<path_match[1]; - - + // string db_name = argv[1]; if(db_name=="") - { - string error = "Exactly 1 argument is required!"; - *response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; - return 0; - } - + { + string error = "Exactly 1 argument is required!"; + *response << "HTTP/1.1 200 ok\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; + return 0; + } + string database = db_name; if(database.length() > 3 && database.substr(database.length()-3, 3) == ".db") { - string error = "Your db name to be built should not end with \".db\"."; + //cout << "Your db name to be built should not end with \".db\"." << endl; + string error = "Your db name to be built should not end with \".db\"."; *response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; return 0; } @@ -214,6 +373,7 @@ int initialize() { if(current_database != NULL) { + //cout << "Please unload your current database first." < response, shared_ptr request) { - //TODO: add a format parameter, better to change tp "?format=json" - string format = "json"; + //GET-example for the path /?operation=unload&db_name=[db_name], responds with the matched string in path + server.resource["^/%3[F|f]operation%3[D|d]unload%26db_name%3[D|d](.*)$"]["GET"]=[&server](shared_ptr response, shared_ptr request) { + + if(current_database == NULL) + { + string error = "No database used now."; + *response << "HTTP/1.1 200 OK\r\nContent-Length: " << error.length() << "\r\n\r\n" << error; + return 0; + } + + delete current_database; + current_database = NULL; + string success = "Database unloaded."; + *response << "HTTP/1.1 200 OK\r\nContent-Length: " << success.length() << "\r\n\r\n" << success; + return 0; + }; +#endif + + + + //GET-example for the path /?operation=query&format=[format]&sparql=[sparql], responds with the matched string in path + server.resource["^/%3[F|f]operation%3[D|d]query%26format%3[D|d](.*)%26sparql%3[D|d](.*)$"]["GET"] = [&server](shared_ptr response, shared_ptr request) { + // server.resource["^/query/(.*)$"]["GET"] = [&server](shared_ptr response, shared_ptr request) { + string format = request->path_match[1]; + //string format = "html"; cout<<"HTTP: this is query"<path_match[1]; - cout<<"check: "<path_match[2]; db_query = UrlDecode(db_query); cout<<"check: "< response, shared_ptr request) { - cout<<"HTTP: this is unload"< response, shared_ptr request) { + server.resource["^/%3Foperation%3[D|d]monitor$"]["GET"]=[&server](shared_ptr response, shared_ptr request) { cout<<"HTTP: this is monitor"<content, pt); - // string name=pt.get("firstName")+" "+pt.get("lastName"); + // string sparql=pt.get("queryContent"); // *response << "HTTP/1.1 200 OK\r\n" // << "Content-Type: application/json\r\n" @@ -405,6 +634,29 @@ int initialize() { // } // }; + //USAGE: in endpoint, if user choose to display via html, but not display all because the result's num is too large. + //Then, user can choose to download all results in TXT format, and this URL is used for download in this case + //WARN: this URL rule should not be published! + // + //NOTICE: we need to remove temp result files after download once, otherwise the disk of server will be run out easily. + // + //Safety: user can attack by using this URL and point a specific filePath to be removed, which is not the download one! + //We do not have the http session ID here and can not provide best safety, but we can set the filePath complicated. + //(then attacker is hard to guess, and the directory is restricted) + //BETTER+TODO: associate the thread/session ID with download fileName, otherwise error may come in parallism + // + //GET-example for the path /?operation=delete&download=[download]&filepath=[filepath], responds with the matched string in path + server.resource["^/%3[F|f]operation%3[D|d]delete%26download%3[D|d](.*)%26filepath%3[D|d](.*)$"]["GET"]=[&server](shared_ptr response, shared_ptr request) { + cout << "HTTP: this is delete" << endl; + string download = request->path_match[1]; + download = UrlDecode(download); + cout << "download: " << download << endl; + string filepath = request->path_match[2]; + filepath = UrlDecode(filepath); + + download_result(server, response, request, download, filepath); + }; + //Default GET-example. If no other matches, this anonymous function will be called. //Will respond with content in the web/-directory, and its subdirectories. //Default file: index.html @@ -531,3 +783,61 @@ void* func_scheduler(void* _args) { void thread_sigterm_handler(int _signal_num) { pthread_exit(0); } + +void download_result(const HttpServer& server, const shared_ptr& response, const shared_ptr& request, string download, string filepath) +{ + cout<<"to download result or not"<distance(path.begin(), path.end()) || + !equal(root_path.begin(), root_path.end(), path.begin())) + throw invalid_argument("path must be within root path."); + if(download == "true") + { + std::string cache_control, etag; + + // Uncomment the following line to enable Cache-Control + // cache_control="Cache-Control: max-age=86400\r\n"; + + //return file in path + auto ifs=make_shared(); + ifs->open(path.string(), ifstream::in | ios::binary | ios::ate); + + if(*ifs) { + //cout<<"open file!!!"<tellg(); + ifs->seekg(0, ios::beg); + + *response << "HTTP/1.1 200 OK\r\n" << cache_control << etag << "Content-Length: " << length << "\r\n\r\n"; + default_resource_send(server, response, ifs); + } + else + throw invalid_argument("could not read file."); + } + if((boost::filesystem::exists(path) && boost::filesystem::is_regular_file(path))) + { + //delete file in delpath. + char name[60]; + strcpy(name, path.c_str()); + cout << "name: " << name << endl; + if(remove(name) == -1) + { + cout << "could not delete file." << endl; + perror("remove"); + } + else + cout << "file delete." << endl; + } + } + catch(const exception &e) { + //cout<<"can not open file!!!"<path+": "+e.what(); + *response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << content.length() << "\r\n\r\n" << content; + } +} + diff --git a/Server/LICENSE b/Server/LICENSE old mode 100755 new mode 100644 diff --git a/Server/README.md b/Server/README.md old mode 100755 new mode 100644 diff --git a/Server/client_http.hpp b/Server/client_http.hpp old mode 100755 new mode 100644 index 2038d93..342b3f4 --- a/Server/client_http.hpp +++ b/Server/client_http.hpp @@ -1,7 +1,16 @@ #ifndef CLIENT_HTTP_HPP #define CLIENT_HTTP_HPP -#include "../Util/Util.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include #ifndef CASE_INSENSITIVE_EQUALS_AND_HASH #define CASE_INSENSITIVE_EQUALS_AND_HASH diff --git a/Server/server_http.hpp b/Server/server_http.hpp old mode 100755 new mode 100644 index 621ec99..c7d0a24 --- a/Server/server_http.hpp +++ b/Server/server_http.hpp @@ -1,7 +1,17 @@ #ifndef SERVER_HTTP_HPP #define SERVER_HTTP_HPP -#include "../Util/Util.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include #ifndef CASE_INSENSITIVE_EQUALS_AND_HASH #define CASE_INSENSITIVE_EQUALS_AND_HASH @@ -424,7 +434,8 @@ namespace SimpleWeb { config.timeout_content=timeout_content; } - Server() : ServerBase::ServerBase(9000) {} + Server() : ServerBase::ServerBase(9002) {} + //Server() : ServerBase::ServerBase(80) {} protected: void accept() { diff --git a/Server/web/PHPAPIExample.php b/Server/web/PHPAPIExample.php new file mode 100755 index 0000000..e1dcd81 --- /dev/null +++ b/Server/web/PHPAPIExample.php @@ -0,0 +1,37 @@ +"; + for ($i = 1; $i < count($array); $i++) { + $href = str_replace(">", "", $array[$i]); + $html.= ''; + } + $html.= '
' . $array[0] . "
' . $href . '
'; + echo $html; + exit; + + case 2: + $filename = 'sparql.txt'; + header("Content-Type: application/octet-stream"); + header('Content-Disposition: attachment; filename="' . $filename . '"'); + echo $result; + exit; + + case 3: + $filename = 'sparql.csv'; + header("Content-Type: application/octet-stream"); + header('Content-Disposition: attachment; filename="' . $filename . '"'); + $array = explode("<", $result); + echo $array[0]; + for ($i = 1; $i < count($array); $i++) { + $href = str_replace(">", "", $array[$i]); + echo $href; + } + exit; +} +?> diff --git a/Server/web/index.html b/Server/web/index.html index b47aa3e..37bf01b 100644 --- a/Server/web/index.html +++ b/Server/web/index.html @@ -1,77 +1,82 @@ - - - - - - + + + + + OpenKG Query Endpoint + + + + + +
- - +

OpenKG Query Endpoint

+
+
+

OpenKG Query Endpoint

+

+
- - - - - -
-
- - +
    +
  • + +
    + + +
    - -
    -
    - -
    - - +
  • + +
  • + +
    + +
    +
  • + +
  • + + +
    + +
    +
  • + +
  • + +
    + +
    +
  • +
+ + + + + - -
-
-
-
- - -
- -
-
-
-
-
-
-
- -
-
-
-
- - - - - - - - - -
- - - - - + - + + diff --git a/Server/web/index.js b/Server/web/index.js index a6703ed..814d58d 100644 --- a/Server/web/index.js +++ b/Server/web/index.js @@ -1,28 +1,232 @@ -function load(db) { - //alert("to load"+db); - $.get("load/"+db, function(data, status){ - //alert("in get"); - if(status=="success"){ - alert(data); - } - }); -} function query(dp) { - $.get("query/" + dp, function(data, status){ + //alert(dp); + var encodeVal = escape(dp); + //alert(encodeVal); + var format = document.getElementById("element_5").value; + if(format == "1") + format = "html"; + else if(format == "2") + format = "txt"; + else if(format == "3") + format = "csv"; + else if(format == "4") + format = "json"; + var argu = "?operation=query&format=" + format + "&sparql=" + dp; + var encodeArgu = escape(argu); + $.get(encodeArgu, function(data, status){ + if(status=="success"){ - $("#queryAns").empty(); - var res = $("

").text(data); - $("#queryAns").append(res); - $("#queryAns").scrollTop($("#queryAns").height()); + //toTxt(); + //alert(data); + if(format == "html") + { + var parts = data.split("+"); + var fileName = parts[2]; + var lines = Number(parts[1]); + //alert(lines); + if(lines > 100) + lines = 100; + //alert(lines); + var items = parts[3].split("\n"); + //alert(items[86]); + var valNum = items[0].split("?"); + var rows = valNum.length - 1; + + var page = '
Click to Return'; + page = page + 'Click to Download'; + page = page + '

Total answers: '; + page = page + parts[1]; + page = page + '

'; + if(parts[0] == "1") + { + + page = page + '

Number of answers is too large, show only 100 of them, click to download the full result!

'; + + } + page = page + '
'; + page = page + ""; + + for(var ii = 1; ii <= rows; ii++) + { + page = page + ""; + } + page = page + ""; + var i = 1; + var j = 0; + for (i = 1; i <= lines; i++) + { + page = page + ""; + //alert(items[i]); + var tmpItem = items[i].replace(/"([^"]*)"/g, "<$1>"); + //alert(tmpItem); + var item = tmpItem.split(">"); + //alert(item.length); + for(j = 0; j < rows; j++) + { + page = page + ''; + } + page = page + ""; + } + page = page + '
" + "?" + valNum[ii] + "
' + item[j].replace("<", "") + '
'; + $("#main_body").empty(); + $("#main_body").append(page); + + var tmp1 = "?operation=delete&download=true&filepath=" + fileName; + var request1 = escape(tmp1); + var element1 = document.getElementById("download"); + element1.setAttribute("href", request1); + element1.setAttribute("download", "sparql.txt"); + element1.onclick = function(){ + element1.setAttribute("style", "display: none"); + } + var element2 = document.getElementById("back"); + element2.onclick = function(){ + if($(element1).css("display") != "none") + { + var tmp2 = "?operation=delete&download=false&filepath=" + fileName; + var request2 = escape(tmp2); + $.get(request2, function(data, status){}); + } + } + } + else + { + var parts = data.split("+"); + var fileName = parts[2]; + var tmp = "?operation=delete&download=true&filepath=" + fileName; + var request = escape(tmp); + var element = document.getElementById("hideLink"); + element.setAttribute("href", request); + if(format == "txt") + element.setAttribute("download", "sparql.txt"); + else if(format == "csv") + element.setAttribute("download", "sparql.csv"); + else if(format == "json") + element.setAttribute("download", "sparql.json"); + if(/msie/i.test(navigator.userAgent)) + { + element.fireEvent("onclick"); + } + else + { + var e = document.createEvent("MouseEvents"); + e.initEvent("click", true, true); + element.dispatchEvent(e); + } + } + /* + + alert(data); + var vl = document.getElementById("queryAns").value; + alert(vl); + //$("#queryAns").value=data; + document.getElementById("queryAns").value = data; + vl = document.getElementById("queryAns").value; + alert(vl); + document.getElementById("myForm").submit(); + */ } }); + } -function unload(db) { - $.get("unload", function(data, status){ - if(status=="success"){ - alert(data); - } - }); -} +function handleQueryExample() + { + var example = document.getElementById("example").value; + if (example === "q1") + { + document.getElementById("element_3").value = "SELECT DISTINCT ?v0 ?v1 ?v2 \n" + + "WHERE \n" + + "{ \n" + + "\t?v0 . \n" + + "\t?v0 . \n" + + "\t?v0 . \n" + + "} \n"; + } + + if (example === "q2") + { + document.getElementById("element_3").value = "SELECT ?v0 ?v1 WHERE \n" + + "{ \n" + + "\t?v0 ?v1 .\n" + + "} \n"; + } + + if (example === "q3") + { + document.getElementById("element_3").value = "SELECT ?v0 ?v1 ?v2 ?v3 WHERE \n" + + "{ \n" + + "\t?v0 .\n" + + "\tOPTIONAL{?v0 ?v2 .}\n" + + "} \n"; + } + + if (example === "q4") + { + document.getElementById("element_3").value = "SELECT DISTINCT ?v0 WHERE \n" + + "{ \n" + + "\t?v0 .\n" + + "\t{?v0 ?v1 .}\n" + "UNION\n" + + "\t{?v0 ?v2 .}\n" + + "} \n"; + } + if (example === "q5") + { + document.getElementById("element_3").value = "SELECT ?v0 ?v2 ?v3 WHERE \n" + + "{ \n" + + "\t?v0 .\n" + + "\t?v2 ?v0 .\n" + + "\t?v3 ?v2 .\n" + + "} \n"; + } + if (example === "q6") + { + document.getElementById("element_3").value = "SELECT ?V1 ?V2 WHERE \n" + + "{ \n" + + "\t?v1 .\n" + + "\t?v2 ?v1 .\n" + + "\t ?v2 .\n" + + "} \n"; + } + if (example === "q7") + { + document.getElementById("element_3").value = "SELECT ?v0 ?v1 WHERE \n" + + "{ \n" + + "\t ?v0 .\n" + + "\t?v1 ?v0 .\n" + + "}\n"; + } + if (example === "q8") + { + document.getElementById("element_3").value = "SELECT ?v0 ?v1 ?v2 ?v3 ?v4 ?v5 ?v6 WHERE \n" + + "{\n" + + "\t?v0 ?v1 .\n" + + "\t?v0 ?v2 .\n" + + "\t?v0 ?v3 .\n" + + "\t?v0 ?v4 .\n" + + "\t?v0 ?v5 .\n" + + "\t?v0 ?v6 .\n" + + "}\n"; + } + if (example === "q9") + { + document.getElementById("element_3").value = "SELECT ?v0 ?v1 ?v2 ?v3 WHERE\n" + + "{\n" + + "\t?V0 ?v1 .\n" + + "\t?v0 ?v2 .\n" + + "\t?v0 .\n" + + "\t?v0 ?v3 .\n" + + "}\n"; + } + if (example === "q10") + { + document.getElementById("element_3").value = "SELECT ?v0 ?v1 ?v2 ?v3 WHERE\n" + + "{\n" + + "\t?v0 ?v1 .\n" + + "\t?v0 ?v2 .\n" + + "\t?v0 ?v3 .\n" + + "\t?v0 .\n" + + "}\n"; + } + } diff --git a/Server/web/view.css b/Server/web/view.css new file mode 100755 index 0000000..f59eaba --- /dev/null +++ b/Server/web/view.css @@ -0,0 +1,866 @@ +body +{ + background:#fffff; + font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif; + font-size:small; + margin:8px 0 16px; + text-align:center; +} + +#back +{ + font-size:16px; +} +#form_container +{ + background:#fff; + border:1px solid #ccc; + margin:0 auto; + text-align:left; + width:640px; +} + +#top +{ + display:block; + height:10px; + margin:10px auto 0; + width:650px; +} + +#footer +{ + width:640px; + clear:both; + color:#999999; + text-align:center; + width:640px; + padding-bottom: 15px; + font-size: 85%; +} + +#footer a{ + color:#999999; + text-decoration: none; + border-bottom: 1px dotted #999999; +} + +#bottom +{ + display:block; + height:10px; + margin:0 auto; + width:650px; +} + +form.appnitro +{ + margin:20px 20px 0; + padding:0 0 20px; +} + +/**** Logo Section *****/ +h1 +{ + background-color:#dedede; + margin:0; + min-height:0; + padding:0; + text-decoration:none; + text-indent:-8000px; + +} + +h1 a +{ + + display:block; + height:100%; + min-height:40px; + overflow:hidden; +} + + +img +{ + behavior:url(css/iepngfix.htc); + border:none; +} + + +/**** Form Section ****/ +.appnitro +{ + font-family:Lucida Grande, Tahoma, Arial, Verdana, sans-serif; + font-size:small; +} + +.appnitro li +{ + width:61%; +} + +form ul +{ + font-size:100%; + list-style-type:none; + margin:0; + padding:0; + width:100%; +} + +form li +{ + display:block; + margin:0; + padding:4px 5px 2px 9px; + position:relative; +} + +form li:after +{ + clear:both; + content:"."; + display:block; + height:0; + visibility:hidden; +} + +.buttons:after +{ + clear:both; + content:"."; + display:block; + height:0; + visibility:hidden; +} + +.buttons +{ + clear:both; + display:block; + margin-top:10px; +} + +* html form li +{ + height:1%; +} + +* html .buttons +{ + height:1%; +} + +* html form li div +{ + display:inline-block; +} + +form li div +{ + color:#444; + margin:0 4px 0 0; + padding:0 0 8px; +} + +form li span +{ + color:#444; + float:left; + margin:0 4px 0 0; + padding:0 0 8px; +} + +form li div.left +{ + display:inline; + float:left; + width:48%; +} + +form li div.right +{ + display:inline; + float:right; + width:48%; +} + +form li div.left .medium +{ + width:100%; +} + +form li div.right .medium +{ + width:100%; +} + +.clear +{ + clear:both; +} + +form li div label +{ + clear:both; + color:#444; + display:block; + font-size:9px; + line-height:9px; + margin:0; + padding-top:3px; +} + +form li span label +{ + clear:both; + color:#444; + display:block; + font-size:9px; + line-height:9px; + margin:0; + padding-top:3px; +} + +form li .datepicker +{ + cursor:pointer !important; + float:left; + height:16px; + margin:.1em 5px 0 0; + padding:0; + width:16px; +} + +.form_description +{ + border-bottom:1px dotted #ccc; + clear:both; + display:inline-block; + margin:0 0 1em; +} + +.form_description[class] +{ + display:block; +} + +.form_description h2 +{ + clear:left; + font-size:160%; + font-weight:400; + margin:0 0 3px; +} + +.form_description p +{ + font-size:95%; + line-height:130%; + margin:0 0 12px; +} + +form hr +{ + display:none; +} + +form li.section_break +{ + border-top:1px dotted #ccc; + margin-top:9px; + padding-bottom:0; + padding-left:9px; + padding-top:13px; + width:97% !important; +} + +form ul li.first +{ + border-top:none !important; + margin-top:0 !important; + padding-top:0 !important; +} + +form .section_break h3 +{ + font-size:110%; + font-weight:400; + line-height:130%; + margin:0 0 2px; +} + +form .section_break p +{ + font-size:85%; + + margin:0 0 10px; +} + +/**** Buttons ****/ +input.button_text +{ + overflow:visible; + padding:0 7px; + width:auto; +} + +.buttons input +{ + font-size:120%; + margin-right:5px; +} + +/**** Inputs and Labels ****/ +label.description +{ + border:none; + color:#222; + display:block; + font-size:95%; + font-weight:700; + line-height:150%; + padding:0 0 1px; +} + +span.symbol +{ + font-size:115%; + line-height:130%; +} + +input.text +{ + border-bottom:1px solid #ddd; + border-left:1px solid #c3c3c3; + border-right:1px solid #c3c3c3; + border-top:1px solid #7c7c7c; + color:#333; + font-size:100%; + margin:0; + padding:2px 0; +} + +input.file +{ + color:#333; + font-size:100%; + margin:0; + padding:2px 0; +} + +textarea.textarea +{ + border-bottom:1px solid #ddd; + border-left:1px solid #c3c3c3; + border-right:1px solid #c3c3c3; + border-top:1px solid #7c7c7c; + color:#333; + font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif; + font-size:100%; + margin:0; + width:99%; +} + +select.select +{ + color:#333; + font-size:100%; + margin:1px 0; + padding:1px 0 0; + border-bottom:1px solid #ddd; + border-left:1px solid #c3c3c3; + border-right:1px solid #c3c3c3; + border-top:1px solid #7c7c7c; +} + + +input.currency +{ + text-align:right; +} + +input.checkbox +{ + display:block; + height:13px; + line-height:1.4em; + margin:6px 0 0 3px; + width:13px; +} + +input.radio +{ + display:block; + height:13px; + line-height:1.4em; + margin:6px 0 0 3px; + width:13px; +} + +label.choice +{ + color:#444; + display:block; + font-size:100%; + line-height:1.4em; + margin:-1.55em 0 0 25px; + padding:4px 0 5px; + width:90%; +} + +select.select[class] +{ + margin:0; + padding:1px 0; +} + +*:first-child+html select.select[class] +{ + margin:1px 0; +} + +.safari select.select +{ + font-size:120% !important; + margin-bottom:1px; +} + +input.small +{ + width:25%; +} + +select.small +{ + width:25%; +} + +input.medium +{ + width:50%; +} + +select.medium +{ + width:50%; +} + +input.large +{ + width:99%; +} + +select.large +{ + width:100%; +} + +textarea.small +{ + height:5.5em; +} + +textarea.medium +{ + height:10em; +} + +textarea.large +{ + height:20em; +} + +/**** Errors ****/ +#error_message +{ + background:#fff; + border:1px dotted red; + margin-bottom:1em; + padding-left:0; + padding-right:0; + padding-top:4px; + text-align:center; + width:99%; +} + +#error_message_title +{ + color:#DF0000; + font-size:125%; + margin:7px 0 5px; + padding:0; +} + +#error_message_desc +{ + color:#000; + font-size:100%; + margin:0 0 .8em; +} + +#error_message_desc strong +{ + background-color:#FFDFDF; + color:red; + padding:2px 3px; +} + +form li.error +{ + background-color:#FFDFDF !important; + border-bottom:1px solid #EACBCC; + border-right:1px solid #EACBCC; + margin:3px 0; +} + +form li.error label +{ + color:#DF0000 !important; +} + +form p.error +{ + clear:both; + color:red; + font-size:10px; + font-weight:700; + margin:0 0 5px; +} + +form .required +{ + color:red; + float:none; + font-weight:700; +} + +/**** Guidelines and Error Highlight ****/ +form li.highlighted +{ + background-color:#fff7c0; +} + +form .guidelines +{ + background:#f5f5f5; + border:1px solid #e6e6e6; + color:#444; + font-size:80%; + left:100%; + line-height:130%; + margin:0 0 0 8px; + padding:8px 10px 9px; + position:absolute; + top:0; + visibility:hidden; + width:42%; + z-index:1000; +} + +form .guidelines small +{ + font-size:105%; +} + +form li.highlighted .guidelines +{ + visibility:visible; +} + +form li:hover .guidelines +{ + visibility:visible; +} + +.no_guidelines .guidelines +{ + display:none !important; +} + +.no_guidelines form li +{ + width:97%; +} + +.no_guidelines li.section +{ + padding-left:9px; +} + +/*** Success Message ****/ +.form_success +{ + clear: both; + margin: 0; + padding: 90px 0pt 100px; + text-align: center +} + +.form_success h2 { + clear:left; + font-size:160%; + font-weight:normal; + margin:0pt 0pt 3px; +} + +/*** Password ****/ +ul.password{ + margin-top:60px; + margin-bottom: 60px; + text-align: center; +} +.password h2{ + color:#DF0000; + font-weight:bold; + margin:0pt auto 10px; +} + +.password input.text { + font-size:170% !important; + width:380px; + text-align: center; +} +.password label{ + display:block; + font-size:120% !important; + padding-top:10px; + font-weight:bold; +} + +#li_captcha{ + padding-left: 5px; +} + + +#li_captcha span{ + float:none; +} + +/** Embedded Form **/ + +.embed #form_container{ + border: none; +} + +.embed #top, .embed #bottom, .embed h1{ + display: none; +} + +.embed #form_container{ + width: 100%; +} + +.embed #footer{ + text-align: left; + padding-left: 10px; + width: 99%; +} + +.embed #footer.success{ + text-align: center; +} + +.embed form.appnitro +{ + margin:0px 0px 0; + +} + + + +/*** Calendar **********************/ +div.calendar { position: relative; } + +.calendar table { +cursor:pointer; +border:1px solid #ccc; +font-size: 11px; +color: #000; +background: #fff; +font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif; +} + +.calendar .button { +text-align: center; +padding: 2px; +} + +.calendar .nav { +background:#f5f5f5; +} + +.calendar thead .title { +font-weight: bold; +text-align: center; +background: #dedede; +color: #000; +padding: 2px 0 3px 0; +} + +.calendar thead .headrow { +background: #f5f5f5; +color: #444; +font-weight:bold; +} + +.calendar thead .daynames { +background: #fff; +color:#333; +font-weight:bold; +} + +.calendar thead .name { +border-bottom: 1px dotted #ccc; +padding: 2px; +text-align: center; +color: #000; +} + +.calendar thead .weekend { +color: #666; +} + +.calendar thead .hilite { +background-color: #444; +color: #fff; +padding: 1px; +} + +.calendar thead .active { +background-color: #d12f19; +color:#fff; +padding: 2px 0px 0px 2px; +} + + +.calendar tbody .day { +width:1.8em; +color: #222; +text-align: right; +padding: 2px 2px 2px 2px; +} +.calendar tbody .day.othermonth { +font-size: 80%; +color: #bbb; +} +.calendar tbody .day.othermonth.oweekend { +color: #fbb; +} + +.calendar table .wn { +padding: 2px 2px 2px 2px; +border-right: 1px solid #000; +background: #666; +} + +.calendar tbody .rowhilite td { +background: #FFF1AF; +} + +.calendar tbody .rowhilite td.wn { +background: #FFF1AF; +} + +.calendar tbody td.hilite { +padding: 1px 1px 1px 1px; +background:#444 !important; +color:#fff !important; +} + +.calendar tbody td.active { +color:#fff; +background: #529214 !important; +padding: 2px 2px 0px 2px; +} + +.calendar tbody td.selected { +font-weight: bold; +border: 1px solid #888; +padding: 1px 1px 1px 1px; +background: #f5f5f5 !important; +color: #222 !important; +} + +.calendar tbody td.weekend { +color: #666; +} + +.calendar tbody td.today { +font-weight: bold; +color: #529214; +background:#D9EFC2; +} + +.calendar tbody .disabled { color: #999; } + +.calendar tbody .emptycell { +visibility: hidden; +} + +.calendar tbody .emptyrow { +display: none; +} + +.calendar tfoot .footrow { +text-align: center; +background: #556; +color: #fff; +} + +.calendar tfoot .ttip { +background: #222; +color: #fff; +font-size:10px; +border-top: 1px solid #dedede; +padding: 3px; +} + +.calendar tfoot .hilite { +background: #aaf; +border: 1px solid #04f; +color: #000; +padding: 1px; +} + +.calendar tfoot .active { +background: #77c; +padding: 2px 0px 0px 2px; +} + +.calendar .combo { +position: absolute; +display: none; +top: 0px; +left: 0px; +width: 4em; +border: 1px solid #ccc; +background: #f5f5f5; +color: #222; +font-size: 90%; +z-index: 100; +} + +.calendar .combo .label, +.calendar .combo .label-IEfix { +text-align: center; +padding: 1px; +} + +.calendar .combo .label-IEfix { +width: 4em; +} + +.calendar .combo .hilite { +background: #444; +color:#fff; +} + +.calendar .combo .active { +border-top: 1px solid #999; +border-bottom: 1px solid #999; +background: #dedede; +font-weight: bold; +} + diff --git a/Server/web/view.js b/Server/web/view.js new file mode 100755 index 0000000..d3a87e2 --- /dev/null +++ b/Server/web/view.js @@ -0,0 +1 @@ +eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('3(7.X){7["R"+a]=a;7["z"+a]=6(){7["R"+a](7.1k)};7.X("1e",7["z"+a])}E{7.19("z",a,15)}2 j=H V();6 a(){2 e=q.1d("1a");3(e){o(e,"P");2 N=B(q,"*","14");3((e.12<=10)||(N=="")){c(e,"P",d)}}4=B(q,"*","1n");k(i=0;i<4.b;i++){3(4[i].F=="1g"||4[i].F=="1f"||4[i].F=="1c"){4[i].1b=6(){r();c(v.5.5,"f",d)};4[i].O=6(){r();c(v.5.5,"f",d)};j.D(j.b,0,4[i])}E{4[i].O=6(){r();c(v.5.5,"f",d)};4[i].18=6(){o(v.5.5,"f")}}}2 C=17.16.13();2 A=q.M("11");3(C.K("J")+1){c(A[0],"J",d)}3(C.K("I")+1){c(A[0],"I",d)}}6 r(){k(2 i=0;i