Quick Access to my selection Last Update: 2022-05-12 22:26:01 IST (Irish Standard Time) Unix epoch: 1652390761
Cloud Computing Operations Engineering/DevOps/SRE Engineering My Books
Python Open Source Utilities Python PHP Java
Docker Commodity Hardware ZFS Architecture
Windows Raspberry Pi Cassandra Relational Databases
  • Cassandra Universal Driver
    A HTTP gateway for all the languages supporting curl/sockets. Written in 2014, a time when there were no drivers for many languages.
    2014 Views: 625 views
Bash Open Source Utilities Bash My Tech Talks Miscellaneous
Old News:

RAB El nou món digital 2022-05-16 [CA]

This content is available in Catalan language only.

Aquest és el guió per al proper programa El nou món digital a Ràdio Amèrica Barcelona, a emetre Dilluns 16 de Maig de 2022. 2022-05-16 14:30 Irish Time / 15:30 Zona horària Catalunya / 06:30 Pacific Time.

This is the excerpt of my radio program at Radio America Barcelona on Monday 2022-05-16 14:30 Irish Time / 15:30 Catalonia time / 06:30 Pacific Time.

Aquest programa es pot veure a Twitch, apareixo a partir del minut 33:

https://www.twitch.tv/videos/1485460296

Notícies i novetats de vídeo

Videojocs / Video games

  • EA Games acaba el partnership amb FIFA, i ja no editarà més el joc de futbol FIFA

Ara faran el EA sports FC.

La veritat és que usar el nom FIFA i les seves condicions els inpedien de fer el tipus de jocs, més dinàmics que volien. També els costava molts diners simplement per a poder usar quatre lletres a la caratula. L’any passat FIFA va demanar de doblar el USD $150 Milions anuals que cobraven simplement pels drets d’usar el nom FIFA. I tal com va dir el president d’EA, la majoria de gent no compra els jocs a la botiga si no que els compra i descarrega digitalment. Així que les quatre lletres de FIFA tenen poc valor per a EA.

Fins a 2021 la saga FIFA ha venut 320 Milions de còpies. Cal sumar-li les de 2022.

https://en.wikipedia.org/wiki/FIFA_(video_game_series)

FIFA ha dit que faran un joc millor, però crec que en aquest cas la gent seguirà a EA, perque són els que realment saben com fer un producte de qualitat i tenen les plataformes. Crear un videojoc d’èxit i la infrastructura per a que funcioni amb milions d’usuaris no s’aprèn en quatre dies.

https://arstechnica.com/gaming/2022/05/ea-friendship-ended-with-fifa-now-ea-sports-fc-is-my-best-friend/

Destacar que diaris com the Irish Independent ho esmenten.

https://www.independent.co.uk/tech/ea-sports-fifa-premier-league-la-liga-mls-b2076337.html

  • Elden Ring

Disclaimer: Treballo per a Activision Blizzard. Comparteixo les meves opinions personals com a persona que juga a videojocs. I work for Activision Blizzard. I share my personal opinions as human being that loves video games.

Parlem d’Elden Ring, un joc open world de la mà de FromSoftware, creadors de la mítica saga Dark Sould o Sekiro Shadows die twice que ha estat nomenat millor joc de l’any.

Des del 25 de Febrer segueix sent el joc més ben valorat tant per a playstation 5 com per a xbox series x.

https://www.metacritic.com/game/xbox-series-x

https://www.metacritic.com/game/playstation-5

Per a la gent que li agraden els videojocs llargs, jo hi he jugat 144 hores i sóc nivell 104, amb 122 hores era nivell 84, i dec haver vist un 25% del joc o menys.

Normalment m’agraden els jocs que duren entre 60 i 90 hores. S’ha de reconèixer que és bonic, divertit i grotesc, i és el seu propi univers. Fa interactuar als jugadors.

És un món, ple de secrets, i es pot jugar tranquilament 500 hores.

I en la línia dels seus predecessors, Darks Souls, tothom mor o te finals més aviat terribles i tristos.

El joc ha venut més de 13.4 milions de còpies a tot el món, des del seu llançament el 25 de Febrer.

Com parlàvem la setmana passada és un joc totalment social, on pots invocar altres jugadors per a que t’ajudin, on altres jugadors t’invaeixen en mig de la partida, i on pots veure el que han fet altres jugadors i on han mort.

Defineix una nova manera de jugar perquè sense guies Internet és impossible descrobrir gran part del seu contingut.

Per als novells vaig escriure alguns trucs: Some tips for beginners at Elden Ring

  • Els jocs més venuts de tots els temps
    • Minecraft: 238 milions de còpies (des de 2011)
    • Grand Theft Auto V: 160M (des de 2013)
    • Tetris (EA): 100M (des de 2006)
    • Nintendo Wii Sports: 82.9M (des de 2006)
    • PUBG: Battlegrounds 75M (2017)
    • Super Mario Bros 58M (1985)
    • Mario Kart 8 / Deluxe 53.79M (2014) per a Wii i Switch
    • Pokémon 47.52M (1996) Game Boy
    • Terraria 44M (2011)
    • Wii Fit 43.8M (2007)
    • https://en.wikipedia.org/wiki/List_of_best-selling_video_games

Trucs

Alternatives a l’office

  • Google docs. I pots compartir documents amb altres persones, i actualitzar-los diverses persones alhora.

Una curiositat sobre Google Docs, com posant en un document And. And. And. And. And. el feia petar. :) https://www.engadget.com/google-docs-and-and-and-and-and-bug-213609808.html

Jo amb el meu doctor, comparteixo les biomètriques en un Spreadsheet de Google.

  • Instal·lar LibreOffice enlloc de l’Office. I en anglès.

El currency, el locale, separador decimal, de dates, pot variar d’un país a l’altre. Utilitzo en tots l’anglès americà i així usi l’ordinador que usi no tinc problemes a cap. (la hora faig servir 24 hours i la data YYYY-MM-DD)

  • Els problemes del Software pirata, i els bots, keyloggers, lladres de comptes…
  • Jo m’instal·lo tot el Software en anglès americà, perque tinc les actualitzacions de seguretat abans, i les hotkeys, les dreceres de teclat no canvien.
  • També podeu utilitzar la suite de google docs des del mòbil i la tauleta, accedint als vostres continguts als núvol.
  • Esmentar que es poden compartir arxius amb Google Drive.

RAB El nou món digital 2022-05-09 [CA]

This content is available in Catalan language only.

Aquest és el guió per al proper programa El nou món digital a Ràdio Amèrica Barcelona, a emetre Dilluns 9 de Maig de 2022. 2022-05-09 14:30 Irish Time / 15:30 Zona horària Catalunya / 06:30 Pacific Time.

This is the excerpt of my radio program at Radio America Barcelona on Monday 2022-05-09 14:30 Irish Time / 15:30 Catalonia time / 06:30 Pacific Time.

Podeu veure el programa a partir del minut 35 a Twitch:

https://www.twitch.tv/videos/1479235573

Previ

Vam comentar sobre com els governs escocès i irlandès subvencionen estudis a estudiants estrangers, i a treballadors que volen estudiar carreres d’IT.

Notícies

  • Volkswagen i BP faran partnership i instal·laran milers de punts de càrrega ràpida per a cotxes elèctrics a Alemanya i a Regne Unit.

https://www.engadget.com/vw-bp-fast-ev-chargers-gas-stations-192019692.html

VW and BP know they’ll both have to embrace electric vehicles, and they’re ready to work together to ease some of the transitional pain. Autoweek reports the two companies are teaming up to install thousands of VW’s Flexpole 150kW fast EV chargers at gas stations in Germany and the UK. Within two years, there will be as many as 2,000 charging units (4,000 charge points) in place at BP stations in the UK and Aral locations in Germany.

