lunedì 28 febbraio 2022

Chrome Os Flex

 Ho provato ChromeOs Flex... diciamo una mezza delusione (pur sapendo che si tratta di una Unstable)


Si tratta sostanzialmente di CloudReady rimarchiato (in molti punti e' presente ancora la scritta CloudReady)

Per avviare il container Linux ho dovuto attivare tutti i flag Crostini in http://flags ed in ogni caso il sottosistema Linux e' molto lento, sono riuscito ad avviare solo le Linux Apps e non un Window Manager

ChromeOS puro funziona ma si vede nettamente che non avendo un hardware ottimizzato come sui ChromeBooks non e' un prestante

L'idea di poter continuare hardware obsoleto con ChromeOs Flex al momento attuale non e' ottimale..tanto vale usare una distro Linux con poche pretese hardware 


Misteri

Un collega mi telefona dicendomi che il suo HD esterno non funziona piu' sottolineando che sente dei rumori (...ma i rumori non vengono dalle casse del PC😀). Gli dico che puo' essere la testina del HD che sbatte a fine corsa 

Non proprio convinto il mio collega apre il case dell'HD e mi manda un video (screenshot nella foto superiore)...la testina effettivamente sbatte a fine corsa ma mi sembra che manchi qualcosa...tipo la testina dell'HD...gli chiedo se quando ha aperto il case e' caduto fuori qualcosa ma si dice sicuro che non c'era niente di rotto

Gli chiedo il modello e gli mando una foto di archivio da Google Photo in cui ovviamente si vede la testina superiore presente



  Il mistero della sparizione della testina dell'HD 





venerdì 25 febbraio 2022

Quadtree in Go

metto questo abbozzo di codice perche', nonostante non funzionante, puo' essere interessante

Ai tempi di Fractint su Dos c'e un algoritmo che divideva il piano di quadrati, se i punti estremi del quadrato avevano lo stesso valore allora tutto il quadrato assumeva lo stesso colore dell'insieme di Mandelbrot, in caso contrario il quadrato veniva a sua volta diviso in 4 quadrati e si reiterava

In questo caso ho cercato di fare lo stesso usando le goroutine  ed la ricorsione


package main

import (
    "fmt"
    "math"
    "math/cmplx"
    "reflect"
    "strconv"
    "sync"

    "github.com/fogleman/gg"
)

var wg sync.WaitGroup

// ATTENZION    E il nome delle variabili deve essere in uppercase
// per poter esportare la variabile e
type punto struct {
    Min_x float64
    Max_x float64
    Min_y float64
    Max_y float64
    Itera int64
}

var punti []punto // slice di struct
var transi punto
var mu sync.Mutex

func calcola(a float64, b float64) int {
    var k int
    c := complex(a, b)
    k = 0

    x := complex(0.0, 0.0)
    for k = 0; k < 25; k++ {
        x_a := (x * x)
        x_a = x_a + c
        x = x_a
        if cmplx.Abs(x) > 2 {
            return k
        }
    }
    return k
}

func dividi(min_x float64, max_x float64, min_y float64, max_y float64) {
    defer wg.Done()

    x1 := calcola(min_x, min_y)
    x2 := calcola(max_x, max_y)

    if (x1 != x2) && (max_x-min_x > 0.005) {

        mezzo_x := (max_x - min_x) / 2
        mezzo_y := (max_y - min_y) / 2
        wg.Add(4)
        go dividi(min_x, min_x+mezzo_x, min_y, min_y+mezzo_y)
        go dividi(min_x+mezzo_x, max_x, min_y, min_y+mezzo_y)
        go dividi(min_x, min_x+mezzo_x, min_y+mezzo_y, max_y)
        go dividi(min_x+mezzo_x, max_x, min_y+mezzo_y, max_y)

    } else {
        fmt.Println(strconv.FormatFloat(min_x, 'f', 6, 32) + ";" + strconv.FormatFloat(min_y, 'f', 6, 32) + ";" + strconv.Itoa(x1))

        s := reflect.ValueOf(&transi).Elem()
        s.Field(0).SetFloat(min_x)
        s.Field(1).SetFloat(max_x)
        s.Field(2).SetFloat(min_y)
        s.Field(3).SetFloat(max_y)
        s.Field(4).SetInt(int64(x1))

        mu.Lock()
        punti = append(punti, transi)
        mu.Unlock()
    }

}

func grafica() {
    dc := gg.NewContext(400, 400)

    dx := 3.0 / 400
    dy := 2.0 / 400

    for _, value := range punti {
        fmt.Printf("%d\n", value)
        min_x := math.Round(value.Min_x*dx) + 200
        max_x := math.Round(value.Max_x*dx) + 200
        min_y := math.Round((value.Min_y * dy)) + 200
        max_y := math.Round((value.Max_y * dy)) + 200
        dc.DrawRectangle(min_x, max_x, min_y, max_y)
        dc.SetRGB255(value.Itera, 0, 0)
        dc.Fill()

    }

    dc.SavePNG("mandelbrot.png")
}

func main() {
    wg.Add(1)
    go dividi(-2.0, 1.0, -1.0, 1.0)
    wg.Wait()
    grafica()
}

Grafica base in Go

 package main


import "github.com/fogleman/gg"

func main() {
    dc := gg.NewContext(1000, 1000)
    //dc.Push()
    dc.DrawCircle(500, 500, 400)
    dc.SetRGB255(0, 0, 0)
    dc.Fill()
   
    dc.SetHexColor("#008080")
    dc.DrawRectangle(10,10,40,30)
    dc.SetRGB255(255, 0, 0)

    dc.Fill()
   
    dc.SavePNG("out.png")
}

martedì 22 febbraio 2022

Webassembly Golang Mandelbrot

Era da tempo che volevo provare WebAssembly (abbreviato wasm).. ho scoperto che sia GoLang che Qt permettono di compilare in Wasm e cosi' ho fatto una prova

Per eseguire applicazioni WAsm si deve configurare il webserver a riconoscere il Mime Type wasm . In Apache e' sufficiente aggiungere la linea in /etc/mime.types mentre in NGinx /etc/nginx/mime.types con application/wasm  wasm;

Il file compilato deve avere l'estensione .wasm

Per compilare il file go.wasm si usa la linea di comando

GOOS=js GOARCH=wasm go build -o wasm.wasm

ATTENZIONE: i file wasm rimangono in cache del browser. In fase di sviluppo e' quindi necessario sincerarsi di pulire la cache con CTRL+SHIFT+R (od usare una sessione anonima)

Per creare il file wasm_exec.js e' sufficiente (attenzione al punto finale)

cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

Il programma genera una immagine dell'insieme di Mandelbrot che viene codificata in PNG e successivamente in Base64 per divenire la src del tag img della pagina web

https://github.com/c1p81/gowasm_mand


wasm.go

package main

// cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

import (
"bytes"
"encoding/base64"
"fmt"
"image"
"image/color"
"image/png"
"io/ioutil"
"syscall/js"
)

func funzione() js.Func {
jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {

//////////////////////////////////////////////////////////////////////////////
var SCREEN_WIDTH int = 400
var SCREEN_HEIGHT int = 400

var re_min float32 = -2.0
var im_min float32 = -1.2
var re_max float32 = 1.0
var im_max float32 = 1.2

var iterazioni int = 1024

var a, b float32
var x, y, x_new, y_new, somma float32
var k, i, j int

var re_factor float32 = (re_max - re_min)
var im_factor float32 = (im_max - im_min)

m := image.NewRGBA(image.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))

for i = 0; i < SCREEN_HEIGHT; i++ {
for j = 0; j < SCREEN_WIDTH; j++ {
a = re_min + (float32(j) * re_factor / float32(SCREEN_WIDTH))
b = im_min + (float32(i) * im_factor / float32(SCREEN_HEIGHT))
x = 0
y = 0

for k = 0; k < iterazioni; k++ {
x_new = (float32(x) * float32(x)) - (float32(y) * float32(y)) + float32(a)
y_new = (float32(2) * float32(x) * float32(y)) + float32(b)
somma = (x_new * x_new) + (y_new * y_new)
if somma > 4 {
if k%2 == 0 {
m.Set(j, i, color.RGBA{0, 0, 0, 255})
} else {
m.Set(j, i, color.RGBA{255, 255, 255, 255})
}
break
}
x = x_new
y = y_new
}
}
}

buf := new(bytes.Buffer)
if err := png.Encode(buf, m); err != nil {
return ("unable to encode png")
}
readBuf, _ := ioutil.ReadAll(buf)

enc := base64.StdEncoding.EncodeToString([]byte(readBuf))

return "data:image/png;base64," + enc
})
return jsonFunc
}

