? users online
  • Logout
    • Open hangout
    • Open chat for current file
<div class="notebook">

<div class="nb-cell html" name="htm1">
<h1>ConTracciami</h1>
<p>
  Progetto per tracciare in anticipo il contagio di un'epidemia a partire dai dati di 
  georeferenzazione spaziotemporale prodotti dai dispositivi cellulari;
  l'obiettivo è quello di usare tali dati per dare indicazioni utili ad effettuare 
  controlli a tampone mirati.
  Questo progetto fa riferimento in particolare ai dati immagazzinati da Google relativi agli
  spostamenti effettuati dai propri utenti durante i periodi di accensione del rilevatore GPS del
  proprio dispositivo.<br>
    </p><h2>Parser</h2>
<p> Iniziamo con descrivere il parser che deve convertire in un database Prolog il file JSON 
  “Semantic Location History” del Google TakeOut (GTO).</p>
  <h3>Analisi del file JSON</h3>
<p>Il JSON è un formato leggero per lo scambio di dati che si basa su un sottoinsieme del linguaggio di programmazione JavaScript.<br>
  I tipi di dato fondamentali supportati sono:</p>
<ul>
  <li> booleani (true e false)</li>
  <li> interi,reali,virgola mobile</li>
  <li> stringhe racchiuse da doppi apici</li>
  <li> array (sequenze ordinate di valori,separate da virgole e racchiuse da parentesi quadre)</li>
  <li> array associativi (sequenze coppie chiave-valore separate da virgole, racchiuse in parentesi graffe)</li>
  <li> null</li>
</ul>
<p>Nel GTO i files JSON “Semantic Location History”, che rappresentano i dati di georeferenzazione
    così come rilevati dal GPS del dispositivo, sono strutturati nel seguente modo:<br>