The expansion should help BP expand its charging network to 8,000 connections by the end of 2024.

  • Rel·lacionat amb això, cal felicitar al govern irlandès, que el 4 de Febrer ha reeditat una iniciativa molt reixida on subvencionen els taxistes que comprin un cotxe completament elèctric amb 10.000 € més 2.500 € addicionals si el converteix en accessible per a cadira de rodes.

Si s’entrega un cotxe antic, més contaminant o amb molts kilòmetres, els imports subvencionats són el doble: 20.000 € i 5.000 € respectivament.

https://www.gov.ie/en/press-release/f1623-up-to-25000-for-taxi-drivers-to-buy-electric-vehicles/

  • Xbox està enllestint la seva plataforma d’streaming de videojocs

Amb l’streamming no cal que tinguis una consola o un ordinador potent.

Ells t’envien la imatge i el so a l’ordinador i tu envies els moviments del comandament o el teclat. Això permet de retransmetre videojocs visualment impactants sense haver de gastar-se els diners en una consola o un ordinador molt potents.

Hi ha altres plataformes que fan això com: Google Stadia, Playstation Now (amb jocs de PS4), NVIDIA’s GeForce Now.

Això lliga una mica amb l’escassetat de processadors que fa que s’hagi d’esperar mesos per a aconseguir una consola d’última generació.

Amazon te una plataforma de subscripció per a Pc i Windows, que no és d’streamming, i que et permet de jugar a jocs gratis i tenir certes avantatges anomenat Amazon Prime Gaming.

Realment les empreses adoren els serveis de subscripció perque els permeten de predir quins ingressos tindran i no s’han de preocupar de la logística de fabricar i d’enviar coses.

https://www.engadget.com/xbox-game-streaming-device-tv-app-samsung-report-201006642.html

  • El CEO d’Intel va esmentar que el shortage de microxips s’allargarà durant el 2023 fins el 2024.

Degut al covid s’ha aturat molt la producció de microxips. Això s’ha vist reflexat en llargs temps d’espera per a comprar consoles com la Playstation 5, Ordinadors Mac, cotxes, o mòbils.

Nogenysmenys Intel està construint dues plantes gegantines a diferents indrets d’Estats Units.

https://www.engadget.com/intel-ceo-chip-shortage-continue-2024-141154415.html

Trucs

  • Starlink

Si viviu en zones rurals on no us arriba fibra, o teniu Internet de 6 Mbits, us pot interessar Starlink.

Starlink proporciona Internet molt ràpida, per satèl·lit, amb baixa latència.

És un servei create per Space X, és a dir, d’Elon Musk, el mateix propietari de Tesla, i ara de Twitter des de fa tres dies.

Operen a molts països. 32. Són a Amèrica, i a Europa. Amb problemes a la Índia pel govern no atorgant la llicència. Tot just han començat a Puerto Rico. Alguns amics meus a Irlanda l’utilitzen i estan súper contents. I molts terminals van ser distribuïts a Ukraïna per a que no es quedessin sense Internet quan Rússia els va envaïr.

https://en.wikipedia.org/wiki/Starlink

Les velocitats que podem esperar per a Starlink depenen de la tarifa, però sol estar entre el 100Mbps i els 500Mbps per a baixada i de pujada des de 12 a més de 25 Mbps amb un preu bàsic de $99 USD mensuals.

Acaben d’aprovar-lo a Perú https://trome.com/tecnologia/starlink-gobierno-autoriza-a-la-empresa-de-internet-satelital-de-dar-servicios-en-peru-elon-musk-mtc-tecnologia-noticia/?ref=tr

Starlink també permet endur-se la connexió Internet, si viatgem pel mateix continent, si anem de camping, etc..

https://www.engadget.com/starlink-portability-internet-spacex-141228324.html

https://www.ookla.com/articles/starlink-hughesnet-viasat-performance-q4-2021

I Hawaian airlines vol oferir Internet amb Starlink als seus vols:

https://www.engadget.com/hawaiian-airlines-spacex-starlink-free-internet-131056087.html

L’únic que s’ha de vigilar és amb les possibles baixades de velocitat causades per… :)

https://www.starlink.com/

Humor

Un oient va comentar que cada cop que diem “tinc que” enlloc d’haig de, mor un gatet.

Així doncs vaig fer aquest Meme. :)

Why I think in Python is not a good idea to raise exceptions inside your methods

Last update: 2022-05-18 10:48 Irish Time

Recently a colleague was asking me for advice on their design of error handling in a Python application.

They were catching an error and raising an Exception, inside the except part of a method, to be catch outside the method.

And at some point a simple logic got really messy and unnecessarily complicated. Also troubleshooting and debugging an error was painful because they were only getting a Custom Exception and not context.

I explained to my colleague that I believed that the person that created that Exception chain of catch came from Java background and why I think they choose that path, and why I think in Python it’s a bad idea.

In Java, functions and methods can only return one object.

I programmed a lot in Java in my career, and it was a pain having to create value objects, and having to create all kind of objects for the return. Is it a good thing that types are strongly verified by the language? Yes. It worked? Yes. It made me invest much more time than necessary? Also yes.

Having the possibility to return only one object makes it mandatory having a way to return when there was an error. Otherwise you would need to encapsulate an error code and error description fields in each object, which is contrary to the nature of the object.

For example, a class Persona. Doesn’t make any sense having an attribute inside the class Persona to register if an operation related to this object went wrong.

For example, if we are in a class Spaceship that has a method GetPersonaInCommand() and there is a problem in that method, doesn’t make any sense to return an empty Persona object with attributes idError, errorDescription. Probably the Constructor or Persona will require at least a name or Id to build the object…. so in this case, makes sense that the method raises an Exception so the calling code catches it and knows that something went wrong or when there is no data to return.

This will force to write Custom Exceptions, but it’s a solution.

Another solution is creating a generic response object which could be an Object with these attributes:

  • idError
  • errorDescription
  • an Object which is the response, in our example Persona or null

I created this kind of approach for my Cassandra libraries to easily work with Cassandra from Java and from PHP, and for Cassandra Universal Driver (a http/s gateway created in year 2014).

Why this in not necessary in Python

Python allows you to return multiple values, so I encourage you tor return a boolean for indicating the success of the operation, and the object/value you’re interested.

You can see it easily if you take a look to FileUtils class from my OpenSource libraries carleslibs.

The method get_file_size_in_bytes(self, s_file) for example:

    def get_file_size_in_bytes(self, s_file):

        b_success = False
        i_file_size = 0

        try:
            # This will help with Unit Testing by raisin IOError Exception
            self.test_helper()

            i_file_size = os.path.getsize(s_file)
            b_success = True
        except IOError:
            b_success = False

        return b_success, i_file_size

It will always return a boolean value to indicate success or failure of the operation and an integer for the size of the file.

The calling code will do something like this:

o_fileutils = FileUtils()
b_success, i_bytes = o_fileutils.get_file_size_in_bytes("profile.png")
if b_succes is False:
    print("Error! The file does not exist or cannot be accessed!")
    exit(1)

if i_bytes < 1024:
    print("The profile picture should be at least 1KB")
    exit(1)

print("Profile picture exists and is", i_bytes, " bytes in length!")

The fact that Python can return multiple variables makes super easy dealing with error handling without having to take the road of Custom Exceptions.

And it is Ok if you want to follow this path, but in my opinion, for most of the developers up to Senior levels, it only over complicates the logic of your code and the amount of try/excepts you have to have everywhere.

If you use PHP you can mix different types in an Array, so you can always return an Array with a boolean, or an i_id_error, and your object or data of whatever type it’s.

Getting back to my carleslibs Open Source package, it is super easy to Unit Test these methods.

