An image of Lake Bled used as a background image for this website

Hello There.

Welcome, traveller to my personal website. Scroll down to learn everything there is to know about me.

Lake Bled, Slovenia

Bradley Camilleri (me)

An icon with the initials 'BC'
About Work Experience Education and Merits Portfolio

About Me

My name is Bradley Camilleri and I am a 19-year-old student currently reading for a Software Development degree at the University of Malta. Throughout my life, I have always been very passionate about all things technology and growing up, it would have been common to see me tinkering with a laptop or a computer. However, as years have passed, I have become more interested in the software that allows us to use the hardware we have in any way we’d like, which has led me to develop both web and desktop applications during my spare time. Through these applications, I feel that I have gained a better grasp of the thought processes needed in order to develop an algorithm and then code it in a programming language.

I recognise the importance of developing software as a team and I feel that I would be an asset to one as I am willing to collaborate, express my ideas and assist others too. Throughout my life, I have always been known as the IT guy which has led to many of my friends asking me the age-old question ‘Why is this not working and how do I fix it?’ This, along with the fact that I had previously worked as an IT support technician, helped me develop the skills needed to work in a team setting.

One last note is that I have taken an information security awareness course that covered the ISO27001:2013 standard. This course involveed the Information Security Management Systems (ISMS) a company should follow and abide by in order to safeguard their data and intellectual property.



You can contact me at camilleribrad (dot) business (at) gmail (dot) com. However, if we have already communicated through my personal email, feel free to use that to communicate with me.



Nationality: Maltese

Natural Languages: Maltese and English

Programming Languages: Java, Python, C#, JavaScript, TypeScript

Markup Languages: HTML, CSS

Databases: PostgreSQL, mySQL, MongoDB

JavaScript Frameworks: ReactJS, Angular, NodeJS

Cloud: Amazon Web Services, Azure

Work Experience

ICECAP's Logo

ICECAP

I.T. Intern

July 2023 - September 2023

Throughout the summer, I was an intern with the Electronic Systems Engineering department at the University of Malta and at that time, the department was mainly working on two projects - ICECAP and MEMENTO. I was placed within the ICECAP project with the task of developing a full-stack web application that would allow users of the medical transporter, being developed for this project, to see the status of the transporter and its payload online.

The desired system had to be developed from scratch meaning that I was responsible for developing an architecture that was reliable, stable and maintainable along with building a user interface that is appealing and easy to use. This included choosing the cloud service provider, database technology and how the services provided by the cloud service provider would be used within the application.
The cloud provider that I had chosen for this project was Amazon Web Services and, although it took some trial and error until I got used to it, I found it quite interesting to see the different services provided by AWS and how they are able to integrate so seamlessly with one another to provide a unified experience. By the end of the internship, I gained quite a bit of knowledge on some of the services provided by AWS including Lambda, Cognito, API Gateway and VPCs.

The internship lasted around three months and by the end of it, I had developed most of the functionality that was expected from me which was very rewarding considering the amount of work and research that had to be done to develop this system. Predicting the development timeline throughout the internship was aided by the fact that we had to set weekly and daily goals for ourselves which would help in keeping us aware of our final deliverable.
Throughout this internship, I was able to make use of the knowledge acquired from my first year of university - mainly those pertaining to databases, web development and networking. I also got to experience a part of the system analysis and design process - mainly the gathering of requirements, generation of specifications and system design, and development of a system.

Arkafort's Logo

arkafort

Technical Support Agent - Service Delivery

July 2021 - September 2022

Whether you are working as an IT Helpdesk agent or a Software Developer, one must be a quick thinker and be able to figure out the solution to a problem in the shortest time possible while, at times, being given very few clues as to what the problem may be.
For the software developer, I am referring to bugs that arise during the development of software and for the IT support technician, I am referring to clients that contact the department because something is not working. In both instances, the more downtime, the more money is lost.

