================================================================================

 api.php

  The ReadLet entry-point WEB-API protocol

  https://www.readlet.it/apps/readlet/api.php

  The ReadLet WEB-APIs internally use the underlying PHP-APIs, by adding the
  management of the API authorization (apikey), of the transaction security
  (PHP session and CSRF token), of the cyclic redundancy check (crc32) and of
  the input/output compression/decompression (gzencode/gzdecode or
  gzdeflate/gzinflate).

  Marcello Ferro <marcello.ferro@gmail.com>
  25/10/2017 - 10/05/2022

================================================================================

 PROTOCOL
  Both the REQUEST and the RESPONSE are a json-formatted string containing two
  fields:
   - "json": again a json-formatted string;
   - "crc32": the CRC32 calculated on the "json" string.

  Both the REQUEST and the RESPONSE can be compressed by using either the
  "b64gze" or the "b64gzd" field instead of the "json" field (see below).
  If the REQUEST is compressed, then the RESPONSE will be automatically
  compressed by default (that is, unless the RESPONSE compression is
  explicitely turned off by setting the "zip" field to "none").

  Details about the name-value pairs available for the REQUEST and the
  RESPONSE in both the standard and the compressed version are provided below:

  REQUEST:
   {
    'json':'{
             "api":"...",                         // api function call (*)
             "apikey":"...",                      // api key (*)
             "zip":"none"|"b64gzd"|"b64gze",      // output compression: none, base64-gzdeflate, base64-gzencode (default is "none")
             "hrc":200|400|...,                   // the http response code to be used in case of RLA_ERROR_* (default is 200)
             "table":"rows"                       // output format: "table" is returned as an array of rows (default)
                    |"cols"                       //                "table" is returned as an array of columns
                    |"inline"                     //                for each column of the table, the column array is returned
                    |"inline1"                    //                for each column of the table, the column value (1st row) is returned (for a 1-row table only)
                    |"text",                      //                "table" is returned as plain text with CRLF as row separator and TAB as column separator
             "...":"..."                          // additional api-specific request params (see api details below)
            }',
    'crc32':<CRC32(json)>                         // json crc32-check (*)
   }

  RESPONSE:
   {
    'json':'{
             "rlaErr":"...",                      // RLA_ERROR_SUCCESS, or error-specific code (*)
             "rlaMsg":"...",                      // empty on success, verbose on error
             "...":"..."                          // additional API-specific response params
            }',
    'crc32':<CRC32(json)>                         // json crc32-check (*)
   }