In my opinion, this level of simplicity, brings only advantages. Including Software Development speed, which is good for the business.

I’m not advocating for not using Custom Exceptions or to not develop a Exceptions Raising strategy if you need it and you know what you’re doing. I’m just suggesting why I think most of the developments in Python do not really need this and only over complicates the development. There are situations where raising exceptions will be a perfectly useful or even the best approach, there are many scenarios, but I think that in most of cases, using raise inside except will only multiply the time of the development and slow down the speed of bringing new features to the business, over complicating Unit Test as well, and be a real pain for the Junior and Intermediate developers.

The Constructor

Obviously, as the Constructor doesn’t return any value, it is perfectly fine to raise an exception in there, or just to use try/except in the code that is instancing the objects.

RAB El nou món digital 2022-05-02 [CA]

Aquest és l’extracte del meu programa de ràdio de Dilluns 2022-05-02 14:15 Irish Time / 15:15 Zona horària Catalunya / 06:15 Pacific Time.

This is the excerpt of my radio program Monday 2022-05-02 14:15 Irish Time / 15:15 Catalonia time / 06:15 Pacific Time.

May the 4th

El proper 4 de Maig és el dia (informal) d’Star Wars. May the 4th que sona similar a May the Force (be with you).

Tots els fans celebren aquest dia mundialment.

https://en.wikipedia.org/wiki/Star_Wars_Day

Videojocs / Video games

Disclaimer: Treballo per a Activision Blizzard i comparteixo les meves opinions personals com a persona que juga a videojocs. I work for Activision Blizzard and I share my personal opinions as human being that loves video games.

Avui parlo de jocs de Nintendo, un altre dia parlaré d’Xbox, de Pc, de Sony Playstation etc…

El dia 29 d’Abril es va posar a la venda el Nintendo Sports.

És la versió actualitzada i millorada del popular joc Wii Sports. Que és un joc molt casual, poden jugar nens, adults que mai han jugat a un videojoc perque es controla amb el moviment.

És un joc molt popular i divertit.

Però poseu-vos la corretja o podrieu trencar la televisió si surt el comandament volant.

Els gràfics són senzills però per a mi el punt fort de la consola Nintendo Switch és passar-ho bé amb més gent.

Te la possibilitat de jugar en línia amb altres persones random, o amb els nostres amics, sols o fins a quatre persones a casa amb la mateixa consola.

He provat el bowling, on 18 persones es van eliminant, i el volleyball. Un d’esgrima, un de futbol amb una pilota gegant i tenis. El d’esgrima és molt xulo perque quan mous la mà es mou l’espasa a la pantalla.

Ve amb una cinta per a lligar a la cama per a poder fer els moviments de xutar o al braç. És divertit.

Com controles els moviments movent el braç és una manera de fer una mica d’exercici també.

Altres jocs de la mateixa natura són el nintendo fitness boxing (i boxing 2), ace tenis, el ringfit adventure.

També són divertits el just dance i let’s sing (karaoke). :)

Estic segur que un joc de karaoke amb cançons en català tindria molt d’èxit.

Descompte jocs de nintendo fins el 5 de Maig

Nintendo també està fent una campanya d’estiu fins el 5 de Maig amb descomptes de fins un 60% en jocs de single player.

Per exemple el The Legend of Zelda: Skyward Sword HD es pot comprar online per 39,99€ enlloc dels 59,99€ habituals. Un 33% de descompte.

Notícies

  • Elon Musk ha comprat Twitter per 44Billion of dollars (44 mil milions per a nosaltres ja que en anglès un bilió són 1000 milions, no )
  • Netflix ha pujat la subscripció

A Irlanda The basic and standard plan will both increase to €8.99 and €14.99 a month respectively, while the premium tier will go up from €17.00 to €20.99.Netflix announced it would offer an ad-supported tier after 200,000 subscribers left the platform — the first such decline in over a decade.

A Costa Rica i al Peru, des del 12 de Març d’enguany 2022, es pot afegir a una amistat que no viu a la mateixa casa per una petita quota addicional al mes.

https://about.netflix.com/en/news/paying-to-share-netflix-outside-your-household

  • El CEO d’Intel va esmentar que el shortage de microxips s’allargarà durant el 2023 fins el 2024.

Degut al covid s’ha aturat molt la producció de microxips. Això s’ha vist reflexat en llargs temps d’espera per a comprar consoles com la Playstation 5, Ordinadors Mac, cotxes, o mòbils.

Nogenysmenys Intel està construint dues plantes gegantines a diferents indrets d’Estats Units.

https://www.engadget.com/intel-ceo-chip-shortage-continue-2024-141154415.html

Trucs

  • Starlink

Si viviu en zones rurals on no us arriba fibra, o teniu Internet de 6 Mbits, us pot interessar Starlink.

Starlink proporciona Internet molt ràpida, per satèl·lit, amb baixa latència.

És un servei create per Space X, és a dir, d’Elon Musk, el mateix propietari de Tesla, i ara de Twitter des de fa tres dies.

Operen a molts països. Alguns amics meus a Irlanda l’utilitzen i estan súper contents. I molts terminals van ser distribuïts a Ukraïna per a que no es quedessin sense Internet quan Rússia els va envaïr.

I Hawaian airlines vol oferir Internet amb Starlink als seus vols:

https://www.engadget.com/hawaiian-airlines-spacex-starlink-free-internet-131056087.html

L’únic que s’ha de vigilar és amb les possibles baixades de velocitat causades per… :)

https://www.starlink.com/

  • Alternatives al Microsoft Office

Alternatives a l’office

  • Google docs. I pots compartir documents amb altres persones, i actualitzar-los diverses persones alhora.

Jo amb el meu doctor, comparteixo les biomètriques en un Spreadsheet de Google.

  • Instal·lar LibreOffice enlloc de l’Office. I en anglès.

El currency, el locale, separador decimal, de dates, pot variar d’un país a l’altre. Utilitzo en tots l’anglès americà i així usi l’ordinador que usi no tinc problemes a cap. (la hora faig servir 24 hours i la data YYYY-MM-DD)

  • Els problemes del Software pirata, i els bots, keyloggers, lladres de comptes…
  • Jo m’instal·lo tot el Software en anglès americà, perque tinc les actualitzacions de seguretat abans, i les hotkeys, les dreceres de teclat no canvien.

Trucs de Zoom

  • Un Zoom és un sistema de videoconferència que s’utilitza molt en teletreball a les empreses.
  • Es pot compartir la pantalla. I es pot demanar control remot. L’altre t’ha d’autoritzar.
  • També es pot dibuixar a la pantalla de l’atri. La opció es diu Annotate.

Trucs de Mòbils

Fer una captura de pantalla:

Android: 

  • Cerca a Google per al teu model.
  • Prem tecla de baixar el volum i d’encendre el mòbil a la mateixa hora. I mantent-los pulsats durant mig segon.

iPhone:

  • 13 i altres amb face id: Prem: el botó del costat i el de pujar el volum a l’hora.
  • Models amb touch id: Prem el botó de home, el rodonet, i el del costat (power).
  • Els que tenen el botó a dalt, han de prèmer el botó de dalt i home.

https://support.apple.com/en-ie/HT200289

Working on a Sudoku Solver in Python (Source Code)

This is a document previous to a live code review session.

It has the information to prepare for the upcoming code review session, where I plan to share the lessons learned, decision I took, mistakes I did, refactors I had to overcome, and tentatively we will refactor code in order to add some Unit Testing.

History

I used to play sudoku with my family, so from time to time I do by myself.

Once I found a sudoku that was impossible and it happened that it was a typo from the newspaper, so, when I found another impossible sudoku I wanted to know if it was me, or if there was a typo or similar, so I decided to write a Sudoku Solver that will solve the sudoku for me.