While working as an IT support agent, I had the following responsibilities:

  • Follow policies and procedures to ensure that assistance was given in an appropriate and secure manner;
  • Have effective communication with clients along with different departments of the company whenever a problem required their input for resolution;
  • Attending to calls, emails and other forms of communication from clients and colleagues in a timely manner while abiding by KPIs;
  • Create documentation on the work that was done with clients or of new/existing workflows;
  • Accessing Active Directory and Exchange Online for the management of users including modification of user properties when certain details of a user had to be changed permanently. This also includes performing the necessary changes on the user’s machine to reflect these changes;
  • Assisting users via remote software or verbally over the telephone if the user was having connectivity issues;
  • First-time set up of user’s machines including logging in for the first time on a system and assisting the user in making sure all important applications work;
  • Installation of software on client machines and repair of software which is malfunctioning (both off-the-shelf software and proprietary software);
  • Having a very good understanding of the Windows and macOS operating systems, the Office365 suite, along with other proprietary software that was used by clients.

cancel
De La Salle's Logo

De La Salle College

Certificate of Merit

Scholastic Year 2018-2019 (Form 4)

  • First in VET IT
  • Second in ICT
  • Third in Mathematics

  • Achievement in: English, Computer Studies, English Literature, Maltese, Physics and Religion
No Certificate of Merit was given for scholastic year 2019-2020 (Form 5) due to the pandemic

Education and Merits

University of Malta's Logo

L-Università ta' Malta

B.Sc. IT (Hons) - Software Development

September 2022 - July 2025

De La Salle's Logo

De La Salle Sixth Form

September 2020 - June 2022

Matriculation Certificate Results, awarded by the University of Malta (MATSEC Department):

  • Advanced Computing: A
  • Advanced Pure Mathematics: A

  • Intermediate Psychology: B
  • Intermediate Physics: A
  • Intermediate English: C
  • Intermediate Systems of Knowledge: B

O-Level Results, awarded by the University of Malta (MATSEC Department):

  • Computer Studies - Level 3
  • English Language - Level 3
  • English Literature - Level 3
  • Italian - Level 3
  • Maltese - Level 3
  • Mathematics - Level 3
  • Physics - Level 3
  • Religious Knowledge - Level 3
  • VET IT - Grade 1

Due to the pandemic, a level was given from the mock examinations done at school except for VET IT where a continuous official assessment (from MATSEC) throughout the years was held and a grade was assigned based on those.

ECDL Standard Certification - Level 3
EQF level 3

cancel

Application Name

Programming Language: C#

Database: mySQL

The Bank of Java application was my first attempt at developing a full-stack application. I had developed other applications in the past, both during my free time and for school, but this was the first application I developed that used a GUI, backend and database.

The idea for the application came from a Java application that I had developed for a school project (also named Bank of Java). I kept the same feature set that was in the Java app (deposit, withdraw, statements and change password) and added some more (management of users, transferring money, first-time setup and an administrator account).
Ironically, the application is developed in C# and this was my first real go at developing an application using a programming language that is not Java. Luckily, since C# and Java are very similar, I did not find C# to be too difficult.

Developing this application made me realise that systems are made up of many different components and that the smaller the component, the better, as it allows you to reuse the component as many times as you’d like without needing to re-do the whole component just to make a couple of small changes to it.

It also made me realise the amount of work that goes into making a graphical application since every animation, button, label, and icon needs to be individually coded and it must also look good no matter what the device.

Programming Language: C#

Database: SQLite

Personally, I am an advocate of the fact that our personal information should be private and that no one has the right to access our data without our consent. Hence, I make use of Signal messenger, which is a messaging application that allows for end-to-end encrypted messaging.
Signal messenger allows you to take a local backup of your messages (since if something happens to one’s phone, one would lose all their messages since they are stored locally on one’s device). These backups are also encrypted with a code which you are given once the backup is complete. But, at one point while using the app, I came to the realisation that if the app were to no longer exist, I would not be able to view the messages in my backup file.

Hence, after finding out how to decrypt the backup (using signalbackup-tools by bepaald and tribut over on GitHub), I was able to develop an application in C# that took the database which holds all the messages in the backup and outputs them for the user to see, including images and replies.

The decrypter tool outputs all images, stickers and database files in one folder. Hence, in conjunction with this app, I also developed another application which aids the user in sorting all the data that comes out of the decrypted backup file. It does this by looking at the database file and sorting the images and stickers into folders according to the message thread they were sent in.