Una struttura dati (un oggetto) di tipo <em>array</em> “<em>timelineObject</em>” costituita da una sequenza di due tipologie
di record principali: “<em>placeVisit</em>” e “<em>activitySegment</em>”, per esempio:
    </p><pre><code>"timelineObjects" : [ {
    "placeVisit" : {
      "location" : {
        "latitudeE7" : 454878470,
        "longitudeE7" : 92027718,
        "placeId" : "ChIJLT2PgNDGhkcR8JLKbYe11Us",
        "address" : "Via Fabio Filzi, 43\n20124 Milano MI\nItalia",
        "name" : "43 Station Hotel",
        "sourceInfo" : {
          "deviceTag" : 1005818352
        },
        "locationConfidence" : 81.328476
      },
      "duration" : {
        "startTimestampMs" : "1552567416000",
        "endTimestampMs" : "1552570110078"
      },
      "placeConfidence" : "MEDIUM_CONFIDENCE",
      "centerLatE7" : 454878275,
      "centerLngE7" : 92026475,
      "visitConfidence" : 94,
      "otherCandidateLocations" : [ {
        "latitudeE7" : 454870123,
        "longitudeE7" : 92054790,
        "placeId" : "ChIJQ1j3T8XGhkcRKs-XGhSxJiI",
        "locationConfidence" : 2.6348245
      }, {
        "latitudeE7" : 454878470,
        "longitudeE7" : 92027718,
        "placeId" : "ChIJqwORgNDGhkcR4VCPkM_ZzlQ",
        "locationConfidence" : 1.2761719
      }, {
        "latitudeE7" : 454879321,
        "longitudeE7" : 92028971,
        "placeId" : "ChIJr3hLgNDGhkcRfdpf1sDd13c",
        "locationConfidence" : 0.5842658
      }, {
        "latitudeE7" : 454883682,
        "longitudeE7" : 92047801,
        "placeId" : "ChIJrVWFQ9rGhkcRlChpwWecYqk",
        "locationConfidence" : 0.19015288
      } ],
      "editConfirmationStatus" : "NOT_CONFIRMED"
    }
  }, {
    "activitySegment" : {
      "startLocation" : {
        "latitudeE7" : 454882939,
        "longitudeE7" : 92034225,
        "sourceInfo" : {
          "deviceTag" : 1005818352
        }
      },
      "endLocation" : {
        "latitudeE7" : 454903992,
        "longitudeE7" : 92038098,
        "sourceInfo" : {
          "deviceTag" : 1005818352
        }
      },
      "duration" : {
        "startTimestampMs" : "1552570110078",
        "endTimestampMs" : "1552570421471"
      },
      "distance" : 288,
      "activityType" : "WALKING",
      "confidence" : "HIGH",
      "activities" : [ {
        "activityType" : "WALKING",
        "probability" : 97.36161082252096
      }, {
        "activityType" : "IN_BUS",
        "probability" : 0.8261683752272773
      }, {
        "activityType" : "IN_PASSENGER_VEHICLE",
        "probability" : 0.4310589663144621
      } ],
      "waypointPath" : {
        "waypoints" : [ {
          "latE7" : 454882583,
          "lngE7" : 92034835
        }, {
          "latE7" : 454890785,
          "lngE7" : 92024230
        }, {
          "latE7" : 454903678,
          "lngE7" : 92038660
        } ]
      },
      "simplifiedRawPath" : {
        "points" : [ {
          "latE7" : 454892321,
          "lngE7" : 92025394,
          "timestampMs" : "1552570230493",
          "accuracyMeters" : 14
        } ]
      },
      "editConfirmationStatus" : "NOT_CONFIRMED"
    }
  }
</code></pre>
<p>Entrambi i records sono a loro volta composti da elementi che possono essere:</p>
  <ul> 
    <li> coppie <code>chiave:valore</code> </li>
    <li> <em>array</em> </li>
    <li> <em>records</em> </li>
  </ul>
<p>Nell'esempio precedente, in “<em>placeVisit</em>” abbiamo due records, <em>"location"</em> e <em>"duration"</em>:</p>
<pre><code>
      "location" : {
        "latitudeE7" : 454878470,
        "longitudeE7" : 92027718,
        "placeId" : "ChIJLT2PgNDGhkcR8JLKbYe11Us",
        "address" : "Via Fabio Filzi, 43\n20124 Milano MI\nItalia",
        "name" : "43 Station Hotel",
        "sourceInfo" : {
          "deviceTag" : 1005818352
        },
        "locationConfidence" : 81.328476
      },
      "duration" : {
        "startTimestampMs" : "1552567416000",
        "endTimestampMs" : "1552570110078"
      },
</code></pre>
<p> seguiti dalle coppie: </p>
<pre><code>
      "placeConfidence" : "MEDIUM_CONFIDENCE",
      "centerLatE7" : 454878275,
      "centerLngE7" : 92026475,
      "visitConfidence" : 94,
</code></pre>
<p> seguite dall'array <em>"otherCandidateLocations"</em> </p>
<pre><code>
      "otherCandidateLocations" : [ {
        "latitudeE7" : 454870123,
        "longitudeE7" : 92054790,
        "placeId" : "ChIJQ1j3T8XGhkcRKs-XGhSxJiI",
        "locationConfidence" : 2.6348245
      }, {
        "latitudeE7" : 454878470,
        "longitudeE7" : 92027718,
        "placeId" : "ChIJqwORgNDGhkcR4VCPkM_ZzlQ",
        "locationConfidence" : 1.2761719
      }, {
        "latitudeE7" : 454879321,
        "longitudeE7" : 92028971,
        "placeId" : "ChIJr3hLgNDGhkcRfdpf1sDd13c",
        "locationConfidence" : 0.5842658
      }, {
        "latitudeE7" : 454883682,
        "longitudeE7" : 92047801,
        "placeId" : "ChIJrVWFQ9rGhkcRlChpwWecYqk",
        "locationConfidence" : 0.19015288
      } ],
</code></pre>
<p> ed infine la coppia:</p>
<pre><code>
      "editConfirmationStatus" : "NOT_CONFIRMED"
</code></pre>

<p>Per quanto riguarda il record “<em>activitySegment</em>” abbiamo tre records <em>"startLocation"</em>, <em>"endLocation"</em>
  e <em>"duration"</em>::</p>
<pre><code>
      "startLocation" : {
        "latitudeE7" : 454882939,
        "longitudeE7" : 92034225,
        "sourceInfo" : {
          "deviceTag" : 1005818352
        }
      },
      "endLocation" : {
        "latitudeE7" : 454903992,
        "longitudeE7" : 92038098,
        "sourceInfo" : {
          "deviceTag" : 1005818352
        }
      },
      "duration" : {
        "startTimestampMs" : "1552570110078",
        "endTimestampMs" : "1552570421471"
      },
</code></pre>
<p> seguiti dalle coppie:</p>
<pre><code>
      "distance" : 288,
      "activityType" : "WALKING",
      "confidence" : "HIGH",
</code></pre>
<p> seguite dall'array <em>"activities"</em></p>
<pre><code>
      "activities" : [ {
        "activityType" : "WALKING",
        "probability" : 97.36161082252096
      }, {
        "activityType" : "IN_BUS",
        "probability" : 0.8261683752272773
      }, {
        "activityType" : "IN_PASSENGER_VEHICLE",
        "probability" : 0.4310589663144621
      } ],
</code></pre>
<p> altri due records, <em>"waypointPath"</em> e <em>"simplifiedRawPath"</em>:</p>
<pre><code>      
      "waypointPath" : {
        "waypoints" : [ {
          "latE7" : 454882583,
          "lngE7" : 92034835
        }, {
          "latE7" : 454890785,
          "lngE7" : 92024230
        }, {
          "latE7" : 454903678,
          "lngE7" : 92038660
        } ]
      },
      "simplifiedRawPath" : {
        "points" : [ {
          "latE7" : 454892321,
          "lngE7" : 92025394,
          "timestampMs" : "1552570230493",
          "accuracyMeters" : 14
        } ]
      }
    }