The bad guys

I had problems solving these two sudokus:

Some Screenshots

The Source Code

You can clone the project from here:

https://gitlab.com/carles.mateo/sudo-ku-solver

You will have to install colorama package, as I used it for giving colors to the output:

pip3 install colorama

The main program sudokusolver.py:

import copy
from lib.colorutils import ColorUtils


class SudokuMap():
    
    def __init__(self, i_width, i_height, o_color=ColorUtils()):
        self.i_width = i_width
        self.i_height = i_height
        self.o_color = o_color

        self.a_map = self.generate_empty_map()

    def generate_empty_map(self):
        a_map = []
        a_row = []
        a_i_possible_numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        for i_x in range(self.i_width):
            a_row.append(a_i_possible_numbers.copy())

        for i_y in range(self.i_height):
            a_map.append(copy.deepcopy(a_row))

        return a_map

    def set_number(self, i_number, i_x, i_y):
        """
        Sets a well known (already defined in the original map) number for a position
        :param i_number:
        :param i_x:
        :param i_y:
        :return:
        """
        self.a_map[i_y][i_x] = [i_number]

    def detect_and_remove_a_number_from_possibles_from_a_row(self, i_y):
        """
        We will elinate this possibility from the row
        :return: Boolean
        """

        b_found = False
        self.o_color.print_label("Detecting numbers to remove from row " + str(i_y))

        for i_x in range(0, self.i_width):
            a_i_numbers_possible = self.a_map[i_y][i_x]
            if len(a_i_numbers_possible) == 1:
                b_found = True
                i_number_found = self.a_map[i_y][i_x][0]
                print("Found a number that will be removed from horizontal and vertical and in quadrant", i_number_found, "at", i_x, i_y)
                self.remove_a_number_from_possibles_in_a_row(i_number_to_remove=i_number_found, i_y=i_y)
                self.remove_a_number_from_possibles_in_a_column(i_number_to_remove=i_number_found, i_x=i_x)
                self.remove_a_number_from_possibles_in_quadrant(i_number_to_remove=i_number_found, i_x=i_x, i_y=i_y)

        return b_found

    def remove_a_number_from_possibles_in_a_row(self, i_number_to_remove, i_y):
        """
        Removes a number from the list of possibles in that row
        :param i_number_to_remove:
        :param i_y:
        :return:
        """

        self.o_color.print_label("> Scanning for removing " + str(i_number_to_remove) + " in row " + str(i_y))

        for i_x in range(0, self.i_width):
            a_i_numbers_possible = self.a_map[i_y][i_x]
            if len(a_i_numbers_possible) == 1 and a_i_numbers_possible[0] == i_number_to_remove:
                # This is the right cell, ignore it
                pass
            else:
                # Subtract the number from the sequence
                if i_number_to_remove in a_i_numbers_possible:
                    a_i_numbers_possible_old = a_i_numbers_possible.copy()
                    a_i_numbers_possible.remove(i_number_to_remove)
                    print("> Removed", i_number_to_remove, "From:", str(i_x) + "x" + str(i_y), a_i_numbers_possible_old, "Pending:", a_i_numbers_possible)
                    self.a_map[i_y][i_x] = a_i_numbers_possible
                    if len(a_i_numbers_possible) == 1:
                        # Trigger it again for the number recently discovered
                        i_new_number_to_remove = a_i_numbers_possible[0]
                        self.o_color.print_success("> Found " + str(i_new_number_to_remove) + " From: " + str(i_x) + "x" + str(i_y))
                        self.remove_a_number_from_possibles_in_a_row(i_number_to_remove=i_new_number_to_remove, i_y=i_y)
                        self.remove_a_number_from_possibles_in_a_column(i_number_to_remove=i_new_number_to_remove, i_x=i_x)
                        self.remove_a_number_from_possibles_in_quadrant(i_number_to_remove=i_new_number_to_remove, i_x=i_x, i_y=i_y)

        self.o_color.print_label("> Leaving scan for " + str(i_number_to_remove) + " in row " + str(i_y))

    def remove_a_number_from_possibles_in_a_column(self, i_number_to_remove, i_x):
        """
        Removes a number from the list of possibles in that row
        :param i_number_to_remove:
        :param i_y:
        :return:
        """

        self.o_color.print_label("V Scanning for removing " + str(i_number_to_remove) + " in col " + str(i_x))

        for i_y in range(0, self.i_height):
            a_i_numbers_possible = self.a_map[i_y][i_x]
            if len(a_i_numbers_possible) == 1 and a_i_numbers_possible[0] == i_number_to_remove:
                # This is the right cell, ignore it
                pass
            else:
                # Subtract the number from the sequence
                if i_number_to_remove in a_i_numbers_possible:
                    a_i_numbers_possible_old = a_i_numbers_possible.copy()
                    a_i_numbers_possible.remove(i_number_to_remove)
                    print("V Removed", i_number_to_remove, "From:", i_x, i_y, a_i_numbers_possible_old, "Pending:", a_i_numbers_possible)
                    # @TODO: Remove, as it's a pointer it is not needed
                    self.a_map[i_y][i_x] = a_i_numbers_possible
                    if len(a_i_numbers_possible) == 1:
                        # Trigger it again for the number recently discovered
                        i_new_number_to_remove = a_i_numbers_possible[0]
                        self.o_color.print_success("Found " + str(i_new_number_to_remove) + " From: " + str(i_x) + " " + str(i_y))
                        self.remove_a_number_from_possibles_in_a_row(i_number_to_remove=i_new_number_to_remove, i_y=i_y)
                        self.remove_a_number_from_possibles_in_a_column(i_number_to_remove=i_new_number_to_remove, i_x=i_x)
                        self.remove_a_number_from_possibles_in_quadrant(i_number_to_remove=i_new_number_to_remove, i_x=i_x, i_y=i_y)

        self.o_color.print_label("V Leaving scan for " + str(i_number_to_remove) + " in col " + str(i_x))

    def remove_a_number_from_possibles_in_quadrant(self, i_number_to_remove, i_x, i_y):
        """

        :param i_number_to_remove:
        :param i_x:
        :param i_y:
        :return:
        """

        i_x_quadrant = int(i_x / 3)
        i_y_quadrant = int(i_y / 3)

        i_x_ini = i_x_quadrant * 3
        i_x_end = i_x_ini + 2

        i_y_ini = i_y_quadrant * 3
        i_y_end = i_y_ini + 2

        for i_y_rel in range(i_y_ini, i_y_end + 1):
            for i_x_rel in range(i_x_ini, i_x_end + 1):
                a_i_numbers_possible = self.a_map[i_y_rel][i_x_rel]
                if len(a_i_numbers_possible) == 1 and a_i_numbers_possible[0] == i_number_to_remove:
                    # This is the right cell, ignore it
                    pass
                else:
                    # Subtract the number from the sequence
                    if i_number_to_remove in a_i_numbers_possible:
                        a_i_numbers_possible_old = a_i_numbers_possible.copy()
                        a_i_numbers_possible.remove(i_number_to_remove)
                        print("X Removed", i_number_to_remove, "From:", i_x_rel, i_y_rel, a_i_numbers_possible_old, "Pending:", a_i_numbers_possible)
                        # Nota: Here I had a bug and I was "liant-la parda"
                        # if len(a_i_numbers_possible) == 1:
                        #     # Trigger it again for the number recently discovered
                        #     i_new_number_to_remove = a_i_numbers_possible[0]
                        #     string_ints = [str(int) for int in ints]
                        #     self.o_color.print_success("X Found " + str(i_new_number_to_remove) + " From: " + str(i_x) + "x" + str(i_y) + "[]")
                        #     self.remove_a_number_from_possibles_in_a_row(i_number_to_remove=i_new_number_to_remove, i_y=i_y)
                        #     self.remove_a_number_from_possibles_in_a_column(i_number_to_remove=i_new_number_to_remove, i_x=i_x)

    def check_if_number_possibles_in_quadrant_is_unique(self, i_number_to_check, i_x, i_y):
        """

        :param i_number_to_remove:
        :param i_x:
        :param i_y:
        :return: b_found
        """

        i_x_quadrant = int(i_x / 3)
        i_y_quadrant = int(i_y / 3)

        i_x_ini = i_x_quadrant * 3
        i_x_end = i_x_ini + 2

        i_y_ini = i_y_quadrant * 3
        i_y_end = i_y_ini + 2

        i_number_of_occurrences_found = 0
        i_x_position_number = 0
        i_y_position_number = 0

        b_unique = False

        for i_y_rel in range(i_y_ini, i_y_end + 1):
            for i_x_rel in range(i_x_ini, i_x_end + 1):
                a_i_numbers_possible = self.a_map[i_y_rel][i_x_rel]
                for i_number_in_possibles in a_i_numbers_possible:
                    if len(a_i_numbers_possible) > 1 and i_number_in_possibles == i_number_to_check:
                        # This is the right cell, ignore it
                        i_number_of_occurrences_found += 1
                        i_x_position_number = i_x_rel
                        i_y_position_number = i_y_rel
                        if i_number_of_occurrences_found > 1:
                            # Unsuccessful
                            break

        if i_number_of_occurrences_found == 1:
            # Success!
            a_i_numbers_possible = [i_number_to_check]
            self.a_map[i_y_position_number][i_x_position_number] = a_i_numbers_possible
            b_unique = True

        return b_unique, i_x_position_number, i_y_position_number

    def check_if_number_possibles_in_row_is_unique(self, i_number_to_check, i_y):
        """

        :param i_number_to_check:
        :param i_x:
        :param i_y:
        :return:
        """

        i_number_of_occurrences_found = 0
        i_x_position_number = 0
        i_y_position_number = 0

        b_unique = False

        for i_x_rel in range(0, 9):
            a_i_numbers_possible = self.a_map[i_y][i_x_rel]
            for i_number_in_possibles in a_i_numbers_possible:
                if len(a_i_numbers_possible) > 1 and i_number_in_possibles == i_number_to_check:
                    # This is the right cell, ignore it
                    i_number_of_occurrences_found += 1
                    i_x_position_number = i_x_rel
                    i_y_position_number = i_y
                    if i_number_of_occurrences_found > 1:
                        # Unsuccessful
                        break

        if i_number_of_occurrences_found == 1:
            # Success!
            a_i_numbers_possible = [i_number_to_check]
            self.a_map[i_y_position_number][i_x_position_number] = a_i_numbers_possible
            b_unique = True

        return b_unique, i_x_position_number, i_y_position_number

    def get_map_drawing_as_string(self, a_map_alternative=None):
        s_map = ""
        i_counter_y = 0
        s_separator_rows = "="

        a_map_to_use = self.a_map
        if a_map_alternative is not None:
            a_map_to_use = a_map_alternative

        s_map = s_map + s_separator_rows * 37 + "\n"
        for a_row in a_map_to_use:
            i_counter_y += 1
            if i_counter_y == 3:
                i_counter_y = 0
                s_separator_rows = "="
            else:
                s_separator_rows = "-"

            s_map = s_map + "|"
            i_counter = 0
            for a_i_numbers_possible in a_row:
                i_counter += 1

                if len(a_i_numbers_possible) == 1:
                    s_number = str(a_i_numbers_possible[0])
                else:
                    s_number = " "

                if i_counter == 3:
                    s_separator = "|"
                    i_counter = 0
                else:
                    s_separator = "¦"
                s_map = s_map + " " + s_number + " " + s_separator
            s_map = s_map + "\n"

            s_map = s_map + s_separator_rows * 37 + "\n"

            # Replace 0 by " "
            s_map = s_map.replace("0", " ")

        s_map = s_map + "\n\n"
        i_total_numbers_found, a_s_numbers_found = self.get_total_numbers_found()
        s_map = s_map + "Total numbers found: " + str(i_total_numbers_found) + " Numbers found: " + " ".join(a_s_numbers_found) + "\n"

        return s_map

    def get_map_drawing_of_possibles_as_string(self, a_map_alternative=None):
        s_map = ""
        i_counter_y = 0
        s_separator_rows = "="

        a_map_to_use = self.a_map
        if a_map_alternative is not None:
            a_map_to_use = a_map_alternative

        s_map = s_map + self.o_color.color_blue(s_separator_rows * ((9 * ( 9 + 2 )) + 10)) + "\n"
        for a_row in a_map_to_use:
            i_counter_y += 1
            if i_counter_y == 3:
                i_counter_y = 0
                s_separator_rows = "="
            else:
                s_separator_rows = "-"

            s_map = s_map + self.o_color.color_blue("|")
            i_counter = 0
            for a_i_numbers_possible in a_row:
                i_counter += 1

                if len(a_i_numbers_possible) == 1:
                    # The right number
                    s_number = str(a_i_numbers_possible[0]).center(9)
                    s_number = self.o_color.color_success(s_number)
                else:
                    a_i_numbers_possible_string = []
                    for i_number in a_i_numbers_possible:
                        s_number = str(i_number)
                        # Replace by the color sequence
                        if i_number == 2:
                            s_number = self.o_color.color_red(s_number)
                        if i_number == 3:
                            s_number = self.o_color.color_yellow(s_number)
                        if i_number == 4:
                            self.o_color.color_magenta(s_number)
                        a_i_numbers_possible_string.append(s_number)
                    # s_number = "".join(a_i_numbers_possible_string).ljust(9)
                    s_number = "".join(a_i_numbers_possible_string) + " " * (9-len(a_i_numbers_possible))

                if i_counter == 3:
                    s_separator = self.o_color.color_blue("|")
                    i_counter = 0
                else:
                    s_separator = self.o_color.color_blue("¦")
                s_map = s_map + " " + s_number + " " + s_separator
            s_map = s_map + "\n"

            s_map = s_map + self.o_color.color_blue(s_separator_rows * ((9 * (9 + 2)) + 10)) + "\n"

            # Replace 0 by " "
            s_map = s_map.replace("0", " ")

        return s_map

    def get_total_numbers_found(self):

        i_total_numbers_found = 0
        a_s_numbers_found = []

        for i_y in range(0, self.i_height):
            for i_x in range(0, self.i_width):
                a_i_numbers_possible = self.a_map[i_y][i_x]
                if len(a_i_numbers_possible) == 1:
                    i_total_numbers_found = i_total_numbers_found + 1
                    i_number_found = self.a_map[i_y][i_x][0]
                    s_number_found = str(i_number_found)
                    if s_number_found not in a_s_numbers_found:
                        a_s_numbers_found.append(s_number_found)

        return i_total_numbers_found, a_s_numbers_found


