Преглед на файлове

Merge remote-tracking branch 'origin' into amministratore

mauro преди 8 месеца
родител
ревизия
41a510377a

+ 1 - 0
azienda/forms.py

@@ -1,4 +1,5 @@
 from django import  forms
+from .models import Azienda
 
 class formAzienda(forms.Form):
   def __init__(self,*args,**kwargs):

+ 21 - 0
azienda/migrations/0018_remove_azienda_unique_azienda_azienda_unique_azienda.py

@@ -0,0 +1,21 @@
+# Generated by Django 5.1.6 on 2025-04-01 14:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('azienda', '0017_assegnazioneazienda_crea_azienda_and_more'),
+    ]
+
+    operations = [
+        migrations.RemoveConstraint(
+            model_name='azienda',
+            name='unique-azienda',
+        ),
+        migrations.AddConstraint(
+            model_name='azienda',
+            constraint=models.UniqueConstraint(fields=('partitaiva',), name='unique-azienda'),
+        ),
+    ]

+ 26 - 0
azienda/migrations/0019_remove_azienda_unique_azienda_and_more.py

@@ -0,0 +1,26 @@
+# Generated by Django 5.1.6 on 2025-04-01 15:00
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('azienda', '0018_remove_azienda_unique_azienda_azienda_unique_azienda'),
+    ]
+
+    operations = [
+        migrations.RemoveConstraint(
+            model_name='azienda',
+            name='unique-azienda',
+        ),
+        migrations.AlterField(
+            model_name='azienda',
+            name='partitaiva',
+            field=models.CharField(default='', max_length=11, unique=True),
+        ),
+        migrations.AddConstraint(
+            model_name='azienda',
+            constraint=models.UniqueConstraint(fields=('nome', 'partitaiva'), name='unique-azienda'),
+        ),
+    ]

+ 24 - 0
azienda/migrations/0020_alter_azienda_nome_alter_sede_azienda.py

@@ -0,0 +1,24 @@
+# Generated by Django 5.1.6 on 2025-04-01 15:01
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('azienda', '0019_remove_azienda_unique_azienda_and_more'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='azienda',
+            name='nome',
+            field=models.CharField(default='', max_length=132, unique=True),
+        ),
+        migrations.AlterField(
+            model_name='sede',
+            name='azienda',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='azienda.azienda'),
+        ),
+    ]

+ 3 - 3
azienda/models.py