</code></pre>
<p> ed infine la coppia:</p>
<pre><code>
      "editConfirmationStatus" : "NOT_CONFIRMED"
</code></pre>


<h3>Parser in Prolog</h3>
<p>Alla luce di quest'analisi del file JSON “Semantic Location History”, è stato implementato
  un parser in SWI Prolog per convertire i dati in esso contenuti in due database PROLOG:</p>
  <ul>
    <li> <code>place( ID, Lat, Lon, T_start, T_end, ID_Place ).</code> <br>
      dove:
      <ul> 
        <li> <code>ID</code> corrisponde all’ identificatore della persona </li> 
        <li> <code>Lat</code> corridponde alla latitudine del posto visitato (placeVisit) in formato E7 </li> 
        <li> <code>Lon</code> corrisponde alla longitudine del posto visitato (placeVisit) in formato E7 </li> 
        <li> <code>T_start</code> corrisponde al tempo di inizio espresso in ms dal 1° gennaio 1970</li> 
        <li> <code>T_end</code> corrisponde al tempo di fine espresso in ms dal 1° gennaio 1970 </li> 
        <li> <code>ID_Place</code> corrisponde all’identificativo del posto visitato. </li> 
      </ul> 
    </li><li> <code>activity(ID,Lat1,Lon1,Lat2,Lon2,T_start,T_end,Activity).</code> <br>
      dove:
      <ul> 
        <li> <code>ID</code> corrisponde all’ identificatore della persona </li> 
        <li> <code>Lat1</code> corrisponde alla latitudine del posto di inizio dell’attività (activitySegment) in
formato E7 </li> 
        <li> <code>Lon1</code> corrisponde alla longitudine del posto di inizio dell’attività(activitySegment) in
formato E7 </li> 
        <li> <code>Lat2</code> corrisponde alla latitudine del posto di fine dell’attività (activitySegment) in formato
E7 </li> 
        <li> <code>Lon2</code> corrisponde alla longitudine del posto di fine dell’attività (activitySegment) in
formato E7 </li> 
        <li> <code>T_start</code> corrisponde al tempo di inizio attività espresso in ms dal 1° gennaio 1970 </li> 
        <li> <code>T_end</code> corrisponde altempo di fine attività espresso in ms dal 1° gennaio 1970 </li> 
        <li> <code>Activity</code> corrisponde al tipo di attività svolto.</li>
      </ul>
</li></ul>
 <p>Quindi gli elementi che del file JSON presi in considerazione sono:</p>
      <ul> 
        <li> Per quanto riguarda “<em>placeVisit</em>”</li>
        <ul>
          <li>i valori di <em>“latitudeE7”</em>, <em>“longitudeE7”</em>, <em>“placeId”</em>, contenuti nei record <em>“location”</em>
          </li><li> i valori di <em>“startTimestampMs”</em>, <em>“endStartTimeMs”</em> contenuti nei record <em>“duration”</em>.
<pre><code>
...
        "latitudeE7" : 454878470,
        "longitudeE7" : 92027718,
        "placeId" : "ChIJLT2PgNDGhkcR8JLKbYe11Us",
...
        "startTimestampMs" : "1552567416000",
        "endTimestampMs" : "1552570110078"