if __name__ == "__main__":

    o_color = ColorUtils()

    o_map = SudokuMap(9, 9, o_color=o_color)
    o_map.set_number(i_number=1, i_x=1, i_y=0)
    o_map.set_number(3, 4, 0)
    o_map.set_number(8, 7, 0)

    o_map.set_number(8, 0, 1)
    o_map.set_number(7, 3, 1)
    o_map.set_number(4, 5, 1)
    o_map.set_number(6, 8, 1)

    o_map.set_number(3, 2, 2)
    o_map.set_number(9, 6, 2)

    o_map.set_number(2, 1, 3)
    o_map.set_number(4, 4, 3)
    o_map.set_number(6, 7, 3)

    o_map.set_number(5, 0, 4)
    o_map.set_number(6, 3, 4)
    o_map.set_number(2, 5, 4)
    o_map.set_number(8, 8, 4)

    o_map.set_number(3, 1, 5)
    o_map.set_number(8, 4, 5)
    o_map.set_number(7, 7, 5)

    o_map.set_number(2, 2, 6)
    o_map.set_number(6, 6, 6)

    o_map.set_number(9, 0, 7)
    o_map.set_number(4, 3, 7)
    o_map.set_number(3, 5, 7)
    o_map.set_number(2, 8, 7)

    o_map.set_number(8, 1, 8)
    o_map.set_number(6, 4, 8)
    o_map.set_number(1, 7, 8)

    # Extra
    # o_map.set_number(2, 0, 0)

    # Speculative
    o_map.set_number(7, 0, 3)


    # Another map
    o_map2 = SudokuMap(9, 9, o_color=o_color)
    o_map2.set_number(i_number=5, i_x=0, i_y=0)
    o_map2.set_number(i_number=9, i_x=5, i_y=0)

    o_map2.set_number(i_number=7, i_x=2, i_y=1)
    o_map2.set_number(i_number=2, i_x=7, i_y=1)

    o_map2.set_number(i_number=2, i_x=0, i_y=2)
    o_map2.set_number(i_number=3, i_x=4, i_y=2)
    o_map2.set_number(i_number=1, i_x=5, i_y=2)
    o_map2.set_number(i_number=9, i_x=7, i_y=2)

    o_map2.set_number(i_number=7, i_x=0, i_y=3)
    o_map2.set_number(i_number=1, i_x=2, i_y=3)
    o_map2.set_number(i_number=6, i_x=3, i_y=3)
    o_map2.set_number(i_number=9, i_x=4, i_y=3)
    o_map2.set_number(i_number=4, i_x=8, i_y=3)

    o_map2.set_number(i_number=1, i_x=4, i_y=4)

    o_map2.set_number(i_number=6, i_x=0, i_y=5)
    o_map2.set_number(i_number=7, i_x=4, i_y=5)
    o_map2.set_number(i_number=4, i_x=5, i_y=5)
    o_map2.set_number(i_number=3, i_x=6, i_y=5)
    o_map2.set_number(i_number=1, i_x=8, i_y=5)

    o_map2.set_number(i_number=5, i_x=1, i_y=6)
    o_map2.set_number(i_number=3, i_x=3, i_y=6)
    o_map2.set_number(i_number=6, i_x=4, i_y=6)
    o_map2.set_number(i_number=8, i_x=8, i_y=6)

    o_map2.set_number(i_number=6, i_x=1, i_y=7)
    o_map2.set_number(i_number=7, i_x=6, i_y=7)

    o_map2.set_number(i_number=9, i_x=3, i_y=8)
    o_map2.set_number(i_number=3, i_x=8, i_y=8)

    # Extra help while not implemented the best algorithm
    # =============================================================================================================
    # |     5     ¦ 148       ¦ 48        |     7     ¦     2     ¦     9     | 148       ¦     3     ¦     6     |
    # -------------------------------------------------------------------------------------------------------------
    # | 13489     ¦ 13489     ¦     7     | 48        ¦ 48        ¦     6     | 148       ¦     2     ¦     5     |
    # -------------------------------------------------------------------------------------------------------------
    # |     2     ¦ 48        ¦     6     |     5     ¦     3     ¦     1     | 48        ¦     9     ¦     7     |
    # =============================================================================================================
    # |     7     ¦ 38        ¦     1     |     6     ¦     9     ¦ 358       |     2     ¦ 58        ¦     4     |
    # -------------------------------------------------------------------------------------------------------------
    # | 348       ¦ 2348      ¦ 3458      | 28        ¦     1     ¦ 358       |     6     ¦     7     ¦     9     |
    # -------------------------------------------------------------------------------------------------------------
    # |     6     ¦ 289       ¦ 589       | 28        ¦     7     ¦     4     |     3     ¦ 58        ¦     1     |
    # =============================================================================================================
    # | 14        ¦     5     ¦     2     |     3     ¦     6     ¦     7     |     9     ¦ 14        ¦     8     |
    # -------------------------------------------------------------------------------------------------------------
    # | 3489      ¦     6     ¦ 3489      |     1     ¦ 458       ¦ 58        |     7     ¦ 45        ¦     2     |
    # -------------------------------------------------------------------------------------------------------------
    # | 148       ¦     7     ¦ 48        |     9     ¦ 458       ¦     2     | 145       ¦     6     ¦     3     |
    # =============================================================================================================
    # By best algorithm I mean that the last in the middle vertical quadrant from the top right horizontally,
    # only 5 can be in a column. That clarifies that 5 must go to the other column in last quadrant, first column. Coord 6x8
    # o_map2.set_number(i_number=5, i_x=6, i_y=8)
    # ERROR traces from a bug fixed to mentioned during the code review
    # Surprisingly this fails
    # > Leaving scan for 8 in row1
    # V Scanning for removing 8 in col 4
    # V Removed 8 From: 4 7 [5, 8] Pending: [5]
    # Found 5 From: 4 7
    #
    # > Scanning for removing 5 in row 7
    # > Removed 5 From: 5 7 [5, 8] Pending: [8]
    # > Found 8 From: 5 7
    #
    # > Scanning for removing 8 in row 7
    # > Removed 8 From: 0 7 [3, 8] Pending: [3]
    # > Found 3 From: 0 7

    o_map = o_map2

    print(o_map.get_map_drawing_as_string())

    b_changes_found = True
    while b_changes_found is True:
        b_changes_found = False

        for i_y in range(0, o_map.i_height):
            b_found = o_map.detect_and_remove_a_number_from_possibles_from_a_row(i_y=i_y)
            if b_found is True:
                print(o_map.get_map_drawing_as_string())

        for i_y in range(0, o_map.i_height):
            o_map.o_color.print_label("Scanning quadrants for row " + str(i_y))
            for i_number in range(1, 10):
                for i_x in range(0, o_map.i_width):
                    b_found, i_x_found, i_y_found = o_map.check_if_number_possibles_in_quadrant_is_unique(i_number_to_check=i_number, i_x=i_x, i_y=i_y)
                    if b_found is True:
                        # Search again
                        b_changes_found = True
                        o_map.remove_a_number_from_possibles_in_a_row(i_number_to_remove=i_number, i_y=i_y_found)
                        o_map.remove_a_number_from_possibles_in_a_column(i_number_to_remove=i_number, i_x=i_x_found)

                    b_found, i_x_found, i_y_found = o_map.check_if_number_possibles_in_row_is_unique(i_number_to_check=i_number, i_y=i_y)
                    if b_found is True:
                        b_changes_found = True
                        o_map.remove_a_number_from_possibles_in_a_column(i_number_to_remove=i_number, i_x=i_x_found)

                if b_changes_found is True:
                    print(o_map.get_map_drawing_as_string())

    # @TODO: Implement check if number in quadrant can only go to a column, to remove the non possible in that column from another quadrant
    # @TODO: Implement check if in a line only one number can go to a column.

    print(o_map.get_map_drawing_as_string())
    print(o_map.get_map_drawing_of_possibles_as_string())