func main() {
fmt.Println("Inizio")
js.Global().Set("go_function", funzione())
fmt.Println(funzione())
<-make(chan bool)
}

 

Index.html

<html>
<head>
<meta charset="utf-8"/>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("wasm.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
</script>
</head>
<body>
<center> 2
<img id="immagine" name="immagine" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4
//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" /><br><br>
<input id="button" type="submit" name="button" onclick="ff()"/> <br>
<textarea id="imgbase64" name="imgbase64" cols="80" rows="200"></textarea>

</center>



<script>
var ff = function() {
immagine.src = go_function(ff)
imgbase64.value = go_function(ff)
}
</script>
</body>
</html>




venerdì 11 febbraio 2022

Ser2Net Go

 Premesso che questo non e' il sistema corretto di usare una goroutine in quanto non termina mai ho provato a fare questo programma che in una goroutine legge i valori da una porta seriale e tramite un channel manda i dati ad un'altra goroutine che invia sulla rete

non e' un codice da copiare

package main
import (
    "bufio"
    "fmt"
    "io"
    "log"
    "net"
    "time"

    "github.com/tarm/serial"
)

/*
per fare i test si puo' creare una porta seriale virtuale con
socat -d -d pty,raw,echo=0 pty,raw,echo=0
il sistema risponde con messaggi del tipo
socat -d -d pty,raw,echo=0 pty,raw,echo=0

2022/01/02 14:53:04 socat[18636] N PTY is /dev/pts/3
2022/01/02 14:53:04 socat[18636] N PTY is /dev/pts/4
2022/01/02 14:53:04 socat[18636] N starting data transfer loop with FDs [5,5] and [7,7]

si apre un altro terminale e si inviano i messaggi sulla seconda porta
echo "messaggio" > /dev/pts/4
il programma in Go deve andare in ascolto sull /dev/pts/3
*/

func main() {
    canale := make(chan []byte, 1024)

    usbRead := &serial.Config{Name: "/dev/pts/3", Baud: 9600}
    //s, err := serial.OpenPort(c)
    port, err := serial.OpenPort(usbRead)
    if err != nil {
        log.Fatal(err)
    }
    scanner := bufio.NewScanner(port)
    go scrivi_channel(canale, scanner)

    listener, err := net.Listen("tcp", "localhost:8000")
    if err != nil {
        log.Fatal(err)
    }
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err) // e.g., connection aborted
            continue
        }
        handleConn(conn, canale) // handle one connection at a time
    }
}