...
</code></pre>
        </li>
        </ul>
          <li> Per quanto riguarda “<em>activitySegment</em>”</li>
          <ul>
          <li> i valori di <em>“latitudeE7”</em> e <em>“longitudeE7”</em> contenuti nei record <em>“startlocation”</em></li>
          <li> i valori di <em>“latitudeE7”</em> e <em>“longitudeE7”</em> contenuti nei record <em>“endlocation”</em></li>
          <li> i valori di <em>“startTimestampMs”</em> e <em>“endTimestampMs”</em> contenuti nei record <em>“duration”</em></li>
          <li> i valori di <em>“activityType”</em>
<pre><code>
...
        "latitudeE7" : 454882939,
        "longitudeE7" : 92034225,
...
        "latitudeE7" : 454903992,
        "longitudeE7" : 92038098,
...
        "startTimestampMs" : "1552570110078",
        "endTimestampMs" : "1552570421471"
...
      "activityType" : "WALKING",
</code></pre>      </li>  
         </ul>
</ul>
</div>

<div class="nb-cell html" name="htm8">
<h4>Implementazione del Parser in Prolog</h4>
<p>S'utilizza il modulo <code>library(http/json)</code> che
supporta la lettura e la scrittura di oggetti JSON.</p>
</div>

<div class="nb-cell program" name="p7">
% Si carica il modulo Prolog per gestire file JSON
:- use_module(library(http/json)).
</div>

<div class="nb-cell html" name="htm9">
<p>In particolare, è stato utilizzato il predicato <code>json_read_dict(+Stream, -Dict)</code>, il quale legge un oggetto
JSON, restituendo gli oggetti(quindi le varie strutture dati) come dizionari (<code>dicts</code>).</p>
</div>

<div class="nb-cell program" name="p1">
% Programma Principale
main_parser:-
   writeln("Inserisci il file di output: "), % chiede all'utente il nome del file dove salvare i nuovi fatti
   read(FPath1),                           % inserisce il nome del file nella variabile "FPath1"
   open(FPath1,append,Stream),             % apre il file se (già esistente altrimenti lo crea)
                                           % e fa l'append di tutto ciò che viene scritto su Stream
   writeln("Inserisci nome file json: "), % chiede all'utente il nome del file JSON da analizzare
   read(FPath),                            % salva il nome del file nella variabile FPath
   check(FPath,Stream),                    % chiama il predicato check/2
   close(Stream).                          % chiude lo Stream in cui sono stati scritti i nuovi fatti

% Il predicato check serve per controllare se ci sono altri file JSON da
% analizzare controllando il nome del file "FPath"; se esiste il file
% attiva il predicato parser/2, se "FPth == y" allora esce dal check.
check( y, _ ):-!.
check( FPath, S ):-
    parser( FPath, S ).

% Parser
parser( FPath, S ):-
   writeln("Inserisci ID_Persona"),  % chiede l'ID della persona di cui si sta analizzando il file JSON
   read(ID),                         % lo salva nella variabile "ID".
   dict_from_json( FPath, Dict),     % attiva il predicato "dict_from_jason/2".
   get_dict(timelineObjects, Dict, A), % estrae dal dict l'oggetto "timelineObject".
   dict_parse( S, A, ID, _ ),             % attiva il predicato "dict_parse/4".
   writeln("Inserisci nome file json o premi y per terminare: "), %chiede il nome del nuovo file JSON da analizzare,
   read( FPath1 ),                     % lo salva nella variabile "FPath1",
   check( FPath1, S ).                  % rilancia check/2.

% dict_from_json salva il contenuto del file JSON in una struttura dati di tipo Dict
dict_from_json(FPath, Dict) :-
  open(FPath, read, Stream),
  json_read_dict(Stream, Dict), % chiamata al predicato di libreria
  close(Stream).

% dict_parse: essendo "timelineObject" una lista, per ogni suo elemento
% applica il predicato dict_to_clause fino ad arrivare al tappo(lista
% vuota).
dict_parse(_,[],_,_):-!.
dict_parse(S,[H|T],ID,[Out|T1]):-
       dict_to_clause(S,H,ID,Out),
       dict_parse(S,T,ID,T1).