The color library lib/colorutils.py:

from colorama import Fore, Back, Style , init


class ColorUtils:

    def __init__(self):
        # For Colorama on Windows
        init()

    def print_error(self, m_text, s_end="\n"):
        """
        Prints errors in Red.
        :param s_text:
        :return:
        """

        # If they pass numbers
        s_text = str(m_text)

        print(Fore.RED + s_text)
        print(Style.RESET_ALL, end=s_end)

    def print_success(self, m_text, s_end="\n"):
        """
        Prints errors in Green.
        :param s_text:
        :return:
        """

        # If they pass numbers
        s_text = str(m_text)
        print(Fore.GREEN + s_text)
        print(Style.RESET_ALL, end=s_end)

    def color_success(self, m_text):
        """
        Colors only this
        :param m_text:
        :return:
        """

        s_text = str(m_text)
        return Fore.GREEN + s_text + Fore.RESET

    def color_black(self, m_text):
        s_text = str(m_text)
        return Fore.BLACK + s_text + Fore.RESET

    def color_blue(self, m_text):
        s_text = str(m_text)
        return Fore.BLUE + s_text + Fore.RESET

    def color_red(self, m_text):
        s_text = str(m_text)
        return Fore.RED + s_text + Fore.RESET

    def color_yellow(self, m_text):
        s_text = str(m_text)
        return Fore.YELLOW + s_text + Fore.RESET

    def color_magenta(self, m_text):
        s_text = str(m_text)
        return Fore.MAGENTA + s_text + Fore.RESET

    def print_label(self, m_text, s_end="\n"):
        """
        Prints a label and not the end line
        :param s_text:
        :return:
        """

        # If they pass numbers
        s_text = str(m_text)

        print(Fore.BLUE + s_text, end="")
        print(Style.RESET_ALL, end=s_end)

    def return_text_blue(self, s_text):
        """
        Restuns a Text
        :param s_text:
        :return: String
        """
        s_text_return = Fore.BLUE + s_text + Style.RESET_ALL
        return s_text_return