func handleConn(c net.Conn, canale chan []byte) {
    defer c.Close()
    for {
        _, err := io.WriteString(c, string(<-canale)+" "+time.Now().Format("15:04:05\n"))
        if err != nil {
            return // e.g., client disconnected
        }
        time.Sleep(1 * time.Second)
    }
}

func scrivi_channel(canale chan []byte, scanner *bufio.Scanner) {
    buf := make([]byte, 128)
    scanner.Buffer(buf, 128)
    for {

        //scanner.Buffer(buf, 128)
        scanner.Scan()
        input := scanner.Text()
        fmt.Println(input)
        canale <- []byte(input)
        time.Sleep(1 * time.Second)
    }

    //time.Sleep(1 * time.Second)
    //canale <- []byte("test")
}

Rest Client in Python

Dopo la versione in Go la medesima funzione in Python 


import requests
from requests.structures import CaseInsensitiveDict
import json

url = "http://xxxxxxxxxxxxx/api/v1/authentication/"

headers = CaseInsensitiveDict()


headers["api-key"] = "apikey"
headers["Accept"] = "application/json"
headers["api-version"] = "v1"
headers["device-language"] = "it"
headers["id-user-session"] = "guest"
headers["Authorization"] = "Basic Z2xxxxxxxxxxxxxxxxxxxxxxxxxxx=="



resp = requests.get(url, headers=headers)

print(resp.content)
if(resp.ok):
    jData = json.loads(resp.content)

    print("The response contains {0} properties".format(len(jData)))
    print("\n")
    for key in jData:
        print(str(key) + " : " + str(jData[key]))
else:
    resp.raise_for_status()

TicTacToe Go

 Volevo provare a creare una macchina di apprendimento per il gioco TicTacToe (Tris) 

Il passo e' stato quello di creare il gioco per umani...la cosa che mi ha dato piu' soddisfazione e' stata la funzione per determinare la condizione di vittoria dei giocatori

In pratica ogni casella del gioco e' associata ad una potenza di 2...si sommano i valori delle caselle e si fa un AND con la maschera di bit delle condizioni di vittoria

il prossimo passo e' salvare le varie partite con una Trie 

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

Il nome delle caselle e' cosi' ordinato

0 | 1 | 2
______
3 | 4 | 5
______
6 | 7 | 8



package main