% dict_to_clause: prende gli elementi di interesse del file JSON
% per creare i nuovi fatti e salvarli nel file di output chiesto
% nel Programma principale. Bisogna analizzare due casi:
% caso in cui l'Oggetto in esame è il "placeVisit";
% si estraggono fatti del tipo:
% place(ID,Lat,Lon,T_start,T_end,ID_Place)
% dove:
% - ID--&gt;ID della persona,
% - Lat--&gt; latitudine del posto visitato (placeVisit) in formato E7,
% - Lon--&gt; longitudine del posto visitato (placeVisit) in formato E7
% - T_start--&gt; espresso in ms dal 1 gennaio 1970
% - T_end--&gt; espresso in ms dal 1 gennaio 1970
% - ID_Place--&gt; identificativo del posto visitato.
dict_to_clause( S, H, ID, place(ID,Lat,Lon,T_start,T_end,ID_Place)):-
    dict_keys( H, [placeVisit] ), % verifica se la chiave di H è placeVisit
    Lat = H.placeVisit.location.latitudeE7,
    Lon = H.placeVisit.location.longitudeE7,
    ID_Place = H.placeVisit.location.placeId,
    T_start = H.placeVisit.duration.startTimestampMs,
    T_end = H.placeVisit.duration.endTimestampMs,
    portray_clause(place(ID,Lat,Lon,T_start,T_end,ID_Place)),
    portray_clause(S,place(ID,Lat,Lon,T_start,T_end,ID_Place)).
% caso in cui l'Oggetto in esame è l' "activitySegment";
% si estraggo fatti del tipo:
% activity(ID,Lat1,Lon1,Lat2,Lon2,T_start,T_end,Activity)
% dove:
% - ID--&gt;ID della persona,
% - Lat1--&gt; latitudine del posto d'inizio dell'attività (activitySegment) in formato E7
% - Lon1--&gt; longitudine del posto d'inizio dell'attività(activitySegment) in formato E7
% - Lat2--&gt; latitudine del posto di fine dell'attività (activitySegment) in formato E7
% - Lon2--&gt; longitudine del posto di fine dell'attività (activitySegment) in formato E7
% - T_start--&gt; tempo di inizio attività espresso in ms dal 1 gennaio 1970
% - T_end--&gt; tempo di fine attività espresso in ms dal 1 gennaio 1970
% - Activity--&gt; tipo di attività svolto
dict_to_clause( S, H, ID, activity(ID,Lat1,Lon1,Lat2,Lon2,T_start,T_end,Activity) ):-
    dict_keys(H,[activitySegment]),
    Lat1 = H.activitySegment.startLocation.latitudeE7,
    Lon1 = H.activitySegment.startLocation.longitudeE7,
    Lat2 = H.activitySegment.endLocation.latitudeE7,
    Lon2 = H.activitySegment.endLocation.longitudeE7,
    T_start = H.activitySegment.duration.startTimestampMs,
    T_end = H.activitySegment.duration.endTimestampMs,
    Activity = H.activitySegment.get(activityType),
    portray_clause(activity(ID,Lat1,Lon1,Lat2,Lon2,T_start,T_end,Activity)),
    portray_clause(S,activity(ID,Lat1,Lon1,Lat2,Lon2,T_start,T_end,Activity)).


</div>

<div class="nb-cell html" name="htm5">
<p>
  Per anonimizzare i dati, una tabella <br><code>cf(ID_INDIVIDUO, CODICE_FISCALE).</code><br>
  gestita sotto le dovute condizioni di riservatezza ed autorizzazione all'accesso, 
  consente alla bisogna di risalire all'individuo etichettato dal 
  <code>ID_INDIVIDUO</code>.</p>
</div>

<div class="nb-cell program" name="p6">
cf('Zagor', 'DRGMRF61H22A472Y').
cf('Goku', 'DRGGKU61H22A472K').
</div>

<div class="nb-cell html" name="htm3">
L'utente dell'App/client utilizza una predisposta specifica funzionalità per accedere
  al proprio GTO e popolare con i propri dati il DB in cloud di fatti del tipo <br>
  <code>db(PROB_CONT, TIME_INIZIO, LAT, LONG, TIME_FINE,IDENTIFICATORE_LUOGO).</code><br>
<p></p>
</div>