News from the blog 2022-04-22

Media/Press

I was interviewed by Radio America Barcelona, in their studios in Barcelona.

RAB is a radio for the Catalan diaspora and expats.

The interview was broadcasted by Twitch and can be watched. It’s in Catalan language:

https://www.twitch.tv/videos/1448895585

You can follow them:

Sant Jordi discounted books (promo)

Tomorrow 23th of April is Sant Jordi (Saint George), the patron of Catalonia, and the Catalan traditional celebration consist in this day women gifting a book to the men they love and men gifting a rose to the women they love.

I created a voucher for all my Python books, so, since during 23th of April you can acquire the four books per $10 USD in total.

This voucher is limited to 100 sales.

https://leanpub.com/b/python3all/c/SANTJORDI2022

Python 3

I wrote an article with a Python 3 code that shows the length for file names in Linux ext3 and ext4 Filesystems and in ZFS Pools Filesystem.

I show basically how ASCii characters over 127 are encoded, reducing the maximum length of 255 bytes for the filename.

ZFS

I’ve updated an article explaining how to create a ZPool raidz (RAID 5 equivalent) from three loop devices based on local files.

Thanks to those that bought my ZFS book this month. :)

HTML and JavaScript

I wrote a super simple code to hide the <p> using jQuery and JavaScript.

Free books

https://books.goalkicker.com/

Books I bought

This month I bought these books.

Firewall

I continued to block any Russian or Belarus Ip Address that connects to the blog.

I also started to block entire ranges of Ip’s from Digital Ocean, as many attacks come from Servers in their infrastructure.

Despite blocking tens of thousands of Ip Addresses, the number of visitors keep growing.

My Health

Thanks to my strict discipline I managed to recover super well and I’m healthier than before and guided by the satisfied doctors we removed two daily medicines.

I started a new medicine that is for the final phase of my recuperation, which doctors expect to be completely. In fact I’m much more healthier than I was before going to the hospital.

Humor

Will AI take the world?
Sadly, true history. The responsibility to deliver is from all of us.

A super simple HTML jQuery JavaScript to hide a text

Some of my students are working on the Front End part, so I help them with JavaScript and jQuery.

Even if I’m super strong in Back End I’m not bad at JavaScript Front End.

So this super simple code will hide the paragraphs <p> using the hide animation from jQuery.

<html>
    <head>
    	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    </head>
    <body>
        <p>Text to hide</p>
        <input type="button" id="button" value="Hide the text" onclick='$("p").hide(1000);'>
    </body>
</html>

I think learning should be taken by steps, and starting by the most simple.

Testing length of Linux ext3/ext4 and ZFS file names with Python 3

Last Update: 2022-04-16 15:22

So, I was working on a project and i wanted to test how long a file can be.

The resources I checked, and also the Kernel and C source I reviewed, were pointing that effectively the limit is 255 characters.

But I had one doubt… given that Python 3 String are UTF-8, and that Linux encode by default is UTF-8, will I be able to use 255 characters length, or this will be reduced as the Strings will be encoded as UTF-8 or Unicode?.

So I did a small Proof of Concept.

For the filenames I grabbed a fragment of the translation to English of the book epic book “Tirant lo Blanc” (The White Knight), one of the first books written in Catalan language and the first chivalry novel known in the world. You can download it for free it in:

https://onlinebooks.library.upenn.edu/webbin/gutbook/lookup?num=378

Python Code:

from carleslibs.fileutils import FileUtils
from colorama import Fore, Back, Style , init


class ColorUtils:

    def __init__(self):
        # For Colorama on Windows
        init()

    def print_error(self, s_text, s_end="\n"):
        """
        Prints errors in Red.
        :param s_text:
        :return:
        """
        print(Fore.RED + s_text)
        print(Style.RESET_ALL, end=s_end)

    def print_success(self, s_text, s_end="\n"):
        """
        Prints errors in Green.
        :param s_text:
        :return:
        """
        print(Fore.GREEN + s_text)
        print(Style.RESET_ALL, end=s_end)

    def print_label(self, s_text, s_end="\n"):
        """
        Prints a label and not the end line
        :param s_text:
        :return:
        """
        print(Fore.BLUE + s_text, end="")
        print(Style.RESET_ALL, end=s_end)

    def return_text_blue(self, s_text):
        """
        Restuns a Text
        :param s_text:
        :return: String
        """
        s_text_return = Fore.BLUE + s_text + Style.RESET_ALL
        return s_text_return


if __name__ == "__main__":

    o_color = ColorUtils()
    o_file = FileUtils()

    s_text = "In the fertile, rich and lovely island of England there lived a most valiant knight, noble by his lineage and much more for his "
    s_text += "courage.  In his great wisdom and ingenuity he had served the profession of chivalry for many years and with a great deal of honor, "
    s_text += "and his fame was widely known throughout the world.  His name was Count William of Warwick.  This was a very strong knight "
    s_text += "who, in his virile youth, had practiced the use of arms, following wars on sea as well as land, and he had brought many "
    s_text += "battles to a successful conclusion."

    o_color.print_label("Erasure Code project by Carles Mateo")
    print()
    print("Task 237 - Proof of Concep of Long File Names, encoded is ASCii, in Linux ext3 and ext4 Filesystems")
    print()
    print("Using as a sample a text based on the translation of Tirant Lo Blanc")
    print("Sample text used:")
    print("-"*30)
    print(s_text)
    print("-" * 30)
    print()
    print("This test uses the OpenSource libraries from Carles Mateo carleslibs")
    print()
    print("Initiating tests")
    print("================")

    s_dir = "task237_tests"

    if o_file.folder_exists(s_dir) is True:
        o_color.print_success("Directory " + s_dir + " already existed, skipping creation")
    else:
        b_success = o_file.create_folder(s_dir)
        if b_success is True:
            o_color.print_success("Directory " + s_dir + " created successfully")
        else:
            o_color.print_error("Directory " + s_dir + " creation failed")
            exit(1)

    for i_length in range(200, 512, 1):
        s_filename = s_dir + "/" + s_text[0:i_length]
        b_success = o_file.write(s_file=s_filename, s_text=s_text)
        s_output = "Writing file length: "
        print(s_output, end="")
        o_color.print_label(str(i_length).rjust(3), s_end="")
        print(" file name: ", end="")
        o_color.print_label(s_filename, s_end="")
        print(": ", end="")
        if b_success is False:
            o_color.print_error("failed", s_end="\n")
            exit(0)
        else:
            o_color.print_success("success", s_end="\n")

    # Note: up to 255 work, 256 fails