The following code is found within the companion app. Given the address of the user on the system along with where the images/stickers/etc… of that user should go, the application grabs each attachment sent (found in the main.parts table) and queries the main.mms table to check if the attachment was sent to the selected user. If so, the application searches the root directory to find the attachment and to store it in the folder the user specified.

                            
string stm = "SELECT \"mid\",\"unique_id\"  from \"main\".\"part\"";
string recipients = "SELECT \"_id\", \"system_display_name\", \"phone\" from \"main\".\"recipient\" where UUID is not NULL";

List<Recipient> recs = new List<Recipient>();
while (rd.Read())
{
    recs.Add(new Recipient() { DisplayName=rd.GetValue(1).ToString(), Phone=rd.GetValue(2).ToString(), ID=rd.GetInt32(0)});
}
rd.Close();
bool parsed = false;
do
{
    do
    {
        Console.WriteLine("Choose a recipient from the following list:");
        for (int i = 0; i < recs.Count; i++)
        {
            Console.WriteLine($"[{i}] {recs[i].DisplayName} - {recs[i].Phone}");
        }
        Console.WriteLine("Type -1 to stop.");
        parsed = Int32.TryParse(Console.ReadLine(), out addressGET);
    } while (!parsed);
    
    if (addressGET != -1)
    {
        if (parsed)
        {
            Console.WriteLine($"Enter the folder where you want to place the images for {recs[addressGET].DisplayName}: ");
            copyTo = "\\" + Console.ReadLine() + "\\";
        }

        cmd = new SQLiteCommand(stm, con);
        rd = cmd.ExecuteReader();

        string[] files = Directory.GetFiles(baseloc);
        string UID;
        int mid;
        string temp;
        FileInfo fi;
        SQLiteCommand cmd2;
        SQLiteDataReader rd2;
        if (conn2.State != System.Data.ConnectionState.Open) conn2.Open();
        string stm2;

        while (rd.Read())
        {
            mid = rd.GetInt32(0);
            UID = (string)rd.GetValue(1).ToString();

            stm2 = $"SELECT \"_id\",\"address\"  from \"main\".\"mms\" where address={recs[addressGET].ID} and _id={mid}";
            cmd2 = new SQLiteCommand(stm2, conn2);
            rd2 = cmd2.ExecuteReader();

            while (rd2.Read())
            {
                var tempArray = files.Where(f => f.Contains(UID)).ToArray();
                temp = tempArray.Length == 0?null :tempArray[0] ;

                if(temp != null)
                {
                    fi = new FileInfo(temp);
                    try
                    {
                        fi.MoveTo(baseloc + copyTo + fi.Name);
                    }
                    catch (FileNotFoundException) { }
                    Console.WriteLine("Moved Attachment: " + UID);
                }
            }
            rd2.Close();
        }
        rd.Close();
        Console.WriteLine("Finished!");
    }
} while (addressGET != -1);
con.Close();
conn2.Close();
                            
                        

Programming Language: Python

As the name suggests, this is a song guessing game. Given a set of locally stored music, it will randomly pick 3 songs and start to play one of them for a specific period of time. The player then has a set of tries to guess which song is playing from the three.

The music machine was my attempt at developing a game in Python and, in contrast to most of the applications in my portfolio, this application does not have a graphical UI, nor does it utilise a database. I had developed this game before I had even started sixth form meaning that the only language I had exposure to at the time was Java. In fact, one of the main reasons for this project was to experiment with the Python programming language.
This game was developed at a point when I was still very naïve to programming, and the source code reflected that. In fact, three years after I had finished the game, while I was in my first year of my software development course, I decided to revisit the project in order to apply the best practices and concepts that I had gained throughout those three years.
When the game was re-developed, I was able to see the effect and importance of modularisation since a program that was bound to one giant Python file, with barely any methods and classes (and lots of repetition), was split into many smaller classes and functions which allowed for code reuse and better understandability of code.

The idea of the game is simple in theory however, since the game uses the music files provided by the user it must include some extra logic to account for all the issues that can arise with the selection of files. This includes ensuring that there are at least 3 music files before starting the game (since the user has to choose the correct song from three options), that music files are not removed from the file system during runtime (otherwise the game won’t be able to find them and play them) and that the music file has the appropriate metadata (to get the song’s name and artist - otherwise the game allows the user to enter it manually).

Markup Languages: HTML, CSS

Programing Language: JavaScript

After developing the School Management System, I decided to give plain old JavaScript a try to see how it differs from a JavaScript framework, and it is here that I made another game, Tetris.