import (
    "fmt"
    "math"
    "os"
    "strconv"
)

var display [9]int // array per mostrare il gioco
var step int       // numero di mossa
var giocatore int
var mossa_valida bool

func reset() {
    for k := 0; k < 9; k++ {
        display[k] = 0
    }
    step = 1
    giocatore = 3
    mossa_valida = false
}

func controlla_vittoria() int {
    totale_1 := 0
    totale_2 := 0

    // per il calcolo della scacchiera ad ogni casella corrispondente un valore di potenza di 2
    // si sommano tutti le caselle occupate da un giocatore
    // poi si effettua un AND logic con le 8 posizioni vincenti

    // giocatore 1
    for k := 0; k < 9; k++ {
        if display[k] == 3 {
            totale_1 = totale_1 + int(math.Pow(float64(2), float64(k)))
        }
    }

    if (totale_1 & 448) == 448 {
        return 1
    }
    if (totale_1 & 56) == 56 {
        return 1
    }
    if (totale_1 & 7) == 7 {
        return 1
    }
    if (totale_1 & 292) == 292 {
        return 1
    }
    if (totale_1 & 146) == 146 {
        return 1
    }
    if (totale_1 & 73) == 73 {
        return 1
    }
    if (totale_1 & 273) == 273 {
        return 1
    }
    if (totale_1 & 84) == 84 {
        return 1
    }

    // giocatore 2
    for k := 0; k < 9; k++ {
        if display[k] == 2 {
            totale_2 = totale_2 + int(math.Pow(float64(2), float64(k)))
        }
    }

    if (totale_2 & 448) == 448 {
        return 2
    }
    if (totale_2 & 56) == 56 {
        return 2
    }
    if (totale_2 & 7) == 7 {
        return 2
    }
    if (totale_2 & 292) == 292 {
        return 2
    }
    if (totale_2 & 146) == 146 {
        return 2
    }
    if (totale_2 & 73) == 73 {
        return 2
    }
    if (totale_2 & 273) == 273 {
        return 2
    }
    if (totale_2 & 84) == 84 {
        return 2
    }

    return 0 // se ritorna 0 nessuno ha vinto
}

func casella(c int) string {
    switch c {
    case 0:
        return (" ")
    case 3:
        return ("X")
    case 2:
        return ("O")
    }
    return " "
}

func mostra_gioco() {
    fmt.Print(casella(display[0]))
    fmt.Print("|")
    fmt.Print(casella(display[1]))
    fmt.Print("|")
    fmt.Println(casella(display[2]))
    fmt.Println("-----")
    fmt.Print(casella(display[3]))
    fmt.Print("|")
    fmt.Print(casella(display[4]))
    fmt.Print("|")
    fmt.Println(casella(display[5]))
    fmt.Println("-----")
    fmt.Print(casella(display[6]))
    fmt.Print("|")
    fmt.Print(casella(display[7]))
    fmt.Print("|")
    fmt.Println(casella(display[8]))
}

func main() {

    var tasto int

    step = 1
    giocatore = 3
    mossa_valida = false
    mostra_gioco()
    fmt.Println("Turno al Giocatore " + strconv.Itoa(giocatore-2))

    for {
        for { // controlla se e' una mossa valida

            if !mossa_valida {
                fmt.Print("Enter move: ")
                fmt.Scanln(&tasto)
                // controlla se e' un tasto valido

                if display[tasto] == 0 { // controlla se la casella e' valida
                    mossa_valida = true
                    display[tasto] = giocatore
                    giocatore = ((giocatore + 1) % 2) + 2
                    fmt.Println("Turno al Giocatore " + string(giocatore+2))
                    break
                } else {
                    fmt.Println("Mossa non valida")
                }

            }
        }

        step++ // aumenta il numero della mossa
        mossa_valida = false
        mostra_gioco()
        v := controlla_vittoria()
        switch v {
        case 1:
            fmt.Println("****************************")
            fmt.Println("*** Vittoria Giocatore 1 ***")
            fmt.Println("****************************")
            reset()
            mostra_gioco()
            break
        case 2:
            fmt.Println("****************************")
            fmt.Println("*** Vittoria Giocatore 2 ***")
            fmt.Println("****************************")
            reset()
            mostra_gioco()
            break
        }
        if step == 9 {
            fmt.Println("***************************")
            fmt.Println("******** Pareggio *********")
            fmt.Println("***************************")
            reset()
            mostra_gioco()
            break
        }
    }
    os.Exit(0)
}

Rest client in GO

Un semplice di client di servizio Restful con GO


