Mi sono imbattuto in un comportamento piuttosto curioso utilizzando DBeaver con un server MySQL locale. All’avvio di DBeaver, il tentativo di connessione falliva con il messaggio: La cosa sorprendente era che bastava aprire un terminale …
Per anni avevo sentito ripetere che Docker è una virtualizzazione leggera. È una frase comoda per iniziare, ma in realtà è fuorviante. L’ho capito nel modo migliore: cercando di capire perché MySQL si comportasse in …
Aprendo Thunderbird mi è comparso un avviso che invitava a intervenire entro il 21 luglio 2026 per continuare a ricevere gli aggiornamenti ESR (Extended Support Release). Partiamo con le istruzioni operative per chi sa già …
Negli ultimi tempi termini come LLM, embedding e database vettoriali sono usciti rapidamente dall’ambito della ricerca e sono diventati argomenti quasi quotidiani. Sono mattoncini coi quali possiamo costruire sistemi capaci di interrogare grandi collezioni di …
Ho condotto un esperimento di scrittura di software per analizzare i risultati di una esportazione delle mie conversazioni con ChatGPT. Ma ho deciso di aiutarmi nell’analisi con un Large Language Model che sicuramente sa fare molto bene questo lavoro e in più con un LLM in locale, per vedere come funziona.
Incontri spaziali. Sembra che Giove e Saturno siano prossimi a scontrarsi ma naturalmente è solo una questione di prospettiva: è la loro proiezione sulla volta celeste a farlo.
Quello che accade realmente è che siamo all’incirca tutti e tre, noi, Giove e Saturno, lungo un’unica linea retta di congiunzione.
Giove e Saturno si incontrano sulla sfera celeste sotto un angolo di 1/5 del disco lunare
Non si tratta in realtà di un allineamento perfetto; più precisamente vediamo entrambi i pianeti sotto un angolo solido pari a circa di 1/5 del disco lunare.
Per esempio questa elaborazione della Nasa mostra cosa si intenda per allineamento tra pianeti. Quello qui rappresentato è la sovrapposizione tra Venere e Giove avvenuta il 30 giugno 2015
Allineamento tra Terra, Venere e Giove del 30 giugno 2015
Questo delle congiunzioni o allineamenti è un evento molto raro sulla scala di una vita umana. L’ultima volta che Giove e Saturno si trovarono così vicini sulla volta celeste successe 4 marzo1226. In quell’anno morirono S. Francesco d’Assisi e Federico IIdi Hohenstaufen.
Non per la congiunzione astrale, beninteso, è solo una coincidenza!
Anche un’altra volta avvenne, il 16 luglio 1623, però da terra non si vide nulla perché la congiunzione avvenne vicino al disco solare, verso il tramonto.
La congiunzione tra Giove e Saturno in realtà avviene molto più spesso, circa ogni 20 anni, ma non sempre entro un angolo così piccolo e in condizione di oscurità favorevole. Una lista delle congiunzioni tra i due pianeti, nel passato e nel futuro si trova in questa risorsa. Trovate tutte le congiunzioni, più o meno notevoli, dei due pianti dal 1206 al 2398.
Appunto, l’ultima volta i cui entrambe queste condizioni si verificarono, fu nel 1226.
C’è da dire che questa è la prima volta in assoluto che noi umani possiamo goderci lo spettacolo così da vicino, grazie alla Scienza e alla Tecnologia.
La non disponibiità di un certificato SSL è all’origine del “problema PXIX”
PKIX: una precisazione
Voglio avvisarvi subito che non esiste in sé un “errore PKIX”. È soltanto un modo breve di descrivere una situazione in cui c’è un problema del client Grails (o a qualunque altro client) ad accedere ad un URL protetto da SSL.
Se vi capita di vedere questa sigla PKIX in un messaggio errore di Grails, si fa riferimento alla Public Key Infrastructure X.509, uno standard usato per definire il formato dei certificati a chiave pubblica (PKC) e delle autorità di certificazione (CA).
Significa che è sorto qualche problema nello stabilire la connessione cifrata SSL con lo storage da cui il client scarica il template dell’applicazione.
Mi è capitato in più di un contesto questo problema (ad esempio nella configurazione di un reverse proxy Apache), però il significato di un simile tipo di sintomatologia risulta abbastanza chiaro nello specifico esempio che vi propongo.
Qual è il problema per cui compare questa misteriosa sigla PKIX?
Questo problema sorge appena si avvia il client Grails:
Ciò che succede è che insorge un problema di sicurezza perché non ho tra i certificati SSL installati nella JVM quello di grails.org da cui il client cerca di scaricare il boilerplate dell’applicazione. Da qui l’errore PKIX.
Una soluzione
La soluzione consiste nello scaricare e installare manualmente il certificato dal sito con Chrome o Firefox, e importarlo nel keystore della JVM.
I passaggi sono un po’ diversi a seconda del browser che state usando per accedere all’applicazione Laravel, per cui per vostra comodità vi illustro i passaggi con entrambi i browser. Per i possessori di Mac: mi dispiace. Per gli appassionati di Edge / Microsoft Internet Explorer: mi dispiace.
Passaggio 1
Scaricare il certificato: puntare il browser all’URL
Una volta stabilita la connessione e visualizzato il sito, cliccare sul lucchetto a sinistra nella barra degli indirizzi; cliccare quindi su “Certificato”, su “Dettagli”, su “Esporta” e fare il download in una cartella che conosciamo, ad esempio Downloads. Questo per Chrome.
Nota bene: questa è un’operazione che potete fare con qualunque sito in https, potete così informarvi sull’autorità emittente, sul proprietario del sito, sull’attendibilità e la validità del certificato di chiave pubblica.
Per Firefox: cliccare sul lucchetto, quindi su “Connessione Sicura >”, su “Ulteriori informazioni”, su “Visualizza certificato”; quindi sulla tab repo.grails.org cliccare sul link “PEM (certficato) e selezionare l’opzione “Salva con nome”. Un po’ più laborioso.
Passaggio 2
Importare il certificato appena scaricato nella keystore della JVM: individuare dunque la directory della JVM, nel mio caso:
/usr/lib/java/jdk1.8.0_25/jre/lib/security
Il file dei certificati è cacerts
Lanciare l’importazione
$ sudo keytool -import -alias example
-keystore /usr/lib/java/jdk1.8.0_25/jre/lib/security/cacerts
-file /home/marcob/Downloads/repo.grails.org
Keytools richiede la password del keystore che al primo utilizzo è changeit
[sudo] password di marcob:
Immettere la password del keystore:
Proprietario: CN=repo.grails.org
Emittente: CN=Sectigo RSA Domain Validation Secure Server CA, O=Sectigo Limited, L=Salford, ST=Greater Manchester, C=GB
Numero di serie: 2560fb52bfdc8f6bb2b3366805e3c911
Valido da: Fri Nov 13 01:00:00 CET 2020 a: Wed Dec 15 00:59:59 CET 2021
Impronte digitali certificato:
SHA1: D6:24:89:09:18:F1:39:E8:D6:6F:DF:EA:88:68:5C:BD:DB:2C:DF:F3
SHA256: 65:39:9F:7D:C3:09:D5:58:ED:E3:C3:82:59:98:BA:22:E2:8F:2D:65:6D:1E:F6:C3:51:55:9B:4F:14:9C:ED:A4
Nome algoritmo firma: SHA256withRSA
Algoritmo di chiave pubblica oggetto: Chiave RSA a 2048 bit
Versione: 3
...
Considerare sicuro questo certificato? [no]: si
Il certificato è stato aggiunto al keystore
Una volta completato l’nserimento del certificato nel portachiavi si può avviare Grails dalla cartella del progetto:
$ grails create-app com.djamware.gadgethouse | Application created at /home/marcob/IdeaProjects/java/gadgethouse | Resolving Dependencies. Please wait… | Starting interactive mode… | Enter a command name to run. Use TAB for completion: grails> run-app | Running application… ... Grails application running at http://localhost:8080 in environment: development
In questo articolo parlerò dei problemi che si incontrano nel refactoring di una applicazione. Più precisamente di quanto espresso dal titolo quindi:
Come gestire l’ORM (Object Relationship Mapping) su tabelle già definite.
Devo riscrivere un’applicazione PHP in Groovy on Grails ma il database non deve essere toccato come specifica di progetto.
Le pratiche di convention over configuration di molti framweork MVC (come Groovy on Grails, Laravel o Django) permettono di creare il database semplicemente dalla definizione delle classi, senza scrivere alcuna istruzione DDL.
Tuttavia se il Cliente non vuole che si modifichi il database, abbiamo una serie di strumenti messi a disposizone dal layer di gestione della mappatura tra oggetti e tabelle adottato da Grails (Hibernate) che ci permettono di uscire dallo standard per adeguarci all’esistente.
Importante: se non si vuole sovrascrivere il database, nel file grails-app/conf/dataSource.groovy va impostato il parametro dbCreate come “update“, non come “create-drop” (mi raccomando).
Se c’è già un campo chiave primaria
Ogni tabella ha come standard la colonna ID che di solito è un number(10) (sto usando Oracle). Se nella definizione della classe aggiungiamo la proprietà id, Hibernate mapperà il campo id nella colonna ID senza protestare.
Il campo version
Hibernate aggiunge per ogni tabella anche il campo version per implementare la strategia di “optimistic locking”. Cioè si vuole gestire una storia del record per cui viene di fatto creata una chiave composita che si riferisce ad un particolare record attraverso la fornitura sia dell’id che del numero di versione. In realtà in molte applicazioni a cui ho lavorato questo tipo di meccanismo è delegato al DBMS, nel quale (soprattutto nei database Oracle che ho gestito) viene scritto un trigger che crea un “giornale” della tabella con dentro tutte le oprazioni fatte sul record: dal primo inserimento, alle succesive modifiche fino all’eventuale cancellazione fisica. Per cui, in questo contesto ho ritenuto sovrabbondante l’introduzione dell’oprimistic locking e ho optato per la sua soppressione.
Per evitare di gestire una proprietà version si deve dichiare che non la si vuole nel dictionary mapping dentro alla dichiarazione del domain (il corrispondente Grails del model nel paradiga MVC):
package myapp
class Utente
...
static mapping = {
version false
}
Il campo version non verrà aggiunto alla tabella.
Il nome della tabella non segue uno standard
I nomi delle classi domain e nelle tabelle prassi abbastanza diffusa sceglierli in inglese, al singolare; però io ho una tabella Utenti per cui faccio un compromesso:
package myapp
class Utente
...
static mapping = {
table "utenti"
version false
}
Specificando nel dictionary statico mapping il campo table posso scegliere di associare il nome della tabella del database “intoccabile”.
Relazioni uno a molti
Come esempio ho un tabella articoli che è figlia di una tabella capitoli: ad un capitolo possono essere associati più articoli. Ho di fatto una serie di articoli che appartengono ad un capitolo per cui si usa la variabile belongsTo per specifcare questa relazione:
package myapp
class Articolo {
Integer id
Float prezzo
String descrizione
Integer attivo
static belongsTo = [capitolo: Capitolo]
In questa dichiarazione, il nome a sinistra del : è il nome della relazione (capitolo in minuscolo), e il nome a destra è il nome dell’oggetto padre (Capitolo).
Il nome delle chiavi esterne non segue uno standard
O, meglio, ne segue uno di suo che non è quello di Grails. Nella tabella Articoli per esempio ho una chiave esterna per realizzare la relazione con i Capitoli: idcapitolo che si riferisce all’id della tabella Capitoli.
Seguendo il suo standard, Hibernate crea il nome <tabella>Id per dichiarare le variabili “chiave”. Sfortunamtamente all’epoca nel database hanno seguito la convenzione inversa IDCAPITOLO (con l’id prima del nome tabella).
Mai paura: si dichiara questa deviazione dallo standard nella creazione del domain:
Si faccia attenzione che per mappare il nome della colonna della tabella database ho utilizzato il nome della relazione definita in belongsTo: non capitoloId (che non è definito da nessuna parte) ma capitolo.
Una tabella ha una chiave primaria composita
Come ultimo caso c’è quello di una tabella con una doppia chiave composta dall’unione di due campi idutente e iddipartimento (dovendo gestire il fatto che un utente può lavorare anche in dipartimenti diversi). È una strategia per gestire una relazione molti-a-molti. Di suo Hibernate vorrebbe che io aggiungessi una chiave artificiale ID ma la consegna data me lo impedisce, posso dichiarare la chiave composita e sopprimere la direttiva di creazione dell’ID:
package myapp
class UtenteDipartimento implements Serializable {
Integer attivo
Date dataInizio
Date dataFine
static belongsTo = [utente: Utente, dipartimento: Dipartimento]
static mapping = {
table "utenti_dipartimenti"
dataInizio column: "data_inizio"
dataFine column: "data_fine"
// relazioni
utente column: "idutente"
dipartimento column: "iddipartimento"
id composite: ['utente', 'dipartimento']
version false
}
nel quale sorgente riassumo un po’ tutte le cose dette nell’articolo.
Attenzione: se voglio creare una chiave composita, la classe deve implementare l’interfaccia Serializable.
Oracle tips: in questo post troverete alcuni consigli utili per gestire situazioni anomale che, quindi, normamente non si dovrebbero verificare: la password di system è scaduta oppure Sql*Plus non si avvia. Aggiungo anche un suggerimento su come creare un nuovo schema e degli utenti di supporto per limitare le operazioni sul database da applicazione.
Problem 1: password di system scaduta
Il problema si presenta tipicamente quando non si accede da molto ad un database. È un’eventualità abbastanza remota se si lavora regolarmente sui sistemi. Nel mio caso avevo un vecchio DBMS Oracle di sviluppo in una macchina Windows 10 che non usavo da un po’ ed era scaduta anche la password di system.
Una semplice procedura consente di risolvere il problema. Da linea di comando si digiti
$ sqlplus system SQL*Plus: Release 11.2.0.2.0 Production on Mer Nov 25 11:57:12 2020 ... Enter password: ERROR: ORA-28001: the password has expired Changing password for system New password: Retype new password: Password changed
Stessa procedura per qualsiasi altro utente. In sostanza Oracle avvia automaticamente la procedura di cambio password nel caso sia scaduta. È chiaro che il ststema è bene non venga lasciato inattivo per troppo tempo, perché chiunque potrebbe impossessarsi del DBMS con questa procedura!
Problem 2: indisponibilità di SQL*Plus
Nel tentativo di risolvere il problema sopra, ho cozzato contro un altro problema che veniva prima in ordine di priorità, ossia non riuscivo nemmeno ad avviare SQL*Plus, il tool di amministrazione/sviluppo di Oracle da linea di comando.
SQL*Plus è uno strumento molto grezzo ma è potentissimo, consente di lanciare ogni tio di comando di amministrazione (DDL) ed elaborazione dati (SQL).
Generalmente si preferisce utilizzare tool con una GUI (Graphic User Interface) come TOAD o Oracle SQL Developer ma questo tool è davvero equivalente, se non più potente.
Nel mio caso l’errore che si verificava all’avvio del comando era il seguente:
C:\> sqlplus PSP2-0667: Message file sp1<lang>.msb not found
Il problema all’origine di questo messaggio è la non corretta valorizzazione della variabile di ambiente ORACLE_HOME, ho impostato (nel mio caso) al valore:
Ecco invece una breve lista di comandi per creare uno schema (uno schema è un utente Oracle proprietario di oggetti) e utilizzarlo per un’applicazione web (da sviluppare con qualsiasi tecnologia).
CREATE USER rewards IDENTIFIED BY smartPassw0rd;
GRANT CONNECT, RESOURCE TO rewards;
GRANT CREATE SESSION TO rewards;
CREATE USER rewards_rw IDENTIFIED BY P4ssw0rd;
Una volta creati gli oggetti, ad esempio creata una una tabella books, devo stabilire cosa l’utente può fare in questa tabella; devo concedere (GRANT) dei privilegi all’utente sulla tabella, andando dalla sua modifica, alla distruzione, alla gestione dei dati. Per questo utente mi limito alle sole operazioni CRUD:
GRANT SELECT, INSERT, UPDATE, DELETE ON rewards.books TO rewards_rw;
È buona prassi non dare i massimi privilegi sul database all’utente utilizzato dall’applicativo per connettersi a Oracle mediante il client. In genere è sufficiente un profilo abilitato alle sole operazioni CRUD, come realizzato dal comando sopra.
Si evita così la possibilità che in modo malevolo (sempre che l’applicazione lo consenta – e lo consente se non è progettata abbastanza bene da inibire comandi SQL – la cosiddetta SQL injection) un attaccante, per mezzo dell’applicazione, lanci istruzione SQL verso il server Oracle.
CRUD
Un’ultima considerazione: CRUD è l’elenco delle operazioni su database definite però in un ambito più genarale e astratto di storage. In pratica queste quattro operazioni (4 verbi) sono richieste e possibili anche in un file system, per esempio: creazione, lettura, scrittura, cancellazione di file, e non è inteso specificatamente per un DBMS. Tuttavia nel linguaggio SQL le quattro operazioni prendono dei nomi specifici:
Ho reinstallato Mysql Workbench versione Community, un tool per l’amministrazione e la gestione di database basati su DBMS MySQL/MariaDB, su Ubuntu 20.04.
Al tentativo di creare una nuova connessione mi sono ritrovato un errore mai comparso prima:
An AppArmor policy prevents this sender from sending this message to this recipient; type="method_call", sender=":1.125"
eccetera.
Il problema (spiegato qui) è che ho dovuto installare MySQL con snap anziché apt, per cui mi sono scontrato con il fatto che i pacchetti installati con snap sono sandboxed, in qualche modo isolati e non possono fare alcune richieste al sistema. Ho dovuto quindi applicare questo comando:
Cos’è una congettura? È una proposizione che si presume vera ma non si è in grado di dimostrare rigorosamente. Le congetture affascinano perché funzionano per tutti i tentativi che si fanno per verificarla, cioè per trovare una dimostrazione di ciò che dicono. E questa loro non dimostrabilità le avvolge di mistero. Facciamo un piccolo recap.
Assiomi o postulati
Sono delle affermazioni così elementari che non possono essere dedotte da affermazioni ancora più semplici. A volte non sembrano molto elementari però si decide di arrestare il processo deduttivo perché non porterebbe più da nessuna parte se non girare il discorso utilizzando dei sinonimi. Ad esempio Assioma I della geometria euclidea:
Tra due punti qualsiasi è possibile tracciare una e una sola retta.
Qui si potrebbe obiettare “cos’è la retta? cos’è un punto? Il mio professore di Analisi I, Ezio Stagnaro, ci fece questo esempio:
Potete sostituire alla parola “punto” la parola “scarpe” e alla parola “retta” la parola “uomo” e verificare se detto così l’assioma funziona. Se poi riuscite a far funzionare l’analogia per tutti gli altri assiomi, vi accorgerete che punti e rette non sono oggetti in sé ma possono essere istanziati nella realtà in qualunque modo questo consenta di non pervenire a contraddizioni.
Proposizioni e teoremi
A partire dai fatti elementari (assiomi) costruiamo affermazioni più complesse (“La somma degli angoli interni di un triangolo è congruente con un angolo piatto” per rimanere nella Geometria Euclidea) che fanno discedere un fatto complesso (tesi) ad un certo numero finito di premesse (ipotesi). Il processo deduttivo che porta dalle ipotesi alla tesi senza saltare passaggi è detto dimostrazione del teorema. Se un teorema ha una dimostrazione l’affermazione è vera all’interno del sistema assiomatico e non può essere negata.
… e le congetture?
Se non riusciamo a trovare la dimostrazione siamo in una terra di mezzo. La proposizione è verificata in un numero più o meno grande di casi, sembra tenere, ma siccome non si possono provare tutti gli infiniti casi, non possiamo essere certi che funzioni sempre. Questa sicurezza ce la può dare solo una dimostrazione rigorosa.
Gli attacchi che i matematici sferrano verso queste proposizioni “maledette” a volte hanno qualcosa di epico, perché sono in grado di resistere per secoli all’assalto di menti sopraffine.
Per citarne un’altra di celebre, oltre a quella di Collatz, basti la congettura di Riemann, secondo la quale gli zeri non banali della funzione Zeta di Riemann hanno tutti parte reale uguale a 1/2. Anche di questa non si è ancora trovata una dimostrazione, benché fosse uno dei problemi inseriti da David Hilbert nell’elenco dei 23 problemi ancora da risolvere alla fine del XIX secolo (il problema numero 8, per la precisione).
Non è nemmeno provato che queste proposizioni non si possono dimostrare, almeno ci si metterebbe l’anima in pace. La proverbiale “pietra sopra” ad esempio è stata messa in un caso famoso: dopo secoli di tentativi da parte di matematici più o meno bravi di fornire una dimostrazione, si è trovato che l’assioma 5 della geometria euclidea – l’assioma delle parallele – non si poteva dimostrare come se fosse un teorema ma che anzi si poteva anche negare, addirittura in due modi, originando due nuovi sistemi indpendenti: le due geometrie non euclidee, quella di Riemann e quella di Bolyai/Lobacevskij.
In generale è stato dimostrato da Kurt Gödel che questo assioma è un punto debole come un punto debole ce l’ha qualsiasi altro sistema assiomatico (teoremi di incompletezza). Quindi in questo Gödel ha messo una pietra sopra sul fatto che in ogni sistema assiomatico ci sia un’affermazione che non può essere né dimostrata né negata all’interno dello stesso sistema.
Infatti si costruisce un altro sistema con una negazione del V postulato che ad esempio generi la geometria iperbolica e anche all’interno di questa non è dimostrabile né confutabile. Lo stesso vale per la geometria ellittica.
Non c’è niente da fare. Però questo teorema ha fatto finalmente in modo che la questione si potesse considerare chiusa una volta per sempre.
Ma in questo caso invece, come disse Paul Erdős, matematico ungherese, a proposito della congettura di Collatz
“La matematica non è ancora pronta per risolvere problemi del genere”
Paul Erdős
La congettura
La congettura di Collatz afferma che la successione così definita:
converge sempre a 1 per n \ge N \in \mathbb{N} . Ricordo che x_n \mod 2 = 0 vuol dire che x_n è pari e x_n \mod 2 = 1 vuol dire che x_n è dispari.
Python: la libreria matplotib
Ora per divertirmi un po’ a vedere come funziona questa successione ho utilizzato Python e la libreria matplotlib che avevo già utilizzato per lo studio dell’apprendimento delle reti neurali.
È semplice installarla come libreria stand-alone per Python 3:
Dopodiché la uso in un programma che semplicemente calcola la successione e la visualizza su un grafico
!/usr/bin/python3
import matplotlib.pyplot as plt
a = input("Dimmi un numero: ")
print("Successione di Collatz a partire da a=",a)
z = int(a)
s = []
s.append(z)
while (z != 1):
print(z,", ")
if (z % 2 == 0):
z /= 2
else:
z = 3*z + 1
s.append(z)
# la congettura d Collatz afferma che si esce sempre dal ciclo
# disegna
x = range(len(s))
plt.plot(x, s, label="Successione di Collatz")
plt.xlabel('iterazioni')
plt.ylabel('successione')
plt.title('Congettura di Collatz')
plt.legend()
plt.grid(True)
plt.show()
Ci si può divertire a vedere il comportamento di questa succcessione che sembra davvero imprevedibile per numeri che non fanno parte della successsione delle potenze di 2. Ad esempio il 103 genera questo andamento
Utilizzo il mio smartphone come hotspot wireless per connettermi a Internet con i dispositivi di casa. Stamattina ho voluto controllare quale fosse la potenza del segnale Wi-Fi perché volevo trovare la posizione ottimale dell’hotspot rispetto alla mia postazione di lavoro.
Prima mi sono studiato come accedere al dato della potenza del segnale Wi-Fiin ingresso dell’antenna (dettagli qui) e poi ho riportato questo dato in funzione del tempo in un grafico animato in modo tale da poter girar per casa e posizionarlo dove ho un segnale più forte, e non è detto che sia accanto al PC 😉
Campionamento della potenza del segnale Wi-Fi
La potenza istantanea del segnale Wi-Fi si può visualizzare con il comando
$ iwconfig wlp2s0 wlp2s0 IEEE 802.11 ESSID:"HUAWEI Y6 2019" Mode:Managed Frequency:2.412 GHz Access Point: F2:E4:A2:93:8C:0C Bit Rate=72.2 Mb/s Tx-Power=22 dBm Retry short limit:7 RTS thr:off Fragment thr:off Power Management:on Link Quality=61/70 Signal level=-49 dBm Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0 Tx excessive retries:171 Invalid misc:9250 Missed beacon:0
Come si vede, la linea
Link Quality=61/70 Signal level=-49 dBm
contiene l’informazione desiderata. Se spegniamo l’hotspot l’output del comando è invece:
$ iwconfig wlp2s0 wlp2s0 IEEE 802.11 ESSID:off/any Mode:Managed Access Point: Not-Associated Tx-Power=22 dBm Retry short limit:7 RTS thr:off Fragment thr:off Power Management:on
Quindi un modo se volete un po’ grezzo di accedere velocemente alla potenza del segnale Wi-Fi è fare il parsing dell’output di questo comando. L’idea è di lanciarlo con regolarità in modo da costruire un campione di dati da visualizzare in qualche modo in tempo reale.
Il primo programma che ho scritto è questo:
#!/usr/bin/python3
#
# Found in: https://www.calazan.com/how-to-continuously-monitor-your-wi-fis-signal-strength-in-ubuntu/
# Mutatis mutandi
#
import subprocess
import time
import argparse
parser = argparse.ArgumentParser(description='Display WLAN signal strength.')
parser.add_argument(dest='interface', nargs='?', default='wlan0',
help='wlan interface (default: wlan0)')
args = parser.parse_args()
print('\n---Press CTRL+Z or CTRL+C to exit---\n')
while True:
cmd = subprocess.Popen('iwconfig %s' % args.interface, shell=True,
stdout=subprocess.PIPE)
for line in cmd.stdout:
l = str(line)
if 'Link Quality' in l:
print (l),
elif 'Not-Associated' in l:
print ('No signal')
time.sleep(1)
Aspetti importanti di questo script sono il package subprocess che consente a Python di lanciare un comando del sistema operativo, in questo caso
iwconfig wlp2s0
Il package argparser fornisce una serie di utilissime funzioni per maneggiare le linee di comando (definire i parametri di avvio, la loro obbligatorietà, i valori di default e finanche la documentazione di help).
Il package itertools fornisce il metodo count() che realizza un contatore progressivo che ci serve per etichettare i campioni di segnale, campioni che vengono prelevati con regolarità utilizzando le funzione del package time..
In sostanza il metodo subprocess.Popen() lancia il comando e il dato desiderato si trova nell’output del comando che comunque non è una stringa e va convertito per potere fare il parsing. Il parsing si utilizza quando il dato è annegato nella sporcizia, per cui ritengo questo mio metodo un metodo piuttosto sporco.
In questo embrione di programma ho il seguente ouput
—Press CTRL+Z or CTRL+C to stop.—
b' Link Quality=70/70 Signal level=-31 dBm \n' b' Link Quality=70/70 Signal level=-31 dBm \n' b' Link Quality=70/70 Signal level=-36 dBm \n' b' Link Quality=70/70 Signal level=-32 dBm \n' b' Link Quality=70/70 Signal level=-32 dBm \n'
Il dato interessante si trova in ogni riga dalla posizione 45 alla posizione 48.
Con una piccola modifica ci facciamo stampare solo il dato desiderato
–--Press CTRL+Z or CTRL+C to stop.--- -32 -32 -35 -31 -31 -35 -35 -35 -36
Visualizzazione del segnale Wi-Fi utilizzando matplotlib
Ora invece di stampare questi valori, li voglio disporre su un grafico. Utilizzo la libreria matplotlib. Il sorgente completo è il seguente
#!/usr/bin/python3
#
# Adopted for reading wifi power signal and plotting it
#
# @author: marco@betaingegneria.it
# @copyright: GPL Affero v.3
# @date 2020-09-25
import subprocess
import argparse
import matplotlib.pyplot as plt
from itertools import count
from matplotlib.animation import FuncAnimation
# init graphics stuff
plt.style.use('seaborn')
x=[] # time series
y=[] # power samples
index = count()
# init wlan signal reader
# parse line command arguments
parser = argparse.ArgumentParser(description='Display WLAN signal strength.')
# interface
parser.add_argument(dest='interface', nargs='?', default='wlp2s0',
help='wireless.py [interface=wlp2s0] [delta=800]')
# sampling period in ms
parser.add_argument(dest='delta', nargs='?', default='800',
help='wireless.py [interface=wlp2s0] [delta=800]')
args = parser.parse_args()
if (int(args.delta) < 200):
print('Please, choose a value >= 200 for delta')
exit()
print('Close the window to exit')
def animate(i):
""" read the wifi power in dBm and plot """
x.append(next(index))
cmd = subprocess.Popen('iwconfig %s' % args.interface, shell=True,
stdout=subprocess.PIPE)
for line in cmd.stdout:
l = str(line)
if 'Link Quality' in l:
y.append(int(l[45:48]))
elif 'Not-Associated' in l:
y.append(None)
plt.cla()
plt.plot(x, y, '-', marker='.', label='WiFi signal strenght in dBm')
plt.legend(loc='upper left')
plt.tight_layout()
# ring a bell every sample
#print('\a')
ani = FuncAnimation(plt.gcf(), animate, interval=args.delta)
plt.show()
Un po’ di parafrasi: la funzione animate() contiene il codice che legge la potenza e, eseguendo il parsing estraiamo il valore in dBm da accodare alla lista y, mentre nella lista x accodiamo i valori del contatore.
Il plot viene fatto utilizzando come skin lo stile seaborn, che comprende la griglia in negativo (bianco su grigio).
Infine ho utilizzato il metodo matplotlib.animation() che può essere configurato per un aggiornamento ogni delta millisecondi – ci sganciamo quindi dalla libreria time – , variabile che gestiamo come parametro di input.
Il risultato è questo
Andamento della potenza segnale Wi-Fi provando a spostare l’hotspot in giro per la stanza
Se si spegne l’hotspot o si esce dal suo range di segnale non verrà plottato alcun dato.
Qualche tempo fa ho acquistato al CERN di Ginevra questa T-shirt che di tanto in tanto indosso:
La lagrangiana del Modello Standard
La formula scritta sulla maglietta è la lagrangiana del modello standard.
Invariabilmente, ogni volta che la indosso, mi chiedono: cos’è una lagrangiana? Oppure cosa vuol dire Modello Standard?
La cosa mi fa piacere perché ragionare di Fisica mi piace sempre un sacco.
La lagrangiana nella Meccanica Classica
Una breve introduzione alla lagrangiana nella Meccanica Classica la trovate qui. Meglio che la leggiate, vi serve per capire un po’ meglio quello che segue.
In sostanza è una funzione di posizione e velocità di un sistema meccanico classico che ci aiuta a scrivere le equazioni del moto.
La lagrangiana in Meccanica Quantistica
La lagrangiana della maglietta è un formalismo che si usa in teoria dei campi ed è l’estensione a questa disciplina del concetto che Lagrange elaborò per risolvere problemi di Meccanica Classica (lui non la chiamava così, siamo noi che abbiamo dovuto attaccare l’aggettivo “classica” per distinguerla dalla Meccanica Relativisitica o dalla Meccanica Quantistica) in sistemi con un numero finito di variabili – o gradi di libertà . Essa dal punto di vista matematico è un oggetto completamente diverso da quello della Meccanica Classica, è una funzione di densità: in questo caso la lagrangiana si applica ai continui e ai campi, che hanno un numero infinito di gradi di libertà.
A grandi linee ogni riga della maglietta è un pezzo della teoria del Modello Standard, il modello che spiega tre delle 4 forze fondamentali dell’Universo:
la forza elettromagnetica – che ti fa tenere il cane per il guinzaglio,
la forza forte, che tiene insieme i nuclei degli atomi,
la forza debole, che permette alle particelle di trasformarsi,
La forza gravitazionale, che ci tiene attacati per terra e move il Sole e l’altre stelle (cit.), finora è la grande esclusa dal Modello Standard.
La lagrangiana prevede 6 termini.
Primo termine -\frac{1}{4}F_{\mu\nu}F^{\mu\nu}
Questo termine è il prodotto scalare del tensore dell’intensità di campo F_{\mu\nu} contenente la codifica matematica di tutte le particelle di interazione – eccetto il bosone di Higgs -, dove \mu e \nu sono indici di Lorentz che rappresentano le componenti dello spaziotempo (t, x, y, z). Contiene la formulazione necessaria affinché queste particelle esistano e descrive come interagiscono tra loro. I contenuti differiscono a seconda delle proprietà delle particelle di interazione. Ad esempio, i fotoni, le particelle di interazione dell’interazione elettromagnetica, non possono interagire tra loro, perché non hanno carica elettrica. Pertanto, il contributo dell’interazione elettromagnetica consiste solo in un termine cinetico, che è la base dell’esistenza di fotoni liberi. La descrizione dei gluoni e dei bosoni dell’interazione debole comprende invece anche i termini di interazione oltre ai termini cinetici. I gluoni, ad esempio, sono essi stessi carichi di “colore” e possono quindi anche interagire tra loro.
Questo porta a una conseguenza entusiasmante: il Modello Standard della fisica delle particelle prevede l’esistenza di stati legati costituiti solo da gluoni, le cosiddette ‘glueballs‘ (letteralmente: palle di colla). Tuttavia, finora nessun esperimento ha rilevato le glueballs.
Il termine i\bar{\psi} D\!\!\!\!/\psi
Questo termine descrive invece come le particelle di interazione interagiscono con le particelle di materia. I campi \bar{\psi} e \psi descrivono (anti)quark e (anti)leptoni. Questo termine ad esempio regola l’annichilazione elettrone-positrone e il decadimento beta.
Il termine h.c.
h.c. sta per hermitian conjugate, coniugato hermitiano: un operatore o una matrice è hermitiana quando il suo prodotto con la controparte complessa coniugata è una quantità reale.
Siccome quando facciamo misure vediamo numeri reali, è necessario che tutte le quantità complesse abbiano il corrispettivo coniugato in modo tale che il prodotto sia un numero reale. Questo è un assioma della Meccanica Quantistica e da’ conto del fatto che le misurazioni sono sempre numeri reali. Il termine h.c. va eventualmente aggiunto al secondo termine (interazione bosone – particella) qualora questo dia un numero complesso. In realtà il secondo termine è sempre un numero reale (più precisamente è un operatore autoaggiunto). Lo chiamano anche hot coffee (caffè che scotta).
Piccolo dizionario: i bosoni (particelle che seguono la statistica di Bose-Einstein)sono le particelle mediatrici della forza (la più famosa è il fotone, che veicola l’interazione elettromagnetica). I fermioni (particelle che seguono la statistica di Fermi-Dirac) sono le particelle di materia ordinaria (protoni ed elettroni per esempio).
Il termine \psi_i y_{ij}\psi_j\phi
Il quarto termine descrive l’accoppiamento di una particella di materia con il campo di Higgs\phi per acquisire massa. y_{ij} è detto campo di Yukawa, vedi bibliografia.
Il termine |D_\mu\phi|^2
Il quinto termine descrive l’accoppiamento di una particella di interazione con il campo di Higgs.
Tuttavia le uniche particelle di interazione (dette anche bosoni) che hanno massa sono i bosoni dell’interazione debole – previste teoricamente da Abdus Salam e scoperte da Carlo Rubbia, per cui questo termine descrive proprio loro (W^{\pm}, Z_0).
Il termine -V(\phi)
L’ultimo termine descrive il potenziale del campo di Higgs (detto più precisamente campo di Brout–Englert–Higgs).
Nella maggior parte delle cose che ci accadono quotidianamente, l’unico termine ad entrare in azione è il secondo. I fotoni non ottengono massa dal meccanismo di Higgs, mentre i gluoni sono privi di massa perché non si accoppiano al campo di Brout-Englert-Higgs.
Come vedete in questa lagrangiana non si parla di gravità. includere la gravità nella teoria di campo quantistica è una delle sfide che stanno impegnando i fisici e i matematici da mezzo secolo e ancora non si vede la luce in fondo al tunnel.
Inoltre il modello standard descrive perfettamente la materia, ma ciò che vediamo è solo il 5% della materia totale, per cui il resto cos’è e come funziona?
Per chi volesse approfondire, in bibliografia c’è un bell’articolo, senza addentrarsi troppo nei dettagli.
Fatemi siete arrivati fin qui se vi è piaciuto l’articolo.
Ringrazio Corrado Tagliente per avermi spronato a migliorare l’articolo.
e così via, cioè anziche venire aggiunto l’ultimo elemento (anche lui una lista) alla lista, venivano sostituiti tutti gli elementi della lista con l’ultima lista calcolata.
Il problema è che stavo copiando ogni volta il riferimento alla variabile w (che è lo stesso ad ogni ciclo) e non il contenuto della variabile stessa (che cambia ad ogni ciclo):
[<riferimento a w>, <riferimento a w>, …]
Per disinnescare l’errore ho fatto così:
for i in range(1,5):
w=P.learn()
print(type(w))
hist_w.append(w[:])
print("hist_w", hist_w)
.gitignore o .git/info/exclude? Vediamo le differenze e il perché a volte Git sembra ignorare le nostre direttive sull’esclusione di alcuni file dal ciclo di vita del software.
Differenza tra .gitignore e .git/info/exclude
Entrambi i file servono a Git per stabilire quali file non entrano nel ciclo di versionamento.
Essi agiscono ad un diverso livello.
Il file .git/info/exclude serve per escludere i file nel proprio clone locale; se qualcuno che collabora con noi non ha escluso gli stessi file che abbiamo escluso noi, potremmo ritrovarci – se facciamo un clone o un fetch – file che sono entrati nel versionamento nell’origin ma che io non ho perché esclusi, o viceversa. Quindi è bene, quando si devono escludere dei file globalmente (per tutti i programmatori) agire sul file .gitignore che invece viene versionato – per cui ogni repository locale se lo trova. Se dobbiamo agire in modo più granulare sui file da versionare (o meno) directory per directory, è possibile scrivere un apposito file .gitgnore in ogni directory in cui serve.
Git sembra ignorare la direttiva di ignorare file
Ho messo dei file da escludere nel file .git/info/exclude (o in .gitignore) ma continuo a vederli come new file quando eseguo il comando git status:
$ git status
Sul branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: app/Http/Controllers/BaseController.php
new file: storage/logs/laravel-2020-07-22.log
new file: storage/logs/laravel-2020-07-23.log
...
In particolare non voglio che i file di log entrino nel versionamento. Ho però inserito correttamente la riga
storage/logs*
in entrambi i file .gitignore e .git/info/exclude. Come mai Git continua a mostrarmeli come file da versionare?
Git utilizza il file .gitignore nel momento in cui aggiunge i file; una volta aggiunti all’indice dei file da versionare Git continua a considerarli tali, a dipetto di modifiche successive dei file di gitignore. Quindi ci sono due modi per uscire dall’impasse:
cancellare fisicamente i file, ma è l’opzione più stupida git rm storage/logs/*
cancellare la cache: git rm --cached storage/logs/*
Infatti l’opzione --cached indica a Git di togliere i file dall’indice ma non dal file system.
Ho trovato queste indicazioni in un paio di risposte di fourm 1 e 2.
Utilizziamo tecnologie come i cookie per memorizzare e/o accedere alle informazioni del dispositivo. Lo facciamo per migliorare l'esperienza di navigazione e per mostrare annunci personalizzati. Il consenso a queste tecnologie ci consentirà di elaborare dati quali il comportamento di navigazione o gli ID univoci su questo sito. Il mancato consenso o la revoca del consenso possono influire negativamente su alcune caratteristiche e funzioni.
Funzionale
Sempre attivo
L'archiviazione tecnica o l'accesso sono strettamente necessari al fine legittimo di consentire l'uso di un servizio specifico esplicitamente richiesto dall'abbonato o dall'utente, o al solo scopo di effettuare la trasmissione di una comunicazione su una rete di comunicazione elettronica.
Preferenze
L'archiviazione tecnica o l'accesso sono necessari per lo scopo legittimo di memorizzare le preferenze che non sono richieste dall'abbonato o dall'utente.
Statistiche
L'archiviazione tecnica o l'accesso che viene utilizzato esclusivamente per scopi statistici.L'archiviazione tecnica o l'accesso che viene utilizzato esclusivamente per scopi statistici anonimi. Senza un mandato di comparizione, una conformità volontaria da parte del vostro Fornitore di Servizi Internet, o ulteriori registrazioni da parte di terzi, le informazioni memorizzate o recuperate per questo scopo da sole non possono di solito essere utilizzate per l'identificazione.
Marketing
L'archiviazione tecnica o l'accesso sono necessari per creare profili di utenti per inviare pubblicità, o per tracciare l'utente su un sito web o su diversi siti web per scopi di marketing simili.
Commenti recenti