<div class="nb-cell program" name="p5">
db(0.01, 1581491705000, 436201975, 135173496, 1581498733000, 'ChIJXfPcGLl_LRMRm7vjV6MGgCg').
db(0.01, 1583516110000, 436196546, 135116121, 1583516225000, 'ChIJ90A6ebt_LRMR22wGClGgkUo').
db(0.01, 1583954404000, 436186150, 135124380, 1583956250000, 'ChIJDzXHbrx_LRMRBg12WxxGvmw').
db(0.01, 1582896321000, 435886750, 135154570, 1582906522000, 'ChIJy9raR7x_LRMRRhJWkTxBE40').
db(0.01, 1583480710000, 436201975, 135173496, 1583514320000, 'ChIJXfPcGLl_LRMRm7vjV6MGgCg').
db(0.01, 1583936177000, 436201975, 135173496, 1583943375000, 'ChIJXfPcGLl_LRMRm7vjV6MGgCg').
db(0.01, 1584466215000, 436196546, 135116121, 1584483310000, 'ChIJ90A6ebt_LRMR22wGClGgkUo').
db(0.01, 1584089100000, 436212457, 135104647, 1584092700000, 'ChIJyWoEGLt_LRMRvgzfLV2KsVQ').
db(0.01, 1584466215000, 436196546, 135116121, 1584483310000, 'ChIJ90A6ebt_LRMR22wGClGgkUo').
db(0.01, 1584984615000, 436196546, 135116121, 1585001710000, 'ChIJ90A6ebt_LRMR22wGClGgkUo').
db(0.01, 1584089100000, 436212457, 135104647, 1584092700000, 'ChIJyWoEGLt_LRMRvgzfLV2KsVQ').
db(0.01, 1583078700000, 436074488, 134977387, 1583080240000, 'ChIJcZ9iX51_LRMRbcXeW1l8lcw').
db(0.01, 1583755200000, 436212457, 135104647, 1583762400000, 'ChIJyWoEGLt_LRMRvgzfLV2KsVQ').
db(0.01, 1582204088000, 419109666, 125312697, 1582205405000, 'ChIJD1dcv9djLxMRoKHz4Aq6BoM').
db(0.01, 1582992300000, 436074488, 134977387, 1582994130000, 'ChIJcZ9iX51_LRMRbcXeW1l8lcw').
db(0.01, 1577840400000, 445345216, 112878593, 1577851205000, 'ChIJy6FHwPrTf0cRe9b4ZQFDU1Y').
db(0.01, 1583514601000, 435693012, 135092219, 1583515505000, 'ChIJb8qK2PuALRMRdemoW7-hAxE').
db(0.01, 1580563708000, 435529356, 135145473, 1580565006000, 'ChIJ8wwSv_GALRMRtit_eXXkC3A').
db(0.01, 1583933288000, 436034718, 135071662, 1583934606000, 'ChIJy93cCYV_LRMRwOclHJ-VEg8').
db(0.01, 1582204088000, 419109999, 125312999, 1582205405000, 'ChIJD1dcv9djLxMRoKHz4Aq6BoM').
db(0.01, 1582883130000, 435885750, 135154630, 1582911024000, 'ChIJy9raR7x_LRMRRhJWkTxBE40').
db(0.01, 1583478910000, 435885750, 135154630, 1583522130000, 'ChIJy9raR7x_LRMRRhJWkTxBE40').
db(0.01, 1577984700000, 435529356, 135145473, 1577986550000, 'ChIJ8wwSv_GALRMRtit_eXXkC3A').
db(0.01, 1583498730000, 435885750, 135154630, 1583516710000, 'ChIJy9raR7x_LRMRRhJWkTxBE40').
db(0.01, 1583954103000, 436186150, 135124380, 1583955905000, 'ChIJDzXHbrx_LRMRBg12WxxGvmw').
db(0.01, 1583485511000, 436201975, 135173496, 1583489411000, 'ChIJXfPcGLl_LRMRm7vjV6MGgCg').
db(0.01, 1583939420000, 436201975, 135173496, 1583943300000, 'ChIJXfPcGLl_LRMRm7vjV6MGgCg').
db(0.01, 1583515830000, 436196546, 135116121, 1583532310000, 'ChIJ90A6ebt_LRMR22wGClGgkUo').
db(0.01, 1583484620000, 435885750, 135154630, 1583495410000, 'ChIJy9raR7x_LRMRRhJWkTxBE40').
db(0.01, 1583514300000, 435693012, 135092219, 1583516155000, 'ChIJb8qK2PuALRMRdemoW7-hAxE').
db(0.01, 1583932088000, 436033718, 135070662, 1583933405000, 'ChIJy93cCYV_LRMRwOclHJ-VEg8').
db(0.01, 1583515830000, 436196546, 135116121, 1583532310000, 'ChIJ90A6ebt_LRMR22wGClGgkUo').
db(0.01, 1581491700000, 436201975, 135173496, 1581498000000, 'ChIJXfPcGLl_LRMRm7vjV6MGgCg').
db(0.01, 1583078700000, 436074488, 134977387, 1583080240000, 'ChIJcZ9iX51_LRMRbcXeW1l8lcw').
db(0.01, 1583743500000, 436212457, 135104647, 1583747100000, 'ChIJyWoEGLt_LRMRvgzfLV2KsVQ').
db(0.01, 1583414888000, 436033718, 135070662, 1583416206000, 'ChIJy93cCYV_LRMRwOclHJ-VEg8').
db(0.01, 1583414888000, 436033718, 135070662, 1583416206000, 'ChIJy93cCYV_LRMRwOclHJ-VEg8').
db(0.01, 1582992300000, 436074488, 134977387, 1582994130000, 'ChIJcZ9iX51_LRMRbcXeW1l8lcw').
db(0.01, 1584984615000, 436196546, 135116121, 1585001710000, 'ChIJ90A6ebt_LRMR22wGClGgkUo').
db(0.01, 1577840400000, 445345216, 112878593, 1577851205000, 'ChIJy6FHwPrTf0cRe9b4ZQFDU1Y').
</div>