--------------------------------------------------------------------------------

 OVERVIEW
  The one and only API call which does not require authorization is the
  "Login" API. On successful login, the response header will include a
  cookie ("Set-Cookie: PHPSESSID=<cookie>; path=/") and the response content
  json will include a token ("token": "<token>"). Both the cookie and the
  token must be sent within the request header in all the subsequent API calls:
  "Cookie: PHPSESSID=<cookie>; path=/"
  "Authorization: Bearer <token>".

 HTTP REQUEST EXAMPLE
  POST /apps/readlet/api.php HTTP/1.1
  Host: www.readlet.it
  Accept: application/json, */*
  Content-Type: application/json; charset=UTF-8   // use "x-www-form-urlencoded" if content is "json=...&crc32=..."
  Cookie: PHPSESSID=...; path=/                   // not needed on Login request
  Authorization: Bearer ...                       // not needed on Login request
  Content-Length: ...
  Connection: Keep-Alive

  {'json':'{"api":"...", "apikey":"...", ...}','crc32':...}

 HTTP RESPONSE EXAMPLE
  Set-Cookie: PHPSESSID=...; path=/               // present only on Login response
  Content-Length: ...

  {'json':'{"rlaErr":"...", "rlaMsg":"...", ...}','crc32':...}

--------------------------------------------------------------------------------

 REQUEST COMPRESSION (gzencode)
  If the 'b64gze' field is present, the request is threated as compressed.
  The "b64gze" field must be calculated as the base64 encoding of the gzencode
  compression of the underlying "json" field.
  The "crc32" filed must be calculated on such "b64gze" field.

  REQUEST:
   {
    "b64gze":"<base64_encode(gzencode(json))>",   // b64gze = base64_encode(gzdeflate(json));
    "crc32":<crc32(b64gze)>                       // b64gze crc32-check
   }

  The ReadLet server will decompress the request by using gzdecode.

 REQUEST COMPRESSION (gzdeflate)
  If the "b64gzd" field is present, the request is threated as compressed.
  The "b64gzd" field must be calculated as the base64 encoding of the gzdeflate
  compression of the underlying "json" field.
  The "crc32" filed must be calculated on such "b64gzd" field.
  
  REQUEST:
   {
    "b64gzd":"<base64_encode(gzdeflate(json))>",  // b64gzd = base64_encode(gzdeflate(json));
    "crc32":<crc32(b64gzd)>                       // b64gzd crc32-check
   }

  The ReadLet server will decompress the request by using gzinflate.

--------------------------------------------------------------------------------

 RESPONSE COMPRESSION (gzencode)
  If the "zip" request filed is set to "b64gze", then the response compression
  is activated and the RESPONSE json is gz-encoded and base64-encoded into the
  "b64gze" response field. The crc32 check will be applied to such field.

  RESPONSE:
   {
    "b64gze":"<base64_encode(gzencode(json))>",  // json = gzencode(base64_decode(b64gze));
    "crc32":<crc32(b64gze)>                      // b64gze crc32-check
   }

  The client should decompress the response by using gzdecode.

 RESPONSE COMPRESSION (gzdeflate)
  If the "zip" request filed is set to "b64gzd", then the response compression
  is activated and the RESPONSE json is gz-deflated and base64-encoded into the
  "b64gzd" response field. The crc32 check will be applied to such field.

  RESPONSE:
   {
    "b64gzd":"<base64_encode(gzdeflate(json))>",  // json = gzinflate(base64_decode(b64gzd));
    "crc32":<crc32(b64gzd)>                       // b64gzd crc32-check
   }

  The client should decompress the response by using gzinflate.

================================================================================

 API table of contents

 Login
 Logout
 GetDoc
 GetDocTable
 GetDocXML
 GetQuestTable
 GetQuestXML
 GetCampaign
 GetCampaignAffiliation
 GetCampaignDocs
 GetUser
 GetUserData
 GetGender
 GetHasProblem
 GetDevice
 GetBool
 GetHand
 GetJobPosition
 GetEducationalLevel
 GetTabletFamiliarities
 GetCognitiveProblems
 GetMemoryProblems
 GetAphasiaProblems
 GetParentType
 GetPDP
 GetAgeBeginEducation
 GetAgeCountryArrival
 GetLanguage
 GetReadingType
 SetUser
 SetUserData
 InitSession
 SendSessionData
 SendSessionContent
 SendSessionDecodingDocTrack
 SendSessionComprehensionDocTrack
 SendSessionComprehensionQuestTrack
 SendSessionComprehensionQuest
 CloseSession
 ReopenSession
 SetSessionAlign
 GetSession
 GetSessionData
 GetSessionContent
 GetSessionDecodingDocTrack
 GetSessionComprehensionDocTrack
 GetSessionComprehensionQuestTrack
 GetSessionComprehensionQuest
 AudioInfo
 AudioDownload
 FormSendParentQuestionnaire

================================================================================

 rl_api.php

 The ReadLet API interface

 When using as WEB-API (see api.php) the relevant fields are "api", "apiKey",
 "zip" ("none"), "hrc" (200), and "table" ("rows").
 The Login API should be called first, to obtain the "token" to be used as 
 "Authorization: Bearer ..." in subsequent API calls.

 The interface can be used also as PHP-API, in which case the only relevant
 input field is "table" ("rows"). Obviously, no authentication is needed.
 The PHP-API may be used in combination with the RLAP_Session* APIs to grant
 the proper PHP session management at application level.

 Marcello Ferro <marcello.ferro@gmail.com>
 25/10/2017 - 08/03/2023

 A---------------------B
 |.....................|
 |.E----------------F..|
 |.|                |..|
 |.|                |..|
 |.| I-----------J  |..|
 |.| |Lorem ipsum|  |..|
 |.| |dolor sit  |  |..|
 |.| |amet.      |  |..|
 |.| |           |  |..|
 |.| |Duis aute  |  |..|
 |.| |irure.     |  |..|
 |.| L-----------K  |..|
 |.|                |..|
 |.H----------------G..|
 |.....................|
 |.....................|
 D---------------------C

 The rectangle ABCD is the DESK (rendered in blue background)
 The rectangle EFGH is the PAPER (rendered in white background)
 The rectangle IJKL is the TEXT

 The TEXT (IJKL) is on the PAPER (EFGH), which is on the DESK (ABCD).

 E has coordinates (x,y)=(0,0)
 G has coordinates (x,y)=(1,1)

 x(E) - x(A) = deskRightWidth
 x(B) - x(F) = deskLeftWidth
 y(E) - y(A) = deskTopHeight
 y(D) - y(H) = deskBottomHeight

 x(I) - x(E) = marginLeft
 x(F) - x(J) = marginRight
 y(I) - y(E) = marginTop
 y(H) - y(L) = marginBottom

 deskRightWidth and deskLeftWidth are flipped on right-to-left layout
 marginRight and marginLeft are flipped on right-to-left layout

================================================================================

 LOGIN & LOGOUT

================================================================================
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                           WEB-API: json = {"api": "Login", ...}

 PHP-API: $out = RLA_Login($in)

 PURPOSE:
  Check the login authentication on the ReadLet GUI.

 OVERVIEW:
  On successful login, the out "rlaErr" is set to RLA_ERR_SUCCESS.

  On unsuccessful login (i.e. login and/or pwd are wrong) the
  RLA_ERR_AUTHENTICATIONFAILED is returned.

  On successful login:
  - the "idUser" is returned, containing the login user id;
  - a "token" is returned, containing the CSRF token set by the server.
    Such "token" must be specified in the authorization header of all
    subsequent API calls: "Authorization: Bearer <token>"
  - the PHP session id (sent as a cookie) must be specified in the header of
    all subsequent API calls;
  - the PHP session "auth" is set internally (will be checked in all
    subsequent API call);

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - the provided login and/or pwd are not valid credentials.

 IN:
  login: string (*)
  pwd: string (*)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: "" | ...
  idUser: int
  token: string

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                          WEB-API: json = {"api": "Logout", ...}

 PHP-API: $out = RLA_Logout($in)

 PURPOSE:
  Logout from the ReadLet GUI.

 OVERVIEW:
  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS.

  On fail, the "rlaErr" is set to the specific error.

 IN:

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: "" | ...

================================================================================

 DOC & QUEST

================================================================================
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                          WEB-API: json = {"api": "GetDoc", ...}

 PHP-API: $out = RLA_GetDoc($in)

 PURPOSE:
  The client asks the server the DB doc record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idDoc: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idDoc: int
   filename: string
   title: string
   notes: string
   type: string
   idLanguage: int (reference to DB language table)
   isDisabled: bool (set to true to hide the record within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                     WEB-API: json = {"api": "GetDocTable", ...}

 PHP-API: $out = RLA_GetDocTable($in)

 PURPOSE:
  The client asks the server the doc as a by-token table

 OVERVIEW:
  Each row represents a token.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the table is
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - the "idDoc" is not found within the "rl_docs" DB table;

 IN:
  idDoc: int (*)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   eid: int array
   gid: int array
   pid: int array
   sid: int array
   tid: int array
   groupType: string array
   token: string array

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                       WEB-API: json = {"api": "GetDocXML", ...}

 PHP-API: $out = RLA_GetDocXML($in)

 PURPOSE:
  The client asks the server the doc xml source.

 OVERVIEW:
  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the "xml" is
  returned.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - the "idDoc" is not found within the "rl_docs" DB table;
  - the xml file cannot be read;

 IN:
  idDoc: int (*)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  xml: string

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                   WEB-API: json = {"api": "GetQuestTable", ...}

 PHP-API: $out = RLA_GetQuestTable($in)

 PURPOSE:
  The client asks the server the questionnaire as a by-answer table

 OVERVIEW:
  Each row represents an answer.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the table is
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - the "idDoc" is not found within the "rl_docs" DB table;

 IN:
  idDoc: int (*)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   qid: int array
   aid: int array
   cor: int array
   tags: string array
   question: string array
   answer: string array

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                     WEB-API: json = {"api": "GetQuestXML", ...}

 PHP-API: $out = RLA_GetQuestXML($in)

 PURPOSE:
  The client asks the server the questionnaire xml source.

 OVERVIEW:
  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the "xml" is
  returned.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - the "idDoc" is not found within the "rl_docs" DB table;
  - the xml file cannot be read;

 IN:
  idDoc: int (*)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  xml: string

================================================================================

 CAMPAIGN

================================================================================
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                     WEB-API: json = {"api": "GetCampaign", ...}

 PHP-API: $out = RLA_GetCampaign($in)

 PURPOSE:
  The client asks the server the DB campaign record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idCampaign: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idCampaign: int
   title: string
   notes: string
   affiliations: string (json=[{id: ..., affiliation: "...", gradeLevel: ..., section: "..."}, ...])
   isDisabled: bool (set to true to hide the record within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                          WEB-API: json = {"api": "GetCampaignAffiliation", ...}

 PHP-API: $out = RLA_GetCampaignAffiliation($in)

 PURPOSE:
  The client asks the server the DB campaign affiliation(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idCampaign: int (*)
  idCampaignAffiliation: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   id: int
   affiliation: string
   gradeLevel: int
   section: string

-----------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                 WEB-API: json = {"api": "GetCampaignDocs", ...}

 PHP-API: $out = RLA_GetCampaignDocs($in)

 PURPOSE:
  The client asks the server the DB campaign doc(s) as a table.

 OVERVIEW:
  If the idDocs is empty, then all non-disabled docs id are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idCampaign: int (*)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idDoc: int

================================================================================

 RETRIEVE DATA: user, gender, language, campaign, readingType, doc, quest

================================================================================
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                         WEB-API: json = {"api": "GetUser", ...}

 PHP-API: $out = RLA_GetUser($in)

 PURPOSE:
  The client asks the server the DB user record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idUser: int

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idUser: int
   idResponsibleUser: int (the idUser responsible for this user)
   idUserCNR: int
   login: string
   pwd: string
   isOperator: bool (true if the user can create other users)
   isSuperOperator: bool (true if the user can create other operators)
   firstName: string
   lastName: string
   birthday: date
   idGender: int (a reference to DB gender table)
   idHand: int (a reference to DB hand table)
   idAgeBeginEducation: int
   idAgeCountryArrival: int
   notes: string
   created: datetime
   modified: datetime

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                     WEB-API: json = {"api": "GetUserData", ...}

 PHP-API: $out = RLA_GetUserData($in)

 PURPOSE:
  The client asks the server the DB userData record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idUserData: int (if empty, then all the records will be returned)
  idUser: int     (if not empty, then the records will be filtered accordingly)
  idCampaign: int (if not empty, then the records will be filtered accordingly)
  token: string   (if not empty, then the records will be filtered accordingly)
  idStatus: int   (if not empty, then the records will be filtered accordingly)
  gradeLevel: int (if not empty, then the records will be filtered accordingly)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idUserData: int
   ...
   created: datetime
   modified: datetime

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                       WEB-API: json = {"api": "GetGender", ...}

 PHP-API: $out = RLA_GetGender($in)

 PURPOSE:
  The client asks the server the DB gender record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idGender: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idGender: int
   gender: string (language-independent string, such as "STR_DB_M", "STR_DB_F", "STR_DB_X")
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                   WEB-API: json = {"api": "GetHasProblem", ...}

 PHP-API: $out = RLA_GetHasProblem($in)

 PURPOSE:
  The client asks the server the DB hasProblem record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idGender: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idHasProblem: int
   hasProblem: string (language-independent string, such as "STR_DB_NO", "STR_DB_YES_FIRST", "STR_DB_YES_UPDATE")
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                       WEB-API: json = {"api": "GetDevice", ...}

 PHP-API: $out = RLA_GetDevice($in)

 PURPOSE:
  The client asks the server the DB device record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idDevice: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idDevice: int
   device: string
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                         WEB-API: json = {"api": "GetBool", ...}

 PHP-API: $out = RLA_GetBool($in)

 PURPOSE:
  The client asks the server the DB bool record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idGender: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idBool: int
   bool: string (language-independent string, such as "STR_DB_YES", "STR_DB_NO")
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                         WEB-API: json = {"api": "GetHand", ...}

 PHP-API: $out = RLA_GetHand($in)

 PURPOSE:
  The client asks the server the DB hand record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idHand: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idHand: int
   hand: string (language-independent string, such as "STR_DB_RIGHT", "STR_DB_LEFT")
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                  WEB-API: json = {"api": "GetJobPosition", ...}

 PHP-API: $out = RLA_GetJobPosition($in)

 PURPOSE:
  The client asks the server the DB jobPosition record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idJobPosition: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idJobPosition: int
   jobPosition: string
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                             WEB-API: json = {"api": "GetEducationalLevel", ...}

 PHP-API: $out = RLA_GetEducationalLevel($in)

 PURPOSE:
  The client asks the server the DB educationalLevel record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idEducationalLevel: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idEducationalLevel: int
   educationalLevel: string
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                          WEB-API: json = {"api": "GetTabletFamiliarities", ...}

 PHP-API: $out = RLA_GetTabletFamiliarities($in)

 PURPOSE:
  The client asks the server the DB tabletFamiliarities record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idTabletFamiliarity: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idTabletFamiliarity: int
   tabletFamiliarity: string
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                            WEB-API: json = {"api": "GetCognitiveProblems", ...}

 PHP-API: $out = RLA_GetCognitiveProblems($in)

 PURPOSE:
  The client asks the server the DB cognitiveProblems record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idCognitiveProblem: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idCognitiveProblem: int
   cognitiveProblem: string
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                               WEB-API: json = {"api": "GetMemoryProblems", ...}

 PHP-API: $out = RLA_GetMemoryProblems($in)

 PURPOSE:
  The client asks the server the DB memoryProblems record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idMemoryProblem: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idMemoryProblem: int
   memoryProblem: string
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                              WEB-API: json = {"api": "GetAphasiaProblems", ...}

 PHP-API: $out = RLA_GetAphasiaProblems($in)

 PURPOSE:
  The client asks the server the DB aphasiaProblems record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idAphasiaProblem: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idAphasiaProblem: int
   aphasiaProblem: string
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                   WEB-API: json = {"api": "GetParentType", ...}

 PHP-API: $out = RLA_GetParentType($in)

 PURPOSE:
  The client asks the server the DB parentType record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idParentType: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idParentType: int
   parentType: string
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                          WEB-API: json = {"api": "GetPDP", ...}

 PHP-API: $out = RLA_GetPDP($in)

 PURPOSE:
  The client asks the server the DB "Piano Didattico Personalizzato" record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idPDP: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idPDP: int
   PDP: string
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                            WEB-API: json = {"api": "GetAgeBeginEducation", ...}

 PHP-API: $out = RLA_GetAgeBeginEducation($in)

 PURPOSE:
  The client asks the server the DB ageBeginEducation record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idAgeBeginEducation: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idAgeBeginEducation: int
   ageBeginEducation: string (language-independent string, such as "STR_DB_1YEAR" ...)
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                            WEB-API: json = {"api": "GetAgeCountryArrival", ...}

 PHP-API: $out = RLA_GetAgeCountryArrival($in)

 PURPOSE:
  The client asks the server the DB ageCountryArrival record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idAgeCountryArrival: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idAgeCountryArrival: int
   ageCountryArrival: string (language-independent string, such as "STR_DB_1YEAR" ...)
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                     WEB-API: json = {"api": "GetLanguage", ...}

 PHP-API: $out = RLA_GetLanguage($in)

 PURPOSE:
  The client asks the server the DB language record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idLanguage: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idLanguage: int
   language: string (language-independent string, such as "STR_DB_ITALIAN", "STR_DB_FRENCH", "STR_DB_ENGLISH", "STR_DB_ITALIAN", "STR_DB_OTHER")
   lang: string (two-character language id, such as "it", "en", "ar", "fr")
   uiOrder: int (order of appearance within the GUI)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                  WEB-API: json = {"api": "GetReadingType", ...}

 PHP-API: $out = RLA_GetReadingType($in)

 PURPOSE:
  The client asks the server the DB reading-type record(s) as a table.

 OVERVIEW:
  If the id is empty, then all the table rows are returned.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idReadingType: int (if empty, then all the records will be returned)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idReadingType: int
   readingType: string (language-independent string, such as "STR_DB_SILENT", "STR_DB_ALOUD", "STR_DB_LISTEN")
   uiOrder: int (order of appearance within the GUI)

================================================================================

 CREATE AND FILL A NEW USER

================================================================================
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                         WEB-API: json = {"api": "SetUser", ...}

 PHP-API: $out = RLA_SetUser($in)

 PURPOSE:
  The client inserts/updates a user record.

 OVERVIEW:
  If "idUser" is specified and it is found in the DB, then an UPDATE is
  issued. Otherwise an INSERT is issued.

  ...

  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS and the
  "idUser" is set to the value corresponding to the DB record.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - on UPDATE, if "idUser" does not exist in the DB rl_users table;
  - the "idResponsibleUser" is not a valid "idUser" in the DB "rl_users" table;
  - the login already exists
  - the triplet firstName-lastName-birthday already exists

 IN:
  idUser: int            (* on UPDATE)
  idResponsibleUser: int (* on INSERT)
  idUserCNR: int
  login: string          (* on INSERT, used only if specified on UPDATE)
  pwd: string            (used only if specified on UPDATE)
  isOperator: int        (used only if specified on UPDATE)
  isSuperOperator: int   (used only if specified on UPDATE)
  firstName: string      (used only if specified on UPDATE)
  lastName: string       (used only if specified on UPDATE)
  birthday: date         (used only if specified on UPDATE)
  idGender: int          (used only if specified on UPDATE)
  idHand: int            (used only if specified on UPDATE)
  idAgeBeginEducation: int (used only if specified on UPDATE)
  idAgeCountryArrival: int (used only if specified on UPDATE)
  notes: string            (used only if specified on UPDATE)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: "" | ...
  idUser: int

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                     WEB-API: json = {"api": "SetUserData", ...}

 PHP-API: $out = RLA_SetUserData($in)

 PURPOSE:
  The client inserts/updates a user record.

 OVERVIEW:
  If "idUserData" is specified and it is found in the DB, or the pair "idUser",
  "idCampaign" is specified and it is found in the DB, then an UPDATE is
  issued. Otherwise an INSERT is issued.

  As a key, you can use either (idUserData) or the pair (idUser, idCampaign).
  If (idUserData) is specified, then it will be used as the key.
  If (idUserData) is not specified and the pair (idUser, idCampaign) is
  specified and found, then the pair will be used as the key.
  If the key was found, then the record gets UPDATED. Otherwise an INSERT is issued.
  If (idUserData) is specified, then it must exists (a check is performed here).
  If (idUser) is specified, then it must exists (a check is performed here).
  If (idCampaign) is specified, then it must exists (a check is performed here).
  If (idCampaignAffiliation) is specified, then (idCampaign) must exists as well,
  and affiliation and gradeLevel will be set accordingly (a check is performed here).

  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS and the
  "idUserData" is set to the value corresponding to the DB record.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - on UPDATE, if "idUserData" does not exist in the DB rl_users table;

 IN:
  idUserData: int                            (* on UPDATE)
  idUser: int                                (* on INSERT)
  idStatus: int                              (0 on INSERT, used only if specified on UPDATE)
  parentName: string                         (used only if specified on UPDATE)
  idParentType: string                       (used only if specified on UPDATE)
  parentEmail: string                        (used only if specified on UPDATE)
  idCampaign: int                            (used only if specified on UPDATE)
  idCampaignAffiliation: int                 (used only if specified on UPDATE)
  idMainLanguages: string (json int array)   (used only if specified on UPDATE)
  idLanguagesAtHome: string (json int array) (used only if specified on UPDATE)
  idGenderIdentity: int
  idTabletFamiliarity: int
  idJobPositionMother: int
  idJobPositionFather: int
  idEducationalLevelMother: int
  idEducationalLevelFather: int
  hasVisionProblems: int (3 states: 0 null, 1 yes, 2 no)
  areVisionProblemsSolved: int (3 states: 0 null, 1 yes, 2 no)
  hasHearingProblems: int (3 states: 0 null, 1 yes, 2 no)
  areHearingProblemsSolved: int (3 states: 0 null, 1 yes, 2 no)
  hasADHDProblems: int (4 states: 0 null, 1 yes-first, 2 no, 3 yes-update)
  areADHDProblemsSupported: int (3 states: 0 null, 1 yes, 2 no)
  hasDDDProblems: int (4 states: 0 null, 1 yes-first, 2 no, 3 yes-update)
  areDDDProblemsSupported: int (3 states: 0 null, 1 yes, 2 no)
  hasASDProblems: int (4 states: 0 null, 1 yes-first, 2 no, 3 yes-update)
  areASDProblemsSupported: int (3 states: 0 null, 1 yes, 2 no)
  hasCognitiveProblems: int (3 states: 0 null, 1 yes, 2 no)
  idCognitiveProblem: int
  hasMemoryProblems: int (3 states: 0 null, 1 yes, 2 no)
  idMemoryProblems: string (json int array)
  hasAphasiaProblems: int (3 states: 0 null, 1 yes, 2 no)
  idAphasiaProblems: string (json int array)
  hasExecutiveFunctionProblems: int (3 states: 0 null, 1 yes, 2 no)
  hasLogicalAbstractiveProblems: int (3 states: 0 null, 1 yes, 2 no)
  isConsentToThisStudy: int (3 states: 0 null, 1 yes, 2 no)
  isConsentToFutureMonitoring: int (3 states: 0 null, 1 yes, 2 no)
  motherName: string
  fatherName: string
  notes: string

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: "" | ...
  idUserData: ...
  token: ...

================================================================================

 CREATE AND FILL A NEW SESSION

================================================================================
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                     WEB-API: json = {"api": "InitSession", ...}

 PHP-API: $out = RLA_InitSession($in)

 PURPOSE:
  The client uploads (insert or update) a session record.

 OVERVIEW:
  If "idSession" is specified and it is found in the DB, then an UPDATE is
  issued. Otherwise an INSERT is issued.

  The "isOpen" flag associated to the session record is set to 1, that is the
  record is associated to a pending session. In other words, at this stage
  only the settings associated to the session are specified: as the session
  will be run, the collected data will be sent by using the "SendSession*"
  functions. As all data have been sent, remember to call "CloseSession" to
  to mark the session as closed.

  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS and the
  "idSession" is set to the value corresponding to the DB record.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - on UPDATE, if "idSession" does not exist in the DB rl_sessions table;
  - on UPDATE, if the corresponding "isOpen" flag is not set to 1 (consider
    calling the "ReopenSession" function first);
  - the "idSessionUser" is not a valid "idUser" in the DB "rl_users" table;
  - the "idSessionDoc" is not a valid "idDoc" in the DB "rl_docs" table;
  - the "idSessionCampaign" is not a valid "idCampaign in the DB
    "rl_campaigns" table;
  - the "idReadingType" is not a valid "idReadingType" in the DB
    "rl_readingTypes" table;

 IN:
  idSession: int
  idDevice: int (reference to DB rl_devices table)
  idSessionCNR: string
  uiOrder: int
  idSessionUser: int
  idSessionDoc: int
  idSessionCampaign: int
  idReadingType: int (reference to DB rl_readingTypes table)
  maxEpisodesCount: int (0 = all)
  notes: string
  options: json string
  audioOptions: json string

  fontFamily: string, default="Lato"
  isUpperCase: int, 0=NO, 1=YES, default=0
  isBraille: int, 0=NO, 1=YES, default=0
  fontSize: float, cm, default=0.6
  letterSpacing: float, cm, default=0
  wordSpacing: float, cm, default=0
  lineHeight: float, percentage, default=140
  marginTop: float, cm, default=1 (margin of the TEXT within the PAPER)
  marginBottom: float, cm, default=3 (margin of the TEXT within the PAPER)
  marginLeft: float, cm, default=1 (margin of the TEXT within the PAPER)
  marginRight: float, cm, default=1 (margin of the TEXT within the PAPER)
  deskTopHeight: float, cm, default=0.5 (margin of the PAPER within the DESK)
  deskBottomHeight: float, default=1.8 (cm, margin of the PAPER within the DESK)
  deskLeftWidth: float, cm, default=0.1 (margin of the PAPER within the DESK)
  deskRightWidth: float, cm, default=1.5 (margin of the PAPER within the DESK)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: "" | ...
  idSession: ...

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                 WEB-API: json = {"api": "SendSessionData", ...}

 PHP-API: $out = RLA_SendSessionData($in)

 PURPOSE:
  The client uploads to the server the basic run-time data associated to the
  pending session.

 OVERVIEW:
  At this stage basic run-time data are specified: the collected data will be
  sent later by using the other "SendSession*" functions.

  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - if "idSession" does not exist in the DB rl_sessions table;
  - if the corresponding "isOpen" flag is not set to 1 (consider calling the
    "ReopenSession" function first);

 IN:
  idSession: int
  readletVersion: string
  timeOrigin: float, unixtimestamp with microseconds
  timeOffsetStart: float, seconds with microseconds
  timeOffsetStop: float, seconds with microseconds
  audioType: string, mp3 | webm
  timeOffsetAudio: float, seconds with microseconds
  paperWidth: int, dots
  paperHeight: int, dots
  isMobile: bool
  deviceName: string, user agent
  deviceDPCMX: float, horizontal dots-per-cm of the device
  deviceDPCMY: float, vertical dots-per-cm of the device
  trainingDocCoverage: float, [0; 1]
  trainingQuestCoverage: float, [0; 1]
  trainingQuestAccuracy: float, [0; 1]

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: "" | ...

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                              WEB-API: json = {"api": "SendSessionContent", ...}

 PHP-API: $out = RLA_SendSessionContent($in)

 PURPOSE:
  The client uploads to the server the bounding box of each character in the
  doc as it is shown by the client to the user.

 OVERVIEW:
  All coordinates are normalized with respect to the PAPER rectangle EFGH.

  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - if "idSession" does not exist in the DB rl_sessions table;
  - if the corresponding "isOpen" flag is not set to 1 (consider calling the
    "ReopenSession" function first);
  - the input table is malformed (e.g. the number of rows is not constant
    along all the columns);

 IN:
  idSession: int
  eid: int array (episode id, starting from 0, always increasing)
  gid: int array (group id, starting from 0, always increasing)
  pid: int array (paragraph id, starting from 0, always increasing)
  sid: int array (sentence id, starting from 0, always increasing)
  tid: int array (token id, starting from 0, always increasing)
  cid: int array (character id, starting from 0, reset on new token)
  unicode: int array (the unicode representation of the character)
  left: float array (char bounding box x-left)
  right: float array (char bounding box x-right)
  top: float array (char bounding box y-top)
  bottom: float array (char bounding box y-bottom)

 OUT:
  rlaErr = RLA_ERR_SUCCESS | ...
  rlaMsg = "" | ...

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                     WEB-API: json = {"api": "SendSessionDecodingDocTrack", ...}

 PHP-API: $out = RLA_SendSessionDecodingDocTrack($in)

 PURPOSE:
  Upload the list of mouse/touch events occurred during the document reading
  task.

 OVERVIEW:
  All coordinates are normalized with respect to the PAPER rectangle EFGH.

  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - if "idSession" does not exist in the DB rl_sessions table;
  - if the corresponding "isOpen" flag is not set to 1 (consider calling the
    "ReopenSession" function first);
  - the input table is malformed (e.g. the number of rows is not constant
    along all the columns);

 IN:
  idSession: int
  timeOffset: float array (time offset with microseconds since docTimeStart)
  eventType: string array
  fingers: int array (the number fo fingers involved in the event)
  x: float array (touch event x)
  y: float array (touch event y)
  isOnDesk: bool array
  isOnPaper: bool array
  isOnDeskSide: bool array
  deskScroll: float array (the vertical scroll of the DESK at the time of the event)
  paperViewTop: float array (the top-most y coordinate of the PAPER at the time of the event)
  paperViewHeight: float array (the portion of height of the PAPER visible at the time of the event)
  isPaused: bool array
  gid: int array (the doc group index shown at the time of the event)

 OUT:
  rlaErr = RLA_ERR_SUCCESS | ...
  rlaMsg = "" | ...

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                WEB-API: json = {"api": "SendSessionComprehensionDocTrack", ...}

 PHP-API: $out = RLA_SendSessionComprehensionDocTrack($in)

 PURPOSE:
  Upload the list of mouse/touch events occurred during the questionnaire filling
  task.

 OVERVIEW:
  All coordinates are normalized with respect to the PAPER rectangle EFGH.

  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - if "idSession" does not exist in the DB rl_sessions table;
  - if the corresponding "isOpen" flag is not set to 1 (consider calling the
    "ReopenSession" function first);
  - the input table is malformed (e.g. the number of rows is not constant
    along all the columns);

 IN:
  idSession: int
  timeOffset: float array (time offset with microseconds since questTimeStart)
  eventType: string array
  fingers: int array (the number fo fingers involved in the event)
  x: float array (touch event x)
  y: float array (touch event y)
  isOnDesk: bool array
  isOnPaper: bool array
  isOnDeskSide: bool array
  isOnQuest: bool array
  deskScroll: float array (the vertical scroll of the DESK at the time of the event)
  paperViewTop: float array (the top-most y coordinate of the PAPER at the time of the event)
  paperViewHeight: float array (the portion of height of the PAPER visible at the time of the event)
  isPaused: bool array
  qid: int array (the question index shown at the time of the event)

 OUT:
  rlaErr = RLA_ERR_SUCCESS | ...
  rlaMsg = "" | ...

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

              WEB-API: json = {"api": "SendSessionComprehensionQuestTrack", ...}

 PHP-API: $out = RLA_SendSessionComprehensionQuestTrack($in)

 PURPOSE:
  Upload the list of answering events occurred during the questionnaire filling
  task.

 OVERVIEW:
  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - if "idSession" does not exist in the DB rl_sessions table;
  - if the corresponding "isOpen" flag is not set to 1 (consider calling the
    "ReopenSession" function first);
  - the input table is malformed (e.g. the number of rows is not constant
    along all the columns);

 IN:
  idSession: int
  timeOffset: float array (time offset with microseconds since questTimeStart)
  qid: int array (question id, starting from 0, always increasing)
  aid: int array (answer id, starting from 0, reset on new question)
  cor: bool array (the answer id is the correct one?)
  sel: bool array (the answer id was selected?)

 OUT:
  rlaErr = RLA_ERR_SUCCESS | ...
  rlaMsg = "" | ...

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                   WEB-API: json = {"api": "SendSessionComprehensionQuest", ...}

 PHP-API: $out = RLA_SendSessionComprehensionQuest($in)

 PURPOSE:
  Upload the list of answers provided by the user as the questionnaire filling
  task is ended.

 OVERVIEW:
  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - if "idSession" does not exist in the DB rl_sessions table;
  - if the corresponding "isOpen" flag is not set to 1 (consider calling the
    "ReopenSession" function first);
  - the input table is malformed (e.g. the number of rows is not constant
    along all the columns);

 IN:
  idSession: int
  qid: int array (question id, starting from 0, always increasing)
  aid: int array (answer id, starting from 0, reset on new question)
  cor: bool array (the answer id is the correct one?)
  sel: bool array (the answer id was selected?)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: "" | ...

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                    WEB-API: json = {"api": "CloseSession", ...}

 PHP-API: $out = RLA_CloseSession($in)

 PURPOSE:
  The client marks a session as closed.

 OVERVIEW:
  The "isOpen" flag associated to the session is set to 0, so the session is
  marked as closed. The "modified" datetime is updated.

  On success, the "rlaErr" is set to RLA_ERR_SUCCESS.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - "idSession" does not exists in the DB "rl_sessions" table;
  - the corresponding "isOpen" flag is not set to 1, that is the session is
    already marked as closed;

 IN:
  idSession: int

 OUT:
  rlaErr = RLA_ERR_SUCCESS | ...
  rlaMsg = "" | ...

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                   WEB-API: json = {"api": "ReopenSession", ...}

 PHP-API: $out = RLA_ReopenSession($in)

 PURPOSE:
  The client marks a session as pending.

 OVERVIEW:
  The "isOpen" flag associated to the session is set to 1, so the the session
  is marked as pending. The "modified" datetime is updated. Please note that
  the data previously stored (audio, data, tracks, quest) are deleted here.

  On success, the "rlaErr" is set to RLA_ERR_SUCCESS.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - "idSession" does not exists in the DB "rl_sessions" table;
  - the corresponding "isOpen" flag is not set to 0, that is the session is
    already marked as pending;
  - the previous data cannot be deleted;

 IN:
  idSession: int
  doDeleteData: int (0|1)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...

================================================================================

 ADD DATA TO PREVIOUSLY STORED SESSIONS

================================================================================
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                 WEB-API: json = {"api": "SetSessionAlign", ...}

 PHP-API: $out = RLA_SetSessionAlign($in)

 PURPOSE:
  Upload the alignment data provided by the alignment module(s)

  Note the "bid" array is calculated as the indexes of the unique bounding
  boxes in the xx_data_content table, see QuerySession.m.
  The "dt" and "bid" arrays must have the same length as the height of the
  xx_data_doctrack1 table.

 OVERVIEW:
  On success, the out "rlaErr" is set set to RLA_ERR_SUCCESS.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - if "idSession" does not exist in the DB rl_sessions table;
  - if the corresponding "isOpen" flag is not set to 0 (consider calling the
    "ReopenSession" function first);
  - the input table is malformed (e.g. the number of rows is not constant
    along all the columns);

 IN:
  idSession: int
  idAlign: int (the type of alignment)
  dt: float array (tNext - tCurr, with a trailing 0 at the end), n = height(docatrck1)
  bid: int array (the bid aligned with content; -1 if not aligned)
  bot: int array (bool)
  eot: int array (bool)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: "" | ...

================================================================================

 RETRIEVE DATA FROM PREVIOUSLY STORED SESSIONS

================================================================================
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                      WEB-API: json = {"api": "GetSession", ...}

 PHP-API: $out = RLA_GetSession($in)

 PURPOSE:
  The client asks the server the DB session record(s) as a table, that is the
  record information known and stored as the session is initialized, even if
  it was not yet run.

 OVERVIEW:
  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idSession: int

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idSession: int
   idDevice: int (reference to DB devices table)
   idSessionCNR: string
   idSessionUser: int
   idSessionDoc: int
   idSessionCampaign: int
   isOpen: bool
   modified: datetime
   idReadingType: int (reference to DB readingType table)
   maxEpisodesCount: int (0 = all)
   notes: string
   fontFamily: string
   isUpperCase: bool
   isBraille: bool
   fontSize: float, cm
   letterSpacing: float, cm
   wordSpacing: float, cm
   lineHeight: float, percentage
   marginTop: float, cm
   marginBottom: float, cm
   marginLeft: float, cm
   marginRight: float, cm
   deskTopHeight: float, cm
   deskBottomHeight: float
   deskLeftWidth: float, cm
   deskRightWidth: float, cm

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                  WEB-API: json = {"api": "GetSessionData", ...}

 PHP-API: $out = RLA_GetSessionData($in)

 PURPOSE:
  The client asks the server the run-time data of the session, that is the
  basic information known and stored only as the session is run.

 OVERVIEW:
  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idSession: int

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idSession: int
   readletVersion: string
   audioTimeStart: float, unixtimestamp with microseconds
   audioType: string, mp3 | webm
   docTimeStart: float, unixtimestamp with microseconds
   docTimeStop: float, unixtimestamp with microseconds
   questTimeStart: float, unixtimestamp with microseconds
   questTimeStop: float, unixtimestamp with microseconds
   paperWidth: int, dots
   paperHeight: int, dots
   isMobile: bool
   deviceName: string, user agent
   deviceDPCMX: float, horizontal dots-per-cm of the device
   deviceDPCMY: float, vertical dots-per-cm of the device

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                               WEB-API: json = {"api": "GetSessionContent", ...}

 PHP-API: $out = RLA_GetSessionContent($in)

 PURPOSE:
  The client asks the server the run-time content layout of the session, that
  is bounding box of each character in the doc as it is shown by the client
  to the user.

 OVERVIEW:
  Each row represents a character, including spaces.

  All coordinates are normalized with respect to the PAPER rectangle EFGH.

  The bounding box (left, top, right, bottom) is specified in normalized
  coordinates with respect to the PAPER rectangle EFGH.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idSession: int

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idSession: int
   eid: int array (episode id, starting from 0, always increasing)
   gid: int array (group id, starting from 0, always increasing)
   pid: int array (paragraph id, starting from 0, always increasing)
   sid: int array (sentence id, starting from 0, always increasing)
   tid: int array (token id, starting from 0, always increasing)
   cid: int array (character id, starting from 0, reset on new token)
   unicode: int array (the unicode representation of the character)
   left: float array (char bounding box x-left)
   right: float array (char bounding box x-right)
   top: float array (char bounding box y-top)
   bottom: float array (char bounding box y-bottom)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                      WEB-API: json = {"api": "GetSessionDecodingDocTrack", ...}

 PHP-API: $out = RLA_GetSessionDecodingDocTrack($in)

 PURPOSE:
  The client asks the server the run-time doc finger tracking during the
  decoding step.

 OVERVIEW:
  Each row represents a touch event.

  All coordinates are normalized with respect to the PAPER rectangle EFGH.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idSession: int

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idSession: int
   timeOffset: float array (time offset with microseconds since docTimeStart)
   eventType: string array
   fingers: int array (the number fo fingers involved in the event)
   x: float array (touch event x)
   y: float array (touch event y)
   isOnDesk: bool array
   isOnPaper: bool array
   isOnDeskSide: bool array
   isOnQuest: false array (not used)
   deskScroll: float array (the vertical scroll of the DESK at the time of the event)
   paperViewTop: float array (the top-most y coordinate of the PAPER at the time of the event)
   paperViewHeight: float array (the portion of height of the PAPER visible at the time of the event)
   isPaused: bool array
   gid: int array (the doc group index shown at the time of the event)
   qid: -1 array (not used)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                 WEB-API: json = {"api": "GetSessionComprehensionDocTrack", ...}

 PHP-API: $out = RLA_GetSessionComprehensionDocTrack($in)

 PURPOSE:
  The client asks the server the run-time doc finger tracking during the
  comprehension step.

 OVERVIEW:
  Each row represents a touch event.

  All coordinates are normalized with respect to the PAPER rectangle EFGH.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idSession: int
   timeOffset: float array (time offset with microseconds since questTimeStart)
   eventType: string array
   fingers: int array (the number fo fingers involved in the event)
   x: float array (touch event x)
   y: float array (touch event y)
   isOnDesk: bool array
   isOnPaper: bool array
   isOnDeskSide: bool array
   isOnQuest: bool array
   deskScroll: float array (the vertical scroll of the DESK at the time of the event)
   paperViewTop: float array (the top-most y coordinate of the PAPER at the time of the event)
   paperViewHeight: float array (the portion of height of the PAPER visible at the time of the event)
   isPaused: bool array
   gid: -1 array (not used)
   qid: int array (the question index shown at the time of the event)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

               WEB-API: json = {"api": "GetSessionComprehensionQuestTrack", ...}

 PHP-API: $out = RLA_GetSessionComprehensionQuestTrack($in)

 PURPOSE:
  The client asks the server the run-time answer tracking during the
  comprehension step.

 OVERVIEW:
  Each row represents an "answer" event.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idSession: int

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idSession: int
   timeOffset: float array (time offset with microseconds since questTimeStart)
   qid: int array (question id, starting from 0, always increasing)
   aid: int array (answer id, starting from 0, reset on new question)
   cor: bool array (the answer id is the correct one?)
   sel: bool array (the answer id was selected?)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                    WEB-API: json = {"api": "GetSessionComprehensionQuest", ...}

 PHP-API: $out = RLA_GetSessionComprehensionQuest($in)

 PURPOSE:
  The client asks the server the run-time final answers to the questionnaire
  during the comprehension step.

 OVERVIEW:
  Each row represents an answer.

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS" and the DB rows are
  returned as columns within the JSON structure.

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;

 IN:
  idSession: int

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...
  rowsCount: int
  table:
   idSession: int
   qid: int array (question id, starting from 0, always increasing)
   aid: int array (answer id, starting from 0, reset on new question)
   cor: bool array (the answer id is the correct one?)
   sel: bool array (the answer id was selected?)

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                       WEB-API: json = {"api": "AudioInfo", ...}

 PHP-API: $out = RLA_AudioInfo($in)

 PURPOSE:
  Get info about the session audio file.

 OVERVIEW:
  Get info about the session audio file.

  On fail, the "rlaErr" is set to the specific error if:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - the idSession is yet not closed;
  - the session options contain an invalid json;
  - the audio recording was not issued;
  - the audio file is missing;

 IN:
  idSession: int (*)

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: "" | ...
  audioType: string
  audioFilename: string
  audioPath: string

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                                   WEB-API: json = {"api": "AudioDownload", ...}

 PHP-API: $out = RLA_AudioDownload($in)

 PURPOSE:
  Issue the download of the session audio file.

 OVERVIEW:
  Issue the download of the audio file.

  On fail, an empty file is returned.

 IN:
  idSession: int (*)

 OUT:
  the audio file as a unsigned-char array

================================================================================

 FORMS

================================================================================
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

                     WEB-API: json = {"api": "FormSendParentQuestionnaire", ...}

 PHP-API: $out = RLA_FormSendParentQuestionnaire($in)

 PURPOSE:
  Update the rl_userData and rl_users record according to the parent
  questionnaire form.

 OVERVIEW:
  firstName, and LastName, parentEmail , parentName, motherName and fatherName
  are encrypted, idStatus is moved to ID_USERDATA_STATUS_RECEIVED
  modified datetime is updated both in rl_users and in rl_userData tables

  On success, the "rlaErr" is set to "RLA_ERR_SUCCESS".

  On fail, the "rlaErr" is set to the specific error:
  - the DB connection is not available;
  - the DB query failed for some reason;
  - the (idUserData, token, idStatus=ID_USERDATA_STATUS_REQUESTED) is not found in DB
  - the idUser is not found in DB
  - the idCampaign is not found in DB
  - the idCampaignAffiliation is not found in DB

 IN:
  idUserData: int (*)
  token: string (*)

  firstName: string
  lastName: string
  birthday: string (date "yyyy-mm-dd")
  idGender: int
  idHand: int
  idAgeBeginEducation: int
  idAgeCountryArrival: int

  parentName: string
  idParentType: int
  idCampaignAffiliation: int
  idLanguagesAtHome: string (json array [id1, id2, ...])
  idMainLanguages: string (json array [id1, id2, ...])
  idGenderIdentity: int
  idTabletFamiliarity: int
  idJobPositionMother: int
  idJobPositionFather: int
  idEducationalLevelMother: int
  idEducationalLevelFather: int
  hasVisionProblems: int (3 states: 0 null, 1 yes, 2 no)
  areVisionProblemsSolved: int (3 states: 0 null, 1 yes, 2 no)
  hasHearingProblems: int (3 states: 0 null, 1 yes, 2 no)
  areHearingProblemsSolved: int (3 states: 0 null, 1 yes, 2 no)
  hasADHDProblems: int (3 states: 0 null, 1 yes, 2 no)
  areADHDProblemsSupported: int (3 states: 0 null, 1 yes, 2 no)
  hasDDDProblems: int (3 states: 0 null, 1 yes, 2 no)
  areDDDProblemsSupported: int (3 states: 0 null, 1 yes, 2 no)
  hasASDProblems: int (3 states: 0 null, 1 yes, 2 no)
  areASDProblemsSupported: int (3 states: 0 null, 1 yes, 2 no)
  hasCognitiveProblems: int (3 states: 0 null, 1 yes, 2 no)
  idCognitiveProblem: int
  hasMemoryProblems: int (3 states: 0 null, 1 yes, 2 no)
  idMemoryProblems: string (json array [id1, id2, ...])
  hasAphasiaProblems: int (3 states: 0 null, 1 yes, 2 no)
  idAphasiaProblems: string (json array [id1, id2, ...])
  hasExecutiveFunctionProblems: int (3 states: 0 null, 1 yes, 2 no)
  hasLogicalAbstractiveProblems: int (3 states: 0 null, 1 yes, 2 no)
  isConsentToThisStudy: int (3 states: 0 null, 1 yes, 2 no)
  isConsentToFutureMonitoring: int (3 states: 0 null, 1 yes, 2 no)
  motherName: string
  fatherName: string
  notes: string

 OUT:
  rlaErr: RLA_ERR_SUCCESS | ...
  rlaMsg: ...