Although Tetris seems simple in theory, similar to the music game there is more to it than meets the eye. For example, I needed to make sure that the tetromino does not keep on going left or right if it meets a border or another tetromino, otherwise, it gets mangled. I also needed to make sure the tetromino does not keep going down once it hits the end of the grid or if it hits another tetromino. I also coded in ghost tetrominoes so that the player would know where the actual tetromino would land. These ghost tetrominoes are coded to imitate the x location of the actual tetromino but to go as far down the grid as possible.

Would you like to play a game of tetris? If so, click here!

The following code is used whenever a block needs to move one line down. It checks if any part of the tetromino has reached the far bottom or if it has reached another tetromino. It then hides the block and regenerates it in its new position (when the same tetromino is going down one line) or generates a new tetromino (when the previous tetromino can no longer keep on going down).
As can be seen, this method uses recursion. This is only done when the user wants to push the tetromino all the way down using the space bar.

                            
function pushBlockDownLogic(pushToBottom, doGameLogic){
    startingPoint+=10
    repeatLogic = true
    generateBlock = true
    
    for(gridNum of tetrisConfigurations[chosenTetrisBlock][tetrisBlockRotation]){
        
        //checking if the block is at the end of the grid
        if(gridNum+startingPoint>209) {
            generateBlock = false
            repeatLogic = false
            break
        }

        //checking if the block is hitting another block
        if(checkIfTetrisTouched(gridNum)) {
            repeatLogic = false
            break
        }
    }

    if(!pushToBottom){
        if(generateBlock){
            removeBlock()
            drawBlock()
            if(doGameLogic) gameLogic()
        }
        else{
            stopBlockAndGenerate()
        }
    }
    else{
        if(repeatLogic) pushBlockDownLogic(true)
        else{
            startingPoint-=10
            removeBlock()
            drawBlock(true)
            stopBlockAndGenerate()
        }
    }
}
                            
                        

The following code is used whenever a new block needs to be generated. It stops the function that pushes down the blocks at specific intervals and disables all keybinds temporarily until the new block is generated. The function also checks if there is a line of blocks.
Then, the function checks if the grid is able to take any more tetrominoes and if so, it generates a new block, otherwise, the game ends.

                            
function stopBlockAndGenerate(){
    clearLineMusicPlayed = false
    gameProgressAudio = new Audio(baseLocation + 'lock.mp3').play()
    clearInterval(pushBlockDown)
    document.removeEventListener('keydown', keyDownActions)

    currentTetris = Array.from(document.querySelectorAll('.active'))
    currentTetris.forEach(block => {
        block.classList.remove('active')
    })

    noClearLine = true
    for(let i=0; i<allGrids.length; i++){
        if(!allGrids[i].classList.contains('tetris-block')){
            noClearLine = false
        }
        if((i+1)%10 == 0 && noClearLine){
            clearLine(i-9)
            if(!clearLineMusicPlayed) gameProgressAudio = new Audio(baseLocation + 'line-clear.mp3').play()
            clearLineMusicPlayed = true
            noClearLine = true
        }
        else if ((i+1)%10 == 0){
            noClearLine = true
        }
    }

    if((startingPoint-10)<=9) {
        gameOver()
    }
    else{
        updateScore(10)
        generateNewTetris()
        for(gridNum of tetrisConfigurations[chosenTetrisBlock][tetrisBlockRotation]){
            generateBlock = checkIfTetrisTouched(gridNum)
            if(generateBlock) break
        }
        if(!generateBlock) gameLogic()
        else{
            gameOver()
        }
    }
}
                            
                        

If a line needs to be cleared, the score is increased and given the index of the first box in the line, the function removes all classes from the boxes in the line and removes them from the main container and from he array that has a reference to all grid boxes.
Then, it creates a new line of boxes and adds them to the array and to the top of the actual grid.

                            
function clearLine(lineStartNumber){
    updateScore(50)
    for(let j=lineStartNumber; j<lineStartNumber+10; j++){
        allGrids[j].classList.remove(...extraClasses)
        container.removeChild(allGrids[j])
    }
    allGrids.splice(lineStartNumber, 10)
    for(let k=0; k<10; k++){
        gridBox = document.createElement('div')
        gridBox.classList.add('grid-box')


        allGrids.splice(k+10, 0, gridBox)
        container.insertBefore(gridBox, container.children[k+10])
    }
}
                            
                        