package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    client := http.Client{}
    req, err := http.NewRequest("GET", "http://xxxxxxxxxxxxxxxxx/api/v1/authentication/", nil)
    if err != nil {
        //Handle Error
    }

    req.Header = http.Header{
        "Host":                  []string{"http://xxxxxxxxxxxxxxxxxx/api/v1/authentication/"},
        "api-key":         []string{"axxxxxxxxxxxx"},
        "api-version":     []string{"v1"},
        "device-language": []string{"it"},
        "id-user-session": []string{"guest"},
        "Accept":                []string{"application/json"},
        "Authorization":         []string{"Basic Z2lvxxxxxxxxxxxxxxsaQ=="},
    }

    res, err := client.Do(req)

    if err != nil {
        fmt.Errorf("got error")
    } else {
        //fmt.Println("--------------------------")
        //fmt.Println(res)
    }
    defer res.Body.Close()

    b, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatalln(err)
    }

    fmt.Println(string(b))
}

JSon in Go

 Leggere Json in Go non e' esattamente banale perche' il linguaggio e' fortemente tipizzato

Se il tracciato record del Json e' fissato e' conosciuto si puo' fare un Unmarshal del tracciato altrimenti con Json dinamici o non conosciuti la situazione diventa piu' complessa

Partiamo da un Json complesso

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

 {
        "statusCode":200,
        "message":"OK",
        "dataValue":
            {
                "versionWS":"v1",
                "language":"it",
                "idUserSession":
                "wguest",
                "user":
                    {
                        "userId":27,
                        "userName":"G",
                        "userSurname":"G",
                        "idUserSession":"c4cefc3032e3f8e63f3ee320b81cf1d5"
                    }
            }
    }

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

per fare l'Unmarshal del Json si deve definire tramite Struct il tracciato record con indicato anche il tipo di variabile associata ad ogni campo...in questo campo essendoci piu' livelli si devono creare delle Struct intermedie per i livelli piu' interni. Da notare che le variabilenelle Struct hanno la prima lettera maiuscola per l'esportazione ed il tag Json corrispondente

Interessa arriva a leggere la proprieta' idUserSession dell'utente (si tratta di gestire una authorization da un servizio Restful)

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

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    UserId        int32  `json:"userId"`
    UserName      string `json:"userName"`
    UserSurname   string `json:"userSurname"`
    IdUserSession string `json:"idUserSession"`
}

type dataValue struct {
    VersionWS            string `json:"versionWS"`
    Language             string `json:"it"`
    IdUserSession        string `json:"idUserSession"`
    Wguest string `json:"wguest"`
    User                 User   `json:"user"`
}

type messaggio struct {
    StatusCode int32     `json:"statusCode"`
    Message    string    `json:"message"`
    DataValue  dataValue `json:"dataValue"`
}

func main() {
    b := []byte(`    {
        "statusCode":200,
        "message":"OK",
        "dataValue":
            {
                "versionWS":"v1",
                "language":"it",
                "idUserSession":"",
                "guest":"",
                "user":
                    {
                        "userId":27,
                        "userName":"G",
                        "userSurname":"G",
                        "idUserSession":"c"
                    }
            }
    }`)
    var mes messaggio
    json.Unmarshal(b, &mes)
    fmt.Println(mes.DataValue.User.IdUserSession)

}

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

fino a qui e' abbastanza lineare. Senza il tracciato record non si puo' fare Unmarshal di una Struct ma si deve passare attraverso una interface e gestire i vari livelli di map fino a trovare il valore richiesto


---------------------------------------------------------------------------
package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    b := []byte(`    {
        "statusCode":200,
        "message":"OK",
        "dataValue":
            {
                "versionWS":"v1",
                "language":"it",
                "idUserSession":"":
                "guest":"",
                "user":
                    {
                        "userId":27,
                        "userName":"G",
                        "userSurname":"G",
                        "idUserSession":"c"
                    }
            }
    }`)

    var dat map[string]interface{}

    if err := json.Unmarshal(b, &dat); err != nil {
        panic(err)
    }
    test := dat["dataValue"].(map[string]interface{})["user"]
    if rec, ok := test.(map[string]interface{}); ok {
        for key, val := range rec {
            if key == "idUserSession" {
                fmt.Printf(" %s = %s", key, val)
                fmt.Println()
            }

        }
    }

}

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



Eth0 su LuckFox Pico Mini A

 Le schede Luckfox Pico Mini A (a differenza delle sorelle maggiori) non hanno un connettore RJ45 e nonostante i pin da saldare non sembrano...