I tried this in an Ubuntu Virtual Box VM.

As part of my tests I tried to add a non typical character in English, ASCii >127, like Ç.

When I use ASCii character < 128 (0 to 127) for the filenames in ext3/ext4 and in a ZFS Pool, I can use 255 positions. But when I add characters that are not typical, like the Catalan ç Ç or accents Àí the space available is reduced, suggesting the characters are being encoded:

Ç has value 128 in the ASCii table and ç 135.

I used my Open Source carleslibs and the package colorama.

Install them with:

pip3 install carleslibs colorama

Some tips for beginners at Elden Ring

Last Update: 2022-05-16 08:03 Irish Time

I played it on Xbox, so these tips are for Xbox.

Runes

When you kill enemies you get runes.

These are used for increasing your stats or weapons stats.

When you die you’ll lose the runes.

You can recover them if you go to the place where you died. You’ll see them shining on the floor. The place you died is marked on the map.

You’ll not lose things like the map, flowers you picked, etc…

You don’t lose your stats.

Horseback mount

After you get the Spectral Steed Whistle bind it to your belt through the inventory or pouch. It looks like a golden ring.

Then you’ll be able to summit it by selecting it (keypad down changes the item selected from the belt) and pressing X.

If you jump over some special spinning wind zones you’ll fly to very high distances.

You can run/sprint!

That’s something I didn’t see in the controls and I was being killed many many times, so I figured it out there has to be a way to sprint.

You can run by pressing the dodge button, B in XBox. Press B and hold it and move to any direction.

You can also use it when you are mounting Torrent, your horse.

Rolling dodges some attacks

Some attacks are avoided by rolling.

Mentioned by my friend Cian O’Brien.

Weight

You can have many items with you, but when you equip them the weight is important.

If you equip too much you’ll be unable jump or roll.

You can have several weapons with you and just equip what you need at each moment (before engaging combat).

Golden runes

You’ll find golden runes that will be kept in your inventory. They are consumables and you can use them to get instant amount of fragments.

Summon Ashes spirits

You’ll find spirits that you can summon in points of interest and to fight bosses.

Flasks

You can balance the number of flasks you have, and increase the number of them by using golden seeds at the sites of grace and the amount of life they replenish if you have the sacred tears.

Sort Chest

At the sites of grace you can sort your chest, and move things from your inventory to the chest and vice versa.

That’s ideal for reducing the items you carry until the appropriate moment to sell the goods.

Chests protected by soldiers in cars

You will find some cars protected by soldiers or big monsters.

It took me many time to realize that in the back of them they have a chest.

Jump and open the chest. Good weapons will become handy at an early stage.

Use the shield

Pressing LB if you have the shield on the left hand will raise the shield and keep it lifted.

This will protect you from incoming attacks.

I killed many enemies and bosses without using the shield, and it was a bit of a pain.

Sekiro style, dying and dying. Raising the shield I was able to beat impossible-to-beat-before bosses easily.

Head Skull

There are head skulls in the map, with bright eyes.

If you crack them hitting with your weapon, you’ll get a golden rune.

You can sell the golden runes to merchants or use them at any time and you’ll get runes. You may have a treasure enough to level up and you may not known.

You don’t loss the golden runes when you die.

Cycling items in your bag

You can bind several items to your back and cycle them pressing the down key on the pad.

If you bind the healing potion to the first slot in your bag if you hold down the cycle key it will always go back to the first item (thanks Cian!)

My friend Michela says: Carles I suggest if i may put the ring in backup pouch because if you map on the menu where healing potions are you risk to call  the horse when u wanna heal

:smile:

If you press and hold Y you’ll see the actions that you have mapped in the pouch. So, it’s also a quick way to access these.

Eliminating groups

Will restore a flask, so you will be able to use another crimson tears. This is capped to your max number of flasks.

Torch

You can buy a torch and use it. Useful for caves and dark places. Equip it as a weapon and just select it.

Traveling to the Round Table

When the requirements are met and you travel to the round table, you can go back by opening the map and zooming out. You’ll see then the round table.

Craft bombs

You can craft bombs if you have recipients to hold them.

Bombs are very useful against some bosses.

In order to craft you’ll need to buy a crafting kit.

Medallions

Michela also recommends: Bosses use to drop medallions. You can equip them in the medallion/s slot.

Use Magic

Once you have a spell you can go to a site of grace and select Memorize Spell.

Then with the up path you can switch.

You need to have a casting tool in any hand and press the attack button for that hand in order to perform the sorcery.

I found my first staff in the Sellia Crystal cave, after killing several of these digging blue crystal enemeies, which is a zone where you travel after you open a chest in a cave in Dragon-Buirnt ruins which you access going down stairs in the runes that have the zombies, where the big dragon is. It’s the Digger’s staff.

The centipedes in that area are very hard but I found them very vulnerable to fire bombs that you can craft and to throwing curved knives that you can buy in merchants.

After you defeat a boss in a cave next to a gigantic plant, you can become Sorceress Sellen’s protegee and she will teach you magic (she sell scrolls).

You can give her the academy scroll, IDK if this is good or bad.

Show glinstone projectiles without aiming

You don’t need to have the focus over an enemy. If you’re looking at the right direction you can just shoot using your staff, and the projectile will go to the enemy automatically.

Use Incantations

You can use incantations, that are another type of spell.

For doing incantations you need a Sacred Seal.

You can buy one in the two commerce women in the round table.

I discovered this after 82 hours of gameplay.

The incantations are based of faith.

Kick stairs

Like in Sekiro Shadows die Twice, after you get to certain parts you will be able to kick a stair so you’ll not need to do all the round to get to a boss.

Try different weapons

Different weapons have different behavior that you may find very convenient.

I recommend you to try different of them.

Some shields parry, which means that if you press the LT action button in the precise moment an enemy attacks, they will become vulnerable for a moment. You can then perform a critical with RB.

Great Runes

When you defeat one of the mega bosses, the demi gods, you will get a great rune.

You can use the great runes after restoring their power (only once) in a tower.

Then you equip a great rune in a site of grace.

They grant some buffs, but to get the most of them you have to use a Rune Arc.

These are dropped by rats and big rats.

Using a Rune Arc when having a Great Rune active gives you buff, like increased stats, until you die. Then you need another Arc.

I used an Arc for the first time when I was level 77.

Hashes of war can be duplicated

The hashes of war give special effects to the weapons. To be honest I have been afraid of using it and ruining a good weapon effect, or losing the ash.

But Ashes of war can be duplicated if you have the proper ingredient, in the smith in the Round Table.

I found the first nomadic merchant selling one of these ingredients just after South Raya Lucaria Gate, coming back after traversing the seal, from Main Academy Gate, just walking through the seal, without examining it, and after killing some packs of wolves.

I found this at level 77…

After 120 hours played I was level 83.

After 150 hours played I was level 111 and I had not yet used a single Ash of war.

Some attacks can be charged

Some attacks, like Loretta’s great arrow, can be charged by holding the fire button.

When it’s fired at its max charge level, it will deal more damage for the same FP cost.

Don’t roll over poison

In some caves you’ll find poison or rott on the floor. Don’t roll over trying to advance faster. That will cover your clothes with the poison and the disease will continue after you leave the infected zone. Just run or walk.

Plants in the caves allow you to level up the spirit ashes

The plants that are in the caves, allow to level up the spirit ashes.