Frontend

Markup Languages: HTML, CSS

JavaScript Framework: ReactJS, with ReduxJS to handle state data

Backend

JavaScript Framework: NodeJS, with ExpressJS for routing

Database: MongoDB

This was my first attempt at developing a full-stack web application. I was always interested in web apps and had always wanted to develop one but I did not know where to start. However, after a bit of research and experimentation, I set sail on my first web app, the (mini) School Management System.

At first, it was a very simple ReactJS application which allowed the user to input homework and it would be displayed on the page. Over time, I then started to add more features like a database, login system, different types of users (teacher/student/admin), administrative control and student groups. By the end of it, I had developed a very good grasp of JavaScript, CSS and HTML which are the three technologies that power most websites that exist.

As I was developing the application, I started to wonder how the web app keeps an authenticated user logged in and how the backend knows who called the API and how it ensures that requests are performed only by people with the necessary rights without having to authenticate themselves every time. It was at this point that I discovered the idea of tokens and how they can be used to represent an authenticated user.
Incorporating such a token in the frontend, to make sure that users do not gain access to restricted pages, was the most challenging since it involved redirecting the user to different pages depending on their access rights which, in turn, would re-run the token checking logic to ensure its valid for the redirected page. Hence, if not properly handled, the logic would result in infinite reloads and constant signouts.

Using MongoDB also made me realise that there are different ways a database can be stored and queried other than SQL. Personally, I enjoyed using MongoDB as it allowed me to see how to query data using something other than SQL and the mongoose API was very easy to use with NodeJS.

Frontend

Markup Languages: HTML, CSS

JavaScript Framework: Angular

Backend

JavaScript Framework: NodeJS, with ExpressJS for routing

Database: mySQL

After spending some time coding in ReactJS for the school management system, I decided to try out another JavaScript framework, Angular. It is here that I created my second web app, the Event Ticketing System.

One major leap forward that I managed to achieve with this system was cryptography. All other programs that I had developed until now stored passwords as plain text, which, I know, is extremely insecure. I had always been interested in cryptography and had intended to implement it in the School Management system however, at the time, I still did not understand what cryptography was exactly.
After dedicating some time to see how cryptography works, I managed to successfully store all user passwords securely in the system’s database. All passwords are hashed using SHA256 and all passwords have a salt added to them before they are hashed, rendering a rainbow table useless. Both the salt and hashed password are stored in the database and to log in, the front end sends the username and password to the backend and the backend gets the user’s salt by performing a query using their username, appends it to the password, hashes it and checks it against the hashed password in the database. If the hashed values match, the user is authenticated.

Speaking of databases, this application was developed before I started university and after the first year of my software development course, I redeveloped the mySQL database from the ground up for two reasons. First of which was to implement organisations within the system and secondly, to shift most of the database operations from the API (NodeJS) to the database itself.
Implementing organisations required a re-design of the database since this change also brought about the introduction of events and ticketholders and users’ access rights were now also bound to a specific organisation. Due to this change, all queries had to be re-designed anyway and thanks to the knowledge I acquired from my first databases unit, I implemented better queries through stored procedures and triggers within the database itself.

This system also has an aspect of logging to it since it keeps track of a ticket’s progress including when and who created a ticket, scanned a ticket, enabled/disabled a ticket and edited a ticket.

In this web app, I also managed to upload a file from the frontend to the backend. This is an Excel file that allows the user to import a large number of tickets in one go, instead of having to add every ticketholder one by one.

Markup Languages: HTML, CSS

Programming Languages: JavaScript

The website that you are currently on was made from the ground up by me. This is the first time I tried out a single-page website, where all the information is found on one long page.

It is also the first website where I put a lot of effort to make sure that it could be viewed properly on as many devices as possible (including mobile devices), in contrast to the School Management system app which was not optimised at all for mobile viewing.

The picture gallery visible in some of these application information boxes makes heavy use of JavaScript due to the carousel at the bottom that dynamically moves, the arrow key shortcuts (you can hit the left/right arrow keys to move between the images) and also for the logic that allows you to view an image by just clicking on it from the carousel, without needed to go through the images sequentially for it.

My Portfolio

Adjacent is a list of my personal projects.
Select an application to find out more.