<div class="nb-cell html" name="htm4">
<p>
  Definiamo <em>nodo spaziotemporale</em>, o più semplicemente <em>nodo</em>, ogni elemento 
  del database, ovvero ogni n-upla <br><code> (TIME_INIZIO, LAT, LONG, TIME_FINE,IDENTIFICATORE_LUOGO) </code><br> 
  caratterizzata dalla probabilità di essere stato <em>luogo/momento</em> (ovvero <em>occasione</em>)
  di contagio <code> PROB_CONT </code>. 
  Il valore <code> 0,01 </code> nell'esempio precedente sta per <em>probabilità minima</em> 
  di essere stato occasione di contagio, mentre il valore <code> 0,99 </code> 
  sta per <em>probabilità massima</em>.
</p>
<p>
  Lato server, ogni 24 ore il DB sarà ritagliato sull'arco temporale relativo all'ultimo
  <em>periodo di contagiosità</em>, probabilmente stabilito in 45 gg, ovvero all'arco temporale massimo
  durante il quale si potrebbe ritenere essere stata contagiata da contatto diretto una persona che non abbia
  manifestato alla data corrente alcun sintomo. Quindi ogni 24 ore saranno eliminati
  dal DB i nodi il cui intervallo di riferimento termina il giorno che precede di 45 gg.
  la data corrente. 
  Sempre lato server, alla ricezione di un aggiornamento GTO VERDE, ovvero aggiornamento 
  volontario da parte di utente NON POSITIVO, 
  records spaziotemporali che si riferiscano al medesimo luogo, abbiano il 
  medesimo valore di <code> PROB_CONT </code> e intervalli temporali sovrapponentesi
  verranno accorpati in un medesimo record che avrà come intervallo temporale l'unione
  dei due, e questo processo itererà fintanto che ci saranno coppie da fondere.
</p>
</div>

<div class="nb-cell program" data-background="true" name="p4">
compatta :-
    db(Prob, Inizio1, Lat, Long, Fine1, IdLuogo),
    db(Prob, Inizio2, Lat, Long, Fine2, IdLuogo),
    Inizio1 \== Inizio2,
    minore(Inizio1,Inizio2,Inizio),
    maggiore(fine1,Fine2,Fine),
    retract(db(Prob, Inizio1, Lat, Long, Fine1, IdLuogo)),
    retract(db(Prob, Inizio2, Lat, Long, Fine2, IdLuogo)),
    assert(db(Prob, Inizio, Lat, Long, Fine, IdLuogo)),
    fail.
compatta.
</div>

<div class="nb-cell html" name="htm6">
Se <code>'Zagor'</code> effettua un tampone al momento <code>1583190000000</code> e questo si rileva 
<code>POSITIVO</code>, 
l'Autorità Sanitaria gli chiede di attivare l'App e, mediante una sua funzionalità, accedere al 
proprio GTO per aggiungere nel DB Prolog del server il fatto <code>positivo('Zagor', 1583190000000).</code>:
</div>

<div class="nb-cell program" name="p9">
%Positivo(ID_INDIVIDUO,DATA_TAMPONE).
positivo('Conte',   1583362800000).
positivo('Khaled',  1582844400000).
positivo('Luca',    1583362800000).
positivo('Rufy',    1582671600000).
positivo('Vallese', 1583190000000).
positivo('Zagor',   1583190000000).
</div>