@@ -6,8 +6,8 @@ class Azienda(models.Model):
    questa classe definisce le società che gengono gestite dal programma.
    ogni utente può gestire una o più società.
    '''
-   nome = models.CharField(max_length=132,null=False,default="")
-   partitaiva = models.CharField(max_length=11,null=False,default="")
+   nome = models.CharField(max_length=132,null=False,default="",unique=True)
+   partitaiva = models.CharField(max_length=11,null=False,default="",unique=True)
    mail = models.CharField(max_length=256,null=False,default="")
    comm=models.CharField(max_length=256,null=False,default="") # email usata come mittente per le comunicazioni
    cambiopassword = models.BooleanField(null=False,default=False)
@@ -32,7 +32,7 @@ class Sede(models.Model):
     nome = models.CharField(max_length=132,null=False,default="")
     info = models.CharField(max_length=256,null=False,default="")
     identificativo = models.CharField(max_length=10,null=False,default="")
-    azienda = models.ForeignKey(Azienda,on_delete=models.PROTECT)
+    azienda = models.ForeignKey(Azienda,on_delete=models.CASCADE)
     cambiopassword = models.BooleanField(null=False,default=False)
     forzanuovapassword = models.BooleanField(null=False,default=False)
     otppassword = models.BooleanField(null=False,default=False)

+ 3 - 51
azienda/templates/azienda.editAzienda.html

@@ -3,17 +3,7 @@
 {% block headersupplement %}
   <script language="JavaScript">
 
-    {% if AziendaEsistente %}
-//      $(window).on('load',function() {
-	$(document).ready(function() {
-	$('#AlertAziendaEsistente').modal('show');
-        $("#dest_nome").html($("#nome").val());
-        $("#dest_partitaiva").html($("#partitaiva").val());
-        console.log($("#partitaiva").val());
-      });
-    {% endif %}
-    
-   </script>
+  </script>
 {% endblock %}
 
 {% block body %}
@@ -109,49 +99,11 @@
     <div class="btn-group">
       {# sperimentale: "avanti" per impostare i diritti amministratore #}
       <button type='submit' class="btn btn-primary" name='AggiornaAziendaButton' value='AggiornaAzienda' {% if admin.sola_lettura %} disabled {% endif %}>Aggiorna/Salva</button>
-      <button type='submit' class="btn btn-primary" name="AggiornaDocumentoButton" value="AggiornaDocumento">Documenti Azienda</button>
-      <button type='submit' class="btn btn-primary" name= 'AvantiAziendaButton' value='AvantiAzienda'>Avanti/Permessi</button>
+      {% if aziendaprensete %} <button type='submit' class="btn btn-primary" name="AggiornaDocumentoButton" value="AggiornaDocumento">Documenti Azienda</button> {% endif %}
+      {% if aziendapresente %} <button type='submit' class="btn btn-primary" name= 'AvantiAziendaButton' value='AvantiAzienda'>Avanti/Permessi</button> {% endif %}
       <button type='submit' class="btn btn-primary" name="indietro">Indietro/Chiudi</button>
     </div>
   </form>
 </div>
 
-<!-- Modal -->
-<div class="modal fade" id="AlertAziendaEsistente" tabindex="-1" role="dialog" aria-labelledby="AziendaEsistente" aria-hidden="true">
-  <div class="modal-dialog modal-dialog-centered" role="document">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h5 class="modal-title" id="TitleModalTitle">Attenzione: Azienda Esistente</h5>
-      </div>
-      <div class="modal-body">
-	Attenzione:<br>
-	L'azienda appena inserita <div id="dest_nome"></div> con partita iva <div id="dest_partitaiva"></div><br>
-	risulta gia' presente in archivio.
-	Se non è visualizzata, è possibile che non ne abbiate i diritti di accesso.
-      </div>
-      <div class="modal-body">
-        <!-- errori form azienda -->
-        {% if aziendaForm.errors %}
-          {{ aziendaForm.errors }}
-          {% for field in aziendaForm %}
-            {% for error in field.errors %}
-              <div class="alert alert-danger">
-                <strong>{{ error|escape }}</strong>
-              </div>
-            {% endfor %}
-          {% endfor %}
-          {% for error in aziendaForm.non_field_errors %}
-            <div class="alert alert-danger">
-              <strong>{{ error|escape }}</strong>
-            </div>
-          {% endfor %}
-        {% endif %}
-      
-  <!-- fine zona errori -->
-      <div class="modal-footer">
-        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
-      </div>
-    </div>
-  </div>
-</div>
 {% endblock %}

+ 47 - 41
azienda/views.py

@@ -89,10 +89,10 @@ def welcome(request):
         print("Non e' stata fatta la scelta corretta",ve)
         return HttpResponseRedirect(reverse('azienda:welcome'))
 
-      print("sceltaazienda = ",request.POST.get('sceltaazienda'))
+      print("sceltaazienda:",request.POST.get('sceltaazienda'))
 
       # attività su nuova/edit azienda
-      if sceltaazienda == -1: #richiesta una nuova azienda
+      if sceltaazienda == -1: # richiesta una nuova azienda
         print('sceltaazienda -1:',sceltaazienda)
         if "AziendaId" in request.session:
           del request.session['AziendaId']
@@ -104,19 +104,30 @@ def welcome(request):
           del request.session['sede']
         return HttpResponseRedirect(reverse('azienda:welcome'))
         
-      elif sceltaazienda == 0:
+      elif sceltaazienda == 0: # azienda nuova
         print('sceltaazienda 0:',sceltaazienda)
         request.session['AziendaIdEdit'] = 0
         print('AziendaId',request.session['AziendaIdEdit'])
         return HttpResponseRedirect(reverse('azienda:editAzienda'))
       else:
+        print('azienda presente - almeno segnalata')
         try:
           azienda = Azienda.objects.get(pk=sceltaazienda)
+          print('azienda trovata:',azienda.nome)
           data['azienda'] = azienda
           request.session['AziendaId'] = azienda.id
-          request.session['SedeId'] = -1 
-          if 'sede' in data:
-            del data['sede']
+
+          ####
+          sede = azienda.sede_set.all()
+          if len(sede) == 1:
+            sede = sede[0]
+            print('singola sede',sede.id)
+            request.session['SedeId']=sede.id
+            data['sede'] = sede
+          else:
+            request.session['SedeId'] = -1 
+            if 'sede' in data:
+              del data['sede']
         except Azienda.DoesNotExist as dne:
           print("errore, oggetto inesistente",dne)
 
@@ -246,7 +257,7 @@ def editAzienda(request):
   data['permesso'] = getAMP(data['admin'])[0]
   print("******",data['azienda'])
   if 'azienda' in data:
-    print('**** azienda presente ****')
+    print('**** permesso: azienda presente ****')
     for t in getAZP(data['azienda'],data['admin'])[0]:
       if t not in data['permesso']:
         data['permesso'].append(t)
@@ -264,8 +275,9 @@ def editAzienda(request):
   print('admin',admin.id,admin.nome)
 
   ### azienda su cui effettuare le operazioni
-  azienda = None
-  aziendapresente = False
+  azienda = Azienda()
+  aziendapresente=False
+
   if 'AziendaIdEdit' in request.session:
     print('trovato riferimento AziendaIdEdit',request.session.get('AziendaIdEdit'))
     azid = request.session.get('AziendaIdEdit')
@@ -275,8 +287,10 @@ def editAzienda(request):
       print('azienda trovata',azienda.nome)
     except Azienda.DoesNotExist as dnf:
       print(dnf)
-      azienda = Azienda()
-      
+      azienda.login=''
+      azienda.nome=''
+      azienda.mail=data['admin'].mail
+    
   if request.method == 'POST':
     print('EditAzienda un tasto è stato premuto')
 
@@ -299,17 +313,21 @@ def editAzienda(request):
         print("####### azienda.mail",azienda.mail)
         try:
           azienda.save()
+          aziendapresente=True
         except IntegrityError as ie:
           print("Errore, azienda gia' presente:",azienda.nome,azienda.partitaiva)
-          data['AziendaEsistente']=True
+          return HttpResponseRedirect(reverse('azienda:welcome'))
 
-        if not 'AziendaEsistente' in data: 
-          request.session['AziendaIdEdit'] = azienda.id
-          print('azienda:',azienda.id)
-          request.session['AziendaId'] = azienda.id
-          data['azienda'] = azienda
+        request.session['AziendaIdEdit'] = azienda.id
+        print('azienda:',azienda.id)
+        request.session['AziendaId'] = azienda.id
+        data['azienda'] = azienda
      
-          ### generiamo un utente speciale per la gestione dei documenti aziendali
+        ### generiamo un utente speciale per la gestione dei documenti aziendali
+        # 1 verifichiamo che non esista l'utente
+        try:
+          Utente.objects.get(codicefiscale=azienda.partitaiva)
+        except Utente.DoesNotExist as dne:
           print("Generazione utente speciale per {}".format(azienda.nome))
           utente = Utente()
           utente.azienda = azienda
@@ -319,7 +337,7 @@ def editAzienda(request):
           try:
             utente.save()
           except IntegrityError as ie:
-            print(ie,"errore")
+            print(ie)
 
           ### nel caso l'azienda non esista, si aggiungono i permessi di base
           print("data['admin']",data['admin'])
@@ -342,8 +360,10 @@ def editAzienda(request):
             print('getAMP:  UTENTE.EDIT')
             setAZP(azienda,data['admin'],"UTENTE.EDIT")
 
-          data['aziendaForm'] = formAzienda(request.POST)
-          return render(request,'azienda.editAzienda.html',data)
+        data['aziendaForm'] = formAzienda(request.POST)
+        if aziendapresente: data['aziendapresente']=True
+
+        return render(request,'azienda.editAzienda.html',data)
       else:
         data['aziendaForm'] = formAzienda(request.POST)
         print("il form 'AggiornaAziendaButton' non è valido")
@@ -351,15 +371,10 @@ def editAzienda(request):
     if 'AvantiAziendaButton' in request.POST:
       print('premuto "AvantiAziendaButton"')
       ### puo' andare avanti solo se l'azienda gia' e' inserita
-      if aziendapresente:
-        print("azienda presente")
-        return HttpResponseRedirect(reverse('azienda:editAziendaPermesso'))
-      else:
-        print("azienda non presente")
-                
-  formaziendafield = None
-  if azienda:
-    print('Abbiamo azienda',azienda.nome)
+      return HttpResponseRedirect(reverse('azienda:editAziendaPermesso'))
+
+  else:
+    # prepariamo il form per l'azienda            
     tmp = dict()
     tmp['id'] = azienda.id
     tmp['nome'] = azienda.nome
@@ -368,18 +383,9 @@ def editAzienda(request):
     tmp['forzanuovapassword'] = azienda.forzanuovapassword
     tmp['cambiopassword'] = azienda.cambiopassword
     tmp['otppassword'] = azienda.otppassword
+    print(tmp)
     formaziendafield = formAzienda(tmp)
-  else:
-    print("Non abbiamo azienda")
-    tmp = dict()
-    tmp['nome'] = ''
-    tmp['partitaiva'] = ''
-    tmp['mail'] = user.mail
-    tmp['forzanuovapassword'] = False
-    tmp['cambiopassword' ] = False
-    tmp['otppassword'] = False
-    formaziendafield = formAzienda(tmp)
-  data['aziendaForm'] = formaziendafield
+    data['aziendaForm'] = formaziendafield
 
   return render(request,'azienda.editAzienda.html',data)
 

BIN
db/db.sqlite3


BIN
static/upload/13496821003/-/1738921291.0952601.saved


BIN
static/upload/13496821003/-/1738921291.1998022.saved


BIN
static/upload/13496821003/-/1738921291.243058.saved


BIN
static/upload/13496821003/-/1738922579.2282233.saved


BIN
static/upload/13496821003/-/1738922682.3998225.saved


BIN
static/upload/13496821003/-/1741940219.9171848.saved


+ 66 - 0
static/upload/Index/1743408181.4905593.saved.cvtd

@@ -0,0 +1,66 @@
+Nome Cognome;Codice Fiscale;Data di Nascita;Luogo di Nascita;email;Sede
+BIRBES ROBERTA;BRBRRT78H53B157I;13/06/1978;ITALIA;birbes.roberta0@gmail.com;STEREO S.R.L.
+HUNDE MAHLET ASHEBIR;HNDMLT67B52Z315U;12/02/1967;ETIOPIA;mahlet0ashebir0hunde@gmail.com;STEREO S.R.L.
+MARIANI MARISA;MRNMRS71C45B157A;05/03/1971;ITALIA;marianimarisa1971@gmail.com;STEREO S.R.L.
+BOUDOUBI RACHID;BDBRHD61C16Z301F;16/03/1961;ALGERIA;rachidboudoubi@gmail.com;STEREO S.R.L.
+SCARATTI ROSALBA;SCRRLB66D68B157Q;28/04/1966;ITALIA;scarattirosalba@gmail.com;STEREO S.R.L.
+ZEWEDU HAILEMARIAM YODET;ZWDYDT81A66Z315I;29/01/1981;ETIOPIA;zeweduyodet@gmail.com;STEREO S.R.L.
+BOZHKO TETIANA;BZHTTN76H60Z138A;20/06/1976;UCRAINA;bozhkotatiana1@gmail.com;STEREO S.R.L.
+MADULI IRENE;MDLRNI83C49D918K;09/03/1983;ITALIA;Iry.83m@gmail.com;STEREO S.R.L.
+COLOMBO MONICA;CLMMNC67P51B157R;11/09/1967;ITALIA;monicolombo31@gmail.com;STEREO S.R.L.
+TONASSI  ROSANNA;TNSRNN60S53C883I;13/11/1960;ITALIA;rosanna.tonassi@gmail.com;STEREO S.R.L.
+DOMINIC FATTI;DMNFTT66P61Z318D;21/09/1966;GHANA;dominicfatti@gmail.com;STEREO S.R.L.
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;

+ 18 - 0
static/upload/Index/1743413103.2650099.saved.cvtd

@@ -0,0 +1,18 @@
+Nome Cognome;Codice Fiscale;Data di Nascita;Luogo di Nascita;email;Sede
+HOSSAIN SAMIM;HSSSMM96A01Z249W;01/01/1996;BANGLADESH;;BAOBAO ISTRIA
+ALMOUJUELA DELIO;LMJDLE82M07Z216U;07/08/1982;FILIPPINE;;BAOBAO ISTRIA
+RAZZAK ABDUL;RZZBDL89C09Z249C;10/03/1989;BANGLADESH;;BAOBAO ISTRIA
+DELENA KEVIN BRYAN ATAJAR;DLNKNB03P09Z216N;09/09/2003;FILIPPINE;;BAOBAO ISTRIA
+BERNALES JOVENCIO JR ;BRNJNC93H03Z216G;03/06/1993;FILIPPINE;;BAOBAO ISTRIA
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;

+ 106 - 0
static/upload/Index/1743499647.7287152.saved.cvtd

@@ -0,0 +1,106 @@
+Nome Cognome;Codice Fiscale;Data di Nascita;Luogo di Nascita;email;Sede
+MUCILEANU BOGDAN VASILE;MCLBDN85S17Z129R;17/11/1985;ROMANIA;bobomucileanu85@gmail.com;PERUGIA
+PASCALIN ANDREI MIHAIL;PSCNRM97R24Z129Y;24/10/1997;ROMANIA;deyuprod@gmail.com;PERUGIA
+PIRIIALA STEFAN ALEXANDRU;PRLSFN99P13Z129B;13/09/1999;ROMANIA;alextreme76@yahoo.it;PERUGIA
+TOSKA TAFIL;TSKTFL84C23Z100K;23/03/1984;ALBANIA;toskatafil1984@gmail.com;PERUGIA
+IGHALO CHARLES;GHLCRL94B20Z335T;20/02/1994;NIGERIA;ighalocharles1988@gmail.com;PERUGIA
+JALLOW BUBACARR;JLLBCR96T25Z317J;25/12/1996;GAMBIA;jalbubacarr25@gmail.com;PERUGIA
+JOHN MOSES;JHNMSS88T12Z335D;12/12/1988;NIGERIA;johnmosesp4@gmail.com;PERUGIA
+LANZUISI EMANUEL;LNZMNL90H04D662D;04/06/1990;FONDI;emanuel040690@gmail.com;PERUGIA
+LUTA RUSLAN;LTURLN87E13Z140Q;13/05/1987;MOLDAVIA;ruslanluta856@gmail.com;PERUGIA
+MICHEAL PETER;MCHPTR89T05Z335E;05/12/1989;NIGERIA;peter.petermike01@gmail.com;PERUGIA
+OSAGHAEDE RICHARD OMONHEFE;SGHRHR80S22Z335Q;22/11/1980;NIGERIA;kesteromon22@yahoo.com;PERUGIA
+PELELUNGA BOGDAN;PLLBDN87B12Z129P;12/02/1987;ROMANIA;bogdanpelelunga@gmail.com;PERUGIA
+PINTRIJEL PAUL;PNTPLA97P27Z129R;27/09/1997;ROMANIA;pintrijelp@gmail.com;PERUGIA
+ROJAS PUJOL JOSE ANTONIO;RJSJNT98B17Z504P;17/02/1998;CUBA;joseantoniorojaspujol@gmail.com;PERUGIA
+SHEVCHUK MYKHAILO;SHVMKH77S14Z138N;14/11/1977;UCRAINA;mykhailoshevchuk1977@icloud.com;PERUGIA
+TRAORE SALIF;TRRSLF93H12Z329M;12/06/1993;MALI;tsalif595@gmail.com;PERUGIA
+VAITI VISAR;VTAVSR89D13Z148P;13/04/1989;MACEDONIA;visarvaiti68@gmail.com;PERUGIA
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;

+ 27 - 0
static/upload/Index/1743515916.3063955.saved.cvtd

@@ -0,0 +1,27 @@
+Nome Cognome;Codice Fiscale;Data di Nascita;Luogo di Nascita;email;Sede
+KENESBECK  ALIYA;KNSLYA99L43Z255Z;03/07/1999;KAZAKISTAN;;CHOPSTICK PRATI
+PALMIERI LORENZO   ;PLMLNZ05T29E506H;29/12/2005;LECCE;;CHOPSTICK PRATI
+SURIANO  LORENZO;SRNLNZ04E15H501X;15/05/2004;ROMA;;CHOPSTICK PRATI
+FABBRI ASIA;FBBSAI01M58I608X;18/08/2001;SENIGALLIA;;CHOPSTICK PRATI
+HOSSAN FOYSAL;HSSFSL93R04Z249P;04/10/1993;BANGLADESH;;CHOPSTICK PRATI
+KIRTANIA  OPURBA ;KRTPRB03S03Z249F;03/11/2003;BANGALDESH;;CHOPSTICK PRATI
+MIAH EMRAN   ;MHIMRN93B20Z249D;20/02/1993;BANGLADESH;;CHOPSTICK PRATI
+HOSSAIN FOYSAL;HSSFSL93R04Z249P;04/10/1993;BANGLADESH;;CHOPSTICK PRATI
+SHEIKH  MD EMRAN ;SHKMMR02T31Z249N;31/12/2002;BANGLADESH;;CHOPSTICK PRATI
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;
+;;;;;