# HG changeset patch # User Sebastien Jodogne # Date 1347780594 -7200 # Node ID 77aec9be0a51f3b29ba42b55e80ab3ee19400e91 # Parent c996319e90bc6655a38818b1e018ef835b28197b renaming of cppclient diff -r c996319e90bc -r 77aec9be0a51 OrthancCppClient/CMakeLists.txt --- a/OrthancCppClient/CMakeLists.txt Sun Sep 16 09:28:56 2012 +0200 +++ b/OrthancCppClient/CMakeLists.txt Sun Sep 16 09:29:54 2012 +0200 @@ -1,9 +1,9 @@ -# Mini-project to check whether "PalanthirCppClient" can compile in a +# Mini-project to check whether "OrthancCppClient" can compile in a # standalone fashion cmake_minimum_required(VERSION 2.8) -project(PalanthirCppClientTest) +project(OrthancCppClientTest) SET(STATIC_BUILD OFF) @@ -20,7 +20,7 @@ add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) endif() -add_library(PalanthirCppClient +add_library(OrthancCppClient SHARED ${THIRD_PARTY_SOURCES} @@ -32,4 +32,4 @@ main.cpp ) -target_link_libraries(Test PalanthirCppClient) +target_link_libraries(Test OrthancCppClient) diff -r c996319e90bc -r 77aec9be0a51 OrthancCppClient/HttpClient.cpp --- a/OrthancCppClient/HttpClient.cpp Sun Sep 16 09:28:56 2012 +0200 +++ b/OrthancCppClient/HttpClient.cpp Sun Sep 16 09:29:54 2012 +0200 @@ -1,5 +1,5 @@ /** - * Palanthir - A Lightweight, RESTful DICOM Store + * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012 Medical Physics Department, CHU of Liege, * Belgium * @@ -31,7 +31,7 @@ #include -namespace Palanthir +namespace Orthanc { struct HttpClient::PImpl { @@ -88,13 +88,13 @@ CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADER, 0)); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 1)); -#if PALANTHIR_SSL_ENABLED == 1 +#if ORTHANC_SSL_ENABLED == 1 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 0)); #endif url_ = ""; - method_ = Palanthir_HttpMethod_Get; - lastStatus_ = Palanthir_HttpStatus_200_Ok; + method_ = Orthanc_HttpMethod_Get; + lastStatus_ = Orthanc_HttpStatus_200_Ok; isVerbose_ = false; } @@ -130,11 +130,11 @@ switch (method_) { - case Palanthir_HttpMethod_Get: + case Orthanc_HttpMethod_Get: CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPGET, 1L)); break; - case Palanthir_HttpMethod_Post: + case Orthanc_HttpMethod_Post: CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POST, 1L)); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPHEADER, pimpl_->postHeaders_)); @@ -151,12 +151,12 @@ break; - case Palanthir_HttpMethod_Delete: + case Orthanc_HttpMethod_Delete: CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_NOBODY, 1L)); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, "DELETE")); break; - case Palanthir_HttpMethod_Put: + case Orthanc_HttpMethod_Put: CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PUT, 1L)); break; @@ -173,11 +173,11 @@ if (status == 0) { // This corresponds to a call to an inexistent host - lastStatus_ = Palanthir_HttpStatus_500_InternalServerError; + lastStatus_ = Orthanc_HttpStatus_500_InternalServerError; } else { - lastStatus_ = static_cast(status); + lastStatus_ = static_cast(status); } return (status >= 200 && status < 300); diff -r c996319e90bc -r 77aec9be0a51 OrthancCppClient/HttpClient.h --- a/OrthancCppClient/HttpClient.h Sun Sep 16 09:28:56 2012 +0200 +++ b/OrthancCppClient/HttpClient.h Sun Sep 16 09:29:54 2012 +0200 @@ -1,5 +1,5 @@ /** - * Palanthir - A Lightweight, RESTful DICOM Store + * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012 Medical Physics Department, CHU of Liege, * Belgium * @@ -34,7 +34,7 @@ #include #include -namespace Palanthir +namespace Orthanc { class HttpClient { @@ -43,8 +43,8 @@ boost::shared_ptr pimpl_; std::string url_; - Palanthir_HttpMethod method_; - Palanthir_HttpStatus lastStatus_; + Orthanc_HttpMethod method_; + Orthanc_HttpStatus lastStatus_; std::string postData_; bool isVerbose_; @@ -68,12 +68,12 @@ return url_; } - void SetMethod(Palanthir_HttpMethod method) + void SetMethod(Orthanc_HttpMethod method) { method_ = method; } - Palanthir_HttpMethod GetMethod() const + Orthanc_HttpMethod GetMethod() const { return method_; } @@ -99,7 +99,7 @@ bool Apply(Json::Value& answer); - Palanthir_HttpStatus GetLastStatus() const + Orthanc_HttpStatus GetLastStatus() const { return lastStatus_; } diff -r c996319e90bc -r 77aec9be0a51 OrthancCppClient/HttpEnumerations.h --- a/OrthancCppClient/HttpEnumerations.h Sun Sep 16 09:28:56 2012 +0200 +++ b/OrthancCppClient/HttpEnumerations.h Sun Sep 16 09:29:54 2012 +0200 @@ -1,5 +1,5 @@ /** - * Palanthir - A Lightweight, RESTful DICOM Store + * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012 Medical Physics Department, CHU of Liege, * Belgium * @@ -29,85 +29,85 @@ /** - * This file contains the enumerations for the access to the Palanthir + * This file contains the enumerations for the access to the Orthanc * REST API in C and C++. Namespaces are not used, in order to enable * the access in C. **/ // Most common, non-joke and non-experimental HTTP status codes // http://en.wikipedia.org/wiki/List_of_HTTP_status_codes -enum Palanthir_HttpStatus +enum Orthanc_HttpStatus { - Palanthir_HttpStatus_None = -1, + Orthanc_HttpStatus_None = -1, // 1xx Informational - Palanthir_HttpStatus_100_Continue = 100, - Palanthir_HttpStatus_101_SwitchingProtocols = 101, - Palanthir_HttpStatus_102_Processing = 102, + Orthanc_HttpStatus_100_Continue = 100, + Orthanc_HttpStatus_101_SwitchingProtocols = 101, + Orthanc_HttpStatus_102_Processing = 102, // 2xx Success - Palanthir_HttpStatus_200_Ok = 200, - Palanthir_HttpStatus_201_Created = 201, - Palanthir_HttpStatus_202_Accepted = 202, - Palanthir_HttpStatus_203_NonAuthoritativeInformation = 203, - Palanthir_HttpStatus_204_NoContent = 204, - Palanthir_HttpStatus_205_ResetContent = 205, - Palanthir_HttpStatus_206_PartialContent = 206, - Palanthir_HttpStatus_207_MultiStatus = 207, - Palanthir_HttpStatus_208_AlreadyReported = 208, - Palanthir_HttpStatus_226_IMUsed = 226, + Orthanc_HttpStatus_200_Ok = 200, + Orthanc_HttpStatus_201_Created = 201, + Orthanc_HttpStatus_202_Accepted = 202, + Orthanc_HttpStatus_203_NonAuthoritativeInformation = 203, + Orthanc_HttpStatus_204_NoContent = 204, + Orthanc_HttpStatus_205_ResetContent = 205, + Orthanc_HttpStatus_206_PartialContent = 206, + Orthanc_HttpStatus_207_MultiStatus = 207, + Orthanc_HttpStatus_208_AlreadyReported = 208, + Orthanc_HttpStatus_226_IMUsed = 226, // 3xx Redirection - Palanthir_HttpStatus_300_MultipleChoices = 300, - Palanthir_HttpStatus_301_MovedPermanently = 301, - Palanthir_HttpStatus_302_Found = 302, - Palanthir_HttpStatus_303_SeeOther = 303, - Palanthir_HttpStatus_304_NotModified = 304, - Palanthir_HttpStatus_305_UseProxy = 305, - Palanthir_HttpStatus_307_TemporaryRedirect = 307, + Orthanc_HttpStatus_300_MultipleChoices = 300, + Orthanc_HttpStatus_301_MovedPermanently = 301, + Orthanc_HttpStatus_302_Found = 302, + Orthanc_HttpStatus_303_SeeOther = 303, + Orthanc_HttpStatus_304_NotModified = 304, + Orthanc_HttpStatus_305_UseProxy = 305, + Orthanc_HttpStatus_307_TemporaryRedirect = 307, // 4xx Client Error - Palanthir_HttpStatus_400_BadRequest = 400, - Palanthir_HttpStatus_401_Unauthorized = 401, - Palanthir_HttpStatus_402_PaymentRequired = 402, - Palanthir_HttpStatus_403_Forbidden = 403, - Palanthir_HttpStatus_404_NotFound = 404, - Palanthir_HttpStatus_405_MethodNotAllowed = 405, - Palanthir_HttpStatus_406_NotAcceptable = 406, - Palanthir_HttpStatus_407_ProxyAuthenticationRequired = 407, - Palanthir_HttpStatus_408_RequestTimeout = 408, - Palanthir_HttpStatus_409_Conflict = 409, - Palanthir_HttpStatus_410_Gone = 410, - Palanthir_HttpStatus_411_LengthRequired = 411, - Palanthir_HttpStatus_412_PreconditionFailed = 412, - Palanthir_HttpStatus_413_RequestEntityTooLarge = 413, - Palanthir_HttpStatus_414_RequestUriTooLong = 414, - Palanthir_HttpStatus_415_UnsupportedMediaType = 415, - Palanthir_HttpStatus_416_RequestedRangeNotSatisfiable = 416, - Palanthir_HttpStatus_417_ExpectationFailed = 417, - Palanthir_HttpStatus_422_UnprocessableEntity = 422, - Palanthir_HttpStatus_423_Locked = 423, - Palanthir_HttpStatus_424_FailedDependency = 424, - Palanthir_HttpStatus_426_UpgradeRequired = 426, + Orthanc_HttpStatus_400_BadRequest = 400, + Orthanc_HttpStatus_401_Unauthorized = 401, + Orthanc_HttpStatus_402_PaymentRequired = 402, + Orthanc_HttpStatus_403_Forbidden = 403, + Orthanc_HttpStatus_404_NotFound = 404, + Orthanc_HttpStatus_405_MethodNotAllowed = 405, + Orthanc_HttpStatus_406_NotAcceptable = 406, + Orthanc_HttpStatus_407_ProxyAuthenticationRequired = 407, + Orthanc_HttpStatus_408_RequestTimeout = 408, + Orthanc_HttpStatus_409_Conflict = 409, + Orthanc_HttpStatus_410_Gone = 410, + Orthanc_HttpStatus_411_LengthRequired = 411, + Orthanc_HttpStatus_412_PreconditionFailed = 412, + Orthanc_HttpStatus_413_RequestEntityTooLarge = 413, + Orthanc_HttpStatus_414_RequestUriTooLong = 414, + Orthanc_HttpStatus_415_UnsupportedMediaType = 415, + Orthanc_HttpStatus_416_RequestedRangeNotSatisfiable = 416, + Orthanc_HttpStatus_417_ExpectationFailed = 417, + Orthanc_HttpStatus_422_UnprocessableEntity = 422, + Orthanc_HttpStatus_423_Locked = 423, + Orthanc_HttpStatus_424_FailedDependency = 424, + Orthanc_HttpStatus_426_UpgradeRequired = 426, // 5xx Server Error - Palanthir_HttpStatus_500_InternalServerError = 500, - Palanthir_HttpStatus_501_NotImplemented = 501, - Palanthir_HttpStatus_502_BadGateway = 502, - Palanthir_HttpStatus_503_ServiceUnavailable = 503, - Palanthir_HttpStatus_504_GatewayTimeout = 504, - Palanthir_HttpStatus_505_HttpVersionNotSupported = 505, - Palanthir_HttpStatus_506_VariantAlsoNegotiates = 506, - Palanthir_HttpStatus_507_InsufficientStorage = 507, - Palanthir_HttpStatus_509_BandwidthLimitExceeded = 509, - Palanthir_HttpStatus_510_NotExtended = 510 + Orthanc_HttpStatus_500_InternalServerError = 500, + Orthanc_HttpStatus_501_NotImplemented = 501, + Orthanc_HttpStatus_502_BadGateway = 502, + Orthanc_HttpStatus_503_ServiceUnavailable = 503, + Orthanc_HttpStatus_504_GatewayTimeout = 504, + Orthanc_HttpStatus_505_HttpVersionNotSupported = 505, + Orthanc_HttpStatus_506_VariantAlsoNegotiates = 506, + Orthanc_HttpStatus_507_InsufficientStorage = 507, + Orthanc_HttpStatus_509_BandwidthLimitExceeded = 509, + Orthanc_HttpStatus_510_NotExtended = 510 }; -enum Palanthir_HttpMethod +enum Orthanc_HttpMethod { - Palanthir_HttpMethod_Get = 0, - Palanthir_HttpMethod_Post = 1, - Palanthir_HttpMethod_Delete = 2, - Palanthir_HttpMethod_Put = 3 + Orthanc_HttpMethod_Get = 0, + Orthanc_HttpMethod_Post = 1, + Orthanc_HttpMethod_Delete = 2, + Orthanc_HttpMethod_Put = 3 }; diff -r c996319e90bc -r 77aec9be0a51 OrthancCppClient/HttpException.cpp --- a/OrthancCppClient/HttpException.cpp Sun Sep 16 09:28:56 2012 +0200 +++ b/OrthancCppClient/HttpException.cpp Sun Sep 16 09:29:54 2012 +0200 @@ -1,5 +1,5 @@ /** - * Palanthir - A Lightweight, RESTful DICOM Store + * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012 Medical Physics Department, CHU of Liege, * Belgium * @@ -27,11 +27,11 @@ #include "HttpException.h" -namespace Palanthir +namespace Orthanc { const char* HttpException::What() const { - if (status_ == Palanthir_HttpStatus_None) + if (status_ == Orthanc_HttpStatus_None) { return custom_.c_str(); } @@ -41,164 +41,164 @@ } } - const char* HttpException::GetDescription(Palanthir_HttpStatus status) + const char* HttpException::GetDescription(Orthanc_HttpStatus status) { switch (status) { - case Palanthir_HttpStatus_100_Continue: + case Orthanc_HttpStatus_100_Continue: return "Continue"; - case Palanthir_HttpStatus_101_SwitchingProtocols: + case Orthanc_HttpStatus_101_SwitchingProtocols: return "Switching Protocols"; - case Palanthir_HttpStatus_102_Processing: + case Orthanc_HttpStatus_102_Processing: return "Processing"; - case Palanthir_HttpStatus_200_Ok: + case Orthanc_HttpStatus_200_Ok: return "OK"; - case Palanthir_HttpStatus_201_Created: + case Orthanc_HttpStatus_201_Created: return "Created"; - case Palanthir_HttpStatus_202_Accepted: + case Orthanc_HttpStatus_202_Accepted: return "Accepted"; - case Palanthir_HttpStatus_203_NonAuthoritativeInformation: + case Orthanc_HttpStatus_203_NonAuthoritativeInformation: return "Non-Authoritative Information"; - case Palanthir_HttpStatus_204_NoContent: + case Orthanc_HttpStatus_204_NoContent: return "No Content"; - case Palanthir_HttpStatus_205_ResetContent: + case Orthanc_HttpStatus_205_ResetContent: return "Reset Content"; - case Palanthir_HttpStatus_206_PartialContent: + case Orthanc_HttpStatus_206_PartialContent: return "Partial Content"; - case Palanthir_HttpStatus_207_MultiStatus: + case Orthanc_HttpStatus_207_MultiStatus: return "Multi-Status"; - case Palanthir_HttpStatus_208_AlreadyReported: + case Orthanc_HttpStatus_208_AlreadyReported: return "Already Reported"; - case Palanthir_HttpStatus_226_IMUsed: + case Orthanc_HttpStatus_226_IMUsed: return "IM Used"; - case Palanthir_HttpStatus_300_MultipleChoices: + case Orthanc_HttpStatus_300_MultipleChoices: return "Multiple Choices"; - case Palanthir_HttpStatus_301_MovedPermanently: + case Orthanc_HttpStatus_301_MovedPermanently: return "Moved Permanently"; - case Palanthir_HttpStatus_302_Found: + case Orthanc_HttpStatus_302_Found: return "Found"; - case Palanthir_HttpStatus_303_SeeOther: + case Orthanc_HttpStatus_303_SeeOther: return "See Other"; - case Palanthir_HttpStatus_304_NotModified: + case Orthanc_HttpStatus_304_NotModified: return "Not Modified"; - case Palanthir_HttpStatus_305_UseProxy: + case Orthanc_HttpStatus_305_UseProxy: return "Use Proxy"; - case Palanthir_HttpStatus_307_TemporaryRedirect: + case Orthanc_HttpStatus_307_TemporaryRedirect: return "Temporary Redirect"; - case Palanthir_HttpStatus_400_BadRequest: + case Orthanc_HttpStatus_400_BadRequest: return "Bad Request"; - case Palanthir_HttpStatus_401_Unauthorized: + case Orthanc_HttpStatus_401_Unauthorized: return "Unauthorized"; - case Palanthir_HttpStatus_402_PaymentRequired: + case Orthanc_HttpStatus_402_PaymentRequired: return "Payment Required"; - case Palanthir_HttpStatus_403_Forbidden: + case Orthanc_HttpStatus_403_Forbidden: return "Forbidden"; - case Palanthir_HttpStatus_404_NotFound: + case Orthanc_HttpStatus_404_NotFound: return "Not Found"; - case Palanthir_HttpStatus_405_MethodNotAllowed: + case Orthanc_HttpStatus_405_MethodNotAllowed: return "Method Not Allowed"; - case Palanthir_HttpStatus_406_NotAcceptable: + case Orthanc_HttpStatus_406_NotAcceptable: return "Not Acceptable"; - case Palanthir_HttpStatus_407_ProxyAuthenticationRequired: + case Orthanc_HttpStatus_407_ProxyAuthenticationRequired: return "Proxy Authentication Required"; - case Palanthir_HttpStatus_408_RequestTimeout: + case Orthanc_HttpStatus_408_RequestTimeout: return "Request Timeout"; - case Palanthir_HttpStatus_409_Conflict: + case Orthanc_HttpStatus_409_Conflict: return "Conflict"; - case Palanthir_HttpStatus_410_Gone: + case Orthanc_HttpStatus_410_Gone: return "Gone"; - case Palanthir_HttpStatus_411_LengthRequired: + case Orthanc_HttpStatus_411_LengthRequired: return "Length Required"; - case Palanthir_HttpStatus_412_PreconditionFailed: + case Orthanc_HttpStatus_412_PreconditionFailed: return "Precondition Failed"; - case Palanthir_HttpStatus_413_RequestEntityTooLarge: + case Orthanc_HttpStatus_413_RequestEntityTooLarge: return "Request Entity Too Large"; - case Palanthir_HttpStatus_414_RequestUriTooLong: + case Orthanc_HttpStatus_414_RequestUriTooLong: return "Request-URI Too Long"; - case Palanthir_HttpStatus_415_UnsupportedMediaType: + case Orthanc_HttpStatus_415_UnsupportedMediaType: return "Unsupported Media Type"; - case Palanthir_HttpStatus_416_RequestedRangeNotSatisfiable: + case Orthanc_HttpStatus_416_RequestedRangeNotSatisfiable: return "Requested Range Not Satisfiable"; - case Palanthir_HttpStatus_417_ExpectationFailed: + case Orthanc_HttpStatus_417_ExpectationFailed: return "Expectation Failed"; - case Palanthir_HttpStatus_422_UnprocessableEntity: + case Orthanc_HttpStatus_422_UnprocessableEntity: return "Unprocessable Entity"; - case Palanthir_HttpStatus_423_Locked: + case Orthanc_HttpStatus_423_Locked: return "Locked"; - case Palanthir_HttpStatus_424_FailedDependency: + case Orthanc_HttpStatus_424_FailedDependency: return "Failed Dependency"; - case Palanthir_HttpStatus_426_UpgradeRequired: + case Orthanc_HttpStatus_426_UpgradeRequired: return "Upgrade Required"; - case Palanthir_HttpStatus_500_InternalServerError: + case Orthanc_HttpStatus_500_InternalServerError: return "Internal Server Error"; - case Palanthir_HttpStatus_501_NotImplemented: + case Orthanc_HttpStatus_501_NotImplemented: return "Not Implemented"; - case Palanthir_HttpStatus_502_BadGateway: + case Orthanc_HttpStatus_502_BadGateway: return "Bad Gateway"; - case Palanthir_HttpStatus_503_ServiceUnavailable: + case Orthanc_HttpStatus_503_ServiceUnavailable: return "Service Unavailable"; - case Palanthir_HttpStatus_504_GatewayTimeout: + case Orthanc_HttpStatus_504_GatewayTimeout: return "Gateway Timeout"; - case Palanthir_HttpStatus_505_HttpVersionNotSupported: + case Orthanc_HttpStatus_505_HttpVersionNotSupported: return "HTTP Version Not Supported"; - case Palanthir_HttpStatus_506_VariantAlsoNegotiates: + case Orthanc_HttpStatus_506_VariantAlsoNegotiates: return "Variant Also Negotiates"; - case Palanthir_HttpStatus_507_InsufficientStorage: + case Orthanc_HttpStatus_507_InsufficientStorage: return "Insufficient Storage"; - case Palanthir_HttpStatus_509_BandwidthLimitExceeded: + case Orthanc_HttpStatus_509_BandwidthLimitExceeded: return "Bandwidth Limit Exceeded"; - case Palanthir_HttpStatus_510_NotExtended: + case Orthanc_HttpStatus_510_NotExtended: return "Not Extended"; default: diff -r c996319e90bc -r 77aec9be0a51 OrthancCppClient/HttpException.h --- a/OrthancCppClient/HttpException.h Sun Sep 16 09:28:56 2012 +0200 +++ b/OrthancCppClient/HttpException.h Sun Sep 16 09:29:54 2012 +0200 @@ -1,5 +1,5 @@ /** - * Palanthir - A Lightweight, RESTful DICOM Store + * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012 Medical Physics Department, CHU of Liege, * Belgium * @@ -31,29 +31,29 @@ #include -namespace Palanthir +namespace Orthanc { class HttpException { private: - Palanthir_HttpStatus status_; + Orthanc_HttpStatus status_; std::string custom_; public: - static const char* GetDescription(Palanthir_HttpStatus status); + static const char* GetDescription(Orthanc_HttpStatus status); HttpException(const std::string& custom) { - status_ = Palanthir_HttpStatus_None; + status_ = Orthanc_HttpStatus_None; custom_ = custom; } - HttpException(Palanthir_HttpStatus status) + HttpException(Orthanc_HttpStatus status) { status_ = status; } - Palanthir_HttpStatus GetHttpStatus() const + Orthanc_HttpStatus GetHttpStatus() const { return status_; } diff -r c996319e90bc -r 77aec9be0a51 OrthancCppClient/main.cpp --- a/OrthancCppClient/main.cpp Sun Sep 16 09:28:56 2012 +0200 +++ b/OrthancCppClient/main.cpp Sun Sep 16 09:29:54 2012 +0200 @@ -1,5 +1,5 @@ /** - * Palanthir - A Lightweight, RESTful DICOM Store + * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012 Medical Physics Department, CHU of Liege, * Belgium * @@ -32,7 +32,7 @@ int main() { // Prepare a simple call to a Web service - Palanthir::HttpClient c; + Orthanc::HttpClient c; c.SetUrl("http://nominatim.openstreetmap.org/search?format=json&q=chu+liege+belgium"); // Do the request and store the result in a JSON structure