<div class="nb-cell html" name="htm7">
A questo punto, sul lato server parte un processo di aggiornamento del DB dei nodi spaziotemporali.
Il processo parte dai nodi nel GTO di <code>Zagor</code> che corrispondono al 
mese precedente alla data del tampone. In corrispondenza di ciascuno di essi si presentano due casi:
1. il nodo non si sovrappone spaziotemporalmente con alcun altro presente nel DB del server:
in questo caso l'effetto è quello di aggiungere un nodo al DB con un alta probabilità di contagio 
<code>PROB_CONT</code>
2. il nodo si sovrappone a qualche altro nodo presente nel DB: in questo caso quel nodo viene
processato nel seguente modo: se l'intervallo temporale di quello nuovo comprende l'intervallo di
quello già presente nel DB allora il nodo nuovo rimpiazza totalmente quello vecchio ma con un valore
<code>PROB_CONT</code> al più alto livello;  se l'intervallo temporale di quello nuovo si accavalla
in anticipo con l'intervallo di quello già presente nel DB allora si generano due nodi corrispondenti
ai due sottintervalli temporali, il primo con <code>PROB_CONT</code> al più alto livello ed il secondo
con <code>PROB_CONT</code> a livello intermedio (il virus potrebbe essere rimasto sulle superifici);
se l'intervallo temporale di quello nuovo si accavalla in posticipo con l'intervallo di quello già presente nel DB allora si generano due nodi corrispondenti
ai due sottintervalli temporali, il primo con <code>PROB_CONT</code> al più alto livello ed il secondo
con <code>PROB_CONT</code> a livello intermedio (il virus potrebbe essere rimasto sulle superifici)

s'elimina
e se ne introduco due con dati georeferenziali identici ma diversi intervalli temporali

con lo scopo di mettere a ROSSO, ovvero di aumentre la PROB_CONTAGIO dei nodi che si sov
</div>

<div class="nb-cell program" name="p8">

</div>

<div class="nb-cell query" name="q1">

</div>

<div class="nb-cell html" name="htm2">
<div class="panel panel-default">
  <div class="panel-body">
    <div class="form-group">
      <label>Sentence</label>
      <div class="input-group">
        <div class="input-group-btn">
          <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Example
            <span class="caret"></span></button>
          <ul class="dropdown-menu">
          </ul>
        </div>
        <input class="form-control">
      </div>
    </div>
  </div>
</div>

<script>
  // Load examples from the predicate examples/1.  notebook.swish() is a wrapper
  // around new Pengine() that fetches the sources using the same algorithm as
  // a query cell and set the `application` to `swish`.
  // notebook.$() is a shorthand for notebook.cell().find(), evaluating to a
  // jQuery object that matches the objects from the current cell.
  function loadExamples() {
    var seen = 0;
    notebook.$(".dropdown-menu").html("");
    notebook.swish({ ask: "example(Ex)",
                     ondata: function(data) {
                     notebook.$(".dropdown-menu").append('<li><a>'+data.Ex+'</li>');
                     if ( seen++ == 0 )
                       notebook.$("input").val(data.Ex);
                    }
                   });
  }
  // Load the examples on page load as well as if the user clicks the
  // dropdown menu, so changes are reflected.
  loadExamples();
  notebook.$(".dropdown-toggle").on("click", loadExamples);

  // Pass selected examples to the input field.
  notebook.$(".dropdown-menu").on("click", "li", function(ev) {
    notebook.$("input").val($(this).text());
  });

  // If the play button of the "parse" query is clicked, run the query,
  // binding Sentence to the input string.  The function
  // notebook.bindQuery() takes the name of a query and a
  // function that collects the arguments and calls the query.
  notebook.bindQuery("parse", function(q) {
    q.run({Sentence: notebook.$("input").val()});
  });
</script>
</div>

<div class="nb-cell query" name="parse">
parse(Sentence, Tree).
</div>

<div class="nb-cell program" data-background="true" data-singleline="true" name="p2">
example("john sees a man").
example("a man sees john").
example("john sees a man with a telescope").
</div>

<div class="nb-cell program" data-background="true" data-singleline="true" name="p3">
:- use_rendering(svgtree, [list(false)]).

parse(Sentence, Tree) :-
    nonvar(Sentence), !,
    split_string(Sentence, " ", " ", Strings),
    maplist(atom_string, Words, Strings),
    phrase(s(Tree), Words).
parse(Sentence, Tree) :-
    phrase(s(Tree), Words),
    atomics_to_string(Words, " ", Sentence).
</div>

</div>