annotate eventLogger.mm @ 29:fabb3a5cdfc9

Timed session improvements. Desperate pathetic attempts to send a simple HTTP POST.
author Robert Tubb <rt300@eecs.qmul.ac.uk>
date Fri, 22 Feb 2013 17:41:38 +0000
parents e2c62db1e265
children c0a6f7c66719
rev   line source
rt300@0 1 //
rt300@0 2 // eventLogger.mm
rt300@0 3 // oscSenderExample
rt300@0 4 //
rt300@0 5 // Created by Robert Tubb on 05/11/2012.
rt300@0 6 //
rt300@0 7 //
rt300@4 8
rt300@8 9 //---------------------------------------------------------------------------
rt300@0 10 #include "eventLogger.h"
rt300@1 11
rt300@1 12 EventLogger eventLogger;
rt300@29 13
rt300@8 14 //---------------------------------------------------------------------------
rt300@1 15 EventLogger::EventLogger(){
rt300@14 16 //QuestionnaireViewController * questionnaireViewController;
rt300@8 17
rt300@25 18 consentGiven = true; // unless told otherwise by introView
rt300@8 19 loggingEnabled = true;
rt300@22 20 serverConnectionOK = false;
rt300@22 21 questionnaireCompleted = false;
rt300@22 22 questionnaireUploaded = false;
rt300@27 23 currentHTTPRequestID = -1;
rt300@27 24 logUploadInProgress = false;
rt300@22 25 ofxiPhoneDeviceType iOSdeviceType = ofxiPhoneGetDeviceType();
rt300@22 26 cout << "Device: " << iOSdeviceType << '\n';
rt300@22 27
rt300@25 28 nextUploadQty = UPLOAD_CHUNK_SIZE; // amount of data uploaded is always more than UPLOAD_CHUNK_SIZE events
rt300@27 29
rt300@8 30 }
rt300@8 31 //---------------------------------------------------------------------------
rt300@24 32 // draw() - show path of last N scroll events - can be scrubbed along?
rt300@24 33 //
rt300@24 34 //---------------------------------------------------------------------------
rt300@29 35
rt300@8 36 void EventLogger::init(){
rt300@4 37
rt300@8 38 readJsonToLog(ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME);
rt300@8 39 sessionStartTime = ofGetSystemTime();
rt300@9 40
rt300@9 41 testConnection();
rt300@7 42
rt300@25 43 logEvent(APP_STARTED);
rt300@29 44
rt300@29 45 stringstream r;
rt300@29 46 r << LOGGING_SERVER_URL << "testConnection?jsontext=" << "{\"test\":\"test\"}&Content-Length=456";
rt300@29 47
rt300@29 48 NSString *urlstring;
rt300@29 49 urlstring = @"http://127.0.0.1:8080/testservice/testConnection?jsontext={\"objc post\":\"obj c post\"}";
rt300@29 50 serverComms = [[ServerComms alloc] init];
rt300@29 51 [serverComms postRequest:urlstring];
rt300@29 52
rt300@29 53
rt300@29 54 urlstring = nil;
rt300@8 55 }
rt300@29 56
rt300@8 57 //---------------------------------------------------------------------------
rt300@28 58 void EventLogger::questionnaireAnswersObtained(vector<int> answers, const char* userComments){
rt300@22 59
rt300@22 60 questionnaireCompleted = true;
rt300@22 61 questionnaireAnswers = answers;
rt300@28 62 questionnaireComments = userComments;
rt300@22 63 uploadQuestionnaire();
rt300@22 64
rt300@22 65 }
rt300@22 66 //---------------------------------------------------------------------------
rt300@27 67 void EventLogger::uploadQuestionnaire(){
rt300@22 68 // show indicator
rt300@22 69 cout << "^^^^^^^^ UPLOADING QUESTIONNAIRE ^^^^^^^^ \n";
rt300@22 70
rt300@27 71 sendToServer("questionnaire", questionnaireToJson(), true);
rt300@27 72
rt300@22 73 }
rt300@22 74 //---------------------------------------------------------------------------
rt300@27 75 bool EventLogger::sendToServer(string functionName, Json::Value jsonData, bool async = false){
rt300@22 76 bool sent;
rt300@29 77 stringstream request;
rt300@22 78
rt300@29 79 request << LOGGING_SERVER_URL << functionName << "?jsontext=";
rt300@29 80 /*
rt300@22 81 if(functionName == "testConnection"){
rt300@22 82 request = "http://127.0.0.1:8080/testservice/testConnection?jsontext=";
rt300@22 83 }else if(functionName == "questionnaire"){
rt300@22 84 request = "http://127.0.0.1:8080/testservice/questionnaire?jsontext=";
rt300@22 85 }else if(functionName == "eventlog"){
rt300@22 86 request = "http://127.0.0.1:8080/testservice/eventlog?jsontext=";
rt300@22 87 }
rt300@29 88 */
rt300@22 89 Json::FastWriter writer;
rt300@22 90 string jsontext = writer.write( jsonData );
rt300@22 91
rt300@27 92 // remove newline
rt300@22 93 if (!jsontext.empty() && jsontext[jsontext.length()-1] == '\n') {
rt300@22 94 jsontext.erase(jsontext.length()-1);
rt300@22 95 }
rt300@22 96
rt300@29 97 request << jsontext;
rt300@29 98
rt300@29 99 cout << request.str();
rt300@27 100
rt300@27 101 if(!async){
rt300@27 102 ofURLFileLoader fileLoader;
rt300@27 103 ofHttpResponse resp;
rt300@29 104 resp = fileLoader.get(request.str());
rt300@22 105
rt300@27 106 cout << "HTTP STATUS " << resp.status << "\n";
rt300@27 107 cout << "HTTP ERROR " << resp.error << "\n";
rt300@27 108 cout << "HTTP DATA " << resp.data << "\n"; // ofBuffer
rt300@27 109
rt300@27 110 stringstream response;
rt300@27 111 response << resp.data;
rt300@27 112
rt300@27 113 if (resp.status == 200){
rt300@27 114 if(response.str() == "OK"){
rt300@27 115
rt300@27 116 sent = true;
rt300@27 117 }else{
rt300@27 118 // not ok
rt300@27 119 // problem serverside
rt300@27 120 sent = false;
rt300@27 121 }
rt300@27 122 }else{
rt300@27 123
rt300@27 124 sent = false;
rt300@27 125 // SHOW AN ALERT TO USER?
rt300@27 126 }
rt300@27 127
rt300@27 128 return sent;
rt300@27 129 }else{ // async
rt300@27 130 ofURLFileLoader fileLoader;
rt300@29 131 currentHTTPRequestID = ofLoadURLAsync(request.str(), functionName);
rt300@27 132 ofRegisterURLNotification(this);
rt300@27 133
rt300@27 134 return true; // ???
rt300@27 135 }
rt300@27 136 }
rt300@27 137 //-----------------------------
rt300@27 138 void EventLogger::urlResponse(ofHttpResponse & response){
rt300@27 139 cout << "gotHTTPRequestStatus\n";
rt300@27 140 cout << "HTTP REQUEST NAME " << response.request.name << "\n";
rt300@27 141 cout << "HTTP STATUS " << response.status << "\n";
rt300@27 142 cout << "HTTP ERROR " << response.error << "\n";
rt300@27 143 cout << "HTTP DATA " << response.data << "\n"; // ofBuffer
rt300@9 144
rt300@27 145 bool sent;
rt300@27 146 stringstream respStr;
rt300@27 147 respStr << response.data;
rt300@22 148
rt300@27 149 if (response.status == 200){
rt300@27 150 if(respStr.str() == "OK"){
rt300@22 151
rt300@22 152 sent = true;
rt300@22 153 }else{
rt300@22 154 // not ok
rt300@22 155 // problem serverside
rt300@22 156 sent = false;
rt300@22 157 }
rt300@9 158 }else{
rt300@22 159
rt300@22 160 sent = false;
rt300@9 161 // SHOW AN ALERT TO USER?
rt300@9 162 }
rt300@27 163
rt300@27 164 // now do request specific stuff
rt300@27 165 if(response.request.name == "eventlog"){
rt300@27 166 if(!sent){
rt300@27 167 // try later
rt300@27 168 nextUploadQty += UPLOAD_CHUNK_SIZE;
rt300@27 169 }else{
rt300@27 170
rt300@27 171 // if success - clear memory
rt300@27 172 theEvents.clear();
rt300@27 173 cout << "UPLOAD SUCCESS\n";
rt300@27 174 nextUploadNumber++;
rt300@27 175 }
rt300@27 176 logUploadInProgress = false;
rt300@27 177 }else if(response.request.name == "questionnaire"){
rt300@27 178 if(sent){
rt300@27 179 questionnaireUploaded = true;
rt300@27 180 }else{
rt300@27 181 questionnaireUploaded = false; // will try next time... when?
rt300@27 182 }
rt300@27 183 }else if(response.request.name == "testConnection"){
rt300@27 184
rt300@27 185 if (sent){
rt300@27 186 cout << "^^^^^^^^ server connection OK ^^^^^^^^ \n";
rt300@27 187 serverConnectionOK = true;
rt300@27 188 }else{
rt300@28 189 serverConnectionOK = false;
rt300@27 190 cout << "server connection ERROR \n";
rt300@27 191 }
rt300@27 192 }
rt300@27 193
rt300@22 194 }
rt300@22 195 //---------------------------------------------------------------------------
rt300@22 196 bool EventLogger::testConnection(){
rt300@22 197 Json::Value root;
rt300@29 198 root["x"] = "y";
rt300@22 199
rt300@22 200
rt300@27 201 sendToServer("testConnection", root, true);
rt300@27 202
rt300@9 203 }
rt300@9 204 //---------------------------------------------------------------------------
rt300@28 205 // this reads the persistent log file , checks if we've used the app before and
rt300@28 206 // if we've answered questionnaire or not
rt300@8 207 void EventLogger::readJsonToLog(const string &jsonFile){
rt300@8 208 Json::Value root;
rt300@8 209 Json::Reader reader;
rt300@5 210
rt300@5 211
rt300@8 212 ifstream theFile(jsonFile.c_str());
rt300@8 213 stringstream fileText;
rt300@8 214 string line;
rt300@8 215 if(!theFile){
rt300@8 216
rt300@8 217 firstEverAppOpen();
rt300@8 218
rt300@8 219 return;
rt300@8 220 }else{
rt300@8 221 while(theFile){
rt300@8 222 theFile >> line;
rt300@9 223 // cout << line; // lots!!!!
rt300@8 224 fileText << line;
rt300@8 225 }
rt300@8 226 theFile.close();
rt300@8 227 }
rt300@8 228
rt300@9 229 cout << "size of log JSON string:" << fileText.str().length() << "BYTES \n";
rt300@9 230
rt300@8 231 bool parsingSuccessful = reader.parse( fileText.str(), root );
rt300@8 232
rt300@8 233 if ( !parsingSuccessful )
rt300@8 234 {
rt300@8 235 // report to the user the failure and their locations in the document.
rt300@22 236 std::cout << "Failed to parse event log JSON: \n"
rt300@8 237 << reader.getFormattedErrorMessages();
rt300@8 238 return;
rt300@8 239 }
rt300@8 240
rt300@8 241 // now put user deets into variables
rt300@8 242 userName = root["userName"].asString();
rt300@8 243 deviceID = root["deviceID"].asLargestInt();
rt300@25 244 nextUploadNumber = root["uploadNumber"].asInt();
rt300@25 245 savedInteractionTime = root["savedInteractionTime"].asLargestInt();
rt300@22 246 questionnaireCompleted = root["questionnaireCompleted"].asBool();
rt300@22 247 questionnaireUploaded = root["questionnaireUploaded"].asBool();
rt300@28 248 interfaceOrder = root["interfaceOrder"].asInt();
rt300@22 249
rt300@22 250 if(questionnaireCompleted && !questionnaireUploaded){
rt300@22 251 // then read it in and upload it
rt300@28 252 Json::Value JQ = root["questionnaire"];
rt300@28 253 Json::Value JArray = JQ["qAnswers"];
rt300@22 254 if(JArray.size() < 2){
rt300@22 255 cout << "Error - status of questionnaire is wierd\n";
rt300@22 256 }
rt300@22 257 for ( unsigned int i = 0; i < JArray.size(); i++ )
rt300@22 258 {
rt300@28 259 questionnaireAnswers.push_back(JArray[i].asInt());
rt300@22 260 }
rt300@28 261 questionnaireComments = JQ["comments"].toStyledString();
rt300@22 262 uploadQuestionnaire();
rt300@22 263 }
rt300@8 264
rt300@8 265 // check for unuploaded evts
rt300@8 266 const Json::Value jlogs = root["events"];
rt300@8 267
rt300@8 268 for ( int index = 0; index < jlogs.size(); ++index ) theEvents.push_back(lEvent(jlogs[index]));
rt300@27 269 if(theEvents.size() > nextUploadQty && ! logUploadInProgress){
rt300@8 270 //try to upload
rt300@27 271 uploadEventLog(true);
rt300@8 272 }
rt300@8 273 // TODO if the total interaction time is greater than a certain amount && no questions answered - questionnaire time!
rt300@25 274 cout << "Total interaction time: " << savedInteractionTime << '\n';
rt300@28 275
rt300@29 276 //timer.setInteractionTime(savedInteractionTime);
rt300@29 277 //timer.setOrderFromPrevious(interfaceOrder);
rt300@8 278
rt300@9 279 }
rt300@9 280
rt300@9 281
rt300@9 282 //---------------------------------------------------------------------------
rt300@9 283
rt300@27 284 bool EventLogger::uploadEventLog(bool async){
rt300@28 285
rt300@22 286 // show indicator
rt300@27 287 logUploadInProgress = true;
rt300@25 288 cout << "^^^^^^^^ ATTEMPTING TO UPLOAD " << theEvents.size() << " EVENTS ^^^^^^^^ .\n";
rt300@27 289 if(!async){
rt300@27 290 bool success = sendToServer("eventlog", logsToJson(), async);
rt300@27 291 if(!success){
rt300@29 292 // try later : NOPE has maximum size
rt300@27 293 nextUploadQty += UPLOAD_CHUNK_SIZE;
rt300@27 294 }else{
rt300@27 295
rt300@27 296 // if success - clear memory
rt300@27 297 theEvents.clear();
rt300@27 298 cout << "UPLOAD SUCCESS\n";
rt300@27 299 nextUploadNumber++;
rt300@27 300 }
rt300@27 301 logUploadInProgress = false;
rt300@27 302 return success;
rt300@9 303 }else{
rt300@27 304 sendToServer("eventlog", logsToJson(), async);
rt300@9 305 }
rt300@1 306 }
rt300@8 307 //----------------------------------------------------------------------------
rt300@27 308
rt300@27 309 //----------------------------------------------------------------------------
rt300@9 310 //void EventLogger::deleteLogFile(){
rt300@8 311
rt300@8 312 //---------------------------------------------------------------------------
rt300@8 313
rt300@8 314 void EventLogger::firstEverAppOpen(){
rt300@25 315 cout<<"no event log file - first APP open\n";
rt300@25 316 nextUploadNumber = 0;
rt300@8 317 deviceID = ofGetSystemTimeMicros();
rt300@25 318 savedInteractionTime = 0;
rt300@22 319 questionnaireCompleted = false;
rt300@22 320 questionnaireUploaded = false;
rt300@8 321
rt300@24 322 ((testApp *)ofGetAppPtr())->showIntro();
rt300@25 323 consentGiven = false;
rt300@8 324
rt300@8 325 }
rt300@28 326 //---------------------------------------------------------------------------
rt300@28 327 // only called when doing supervised tests
rt300@27 328 void EventLogger::newUser(){
rt300@27 329 cout<<"setup new user\n";
rt300@29 330 deleteLogs();
rt300@27 331 nextUploadNumber = 0;
rt300@27 332 deviceID = ofGetSystemTimeMicros();
rt300@27 333 savedInteractionTime = 0;
rt300@28 334 totalInteractionTime = 0;
rt300@28 335 sessionStartTime = ofGetSystemTime();
rt300@27 336 questionnaireCompleted = false;
rt300@29 337 questionnaireUploaded = false;
rt300@29 338
rt300@29 339 ((testApp *)ofGetAppPtr())->showIntro();
rt300@27 340
rt300@27 341 }
rt300@8 342 //---------------------------------------------------------------------------
rt300@8 343 // called from alertView OK in iViewController
rt300@8 344 void EventLogger::setUsername(const char *u){
rt300@8 345 userName = u;
rt300@28 346 // start interaction clock
rt300@29 347
rt300@29 348 //timer.startInteractionClock();
rt300@29 349 [((testApp *)ofGetAppPtr())->tsc startTimer];
rt300@28 350 }
rt300@28 351 //---------------------------------------------------------------------------
rt300@28 352 void EventLogger::thinnedLogEvent(lEvent newEvent){
rt300@28 353 static lEvent previousEvent(APP_STARTED); // initialised as whatever. hopefully won't log
rt300@28 354 static int eventCounter = 0;
rt300@28 355
rt300@28 356 // if first event then log it. it won't be, but still.
rt300@28 357 if(theEvents.size() == 0){
rt300@28 358 theEvents.push_back(newEvent);
rt300@28 359 previousEvent = newEvent;
rt300@28 360 return;
rt300@28 361 }
rt300@28 362
rt300@28 363 // if previous event is more than 300ms ago, or event type has changed, log both of them
rt300@28 364 int gap = newEvent.eventTime - previousEvent.eventTime;
rt300@28 365 if(gap > 300 || newEvent.eventType != previousEvent.eventType){
rt300@28 366 // if prev event not logged, log it
rt300@28 367 if((*theEvents.end()).eventTime != previousEvent.eventTime){
rt300@28 368 theEvents.push_back(previousEvent);
rt300@28 369 }
rt300@28 370 theEvents.push_back(newEvent);
rt300@7 371
rt300@28 372 }
rt300@28 373
rt300@28 374 // otherwise only record every Nth event
rt300@28 375 if(eventCounter >= EVENT_THIN_FACTOR){
rt300@28 376 theEvents.push_back(newEvent);
rt300@28 377 eventCounter = 0;
rt300@28 378
rt300@28 379 }
rt300@28 380 eventCounter++;
rt300@28 381 previousEvent = newEvent;
rt300@7 382 }
rt300@8 383 //---------------------------------------------------------------------------
rt300@5 384 void EventLogger::logEvent(const leventType& evtType,const TwoVector& centre, const double& scale, const int& sliderID, const double& sliderVal){
rt300@3 385 //cout << "log: " << evtType << "\n";
rt300@1 386
rt300@1 387 // scroll has 2 double coords
rt300@1 388 // zoom has 1 double scale
rt300@1 389 // save preset has 2 coords
rt300@1 390 // switch view has view type
rt300@9 391 // slider change has int slider index and 1 float value
rt300@1 392
rt300@4 393 // get time for key index
rt300@4 394
rt300@5 395 // thinFactor
rt300@5 396 if(!loggingEnabled) return;
rt300@4 397 switch ( evtType ) {
rt300@28 398 // data thinning here
rt300@28 399 case SCROLL:
rt300@28 400 thinnedLogEvent(lEvent(evtType,centre.x,centre.y));
rt300@28 401 break;
rt300@28 402 case ZOOM:
rt300@28 403 thinnedLogEvent(lEvent(evtType,scale));
rt300@28 404 break;
rt300@28 405 case CHANGE_SLIDER:
rt300@28 406 thinnedLogEvent(lEvent(evtType,sliderVal , 0.0 , sliderID));
rt300@28 407 break;
rt300@29 408 // non thinned data
rt300@4 409 case SAVE_PRESET:
rt300@5 410 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 411 // Code
rt300@4 412 break;
rt300@4 413 case SAVE_DESET:
rt300@5 414 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@4 415 break;
rt300@28 416
rt300@5 417 case SCROLL_STOPPED:
rt300@5 418 theEvents.push_back(lEvent(evtType,centre.x,centre.y));
rt300@22 419 cout << "SCROLL STOPPED EVENT\n";
rt300@22 420 break;
rt300@22 421 case SNAPPED_TO_PRESET:
rt300@22 422 theEvents.push_back(lEvent(evtType,centre.x,centre.y,sliderID));
rt300@22 423 cout << "SCROLL STOPPED EVENT\n";
rt300@4 424 break;
rt300@25 425 case SWAP_VIEW:
rt300@25 426 theEvents.push_back(lEvent(evtType,0.0 , 0.0 , sliderID)); // slider ID is which view
rt300@25 427 break;
rt300@4 428 default:
rt300@25 429 // default is just an event type with no values
rt300@25 430 theEvents.push_back(lEvent(evtType));
rt300@4 431 break;
rt300@1 432 }
rt300@27 433 if(theEvents.size() > nextUploadQty && !logUploadInProgress){
rt300@27 434 //try to upload asynchronously
rt300@27 435 uploadEventLog(true);
rt300@7 436 }
rt300@9 437 //sessionTime = (ofGetSystemTime() - sessionStartTime);
rt300@28 438 totalInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime); // milliseconds
rt300@28 439
rt300@1 440 }
rt300@29 441 //--------------------------------------------------------------------
rt300@29 442 // called from newUser
rt300@29 443 void EventLogger::deleteLogs(){
rt300@29 444 // the
rt300@29 445 theEvents.clear();
rt300@29 446 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@29 447 ofFile logFile(fname,ofFile::WriteOnly);
rt300@29 448 logFile << "";
rt300@29 449 logFile.close();
rt300@29 450 }
rt300@8 451 //---------------------------------------------------------------------------
rt300@7 452
rt300@7 453 void EventLogger::exitAndSave(){
rt300@25 454
rt300@25 455 if(!consentGiven){
rt300@25 456 logEvent(CONSENT_DENIED);
rt300@25 457 Json::Value jlogs = logsToJson();
rt300@25 458 // try to upload TODO (no - might hang and prevent exit???)
rt300@27 459 uploadEventLog(true);
rt300@25 460 return;
rt300@25 461 }
rt300@25 462 logEvent(APP_EXITED);
rt300@25 463 savedInteractionTime = savedInteractionTime + (ofGetSystemTime() - sessionStartTime);
rt300@7 464 // save user details
rt300@8 465 string fname = ofxiPhoneGetDocumentsDirectory() + EVENT_LOG_FILENAME;
rt300@8 466
rt300@25 467 // try to upload TODO (no - might hang and prevent exit???)
rt300@27 468 // do it async because event list needs to be cleared to prevent saving on device
rt300@27 469 uploadEventLog(false);
rt300@7 470
rt300@8 471 // write to file
rt300@25 472 // json without the logs that were uploaded!
rt300@25 473 Json::Value jlogs = logsToJson();
rt300@8 474 ofFile logFile(fname,ofFile::WriteOnly);
rt300@8 475 logFile << jlogs;
rt300@29 476 logFile.close();
rt300@8 477
rt300@8 478 }
rt300@8 479 //---------------------------------------------------------------------------
rt300@8 480
rt300@8 481 Json::Value EventLogger::logsToJson(){
rt300@8 482 // put all logged events into Json formatted string
rt300@8 483 Json::Value root;
rt300@8 484
rt300@8 485 vector<lEvent>::iterator eventIter;
rt300@8 486
rt300@22 487 root["programVersion"] = PROGRAM_VERSION;
rt300@8 488 root["userName"] = userName;
rt300@8 489 root["deviceID"] = deviceID;
rt300@25 490 root["uploadNumber"] = nextUploadNumber;
rt300@22 491 root["iOSdeviceType"] = iOSdeviceType;
rt300@25 492 root["savedInteractionTime"] = savedInteractionTime;
rt300@22 493 root["questionnaireCompleted"] = questionnaireCompleted;
rt300@22 494 root["questionnaireUploaded"] = questionnaireUploaded;
rt300@22 495 if(questionnaireCompleted && !questionnaireUploaded){
rt300@28 496 root["questionnaire"] = questionnaireToJson();
rt300@22 497 }
rt300@8 498
rt300@8 499 int i = 0;
rt300@8 500 for(eventIter = theEvents.begin(); eventIter < theEvents.end(); eventIter++){
rt300@8 501 root["events"][i] = (*eventIter).eventToJson();
rt300@8 502 i++;
rt300@7 503 }
rt300@25 504 root["numEventsHere"] = i;
rt300@8 505 return root;
rt300@8 506 }
rt300@22 507
rt300@8 508 //---------------------------------------------------------------------------
rt300@22 509
rt300@22 510 Json::Value EventLogger::questionnaireToJson(){
rt300@22 511 // put all answers into Json formatted string
rt300@22 512 Json::Value root;
rt300@22 513
rt300@22 514 vector<int>::iterator aIter;
rt300@22 515
rt300@22 516 Json::Value questionnaire;
rt300@22 517
rt300@22 518 int i = 0;
rt300@22 519 for(aIter = questionnaireAnswers.begin(); aIter < questionnaireAnswers.end(); aIter++){
rt300@22 520 questionnaire[i] = (*aIter);
rt300@22 521 i++;
rt300@22 522 }
rt300@28 523 cout << questionnaireComments << "\n";
rt300@22 524
rt300@22 525 root["qAnswers"] = questionnaire;
rt300@28 526 root["comments"] = questionnaireComments;
rt300@22 527 root["userName"] = userName;
rt300@22 528 root["deviceID"] = deviceID;
rt300@22 529 root["iOSdeviceType"] = iOSdeviceType;
rt300@22 530 root["programVersion"] = PROGRAM_VERSION;
rt300@22 531
rt300@22 532 return root;
rt300@22 533 }
rt300@8 534 //---------------------------------------------------------------------------
rt300@8 535 //---------------------------------------------------------------------------
rt300@22 536 //---------------------------------------------------------------------------