From eacb62544711bcde8febb4a876d773620f19ba24 Mon Sep 17 00:00:00 2001 From: Welcome Date: Tue, 10 Feb 2026 14:11:55 +0200 Subject: [PATCH 01/21] Set up basic project structure --- index.html | 0 js/landing-page.js | 0 js/services/local-storage.js | 0 pages/main.html | 0 styles/landing-page.css | 0 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 index.html create mode 100644 js/landing-page.js create mode 100644 js/services/local-storage.js create mode 100644 pages/main.html create mode 100644 styles/landing-page.css diff --git a/index.html b/index.html new file mode 100644 index 0000000..e69de29 diff --git a/js/landing-page.js b/js/landing-page.js new file mode 100644 index 0000000..e69de29 diff --git a/js/services/local-storage.js b/js/services/local-storage.js new file mode 100644 index 0000000..e69de29 diff --git a/pages/main.html b/pages/main.html new file mode 100644 index 0000000..e69de29 diff --git a/styles/landing-page.css b/styles/landing-page.css new file mode 100644 index 0000000..e69de29 From 458e40340339d886cba4838c41e73a541a3aa012 Mon Sep 17 00:00:00 2001 From: Welcome Date: Tue, 10 Feb 2026 14:50:18 +0200 Subject: [PATCH 02/21] Created basic local storage service --- js/services/local-storage.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/js/services/local-storage.js b/js/services/local-storage.js index e69de29..e1b3771 100644 --- a/js/services/local-storage.js +++ b/js/services/local-storage.js @@ -0,0 +1,24 @@ +class LocalStorageService{ + constructor(){ + + } + + static createUser(username,password){ + let users=JSON.parse(localStorage.getItem('users'))||[]; + const user=new User(username,password); + users.push(user); + localStorage.setItem(JSON.stringify(users)); + } + + static createChat(userId1,userId2){ + let chats=JSON.parse(localStorage.getItem('chats')); + let chat=new Chat(userId1,userId2); + chats.push(chat); + localStorage.setItem(JSON.stringify(chats)); + } + + static createGroup(){ + + } + +} \ No newline at end of file From de29e6c780e5db9a42a297b6d1cd8686ebc5c4ab Mon Sep 17 00:00:00 2001 From: Welcome Date: Tue, 10 Feb 2026 15:25:49 +0200 Subject: [PATCH 03/21] Added basic user model --- js/landing-page.js | 8 ++++++++ js/models/user.js | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 js/models/user.js diff --git a/js/landing-page.js b/js/landing-page.js index e69de29..9d82986 100644 --- a/js/landing-page.js +++ b/js/landing-page.js @@ -0,0 +1,8 @@ +import User from "./models/user.js"; + +console.log("Hello"); + + +console.log(User.isUserNameUnique('galane')); + +console.log(User.generateUserId()); \ No newline at end of file diff --git a/js/models/user.js b/js/models/user.js new file mode 100644 index 0000000..183d1c0 --- /dev/null +++ b/js/models/user.js @@ -0,0 +1,23 @@ +import LocalStorageService from "../services/local-storage.js"; + +class User{ + constructor(username,password){ + + this.id=User.generateUserId(); + this.username=username; + this.password=password; + this.isLoggedIn=true; + this.lastSeen=Date.now(); + } + + static isUserNameUnique(username){ + let users=LocalStorageService.getUsers(); + return !(users.find(user=>user.username===username)); + } + + static generateUserId(){ + return LocalStorageService.getUsers().length+1; + } +} + +export default User; \ No newline at end of file From a8683a4c4951b336abef2e8c9d071218844a5500 Mon Sep 17 00:00:00 2001 From: Welcome Date: Tue, 10 Feb 2026 15:44:36 +0200 Subject: [PATCH 04/21] Added models for chat, and message --- index.html | 14 ++++++++++++++ js/landing-page.js | 8 -------- js/models/chat.js | 19 +++++++++++++++++++ js/models/group.js | 0 js/models/message.js | 9 +++++++++ js/services/local-storage.js | 9 ++++++++- 6 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 js/models/chat.js create mode 100644 js/models/group.js create mode 100644 js/models/message.js diff --git a/index.html b/index.html index e69de29..b6f5ea2 100644 --- a/index.html +++ b/index.html @@ -0,0 +1,14 @@ + + + + LocalChat + + + + + + + + + + \ No newline at end of file diff --git a/js/landing-page.js b/js/landing-page.js index 9d82986..e69de29 100644 --- a/js/landing-page.js +++ b/js/landing-page.js @@ -1,8 +0,0 @@ -import User from "./models/user.js"; - -console.log("Hello"); - - -console.log(User.isUserNameUnique('galane')); - -console.log(User.generateUserId()); \ No newline at end of file diff --git a/js/models/chat.js b/js/models/chat.js new file mode 100644 index 0000000..1456092 --- /dev/null +++ b/js/models/chat.js @@ -0,0 +1,19 @@ +class Chat{ + constructor(userId1,userId2){ + this.id=Chat.generateChatId(); + this.user1Typing=false; + this.user2Typing=false; + this.messages=[]; + } + + static generateChatId(userId1,userId2){ + if(userId1>userId2){ + return userId1+'-'+userId2; + } + else{ + return userId1+'-'+userId2; + } + } +} + +export default Chat; \ No newline at end of file diff --git a/js/models/group.js b/js/models/group.js new file mode 100644 index 0000000..e69de29 diff --git a/js/models/message.js b/js/models/message.js new file mode 100644 index 0000000..a3891e3 --- /dev/null +++ b/js/models/message.js @@ -0,0 +1,9 @@ +class Message{ + constructor(content,senderId,replyTo){ + this.id=Math.floor(Math.random()*99999); + this.content=content; + this.senderId=senderId; + this.replyTo=replyTo; + this.timestamp=Date.now(); + } +} \ No newline at end of file diff --git a/js/services/local-storage.js b/js/services/local-storage.js index e1b3771..735fb13 100644 --- a/js/services/local-storage.js +++ b/js/services/local-storage.js @@ -21,4 +21,11 @@ class LocalStorageService{ } -} \ No newline at end of file + static getUsers(){ + return JSON.parse(localStorage.getItem('users'))||[]; + } + +} + + +export default LocalStorageService; \ No newline at end of file From eae0b3793d7c16a3bd55916a17f62b92511dc1dc Mon Sep 17 00:00:00 2001 From: Welcome Date: Tue, 10 Feb 2026 16:27:06 +0200 Subject: [PATCH 05/21] Added session manager for log in and log out --- js/models/user.js | 4 ++-- js/services/local-storage.js | 4 ++-- js/services/session-manager.js | 37 ++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 js/services/session-manager.js diff --git a/js/models/user.js b/js/models/user.js index 183d1c0..62258b0 100644 --- a/js/models/user.js +++ b/js/models/user.js @@ -6,8 +6,8 @@ class User{ this.id=User.generateUserId(); this.username=username; this.password=password; - this.isLoggedIn=true; - this.lastSeen=Date.now(); + this.isLoggedIn=false; + this.isOnline=false; } static isUserNameUnique(username){ diff --git a/js/services/local-storage.js b/js/services/local-storage.js index 735fb13..4bed3e5 100644 --- a/js/services/local-storage.js +++ b/js/services/local-storage.js @@ -7,14 +7,14 @@ class LocalStorageService{ let users=JSON.parse(localStorage.getItem('users'))||[]; const user=new User(username,password); users.push(user); - localStorage.setItem(JSON.stringify(users)); + localStorage.setItem('users',JSON.stringify(users)); } static createChat(userId1,userId2){ let chats=JSON.parse(localStorage.getItem('chats')); let chat=new Chat(userId1,userId2); chats.push(chat); - localStorage.setItem(JSON.stringify(chats)); + localStorage.setItem('chats',JSON.stringify(chats)); } static createGroup(){ diff --git a/js/services/session-manager.js b/js/services/session-manager.js new file mode 100644 index 0000000..21d8efb --- /dev/null +++ b/js/services/session-manager.js @@ -0,0 +1,37 @@ +import LocalStorageService from "./local-storage.js"; + +class SessionManager{ + + static Login(username,password){ + let users=LocalStorageService.getUsers(); + user=users.find(user=>(user.username===username && user.password===password)); + if(user){ + user.isLoggedIn=true; + user.isOnline=true; + + sessionStorage.setItem('user',JSON.stringify(user)); + return user; + } + + return false; + } + + + static Logout(user){ + user.isLoggedIn=false; + user.isOnline=false; + sessionStorage.removeItem('user'); + } + + + static setTestValue(){ + sessionStorage.setItem('test','test value'); + } + + static getTestValue(){ + console.log(sessionStorage.getItem('test')); + } +} + + +export default SessionManager; \ No newline at end of file From 02314d39fcd72ad0027db666e4020ee8be997ae4 Mon Sep 17 00:00:00 2001 From: Welcome Date: Tue, 10 Feb 2026 21:09:37 +0200 Subject: [PATCH 06/21] added html for landing page --- index.html | 26 ++++++++++++++++++++++ js/landing-page.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/index.html b/index.html index b6f5ea2..5f36916 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,33 @@ LocalChat +
+
+
+ +

Welcome Back...

+

LocalChat is a local chat appYour data is stored securely in your own computer, no one but you will be able to access the data

+
+
+ + +
+ +
diff --git a/js/landing-page.js b/js/landing-page.js index e69de29..1b2c575 100644 --- a/js/landing-page.js +++ b/js/landing-page.js @@ -0,0 +1,54 @@ +let isSignIn=true; +const defaultHeading=document.getElementById('welcome-heading'); +const defaultQuestion=document.getElementById('toggle-question'); +const defaultView=document.getElementById('toggle-action'); +const defaultMessage=document.getElementById('welcome-message'); + + + +function toggleView(){ + let heading=document.getElementById('welcome-heading'); + let toggleQuestion=document.getElementById('toggle-question'); + let toggleView=document.getElementById('toggle-action'); + let toggleMessage=document.getElementById('welcome-message'); + let submitButton=document.getElementById('submit-button'); + + + + if(isSignIn){ + heading.textContent='Hey newbie...'; + toggleQuestion.textContent='Already have an account?'; + toggleMessage.textContent='LocalChat is a local chat appYour data is stored securely in your own computer, no one but you will be able to access the data.'; + toggleView.textContent="Sign In"; + submitButton.textContent='Sign Up'; + + } + else{ + heading.textContent='Welcome Back...'; + toggleQuestion.textContent='Don’t have an account?'; + toggleMessage.textContent='LocalChat is a local chat appYour data is stored securely in your own computer, no one but you will be able to access the data'; + toggleView.textContent='Sign Up'; + submitButton.textContent='Sign In'; + + } + + isSignIn=!isSignIn; + console.log('done'); +} + + + + + + + + + + + +function main(){ + console.log('Main method test'); + defaultView.addEventListener('click',()=>toggleView()); +} + +main(); \ No newline at end of file From 122ce4ec86b9459ed0057f37df7dbe51c6257de1 Mon Sep 17 00:00:00 2001 From: Welcome Date: Wed, 11 Feb 2026 09:24:43 +0200 Subject: [PATCH 07/21] Implemented auth functionality --- js/landing-page.js | 49 +++++++++++++++++++++++++++------- js/services/local-storage.js | 2 ++ js/services/session-manager.js | 18 ++++++++----- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/js/landing-page.js b/js/landing-page.js index 1b2c575..b0b902b 100644 --- a/js/landing-page.js +++ b/js/landing-page.js @@ -1,9 +1,12 @@ -let isSignIn=true; -const defaultHeading=document.getElementById('welcome-heading'); -const defaultQuestion=document.getElementById('toggle-question'); -const defaultView=document.getElementById('toggle-action'); -const defaultMessage=document.getElementById('welcome-message'); +import LocalStorageService from "./services/local-storage.js"; +import SessionManager from "./services/session-manager.js"; +import User from "./models/user.js"; + +console.log(LocalStorageService.getUsers()); +let isSignUp=true; +const defaultView=document.getElementById('toggle-action'); +let authButton=document.getElementById('submit-button'); function toggleView(){ @@ -15,10 +18,10 @@ function toggleView(){ - if(isSignIn){ + if(isSignUp){ heading.textContent='Hey newbie...'; toggleQuestion.textContent='Already have an account?'; - toggleMessage.textContent='LocalChat is a local chat appYour data is stored securely in your own computer, no one but you will be able to access the data.'; + toggleMessage.textContent='LocalChat is a local chat app.\nYour data is stored securely in your own computer, no one but you will be able to access the data.'; toggleView.textContent="Sign In"; submitButton.textContent='Sign Up'; @@ -26,17 +29,44 @@ function toggleView(){ else{ heading.textContent='Welcome Back...'; toggleQuestion.textContent='Don’t have an account?'; - toggleMessage.textContent='LocalChat is a local chat appYour data is stored securely in your own computer, no one but you will be able to access the data'; + toggleMessage.textContent='LocalChat is a local chat app.\nYour data is stored securely in your own computer, no one but you will be able to access the data.'; toggleView.textContent='Sign Up'; submitButton.textContent='Sign In'; } - isSignIn=!isSignIn; + isSignUp=!isSignUp; console.log('done'); } +function authenticate(){ + let username=document.getElementById('username-input').value; + let password=document.getElementById('password-input').value; + if(!isSignUp){ + if(User.isUserNameUnique(username)){ + //Create an account + LocalStorageService.createUser(username,password); + console.log(LocalStorageService.getUsers()); + } + else{ + alert('Please enter a new username, make it unique'); + return; + } + } + //Login + let user=SessionManager.login(username,password); + console.log(user); + if(user){ + console.log('logged in as '+ user.username); + //Navigate to the main page + } + else{ + alert('Login failed, ensure you have entered correct credentials'); + return; + } +} + @@ -49,6 +79,7 @@ function toggleView(){ function main(){ console.log('Main method test'); defaultView.addEventListener('click',()=>toggleView()); + authButton.addEventListener('click', ()=>authenticate()); } main(); \ No newline at end of file diff --git a/js/services/local-storage.js b/js/services/local-storage.js index 4bed3e5..93b26c5 100644 --- a/js/services/local-storage.js +++ b/js/services/local-storage.js @@ -1,3 +1,4 @@ +import User from "../models/user.js"; class LocalStorageService{ constructor(){ @@ -22,6 +23,7 @@ class LocalStorageService{ } static getUsers(){ + console.log(JSON.parse(localStorage.getItem('users'))) return JSON.parse(localStorage.getItem('users'))||[]; } diff --git a/js/services/session-manager.js b/js/services/session-manager.js index 21d8efb..cdb16a1 100644 --- a/js/services/session-manager.js +++ b/js/services/session-manager.js @@ -1,14 +1,20 @@ import LocalStorageService from "./local-storage.js"; +import User from "../models/user.js"; class SessionManager{ - static Login(username,password){ + static login(username,password){ let users=LocalStorageService.getUsers(); - user=users.find(user=>(user.username===username && user.password===password)); + let user=users.find(user=>(user.username===username && user.password===password)); if(user){ - user.isLoggedIn=true; - user.isOnline=true; - + for(let i=0;i Date: Wed, 11 Feb 2026 10:09:18 +0200 Subject: [PATCH 08/21] added redirect to main page after login --- js/landing-page.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/landing-page.js b/js/landing-page.js index b0b902b..2d1e1ac 100644 --- a/js/landing-page.js +++ b/js/landing-page.js @@ -60,6 +60,7 @@ function authenticate(){ if(user){ console.log('logged in as '+ user.username); //Navigate to the main page + window.location.replace('./pages/main.html'); } else{ alert('Login failed, ensure you have entered correct credentials'); From b39f1074f3410ba9dbbfd86058a918daee4b7281 Mon Sep 17 00:00:00 2001 From: Welcome Date: Wed, 11 Feb 2026 11:45:25 +0200 Subject: [PATCH 09/21] Added users list and open chat functionality to main page --- index.html | 2 +- js/main-page.js | 75 ++++++++++++++++++++++++++++++++++ js/services/local-storage.js | 5 ++- js/services/session-manager.js | 4 ++ pages/main.html | 69 +++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 js/main-page.js diff --git a/index.html b/index.html index 5f36916..9ffe829 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ - LocalChat + Authenticate | LocalChat
diff --git a/js/main-page.js b/js/main-page.js new file mode 100644 index 0000000..61a6038 --- /dev/null +++ b/js/main-page.js @@ -0,0 +1,75 @@ +import LocalStorageService from "./services/local-storage.js"; +import SessionManager from "./services/session-manager.js"; +import Chat from "./models/chat.js"; + +console.log('Logged in user is '+JSON.parse(sessionStorage.getItem('user')).username); + +function populateUsersList(show='all'){ + let users=LocalStorageService.getUsers(); + let currentUserId=SessionManager.getUser().id; + + console.log('Users are '+users); + let userList=document.getElementById('users-list'); + + + for(let i=0;iopenChat(currentUserId,users[i].id)); + + //Append tile elements to the tile/list item + userTile.append(userProfilePicture); + userTile.append(username); + userTile.append(lastMessage); + + //Append the tile/list item to the list; + userList.append(userTile); + + console.warn('Added user: '+users[i].username); + + + } +} + +function openChat(userId1,userId2){ + let allChats=LocalStorageService.getChats(); + let chatId=Chat.generateChatId(userId1,userId2); + let currentChat=allChats?.find(chat=>chat.id===chatId); + let chatsList=document.createElement('ul'); + let messagesBox=document.getElementById('messages-box'); + let messagesCount=currentChat?.messages?.length; + + for(let i=0;i0?messagesBox.innerHTML=chatsList + : messagesBox.innerHTML='

No messages yet

'; + +} + + + +function main(){ + populateUsersList(); +} + +main(); \ No newline at end of file diff --git a/js/services/local-storage.js b/js/services/local-storage.js index 93b26c5..672d2ec 100644 --- a/js/services/local-storage.js +++ b/js/services/local-storage.js @@ -23,10 +23,13 @@ class LocalStorageService{ } static getUsers(){ - console.log(JSON.parse(localStorage.getItem('users'))) return JSON.parse(localStorage.getItem('users'))||[]; } + static getChats(){ + return JSON.parse(localStorage.getItem('chats'))||[]; + } + } diff --git a/js/services/session-manager.js b/js/services/session-manager.js index cdb16a1..76b7b05 100644 --- a/js/services/session-manager.js +++ b/js/services/session-manager.js @@ -29,6 +29,10 @@ class SessionManager{ sessionStorage.removeItem('user'); } + static getUser(){ + return JSON.parse(sessionStorage.getItem('user')); + } + static setTestValue(){ sessionStorage.setItem('test','test value'); diff --git a/pages/main.html b/pages/main.html index e69de29..f466aad 100644 --- a/pages/main.html +++ b/pages/main.html @@ -0,0 +1,69 @@ + + + + Main | LocalChat + + +
+ +
+ + + +
+
+ chatee profile picture +

+

+
+ +
+ +
+ +
+ + send-icon +
+ +
+ + + + + + + + \ No newline at end of file From a35bc7dacb33a42c7581eb96d5d6c8035ad56f26 Mon Sep 17 00:00:00 2001 From: Welcome Date: Wed, 11 Feb 2026 12:37:46 +0200 Subject: [PATCH 10/21] Added send message functionality --- js/main-page.js | 10 ++++++++++ js/models/chat.js | 4 ++-- js/models/message.js | 9 ++++++--- js/services/local-storage.js | 26 ++++++++++++++++++++++++++ js/services/session-manager.js | 1 + 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/js/main-page.js b/js/main-page.js index 61a6038..01ba908 100644 --- a/js/main-page.js +++ b/js/main-page.js @@ -46,6 +46,9 @@ function openChat(userId1,userId2){ let chatsList=document.createElement('ul'); let messagesBox=document.getElementById('messages-box'); let messagesCount=currentChat?.messages?.length; + let sendIcon=document.getElementById('message-send'); + + sendIcon.addEventListener('click',()=>sendMessage(chatId)); for(let i=0;ichat.id===chatId); + if(!currentChat){ + console.log('Creating chat'); + currentChat=new Chat(chatId); + chats.push(currentChat); + } + + console.log('Chat created :'+currentChat.id); + currentChat.messages.push(message); + + for(let i=0;i Date: Wed, 11 Feb 2026 13:13:08 +0200 Subject: [PATCH 11/21] Implemented show hide for messages --- js/main-page.js | 24 +++++++++++++++++------- js/services/local-storage.js | 1 - pages/main.html | 4 +++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/js/main-page.js b/js/main-page.js index 01ba908..809ab0f 100644 --- a/js/main-page.js +++ b/js/main-page.js @@ -43,29 +43,39 @@ function openChat(userId1,userId2){ let allChats=LocalStorageService.getChats(); let chatId=Chat.generateChatId(userId1,userId2); let currentChat=allChats?.find(chat=>chat.id===chatId); - let chatsList=document.createElement('ul'); + let chatsList=document.getElementById('chats-list'); let messagesBox=document.getElementById('messages-box'); let messagesCount=currentChat?.messages?.length; let sendIcon=document.getElementById('message-send'); + let noMessages=document.getElementById('no-messages'); sendIcon.addEventListener('click',()=>sendMessage(chatId)); + if(messagesCount>0){ + noMessages.style.display='none'; + chatsList.style.display='inline'; + } + else{ + chatsList.style.display='none'; + noMessages.style.display='inline'; + } + for(let i=0;i0?messagesBox.innerHTML=chatsList - : messagesBox.innerHTML='

No messages yet

'; + } diff --git a/js/services/local-storage.js b/js/services/local-storage.js index f5529a5..ee15871 100644 --- a/js/services/local-storage.js +++ b/js/services/local-storage.js @@ -30,7 +30,6 @@ class LocalStorageService{ chats.push(currentChat); } - console.log('Chat created :'+currentChat.id); currentChat.messages.push(message); for(let i=0;i
From 585ad2d3f099e5e2786d8efb610dfd8faf9c1f4a Mon Sep 17 00:00:00 2001 From: Welcome Date: Wed, 11 Feb 2026 13:51:06 +0200 Subject: [PATCH 12/21] Basic HTML structure complete --- js/main-page.js | 10 +++++++++- pages/main.html | 26 +++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/js/main-page.js b/js/main-page.js index 809ab0f..6100e7a 100644 --- a/js/main-page.js +++ b/js/main-page.js @@ -81,9 +81,17 @@ function openChat(userId1,userId2){ function sendMessage(chatId,replyTo='none'){ let messageInput=document.getElementById('message-text').value; - LocalStorageService.sendMessage(chatId,messageInput,replyTo); +} +function displayUserProfile(userId){ + if(userId===SessionManager.getUser().id){ + //The current user's profile + } + else{ + //Show the chatee profile + + } } diff --git a/pages/main.html b/pages/main.html index bfade1e..7b73fdb 100644 --- a/pages/main.html +++ b/pages/main.html @@ -41,7 +41,7 @@
chatee profile picture -

+

@@ -59,8 +59,28 @@
From 5037d41699abf9c3cb010fced0ffa0a2701d3188 Mon Sep 17 00:00:00 2001 From: Welcome Date: Wed, 11 Feb 2026 14:37:55 +0200 Subject: [PATCH 13/21] Added user search --- js/main-page.js | 38 +++++++++++++++++++++++++++++++++----- pages/main.html | 2 ++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/js/main-page.js b/js/main-page.js index 6100e7a..313f167 100644 --- a/js/main-page.js +++ b/js/main-page.js @@ -4,12 +4,26 @@ import Chat from "./models/chat.js"; console.log('Logged in user is '+JSON.parse(sessionStorage.getItem('user')).username); -function populateUsersList(show='all'){ - let users=LocalStorageService.getUsers(); +function populateUsersList(users){ + //First of most, clear list + let userList=document.getElementById('users-list'); + let noUsersText=document.getElementById('no-users'); + userList.innerHTML=''; + + + if(users.length===0){ + userList.style.display='none'; + noUsersText.style.display='block'; + } + else{ + userList.style.display='block'; + noUsersText.style.display='none'; + } + + let currentUserId=SessionManager.getUser().id; console.log('Users are '+users); - let userList=document.getElementById('users-list'); for(let i=0;iuser.username.toLowerCase().includes(textToSearch)); + console.error(usersToReturn); + + populateUsersList(usersToReturn); +} + + function main(){ - populateUsersList(); + let searchIcon=document.getElementById('search-icon'); + searchIcon.addEventListener('click',()=>searchUsers()); + + populateUsersList(LocalStorageService.getUsers()); } main(); \ No newline at end of file diff --git a/pages/main.html b/pages/main.html index 7b73fdb..9d2b899 100644 --- a/pages/main.html +++ b/pages/main.html @@ -34,6 +34,8 @@
+ +

No users found

From 21c5ecf0f87fe16734ca349871f9e184b3447384 Mon Sep 17 00:00:00 2001 From: Welcome Date: Wed, 11 Feb 2026 14:55:35 +0200 Subject: [PATCH 14/21] Added online offline checks --- js/main-page.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/js/main-page.js b/js/main-page.js index 313f167..0670169 100644 --- a/js/main-page.js +++ b/js/main-page.js @@ -31,6 +31,18 @@ function populateUsersList(users){ let userProfilePicture=document.createElement('img'); let username=document.createElement('h3'); let lastMessage=document.createElement('p'); + let onlineBadge=document.createElement('p'); + + + onlineBadge.textContent='⦿'; + onlineBadge.style.color='red'; + + if(users[i].isOnline===true){ + onlineBadge.style.display='inline'; + } + else{ + onlineBadge.style.display='none'; + } userProfilePicture.src=users[i].profilePicture||'../assets/images/profile-icon.png'; username.textContent=users[i].username; @@ -43,6 +55,7 @@ function populateUsersList(users){ userTile.append(userProfilePicture); userTile.append(username); userTile.append(lastMessage); + userTile.append(onlineBadge); //Append the tile/list item to the list; userList.append(userTile); @@ -119,6 +132,12 @@ function searchUsers(){ populateUsersList(usersToReturn); } +function applyFilters(){ + //This is a nice to have, implement if there's time +} + + + function main(){ From 52f3b69f9e929794f9767a079f451355acb15f62 Mon Sep 17 00:00:00 2001 From: Welcome Date: Wed, 11 Feb 2026 15:37:26 +0200 Subject: [PATCH 15/21] Implemented edit profile functionality --- js/main-page.js | 25 +++++++++++++++++++++++-- js/models/user.js | 1 + js/services/local-storage.js | 25 +++++++++++++++++++++++++ pages/main.html | 3 ++- 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/js/main-page.js b/js/main-page.js index 0670169..bac4d2f 100644 --- a/js/main-page.js +++ b/js/main-page.js @@ -70,11 +70,25 @@ function openChat(userId1,userId2){ let allChats=LocalStorageService.getChats(); let chatId=Chat.generateChatId(userId1,userId2); let currentChat=allChats?.find(chat=>chat.id===chatId); + let chatee=LocalStorageService.getUser(userId2); let chatsList=document.getElementById('chats-list'); let messagesBox=document.getElementById('messages-box'); let messagesCount=currentChat?.messages?.length; let sendIcon=document.getElementById('message-send'); let noMessages=document.getElementById('no-messages'); + let chateeName=document.getElementById('chatee-name'); + let chateeStatus=document.getElementById('chatee-status'); + + chateeName.textContent=chatee.username; + + + //Display online/offline status + if(chatee.isOnline){ + chateeStatus.textContent='Online'; + } + else{ + chateeStatus.textContent='Offline'; + } sendIcon.addEventListener('click',()=>sendMessage(chatId)); @@ -122,6 +136,7 @@ function displayUserProfile(userId){ } + function searchUsers(){ let users=LocalStorageService.getUsers(); let textToSearch=document.getElementById('search-text').value; @@ -136,14 +151,20 @@ function applyFilters(){ //This is a nice to have, implement if there's time } - - +function updateProfile(){ + let username=document.getElementById('username-input').value; + let password=document.getElementById('password-input').value; + LocalStorageService.updateProfile(username,password); +} function main(){ let searchIcon=document.getElementById('search-icon'); searchIcon.addEventListener('click',()=>searchUsers()); + let saveEdits=document.getElementById('save-edits'); + saveEdits.addEventListener('click',()=>updateProfile()); + populateUsersList(LocalStorageService.getUsers()); } diff --git a/js/models/user.js b/js/models/user.js index 62258b0..4d79e3a 100644 --- a/js/models/user.js +++ b/js/models/user.js @@ -8,6 +8,7 @@ class User{ this.password=password; this.isLoggedIn=false; this.isOnline=false; + this.lastSeen=Date.now(); } static isUserNameUnique(username){ diff --git a/js/services/local-storage.js b/js/services/local-storage.js index ee15871..97ed4da 100644 --- a/js/services/local-storage.js +++ b/js/services/local-storage.js @@ -1,6 +1,7 @@ import Message from "../models/message.js"; import User from "../models/user.js"; import Chat from "../models/chat.js"; +import SessionManager from "./session-manager.js"; class LocalStorageService{ constructor(){ @@ -55,6 +56,30 @@ class LocalStorageService{ return JSON.parse(localStorage.getItem('chats'))||[]; } + static getUser(userId){ + let users=LocalStorageService.getUsers(); + return users.find(user=>user.id===userId); + } + + + static updateProfile(username,password){ + let users=LocalStorageService.getUsers(); + let user=SessionManager.getUser(); + + if(user){ + for(let i=0;iProfile - + + From 01b313fbc3d62337a2b181eaca0b6dbd549ccf2b Mon Sep 17 00:00:00 2001 From: Welcome Date: Wed, 11 Feb 2026 15:46:37 +0200 Subject: [PATCH 16/21] implemented logout functionality --- js/main-page.js | 3 +++ js/services/session-manager.js | 19 ++++++++++++++++--- pages/main.html | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/js/main-page.js b/js/main-page.js index bac4d2f..2db2d16 100644 --- a/js/main-page.js +++ b/js/main-page.js @@ -165,6 +165,9 @@ function main(){ let saveEdits=document.getElementById('save-edits'); saveEdits.addEventListener('click',()=>updateProfile()); + let logout=document.getElementById('logout'); + logout.addEventListener('click',()=>SessionManager.logout()); + populateUsersList(LocalStorageService.getUsers()); } diff --git a/js/services/session-manager.js b/js/services/session-manager.js index a650550..e33654c 100644 --- a/js/services/session-manager.js +++ b/js/services/session-manager.js @@ -24,10 +24,23 @@ class SessionManager{ } - static logout(user){ - user.isLoggedIn=false; - user.isOnline=false; + static logout(){ + let users=LocalStorageService.getUsers(); + let user=SessionManager.getUser(); + + if(user){ + for(let i=0;iProfile - + From 45d1e4d0cae43971028b2322770fc9569601bd47 Mon Sep 17 00:00:00 2001 From: Welcome Date: Wed, 11 Feb 2026 16:06:19 +0200 Subject: [PATCH 17/21] implemented user side profile --- js/main-page.js | 6 +++++- pages/main.html | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/js/main-page.js b/js/main-page.js index 2db2d16..87436ec 100644 --- a/js/main-page.js +++ b/js/main-page.js @@ -5,7 +5,6 @@ import Chat from "./models/chat.js"; console.log('Logged in user is '+JSON.parse(sessionStorage.getItem('user')).username); function populateUsersList(users){ - //First of most, clear list let userList=document.getElementById('users-list'); let noUsersText=document.getElementById('no-users'); userList.innerHTML=''; @@ -78,16 +77,21 @@ function openChat(userId1,userId2){ let noMessages=document.getElementById('no-messages'); let chateeName=document.getElementById('chatee-name'); let chateeStatus=document.getElementById('chatee-status'); + let chateeSideName=document.getElementById('chatee-side-name'); + let chateeSideStatus=document.getElementById('chatee-side-status'); chateeName.textContent=chatee.username; + chateeSideName.textContent=chatee.username; //Display online/offline status if(chatee.isOnline){ chateeStatus.textContent='Online'; + chateeSideStatus.textContent='Online'; } else{ chateeStatus.textContent='Offline'; + chateeSideStatus.textContent='Offline'; } sendIcon.addEventListener('click',()=>sendMessage(chatId)); diff --git a/pages/main.html b/pages/main.html index 2deabce..3cebc01 100644 --- a/pages/main.html +++ b/pages/main.html @@ -80,8 +80,8 @@

Profile

-

-

+

+

From b301a61527f803fa4abbca2e970f6de9e5c69c54 Mon Sep 17 00:00:00 2001 From: Welcome Date: Thu, 12 Feb 2026 11:00:14 +0200 Subject: [PATCH 18/21] added groups --- assets/images/logo.png | Bin 0 -> 18197 bytes index.html | 17 ++-- js/landing-page.js | 4 +- js/main-page.js | 163 ++++++++++++++++++++++++++--------- js/models/group.js | 10 +++ js/models/message.js | 2 +- js/services/local-storage.js | 24 +++++- pages/main.html | 5 +- styles/landing-page.css | 112 ++++++++++++++++++++++++ 9 files changed, 282 insertions(+), 55 deletions(-) create mode 100644 assets/images/logo.png diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e084b2a06e46a24db0d928d1da69180a9c7f287c GIT binary patch literal 18197 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 literal 0 HcmV?d00001 diff --git a/index.html b/index.html index 9ffe829..3f3212b 100644 --- a/index.html +++ b/index.html @@ -2,21 +2,24 @@ Authenticate | LocalChat + +
-
-
- +
+
+ logo image

Welcome Back...

-

LocalChat is a local chat appYour data is stored securely in your own computer, no one but you will be able to access the data

+

LocalChat is a local chat app
+ Your data is stored securely in your own
computer, no one but you will be able to access the data

-
diff --git a/styles/landing-page.css b/styles/landing-page.css index e69de29..bfe13d7 100644 --- a/styles/landing-page.css +++ b/styles/landing-page.css @@ -0,0 +1,112 @@ +*{ + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; +} + +main{ + display: flex; + height: 100dvh; +} + +article{ + flex: 2; + display: flex; + flex-direction: column; + justify-content: center; + background-color: #ff383c; + color: white; + border-top-right-radius: 20px; + border-bottom-right-radius: 20px; + padding-top: 3%; + padding-left:2%; +} + +aside{ + flex: 1; + display: flex; + justify-content: center; + margin-top: 15%; + padding: 8px; + height: fit-content; +} + +#logo-image{ + width: 30%; + margin-bottom: 50px; +} + + +#welcome-heading{ + font-size: 3rem; + margin-bottom: 30px; +} + +#welcome-message{ + font-size: 1rem; +} + +#text-logo{ + font-size: 35px; + margin-bottom: 100px; +} + +#text-logo span{ + color:#ff383c +} + +input{ + display: block; + margin-bottom: 40px; + width: 100%; + height: 30px; + border: #d9d9d9 solid 1px; + border-radius: 6px; + background-color: #ffffff; + padding-left: 10px; +} + +button{ + display: block; + width: 100%; + background-color: #2c2c2c; + border: 6px solid #2c2c2c; + color: white; + margin-bottom: 60px; + height:40px; + border-radius: 6px; +} + + +#toggle-question{ + display: inline; + font-weight: bold; +} + +#toggle-action{ + display: inline; + color:#ff383c; + font-weight: bold; +} + +#landing-form{ + width: 55%; + text-align: center; +} + + + +@media (max-width:600px) { + article{ + display: none; + } + aside{ + flex: 1; + display: flex; + justify-content: center; + margin-top: 45%; + padding: 8px; + height: fit-content; +} + +} \ No newline at end of file From 0f13d7e80b3333c9dfe0d8d11dd1d30488ab5b25 Mon Sep 17 00:00:00 2001 From: Welcome Date: Thu, 12 Feb 2026 13:13:33 +0200 Subject: [PATCH 19/21] Added nav section styling --- assets/images/icons/add.png | Bin 0 -> 3849 bytes assets/images/icons/image.png | Bin 0 -> 15618 bytes assets/images/icons/profile.png | Bin 0 -> 1107 bytes assets/images/icons/search.png | Bin 0 -> 897 bytes assets/images/icons/user.png | Bin 0 -> 17531 bytes js/main-page.js | 8 +- pages/main.html | 16 ++-- styles/main-page.css | 155 ++++++++++++++++++++++++++++++++ 8 files changed, 169 insertions(+), 10 deletions(-) create mode 100644 assets/images/icons/add.png create mode 100644 assets/images/icons/image.png create mode 100644 assets/images/icons/profile.png create mode 100644 assets/images/icons/search.png create mode 100644 assets/images/icons/user.png create mode 100644 styles/main-page.css diff --git a/assets/images/icons/add.png b/assets/images/icons/add.png new file mode 100644 index 0000000000000000000000000000000000000000..dc1d6d01a27590969aacc3e67aa66a5eb2b4563f GIT binary patch literal 3849 zcmeHKX;4#H7Cs?tfzQt<{;YprqBu^pkuf)k>Tr5$2LL0Vdx!#DA<$q|PVqZ|@gG3Ar=)mn5u>a%T6 zdd0h!d#_cb*ob6f6z?ZN%Z>7AztkbFR*z0Lg?T5QaT6J@&C9$>%N#3yanenc9+lU7 zxWG8icv6>osCk9?wWMXm=0#LQbaKa!&THcCmfBuF)x*Cs-Q`(1HjSz+D{n3gp%P7H z+ECeEqZ{L?v_`sk5^2UNE)my|7u>9cudr5(UP`Eu8KiNuc->7~3vhR~M3j551=KVl z>17GQE7K)|Q>z0i??k$zC#*GZQ=G*9=)tWIMgUwTgMO~+?PWtEVei~fkx&l`q+Te$ z?S{4H$%G6E=_J}9cdY*c(O&jaB+Pv0;iC1muG+qlIufVeFrh#kt!6_>xkwDs=sA+0 zwFp#G)RTZiLlnbSS(8GO{7m9n!%t_G6`IW0?%Y-rs26n1ma8%+F5WA&1*6LHftIHU zS0}`Xqs=%2a=+}0QgvqkV`AdLpdLJaow7=8qpoT+rDl9wGouR@${f+~Q@7?8&o(a- zP#xNc2kD}r$8OE0(Q@a9c*QOUFfLU-D=A;TKUR~xpog9Wc1M^2rRP*ZK#(uMS8GWCCv}$$OZTyq z4*%oVu}m~TG-Vhz6aOlPlzV8flvszV?>w>V@1UvqNVp$sly*u7@@IT7Gpcg(Pc0eiYIGLM zC>sB5ryYzwGv;O4i}`+v$&r0i%kej8&N(8^o?)piu4za{2*#mISQlD?wyb_3wyvgI zfYY63-W@8hWCf$Omap|B*3)z4fV;=t_2NLRqM_H4`_a6`3l&g~dHp#4-7NLnuA{5>=lg(smBto?D%p%p0@}nJ43)DcRT=p6Z*|`OjjYv%(Op z2B%#z{wQhP;6};Tm!zOMtES!?z?tzxtdFMjmuqTtWXaTm~jI^V~>QvBa*f zHcej_0s>B9VWq^YViV0mt&)s?zrTwhFR0o2Ob%AUbu|U24Z=YAcUKTkj82z30WOt> z1+X6V2Lo(Q8DL?%TlqRr`s3~ro^&At4EFB8lT^NC(0VfEq9f$5$`&4|UwvDvcp1Xc1HaXD|$ z1rGu|QHyV&L`(%}Kd zl+hEz`!ZvoFf{?IK{9f%zE)3t9h~l7LF`9|$_V~h_2X!rHDwh6x2a;TOQY}mVj0OB zobtD$@c}G<%#o%Xi_V$#v3oStL1g4#<%MPC35_9ixCL>Glq(jvM?aSMO>a?Wpbp){ z*Y^&TWj%a9P*$Z?b*1eD<$>cgcfx`1y1r z7=2+9VV0;Puw#RkzE@r%m?F*=;lRhESY?mUQ`-y9uHtMTmd+_YeF-xBvF)ok!NcQU zo+q$vlgr@q>9YmG+Js}-DVOH~-d6AkS%I*z=9X=s{MX}?WccC3WP$Kr%`Jhgbewd# zpI;yp+r=L6lq8YAst@L==pzY=t9@~3gGu@z1SPPsW*2ppur4PlQX4(9I)>4uJ9vR8 zIL`e8xc{r6fbEahm(i&tD3JWrp`hk*qvYS|0yENamt47gzL9ha%i7GFK>$YEuDT5T z^HS#rSM>=rei!S_axNMA^D0qBQDk^Si)^@@7(r7z(o>oG7euz&CakTFfpwl@fgj`R yS*dF33fllvZ4#eA74`$=L?OcM$_!$rs>vCV`GTWkJv8mN70?|4J_2uM-oF9UACIU1!ajSiz1F|x{O3RC zdM5uJkGNRO2g?`U(z^2K-RSlt9>vG!^tq2C>pMR zpB>jeUl3fe~@es>fG6Ae-n%h-v1qhQN8{T1U2%CjZ>&8>P&^Mo8=_Dc`7rhh z;>f#;|y_qRW5Dc zWyI#uD2gWIIKJzbGs72p)lgpe@QZrw0XO^1(f4`@dol{cdn(K4@};ZaCc1nd#{9#C z zqDX&g0ygM0H3gqIF+v>HFghFhj;x$}1>$6<)47{p!to0Qu(-VZmh52PG1E`oLwzG3 zRhQ{5pQpZXhVtqf?W1YsZx&0*U^f-yUWp>sJ496d>?=Z9vS7yP+P|AYI0#jv(cs-*@Uq{w^Ji*Ow(yD(CPFnD*hgb zI9bBbpc90;-T^blG{ChTl71F1J3-{^AP7wA)gqOZbJUieLuN~C=t4b@?gpXZ0ValF zY&HR??@Yvm_qM8~`m_0tsITOqEsufzIKVl z`4dcCd4{Ex4T{x(+RAAvi^r&ym$*7J!xtYo#-DxqEdS;|JH`RM15^T2bfOs-`p1$nww3KWb&x1g~Ebh{l{YIl<- z=^dg7LzZmXo;cLbTb6Zi7j3FMajy)#>9DS7s@$&QmF^ z(5V%*%35h(TsL$LM&AKCRzF>QT5`*J$D|nzP;C{ccl()Ij``#_FYt%|@eBOHzyCb< z{_W#DbfwC&m0)pwgG#f_nj&nc9TLb&yUjWc!)7*sZ#{pJzq#*mKKh08oSUu?#r9^T z4r7yst}Cxh(XOr_FIF>ppy47U5@QHi>(ZurPiKDZZ zo;tjI^?BCMe1nzeKF{j8Z&93nj`Gq;D$6J2LLRo8#ZBhO=0-GV1H*KP+)+X^M~i-* zI3M#TpS;AUzjT3fXJ(mSS?7wGWIgJ#zO*91I~3Oz=~nBkcLFN0#j>4ZGPIamTa{(U z6vcHHR@V57|Mq#l`oI&EYYlM{lO{{t^hGFnxw~i6VhT-9)=N@hT z3?Tkg08SqL@I+x~;%IC|6ZLKj!%AYwC2TK6&{(EA|12vPzCvT=ytt`~DY@aA5gFfN zbZ84hV>`*@^R%2TeB)G;zy10du1rfHJ84#1O%}3!)PojOtJn!o=UU>rhIF7qH(g*o zkzsLdiIr22Qa$r9<#UhHoP3tni^%+)|*64I2lEa6vouqL4{{hq& z>h%_>O*O4FEgOf^Q zC2|-7(6$o@MS*4zHcM3Io~O3_JYn%1b}~(7@0)P9{yJ@MC!al+;42TEWKr%JDFd0U zty0{!i&&FMwCc38309USVRZqkFp427T8Rx=`(s4sA0ki#`^o z&-3unhj{Nj|1aNoWSVBj+jL!IWj)|}Eeu1N(xUD9DxLZoZK;Ju`6@xPNE9?DoNWGR zvswI!LHvmTY!)XcviZTIeM4I&GDEVW;Uf(1eFI~M-o(hkJ1OkEiQ#MCL~iR#u)RF7 z?MZ@ki903C%vKWP${PB2&`xdR-e=o9|LiGN+W{>vz3EQH%!t4bDI^@4c1(5Z0%5Bm zK8rB%31v;~$>&KgUSK5CPrr>u8_07aS$UvE?ljhE)ix+q7O6K%bVU(HVrarM-J|hO2;xr!pq&`J&(Duf zID`AK^E+|!J4oht<7c+urU%FljFU|F(ZAzX<*7q-O<7|yk6qY{of*Rr7uGrkpL}?V z^XC^OL&{YB1V*F6N-9fXWQZXfMGd@ zagus~1D2zVAVu8!ZrPjO5%(6@fGDivrd(2k6QujMkQmsB?WdJBH2K`Id7eITSzNV3 zBi&C{7G|b$^o@;>Y_GF?=@jeb5@8TvE?y$x#ya`SGDYgvx^jx9C}isV=eTs{bCgyuP%Ta=2t9Rpb@}9b_4ptAXa2Zf zgHGqJD30!qG>bUyU24c3K-!761ah^qt|&Q6dF3({MZER7C-E{l`o|8E&Trl9x+^{S z>;-{$dXaLqMq7O5OZ56qg2CN8@K&Z2d=@ELCg$8lSe=#C4r2sOxqp_fB#fnOf|6z7rcLN6xUCY?mINP?2@y6RKn{n zI?r?G=2@O!q_1xRqq{&9RLS&hW!p7xW6S=xVkvwNX6I+;lza z3J{@}z;rE@u^J$&KeT&0+xHxjyKlqK4XFP#u7a4KEs!qsNh;;>lS%w^mho-d`K>p+ zUY2VrpqB_L(<~Gl9KTQ|Rd@xN!Iy|u9JU;I8(a6ig&hKM_u=1T$G+cSZ0r#I`RzDv zMj6#r8tbRtJNd*t6F&;49|@oxTOTkC@))KReOLU^(TYyeSUW{~^+|zthLlw$mvM1j z8%q!Ll6?}p9TC4K9alMhagmQ6uQ9V)r%@8%`C+W6g`G`frxKfiq+D9ZnZAfCD>ty{ zVh|e^*4PBW>I`(-0>WWrbnE5*ybOIjQ6h z>g$tvh3$L!5r_H1&Nqv5cVX}rL);dHA>B@!u)T)Wnil{Yghm&oZ|G;DSikAwPSB++ z*Nh}BtoDrbU4sWtmsx2U*mD1tn<6N$4;^H_Ql_@Jh_f~?dMyy>cXXJxi)C7} z5KsAS4Xe39CyGg>lDKA!VS#CA*kPcj##kDpK}4+jVlTQ1M;yl{olbJ=ZFgYED^8y} zrQgdeEUa>FK9m5rDU9B#>k=5fXGt}fdcLWOkK^ZY(qovWi!0HdP7INB3%4&n{(t_^ zYPYE||GhsqGx%Q9Rzy-ssN1X%s<7!q9sJZNv7M#ftWv2jQmIU{w!X&n+y!Qrt}uP& zX^B{+RZ~@gYjS?RP9m8?LXCK13E%ff$wjA@7ARggM@CWDQH2G`88>JM5L1(K@iS?n zMol~wV77`FrFqKD5KB?g2qO&fRjdUwR2)D+#>#mO$rDrOVhQp{{A?+k8SBq7QOMCK zZ?Ljbq`x)8(~BYNHBSqf1l=Et;A6cTmaN(KF&!U2JC2(jA?%d#G(N}8lgjVz(OI4! zILsgT-gDKvsZ~Y^>w@E}gJNqg^98K1OwRhGcOG+f9&66mZmk(5hj|vQ5jtF$^ME zo@+(~9l3wK%4DfSAm9*(#%k!ASe9)%?sukO2@o*MSp5XVVV8tsux)gJKss`x+QN%V ztXFDOYY}m`O4wT0buCPdS9hvQ%^B!{>G>Iw*?x^ZiX|z`HgC#8aMTnuG(4<&iQ`lc7>K1V{LC=k`wO8TW;AD1_^9n>kf^R;*4E>{^ zYw9b@G^<6@nG|z#mvJi_k|jCqZ)9kf=Qgv6*mf{w0bT^5+}x_yuoP?z0f>a|+S(eC zVTw9Hn@VU?_ zkO@19L9Id`hUIT&20?X>vMJEQVWXL`nQamZktH z&YdR`5T0ccEH0Cj*28iIT$!j*q8oIuf|e%b$|9PQ8Eq_8Q7o0lOj(`Pt#DO!K$3$* z67D4OL{@^>a0%sp^pt|ej1glCG+&xAvTZDZIMA0TksYS1%M&)O000mGNklQqW77sS*6)8!)ALWj}(39(Z^2 zqT~Aj)cN-shN1DObHgE22|e}(6(~Xl!@A_lsx0Oz34f533IGXBB$FCd3T7&}g!sBQ zA=6*4`81^m*EZG&%d3RTQ}nE)D7PvYK8Ub8T45=E;h2ysXR!2e!X|=*xZ9xHb7@&v z)T(1NYiyKPIB{;0V`nEhsRHZV^gPA&bpcaV9$UkZUPJ+}=em*j&oE6z`+l_nGU8$3 z#cHuaFDPzwEo!xv1b&N+l`Bj>{THm9{!3~XKSpQzbIRdWtWdt)1q{OgdX4WM@BZ$G z-uw3el=a=N6Y_Jt8kXF{pch%2)pc3b4yq1o=}TuczCMLxA)0K2`R zi9@v$&^J6ndEqL-+&OH=6)6{R6+Dno37cy~vKULxi46@Qs1Zdi{J4W_$3&$ihynrG z)cF9@ws9goues6Nb)&R!krPip%<-ol<;s~el-Jh9b6o;0P+Q}wR9ei;uk!e_=T!D; zGcnRH59q4PF2}AcQdym6Zgxsh`P^n2*NgIjtQaRn$8;#ymsIsRPrEuLk7x*xSnYd% z`R`!0c|xP#eDA&7)qCl+NUIsirDSdz@B*#n$0<*KhT76G;!aFuZB7F?&xI?;nO$p9 zl)kD~G(bh?2#@KCp_0}T-PvhO^<^t%vy(~OPDfi8^MrEYKyoM6!rIbpu~ylW%k`x_ zEgaZ#cT*DzWl=__NxwiXBrJB14RGzAZ5%$Zn?{|~Tu{5h+=UCctqOTJ zl#4o8x-OQ)Y1S)x?h*&KC%NsqExhK)2s_6zpfNS;b=s8%y9OenWQI)tPTbTWqdV^; z@`vg8+sF;x%s~Hs#Z1$xH7hK;xUV2+(#x6)2ug%mo5=YWMg~u ztSge9MAl>q&|Z}5O%}lwD+rjr}@xlzR8J`Qv{VdzGLHhK91*VFS&#tIwZ_N(TPv1*p?%$(@~_26h!*7K0~P% zCCQpt&o_Dih%YTKB%5<^EL)3Vp$Sv3mnfH}sF!C&TLQ1Stp2AVsO5uJ>G0;Qy%)6} zfSPbjwOV5K!jmj7s$wyJnMS=uTW;Iw$Zi6UIIty-3lxU;FuLm{jBnk=VA{aS9c1gy z9hlm4Sem^Et|dV{Kx{+=(t)ueYAknd*UGdMbxlpWD+_FESIrZMX{Bh9ILy-Lu*dkC zndvy26Y=Z>uh=)i@2CQE=SyGCu0kMvw}p+ijjO`0ZTbpEKBnu_ZUlX8j}~li4(6#4^Gi4KToH%LTUXREd?_- zISyuTVV9(HFB4auC90l<&hjQ^COTww*N0(9Mf|aR^)%&~lQc_{bT#P^3yc)DJD~TZ z-jgH>+u45O8`*XE^^ESngKXa}3FLip4WF4HO>y?BCbmP43SDIe3g4KfMRK*lZ5?S0eA^WT1AE|KW|d@vh%| z6|WYc`7L{}RVR$Q9eIR9YG@Z_McJ3$c{_=|K~`15S}4}kr-3JcU0s{b3}Saz`NV(z zSA6;}evieApFtBN_OFovt*LtRd6l##$>&Be4P%qinxeC6>6AEe5~Fqoqj7nY^2}m! zGG8jL9`2RUSLQBj1=sOCk4$=yTyBg+x}Q)H(KKx`g%LdQS#D&DejC8mb&2c<$P+y zh3DF&R5t1pD8oAri6cTnBNDK&yuu)n8Np4Y$!p^%()}V6J*Z4Cl1FmYSXLZaF5(D~ zB_a*kRh`gO%NhY)xyXsR5-n|e8di*}#TxLF{Il1;nqRx~HilK(%a8A*u=6@b55Alo zFS(teT?g<}X&lGI5=GEk4AUVuG(s+GlW^MFb3TqA%yQ>T50OoI*aEPxKSxGf*Eez< zzOOazmZ%66tOACa1S>_Le^YbMa$e&4+?8)~;qsRiC{I#VAT3ubG@F51B$p0uH#bgy z<#2QLDz-F`pDcj*C(xcMhK=KAu{5Yyd90y;;8+Mu3(ppKa+yF}))7ybwnIX$Vac-Q z7v`}Af+R_wFV;Tk>(_^g_Q|bcxZa6;u`9XgFj+gOk zcicuIoy8HDPAZF^%HXFno8Jw?Qc!C_7|6N|dU`UB4IJCSPNo=`*u(ypzl8%gzmdKB z4{^=To%jitZ6gIyi9y{g;AtUi%}9&iD;!j%Z8xZ@aIz@57D#3-EuCV1?kQ2*EK#U? z6vdZTCs|xR$BHnkl;$SPup1t>y?#8)!?%;fDz&#u%bP&Pa$Q%0PYrA(IkcTb{}^6o z7&A41Y1vq|N$+UuVJ!jjsc$^S>{^+o;ZmA9j}deUB_HC%03CtZjT~Z$awnOiW@Oxp_XA1Yf;TO#xyO2F>#MW#n;W1S-D?G6!oq# zF%470F>vG!s5+BUF(cJCDwiGPz>e+svQj^`NV+DC>LNyB6vOn?pQfvE_Rejro>peF zf@KC8Ut2%4q-EP^;B@6(WvPVawP`AqDMjYu^=2|XwB2?b-5@}MHsRV899fMefNVdF z*Ed4{-diZ_ID*qRM(ieV(?eK}k7c_Wu*uBoI)C!Tqda(ap0-RpY&3}_#M?oj!azn* zYfbrw#$XsknuLi%-N_SqDS|lCw{R2eL^8*Lp&WPIbO_IJF$gv8E{1rhx3Iln6f3oB zEl#q0`6RLKbTmdsu53A`GQkqDw5O?OcYDE0pKUF&qi1ec^bMOO?K?x-^vQX#x|=6q zL!*3&jrB_`FCVA8`Yevw!ZNz(Rve?L&vh&_A~r$-ad$VU(-B8TVP}VFx<+0?NlE<* z-Qr~myACsW=nm3b_Tr?oByxke3AvH$lgba{DKfdKejMASC0%uHX`Qnh2DLWKoj=Xq z3Auw|YSLX=T7+)L09lY{Co~Y9$0GFlm6a3)avNKg;#dYl*(BRD1{1>tZ1r7N9v!#Z zgxUn}mNYhbMMoJ>bMZ3eMxXcbQ;C&rsW$GPEr@xZJd0H^!PqfqdQ6FhcLY)m==a%Y&K$WwBpHRo@Le5 z<~K^L)B>J5J4;*O-Sy^M>DLyeuK@%YSh7^JUBMXGLJ!BbETXH*MphBqRv)phbCj9n ztQNcSA=~us-)3 zXP)~eCm#DM_kHp&m_Ge5_4S3#)G?4;^366|29t#1$+K7Hv8_D&um4?gL;J~P`$)-H zY}*h>2s9fT@Tq%<;)bPvSRAyz}jE;?CP{VzHq?I3A7w zbTZ<;k==^ORZ)Y)EH+_fLDt#8n>Y-Lx~^8g&+Ral_82RqF-(VE0O}}^wQ40QtBW*B z3o6VmQdb?()|lK)m-V!fzmL5yc{2xY`7LgIkg)yy8 zs20%-j0rQ{w~b_Wl=Sd^vP1hwqziH(2g}kbxE`iy6DgQ97{}pjqRk>_~c4?KirWC5*j>yu`5eNT~)&a@L5MMN~(zM0g!8YZrr!cFAKj~!;)!M8EA{bt-$3e(htEZ4>L(ztH2cY^O8hGFQtN$&`{ z4F$HMqU^G2XfqU22~M0i#qEa@0%(a-Cm-VS%naSNRibSNSoeIoGXF^TIht(P>s!3! z1q~vB)V%sEaUx4QGpc7;xSmBSonRp0V7U&aV_+pbk^(0^yp8OZJ=lt_YfBgDN>Wu; z7MVMJjHxFcVfyH|C|`U^>18Mrx0X13D zW5=ghZ>DH9vNW0=j@idh|1NTc-Q>65!NBgfF~0BZ?7ZP$vGe+W!LFCQhih;BBd)vo zf8yrX{1GpC)&C~9R_@tbQiB+SzkkGvlI?Dtpi?I7mbId59Ne~*FDS?SH4Vn|9gN!3 zs>w}qVrG?aY&TXaM=mxuBdOzMA-3=oy{x#GZrOB7vvjfrtokbT^axAlkYtX59zeng zF>OXrZ)3;H{#OpX{14cD<3DHDk>6+Q{K(9R970(e4)lc&l~Inum1ISaQ!QOo1J(37T5lx|C!yt@lLM0>uzrTH~$B>{oDV@ zOWyTvN*$jqyRIQE4QR^BFE3S@TPm}()MSf-&-RfNhjJT4Dm;Aq=?lb8o|oMIZduve zDQvxoWKZjwrWVoKY=&XdQwENo$C4V6+hQ0-ua!*0FfavNy!Nz+{uu4jB~>J*C@r6$ zxN?Seb(yeJ0u>bvS!;jB>f`uJhYX4dv2nC^bp&}ws1{8&;FfTG4tY;UbeA# zkx0NrDrLnz*L8eiEkfLBNvsy>RyUOPM%r*Hvs&EX>B$C`+%uH52C7g;y()CKspqQ+ zMBDEHvyG9Fam-6~nh%|0<>+%%E>BTciNA7jiq82tUVZ1UlgtfDv&9m>Azyv=0@HPi zQa4SzVc{ea?4QVxG&`!o1T2?a3jN!0oCG~8GcaJY@qLG3{Jry2rkgBGx z66-T~8fe$lBm|zN3B?LfG|CDb9YPgXJF8Q~61-iB;F(gLWVFHBYLU|Fs(7hNS4n$U z8BVAc3qVs=VM`Tc1~cRjjbe>t$tsX=c?IjLo;h1&Fi{}CYZn?djb@XlPMoJWcZJo} zWgcFOc;vE*9rieVLjxQ+Fv|9key(1*xCxYD7(WEI&7XeMOWD*f)28iV=Xc`f50WnI zqkrHKgX1qJ(RTLss8nm}ouBqNVTNHi)w|0OQ5uFOWhbErnCbLRYpfcu0*j$YiqS`e$1R7p z@bt;^T&;NIa>ERc9AK%Dq_R3kvOkZVNz$s8HZ3r66L|G?1%-|*v_j;j>AFb}a9vqd zkQ>9bLaa`mnkIO4xx~!MD$DDuDuyme02gW3ssx>e7N7^A#$(x7mLp5cw z!b@NXbd**`CUj-pR~~c8WrVHl+-3a3L&ve!DAKufzgt#(8x zt1#MY=mR(dn29aesZsIe4qmxukZP$zt-L|8xXwzg#@t+qmXV=4b5Rv$gSb<}5*M+y zhK<(mIE|bF5L@!>r#Om5Q>urzb+Pvy}F-^HmtVy+%hnnguQs4-(1uSt_ zq`cA$Lk!>C1aTnklJ_j~a=n3Ul5En&vkg5bl*Cx(?B$DGn7YKQ0@cdQX-ZRPsm)y^ z&~|H}9mJ@-B0gTDy*^8;w8WG)j4o(V^TU0_@}x}81xd9?!1atF>di}Kv1X;pBgf7& zSjgdMto*$r)|v0N-p80&ebm-wIQht@j_VAY00wmLkE1U1R#YbKSTUAkfs-aQvjnkA z7+U%{QU_|iI-lXPvC(E>J>cqEi@J8}O7)Q1+A^)|5J|_zEUjURy9gret$Vfb5k_SV zBbg%8pO$r2u&b+#nKkNBijizYHk%@s@=42TGLlBQOaj~Ovbw&&g)0|0b>=viFFw!A z*(X>y`2efuo?v78G)1*FfqUufQ+)2BM`Vd1iGe&@2294r^O8;hFF+B3Hpv~!WMyHQ z;(C#nAKs496MzhT#cPPE53ZnW(xU?bjq3marXDmgkf9Ju>Mu*>s9bHp5`Pk0C|b zT-u=>Rk^Zwg@=zl&CzEc=E-Ls;PJ=4#)A)ilfVAbH+b(~f0;?~rlm!zi!YNI zpS?SViNh|jfQv*`jsja>u0UmNfjy&X4jg(ZxS1Xln}w6M__nb)MQP?dm!JANPk!~I zTs`wBXO2I?m1ED4PxqG&zWSZ__iiwIFNH#(WSV@T#~+3OH1x$ZObo-qFl~Wn>oQrO zRwGho5Oq7W17t0Ep1o4!=(!D6YbDwW7_PKlM?4coT|(t@mg5o&5WBX9o$JRpBf?f$ zL1qO<*SXa-nn8ksAK*9+zUQgAB$Ek&>67vkdQO%;?Y0$UoqfuL(tb==)=-vcZ|WI~ zFm@V(#i9+lPl}Y*d+^S-~`HB3)-%E~e%dDEb?siw#BLy<4})BL*-G zOLIiO+oG{5>++x z2+aOMfziPNg?x4sY~Pc|0Jes#;LG!8r<5XgYggRMo1}af{G{lF+Mw@)rW#>>vytYhMyp@aUxXlvD{yerO?MoW? zdSIx)Vyh(8(cXruoVwGh$)y53+hTlZj6s&s<+{frl@@TaI$yvi<;HFzfurUp)1l zgR;`A)2lrDt3OFNom;&(s6J9?cd~g z-u@PDe#Ol=8lpQiN+6jN+csqSu(g_~yl%)MO)W^$lT{^S1q>5k9Oy`DxV9}|olV#E z<<5yrP8OEIPo{9ZG|5zsj6m#{Jn4bwc`0n$!P8>6o-5)HHz_9o;>f06=@Lce=6rhk z(@v#H_GLMIcn^6kP&J5|n_uCnuir1eJ1W^*(zPZvRoxfX*9a|-fwV)?>S9L?Elm4; zyy*Bo06QK3gO+8956vE!Z1SODU>Itag_Xz=E3lyEB{PK5j5l6)E&udQui+p6)^Bp{ zfj!)Q%gr3wznj=~aZC#@KY-gmp(v*UM6Zz0ZeoTpo~&w2@}fV{AtRuC*Or?)vP6q? zHcdicB$7$FZvsD+!IfZ7`Z}*Mq%#GwN*@!cJeHn87~vQZzAV@FQ=mzQrrZ@%78w#* zjzBf&>(7$kGQyE-cd&EUHnIvN9nGQH4(ax!jRRraQq6Ob+4(DM$m3G|V|cRgM9L$b z&rS{P*!wYFbeJ#tOrc=Nh2s~jum{@rnn|p|gieBXY}1Jy0uuBMZKY2U_V$;*oVWeP z8*#lHTUBaWZ$o-~Tm!c;1thjfB=9Uly=cOwzV{_v_6^(gX?63N1UY?A%SDoEo+OZO zTR3tzOM5YhtLS}}rJ1@vr469o0$Sq8SbcW80fx3f)1CvSM`)N>x?aO4l0`>)UNVzn zLJNH7t6$44H{7Dx*rZb)f$k5?n5Nzv-8QA_8tau6+V z%;1Okfy4ZP?^;FogYqur$1!@Bgp1Jlv_iHXmJoO@?a-E3wrGYf-PqQunK+iq{yls6 z>T{=gc5+2l)K6EO*D)+cWl71tLCKPS5^|xeCbM@WL0(x$CSlXle0iPAC_!Yy~ak?s3$6!VPZ=pMs# zrYy_)AU|-JKkyyHFiH@`BtzLTb`9-jaO(kL>A!?r$~8S=xnX}H&!OQYyN43=Wzw5mmk=m9O*EZKkd!-n z>emy|_xg4Oh@*Q=%fxYA{2oZsai-~D7$&A+lTIfXm3!_fnC#Ct$!bvs(i!>(w=&qj zgBx#pC3_FPj7F!ArL`_&V>`f1u+h!&%@aOG-y6B*HSb~9HMdKO`Rv+vEx7^Fj>c{1 z8N6`3?}fMTe>K1V>kHpJ&$~Ye!UvnuSy$)QI6t+_BsZZ zBosihxtzFcfd0ZD=~R|PA}J0`;QL8klb8L-^YC~oCfo|AAay%DdfA_tww2MZHAetGc3+s zWqSGyPJ5amza<&c;p#$zqo*reU2V|q#B3B>%GHC-qUm6MkeuxaoH5ec%k8&(_HEmV zBg@IB94rkmohmTUKQ3|~C07{RbeBYS06&?>^)t8v%k$GXi40yMEBEi6Ph&eij+fT= ze$s_u3d0lh4U7uJ2}VYSaZ;j>u8m=P*%A8 zLc(BWb%UplUEwQ7FY)cCH~8|ymziHJBOWUWo4eJ1=--b7uuw=$)oP9RB^?_}98}tv zr?o`wCyVDM@e+BwbRWs|5PoVHU#_2&#dreKPxs?`x=z5Q^f{Rw6cBxz*Sm>=-Usn| znN2cFq}9$Un57bFdM)zD!Sk>*cEhyjSHw=I(u@q`*}iofb&2`5^kILYkNrD#Fr4+s z7n0QFaUDhDnZ+W{9b4d`N2d7pLucP3>r+hNhaTn+J^P)L`w#Bf;oADb$W_aZh*PzE0oF=vV|Qqt$w!e+{exXM@VM- zNy!ZpDnj(!)^w5>Jz)GiW^w>KSroh!3#*_yux&Tf zRf{d#4`TSb*77KAEYj}%Z~kp=7qOLp)qy-;w0aG;#roI_j<$STn}Y)9Z(7>3>*56koE-D7FNTv?c7p9U)N3tQ!BTqb!)hKcN(Z3_E&TwGwI0-YB zKCIF#m!uJEEUYfDwzMp_4jJ6CO(5=PZ0B_pC3zk>yH0?m1;}GLHnyL@v|WK@s@YhU zg<;tOQ&xtdf2P!)CU1agTAMA@Zl0UWf?=!3(dC)b^O8~_O>v^D$lsJ&aMO9p%_2#o z&DC=c^Nmk_fN$OZH>_-QNDUq!r|OC?&W@G#rLtqhUjNk0rRVQ>@>BQxNZ#W`hxww< zKlbDOA9=^riL2-CSY2PA3X~a?8VxoYDb7u{_}bSW;}akGV~#)kNv=HeB@#}REq$(J z%vNqVa)YGLoQkI=UMizJHiMY70RL(+x4i{N>hVd$L^Rq|KJoq;bH!S*KJ-l_237mZaVVPJGPIG zO^qt*b(Q)=jw9>ZM|S&7G~Mlz0})R?dX&Gs_x(Knz@PKv1OJtY;So+8dq~j|)>hUC zb>EuE`plIjS_03Oi^fKzLO?9cVobwOGcjx%!&DQPu|SI>Q)mh_0T*f!169yN1%qCB zZDw{!)o}%aP8-ipi}zZzw5Kf0=|%C^|L(tJ|E<4E|IVA}8{CekzFpBkGL=(rrj)?I zl#}VZf=Osy=4|MZk7ijJ47l{=oi|DK-;JaoJ;LVfsY{yy@@@0j}9U;OJMt84Qg z(mZ8Z8kBe@ol4?520a%V&W&=-k=N0cwkiznWOQU3q4bw2Yid=>v=nGgFSVq-I&>9m zV!3rg)ok1MH?1%dO0ldCJs^rA0jCl6+*V))J?m486)XZ(Q|gsEPhXf<8rCMKh@LO> zgK6R=-AG8$@Q3E&FbyQmtcJCT-=$ScddtON9zJIaMVP zupr=-U7+2$mMkgmfo5oqI*(yt7^dDV0cjEnaLetLTmdF|j=lOY);Dw|e;W z^d?{RChWKg?R_^z@}q>Zjv#0Y@ERRebppAwolemS+gQ3E9bp*h_ckYIizG6`BvM(L z3U1YUjjkxcHcaWxJ_bg|xpeUgnW0e*?7M;WsS6M7xbuc1m!JCB2i48b_4jiF*n9fd zKlR5`PkjA@Z?WCNyN0&!o*M2SnVyyVu`lg^}YO_Qm)S$w&8q!iCl=3xoYOghcN za+%Z9>yk8vl7kqy4kuU$*?O(s=T~q4j=l=VJ0QlWeJb3@V z``7~?|6g`I^6)p`^X9ky?o^*j=M4dtO=oarah@V-Ha9>`#nra>uJ^wJ`i6#i;`Ab2 zX~S4nCZi$Hev9q7*q%o+pQBT)sJc_fO{6hxlNSIC>8em!RLOq5n`9uHr*||u9p%GG z5Rf$mt)%OcbllQPv;Mx9-mv4yzyH^-yT5ncFRGcpsE%IT&(){?>Vxn9!(ZRg?Z)p4 zqhM-jbzKv;*(jGVwB6a3)%4sir+tk;h)ot7v=vk$xos%Zij|8tOGR;Gn}+z!v>j{# zhZxW>EqeEcTA1Em^XZuyu0U!<0j7eEqafua5)AYY>mH}n3fk{msf0WJ_Wl3lo_D?V zNa@An{6&2Jr2zQdf&IxJzUpK5{pnphwv3P8F*-c_@%{Vvm4-%o5~h!d3CW&RT9Z#G ziMKdATOm|H*o-Vh7y{8$(AmVT*I_L9A~k_5!6^5QwPji2@$>T%!e#9tC+XLMc&St= zw%m_nnRk5o!@pnn;(z`h?|JZJ?<)1W_+>Qnm(l4D_W5W3`)eNj%lH5GT_63w-ck_% zz14z`+n#;GQgGS1Z7ZolAD0$ea^ohUSUG0^e zo^5E0)s*!%rz6Y{U0k|!N7syYeC~tqyz8?c{3j3cD>!~70KRx0fBnIC-v6yn{J~wH z|L{LQJnhvANzcFIz}BtrIWxQVajBDsqBuGcLkR)c11pwG_gprP;^`ocrlT-?DCl%Q z-f4E6{C@xd0RR8D>?eHy000I_ cL_t&o0F3CaAvM<+80&(7-B|HJx=c^a4SE0#CmV!>k8x$hbiBFT1h$JP$7rl)Ar= zJGsFl&nyu;KTT)yunsesp7gvxaEm1X1=dL?V(cCkkX4dNV(LpWn9}hAL9yjq{6Cx` z$C}QunicF8b2RV*iFn@RwG0@7x!Q$MU$S;QA$tu~5PbK)tzt%GPHj|zcs z8oB4v*}N_=+);W^3jiTBa6vGRi=neUJ1hjEEzi%-I;8+<7?Uib8qz~y2XbR)L~u7_ z=Aw5gAc__0&KAO4Fihn(#a1&X!{#z;vJ?<8N+@pH;N+^lQl#lTx&!nEyk$Wf8Kr?3 zZXUXeND$F${ z1XJll$^|jPHOFMjPb9C(yrlgo+(wq0>>3FG(|#a8_RoIcWxi>i?|-0#~RHd~wg>WWtdh#I8|o<3L&BN(ex=~x$CP?oyd6|2s2 zs74X2)+GylU&SfcSQlLwRpzy}6yieObp)IL7F0oGe3V*Ts7q3EO;;}Buz$=TdXQi0 zvWSvRH1+R)9LZpL9qX_d!vI;Hy6KYB0UO}1nk+J%{S8+>fVjqfR~AVEhv;?dfeU;g zWAr3CC6EuXp)9h)f&h&8eJ?ecNvVib-$mCi^`T3?0&f2T009601CA-x00006Nklro;>5XTiuKdHq>t9%q@uouB$1Sb(3M!;qOL;ys97XcapUIcg%I6wdr0o?CD#}2)+ zEU)sej_RgodiwF7p4S!*{_*es0&sbG8Qt96#8+2WZDe;Y)i3W_$h8$H@*`25gzra3 zM*|YI3WY)qS)EJu`x?K#zV2RJT$C8wm~sJ-xO{$oJ|Izph($P$iid}X)svHxH~i{( zhIXuAJGRY?>Ll)?`#7T^x*v0XCh1SwDZ;OT|Deb(HIUKC1c0+8KX)!mjDo;WlVf>5@aSecD{+7qaqcmp(XM<;^m%_6aZ#l#Vf2iGp{Hpx~+)Q z664@tPk>lig%p4fhL0qF^%1uG!*2q3?FsKm+%hL4^R5U0bje_CXWyj1GXX-&W+#vj zfU;Qw{GHo5`@%6CQL6BDpg{jMRgsml9njr2xo+cfLVl zU8CwA(5~{X4*;TP+Uv6ZwC32TVm7%412u~$+J!YrRtu~47^|(l) zi;;bOieZxlGWWwI696lr*X)ke9oSNdeNrP)580Pwu!Rh}oxVtSik-kp5Sajc1m`9! zN6ZGQkYLldK_{t+-z@+&fwdr30uTr>8|aCzoQQy5=yw347f!dDXZixyVf+rhCAmL- zri!^B)&d}@Cj!0_JRb59iqwaxXZjKSnDG}_6*x$K>H})2684hY7(fzqTbTs{P$A5x z15hRdLU&9P0Bz~Te+7UNxj&n_!E!a!mQMWX0F)$;e**vj|NrKo2FL&a00v1!K~w_( XJK-fzy6`Vb00000NkvXXu0mjfU7wG3 literal 0 HcmV?d00001 diff --git a/assets/images/icons/user.png b/assets/images/icons/user.png new file mode 100644 index 0000000000000000000000000000000000000000..bd07199e06ede3249a5a92540f0b0e118080d98d GIT binary patch literal 17531 zcmXwB2|SeF*MG*?B5StnWl46~GIkZl9yHKbWf-|0D3>S@bn4w3(MP+W)qX6XfsjFX`s# z?(2Bl+ey;P$0c<|g%g7KA>>s}^MJR@6aH`SKD0YI@Sk5Pq0g@i%oDDtsH=E2GI37i zye);$Gg!F$lXP;VI!kHv#ubzLX`w@n_zW_=mk!l|^UT)-pX~;{q`1pIGBG+j+A(1_ z5mIYx*}Zj;jq-DGR<^Jl+<7v*x&EfTtE~Tqm-GJHp8UoIF0En;Wt${*KMo(<&c)}39;!l%X^eD`L#(6AEOuKTAwsAX3!Tg@ zj6Nt!eqtv^_><>ggttbzlE3%P9d+hnDhU~6|r5t%0pa1%0*a#;l!oshCk@n-oy_JhFIe*i_G^wjp}0R`XI>C`>%mHzLlua9QI=D%*M2;FSaqu=n6lf zsmQ$6Q-OJ!R}P|qfqA4Z z`#Edj`vp~R;Lixgq#BZ^cj)au$}!g4uTIb_<>-ccaM3|3o#nEQV4hnRLC@4Z6`07f zLGUS$mlHxNq;Sur5ZfWIZ;6doom-BoU2}s~=4XU?bCEa?qk!dp9?hsEmCl;5OpTjic4WstFQ`Ekr}Uqd9ij z>7f0Va@n{9VjXIApxrG9HzYqe8Mtd)Y`))_*NO{sg?eSvMh}gXh(5@;OWagzue@{v zqjTcQ1EB^jIOg7xN6*0$*7Fs*VdgR>JuRN7P`Sh6Fn-&EmJX`@J(7GMF!&x;n64f6 z=&m(>T&Q6}FSi0roazddIi(pNN+l3!kY-QkAk8X4LY&YMg#g)zC@18R;^^{Ju;D6R ztj$ynXZTyF0g10GHm~(SoURY2gt&bE8rb4#1&_i<${D;X&LX{D64k^KN>b?I{@E~G z3b*o^1fnf6OoaY7to~Ph&Ms0;KI1jgmW(b)+HYD6=0yqo%F69He`=<8imGGusOa{DV&j+ zPGcJAzd3%ju;Er%i#IoPWEoGiKze;LCDaq7r6Vc%Gr)FC4>0deF1jVnT!tvUjPQkm zA>Z_JFOtKq!WlJU(;mJU>)GRTL(oEVjk(*0n9?`&kD9Y!)QmuOFNw~`raR!#@E#Si z$t4%RU`W;M&p0LLGOtx6x>}ddqJ?l7%yPp0-HWN zl}IELOE@ke@GtUlLg|10j-S{do5U`n6zCv^5BmFN$kO>>SXdTpEwkHMZ8aYK&6@?9 z^w+~jk6ir*G$8m(xol#NdOR^0c@C)9u8uzbK9Z3U=cK&83k3aNCJ%NpMZvho~5 zvq9k%B7{8)(IaHPW-kvX#NhL{>)BY)!=@3^vmHxpXuDo+blzhJckmuC9EK#~4wgQ( zn+)Q)Af(!_m)qospjL>Z#0dayCjxCPO=6Mdrh-atydt8IUgf5QJc9HH2OWkApiFuW zgMMH=*icz`SQ61gETPdAK|RE-zymG${_T>|tG&V!22HL7ApOxRcHT1DknQ(!*=+2w zE#8+-2Zr$sF~NIT7oaE6j4EJ8S|z{VWn)VoaVcOo`aonG?zyLlbSAd^M`QT}?H<5G72rF9of`dhhdPXdwk`XP+G^NL_d zt}nxrb1xtcFi&;PXZ^q^K&Hb;-9JUX(XaXFDWwCBTltkmP}Eemp$iO3+D#eLr;yEi zOn!5tb|8`Xfg;-#nz>cfm2oWmMf`s>9P-gUi@is_4W}RI!obwmKkoUf;SNUY9GK>+j zM^hIF!$3KqxP309ltY9@ST95jcXSc2blF$$2I{v~D^<{-g_Gg=;^hhj0zIJ;3bEn- z4Tla1$?K|E;Ms+ieFX(_InI_8+a^ zm&6i6>j;dV+VHa2?hWkDvr}Qvw7djT3iyJZWcpbPImms{Lwf!5tjsBuyg^jKsE7S} zcBXShf%e>=DaBMnr0HeumBVKu-1K71HTyeBVNbM(&1-M-a!vpQo|F>!J+H#co_Djo z;$uoZ#8ujSuyFriA@;$dko47jOnrE1tFhiuj`N1fJCpNFmf)*O=-$E`4#CIKgF;6j zbP8)hGk(s5RckN2j53Z|4w+%z3N(z+(oE2sfBxuJ!p)Ki6OjQo%Gor^bD4K96}ZYd zBRIXSui<;F3y1*p?w{erh@oSX4~s63P*KWr(y`J|utrm`(mcFTc%whQmN~9H!5|iO zSFixQtSfj2!ThLLgwO#X#i?KO=OfCD)_7W_j_RVE^fFU|S1SE1r5uFiR`xZ)5C7Ao=3ZC1*FQ>Jot&=anj)7^b!sx> z*Vf8}g@xtR)S4F|N;i9aoK*qwY`>-fZ7_U#u#;$i-NNW==uYHy(P`!XledQ6zzetCR6go;FaId8YHVC)h|Mc-= z7OL_NBKAVt+$lo?gKrr!O}~eDaxwfK^v_63Wzyisro|Rc-) z<4r_zqE6`-41AhhuLf(Rs{=I}PNBc8#m@x++q#L5G+4ldnTt9}NJ@&P{tyi~vrj3M zv%Y@c(AZckp5qb^j^K){56eFFgb*so8&SzhjsVSN;6oL1&b(*idVFIi~5V=e^dh!bSMYd|~p+dh+CGsQMa5YFXQ;FM`19yz2FHuiwh}a_9c?WJBa2*~kZ9EH5}*R1x@(raMXezl}_fCkg_NvPwvZi@V;x-;8D? z_7REn%OmAin5pP*_p4nXT(l6KkmJc2K12v_2VOrcM{Wh$Ep(@4?^5ArXCHN^Ddz_^ zcp_-(=a8sjmZ|j#YOodH-?FpX+J#wY9@^ESkuj7M=XB4y#W6n|Ag_-7X(6n-z=F zVKf1M&2RH@&bH*Epq-VuZ?`?Z+MyI-5BoI(n~i;;V_TLmj|`JjqEMn#?Kzdjw> zbQj>rSj8Vu~*5mJaFEZMyvP%^Y7@>)#D#?ZUU0B2>jzS z1RW@C>zI$Njc@5qdXLFrxm$AA+usZD`yAZ0iWdp3X`H{T-_c7E=CQn92=bo=gD5xW z-&l{JKERq6_oPtHPus6q4bKghXug{t1#^WQH%Uen)CIh>C@hF(ml93yNsc9B;Ns!w zZwxuOtOL0hAorO{-?2}3ki;s0Z4@As5yZXIwX-v6*}DtP@8qdhc?ASqJ=ozh5oDI( zp;$qi;#-T&$9xsJORFlqfCDddmHUJ6Upd{zr)nn3`e5bfS-?fyv`qu^{g^=>k(Jlun{|u1lsjHIa!}2 zjA)nna=5EYs9$Ef(zEu@o?Uc7%*gGXZs2S*`u913gZi0=UqpydSz^9FD&a!F zEE7;YaiqWA*gXX8PpA9$HEC%#^Bnmxet$;_2n3!yM_h=r5Ko1vTRZw?On?*lwDHyT zc6n}>N&jbeuS-LKH$5q&(4n2p=3_T!M3}H zM;Ds0T3;V;4A4EvfXX_qPzNBVtRO)(Yj=(&LGPNZEc>lS=O+q!=36Xw4F4 zd)w19c9x;%z4`Z)RL6V`Tc@kbW4}d9P$YlCK{~Kd{S-*GyIsK=5IZMcp(my zz**u32AshX{rZ)rc>%UmRLFvT*(Il?U2m{g_JrdFNQ`LMMW{i;NC~>e@*LtpLGc)fdkc`{dSTxCwWOT zQ_~t(Ed5t`QIr&|isPjxT-wm&`RD2gROJUYc6NhyC=dm7t6EsgqYIh)1$3nMzYuT~_tRA#juDfY|9dVcfkLK_qk-?Na=>15cBsjF`= zqm7YPB3lzje&!4gtESe^V9*Cy|IqmGU9b`HQGki>B}s8{^y_V6LH(&h*HbVezv zG9@u7$$<2Jp4l0y?g46?uh4|UV#CZOkn;i#iNJx=5SJM3@@-D=G^rD&|A`|x>@Pw` zGZ|CtD?sZ#lAq(=4==s-3U@!cov%RuI*JLyu8VM(4w)gP&8iw)5tPyutJv;>bEw}SCP{Bh3AgjO zQ$lj%6m|1gd5rsC^EwOqFB+uRU+4$6@lVoDnuz?mAqhx_UWg{?i?WOyFZ^8z@N*8Q!7H*i>=kKXI9+1G=^s+>AbrW8K&zJ8+n` z`Am05634F%h1%hNL6cOxefGy+I9)S}+prq8?xxFQqn05gvd_d5KZZ6^)wkd0?q`B5 zXHsyY_Cp1kA^odNn0$T2$ifaL@^z=v4N<3l8OXB0{JUsUjih(NW7KeOBf%fOwxQOf zrsC`rVT{0`sujwfHxBhSlF;&DQI5{m($>s1l_m0_mY*C&v)9vX#@LUzVY?G*jS4Ey zM!RuiRy>d8iN%TAxg>vd4r#pH?%rC*F-tzwF8}C;N~M`uP{}O;sHwkw_$ifqs^Pqk z5@{2i^FAnrR1#*ipoRw;>%EP^8Qcc%8+cT^R;6{W)FPUTtL&XcVaE{8>W43)vNC^v z{o;|LAl=T)gPGeAWIYPuKc;P(MV}6q6sr#QlbnnUvT3w)_=!48^v?kd=^(8?d$zAB{yy_32)&^r9s*jpCQ_wHFMDf106^u%AIN{KresWQ(uat z8K%bXba1z9irIQ(!X*b$@|8B+3@>h68z^ZQ|5*GlrrPq>K7W{NQRoAQ*A94QBx^*= zt2UWEuB)10!dyTi%6<%EjBkkktj8=*bG9Jp-`kNMQBIGJ9|rDPRes-Y!ufgA-G+~U zXtq-%#XX5c-|>gOyEiMp=d(K~S3fNaPhT3CE%9(6pUxMG@tj+l@eK}yRYkf}b8!He z@OM(C!%2C~xidlk`#81tfyBxO5_XuXjzv))54g%*#NvtO)^z@|soUkOU zp}F#j;h4|8NmCLYoHz*c~AIw*sLfjkCe+CJ!tiC1;ndi4yk3kam#{EMaQ9 zOnPt+syciDYyR>@C_}M2v5ey8hrU#jKyS2yU7;J)%N~q^1wM8^b#q{xL}#5~+9HCU zEPs&10kUD{s>Q4M&R(t+0+4Yc%O5p{N5b5(Z(^Zc(j$=^!W1o6w7ub`4Il}{v93e4(;E0b4?_!8wRk5s6cpGt&JPTOd) z1H7788Z&_7`kF>A{qMshg`$a6Hz?pZPGasqanydgy=?!P1P0YPI@{v(WCGm3YlM1f zZS@!N0?P8ihFl>os)1+1C<7SPDj^czB_jq)W|oe_w^Z`{tr-P>e!_s|S`>pnwvYiZJG|>Rgjnlp^VTFT4&Rf229Y37hU$ue#^zI)Wz0^@Gm^ z3Wtc5oY1=y$8nBEa*`3Kenc7GDuh}2A80tpGDkfD0X+$WBDBs4F`oi400Ve~iUhY& z`Uw2a<+X-wx);XM8j8$O=Qv%7-{Xz$HGM}3KsrL@E99y&a#!IH`msBeD$9+!s#{K# zl+%gFE}ACZXW+H1m5+IYOz!2wG;Ya6pIxLMrVsQmqr?4xQ$NCRaO&yKDhZd#XLeV@ ziCvFT$^y`0p@~S*)mcqnW2i_V{+Srd9kF}Ffqhb#nVk43$l*RC^=T)vo2~MX)kY=? z)_3Zv+J5z`2TCRzq{Ko2G{dL&e|_K#y9dW@h7o@*E^;g-ha1vFXmRrJfOE((`bLZk zITXSkbyeO6$sB_TI6yID{S=iI&oCwB6DH_QvmyPzpMTYMHaU<(aMtKHIhC$EXQuU9TU(#E z-2rhtM+q+p#cc7sj`tZw=H|}i2|y(+^5L+t{(`-oIOy;2A00Sc)y4Xi#{(Ml)$>f& zLpk7(5L-4Te{!7Fv!+fd%uVm^;{#4>I9A~c`7HFCd$jNeCV?5S>TX+l^1gwA*IMU1 z1F5TkqzW#k+&=yD0kZ%kEyx`8{i8VWquJt}0Q279sG%;s+&osA`x=aoF0#;EOh{4S zfj6Vmh#K&+PB768aW=^Ou)6$YEbE@RPGn9Y~7^^+C9@tLHQO zu6L{Jl)Z?Jy%?|iCN_LJ3x-iPFy2H`H@EDloOb^Y|G!KYNjnDwJTW6<;t&uJ;N<;% zz@ts4?B{%0TEl}oA(SJp2pB6syw-t`jYdX8sA zK@ipfSeuX;Kd6;B|e_U+t#l*&mvP|VYbm=hEKjOHhm)b zInCo)eeeBN48Ti8!mNo`-D!rSuAbM+SIVZDOf*_GC7nXyR)&|vqt04-=dQ1x8Zv0D z(ALpWT4wf4q}G3)Y6L5C8ZJ?#iEQOM(ZpSAnUQusp7Fb{4NarUtqhd?{>t&dN3cA~ zexhvA$zYKSpc*rrnv!CAsUsT-xN=G9LqWmCei=;68Z~6kh@WgYV2Rr-rtyz%pBt<5 zPZu0IY~2bVhrFI$JwNt&721SN+st@d9c=SB45`;Y(t*}ufqYbhwn=lNdftWn-C~fM zVS?(NJUm_?!@bkM$|%wq@U(*%m}WKk-DGBY`F+4{Bz|P%GSv|-nl$@Zg-a?xBrg1BPe_6cwxBImYK5c)v2B*VjO3pu6_zT2^G$3DJ0GGylob2u*u3NqM6oh zb@J$W+wLKGk6v$WOFzgM;oXdGwmRhYy9vE|n@#COtN-B*JUYRG*WJV9XK!;gKw|(3`v63ivShb zOY#Y`92Uf%C3Zm^+mTb|S+gLBaQ5*ro$=O{m6gTXqGF*bpQli`z(V7Gat!BQfj2p_LWfex+=Jn8s*#VZTtFod z-qRS;k?uMsbdCvnbQ|PpA5)bs)cX|yLt30}UXs7mLLWv=&I{weJiGp+q;4h989k>7 zc5UZBvGu&&jgg6?h)kpGN$c(9(F)6syQbhYOp1^NnlrpF7unVM^|PFRCVCx7(SH%6 znF=zpa&ko=0r1`?mx?|sKqV7o05+|tHE&Sse>BX845|;i{O>% zrT=Ou9UUD=?o@~W5P&iqU0rp7N}9-V%JWdDvc+gudQHKetFJ-Y5C(*AwvvS&e%IRW z^r5+lnho~DAv+U=@$vss!5$uOwHY*Z;1~y#9OrjuDfSSy7V>N5R_5ha13!Nj0q;PP z$?k6T`S@o9S6s$u=6qXC2v+iq5gGAjcHd$!z6YdBrDqthV`t#wKXBDwzq(Q~avWUg zjP`BCa_l^jl283{5V=E3@my_)ohAY#U{}KoaC=N^y|XO5QCVLv-fnG?-6zdM1p;=~8=|Zr z&)e})SRRbG68A)~^%etXkIDbFsU#sKbuqmsHTDt4RgUxH^0m?JEPyv)U~XTZOn*71 zxb_3=jVuTG$fv*t$#%D}vC=_Q-W)$}W3L|ky;J^1+}$)$zGISX?YR;moN~ITh8y?w z&sK^@(DlyF&aPjPg###g3Gps>kPCSA>J`aB#C$bqCmZs$01oD|qa;;Xl})kTE>C0& zgTH&F4fulx#EBP9P=C22N9LU?3w(`tflcv;wzg})Y1VATOGF$LgIz*}vo#9JFH=|#?xWRCq( zWhtFyQ;b$yFV)RjYmL+5Nkl%svw`B1r2ecNLKijUpI#IZisKOTIt@ED#O)+1c5^G^d8RVNhU+O))Ao)TqX`8_j~N z{4n@j()Myb@N@vnSmI>Wp^*FAr07CpN-ot9R3cp6I({pumm&9p?IT*;42_K30t2Zw z;l1uJpo}K&{G+!`_NA$@WC2D&mYO%k#9~Rg!j29kvWr2(_-(^sv{(}CsnEO-U1|rp zx=2!IN?JpXPmKqHW}53iK+n!R=h-uoh|Re!mf)#p39?kbMv_ln6LqgNPu~WTiH@cP z%J%diypj51f}UG@Y+4bU#^*+-T)aAZPjPtV(7zqiilYMQ)b6)6#$Yr{ScaDkcqL8A z*CyAr1C$Z^Z^$2ywStpLnOpE5D#}vRg2lh1vY?#GwWI(|aXBysSQVJ#|Na#kBEq#l z>A-zz-U3fkICJ|qrGr_?hxOrZ*qg*p(u-HuVl4`DBO)G-R!Pt=!+xFvj$aN+EeGXy zcBvC#^m1>pql>fPGA~-R`c{GYKv&m`4>#1d;GSpVE_`z7;iY4UdlO6MpHgW`P_;Z} zDC9ZmRDo=BLGn6OExW=6XtyyoMU?$8@5%mFwkrz!heR5etu z^HDmyy(jhOXHCTiU|-odJ22`jXwaaE2zKeX4iezdO%srR{@vv^zxfd4;CWLyLHLRR z>DdRzhf1-3DO5i6xh}Ru_}W;#VL#)Sc>{G&*$D{|B#~S4$6UcB_NDI5zq3FEgdhS1 zIsjX2yK@~B3C!fa-&4)_gBsp0RBE#w;S9q_UuhuUg;Z?}l1*I-=HZ)k2HQII@ z_P{@%6zuCjSYoAGWO(Puc2;+~dM6`@Rhw&T^lFT=IH>Iha1=`@BzHHpGz;+}O|(=~xGM985XR zNQ0z6k3mt6-H`#gFW9-HeSL=WD`S|3Nd)ju6Lq&p>Ytqv_PfYDaBw1Im=pGrgJMmh z-Fhg3c0uG=0|yd4AiHi4V2CtqsAzsk9_oUxWdc$E= z5=%deyk>&<+$wESl528E#VQs^^6q%_hrtiPyYuDK?CV`stzF;fU?8A3ef(r z^xe4vr2fUl$PcsM`$^myOrgVo9vY#LY`!Sz%Y&#JEDN>l?kWgk!~^$T?F(0e z4Nc9s6luJf0F8hDz94WwDkXy`0zNkyIO&f?$o~6f@`m@yice}INZmu&#=*|3i>32U z&($%LDQRha05l04BPm`FP`fD#n;pluf>B1@nTd}Pg`Q5htnm%grg+jV5-;++j0Ae|4!&- zFi;uJ%jwxV&lK2G#SZ)r2pRb`fDOpOR<>)5mhFd~U3O#{a1kCs@kezq4jJ|IK2SL$ za9B;`p|+j5Fg<#+L=JXqTic9XxHRhaZTo*^i)oZZrTg|%g+T}u7~bZrdR|}(bh&>& zJenRO=B@6Nw(5u4ep>ahnIR5l>i|IR4t!b^z=sOGcbwrc3be~~I9tA1qrxQs(*Z?h zaJ*2Hhi)Z&S}D<5OxMcH0EHHicg3ZEN+Bpi8@5w_EFxt^6edUq{zEOrs4~@gA8U3g z;Ah)Z44{=kHRb6?dbyzLqq!Ba6?@V!WWlhv_lxaBr3!c>0OPL{P*h6^;5joA*5OwY|nHbRa}cPV8hN7bKR@9VPJSz!|_p zY=sAc5+Zhef8I*ze6*EpL`qa?LxQ|;;x);nx%04T5`=$u{!DzvnL2#KaHR^i>w;9t zSjhyb#^mH^z(b9xuI}#lrnm3-#<32Tble=e0e1jhg~;@k-|p)UKb+0jr7qoM!!+G5 zU5YmLM{OiNP$uJF=g4qzc9H61g;SGjD+iS<+0>^|PTvwNCu}N!(Bz|atQEw_U1MuR z%DzA4`!!h7W=E(c=^8f2_`$)}%ja#6elH{wsrUnaFD%>;LCgEZPz8T5i>~{a#snev z*A$x6%0MaS0OlTB&E)LFnJVmry9%Fnd#Qd8x5TB9eY3YzW4SEw<9N0m9+ z4E7foK@~0S7@DT}$^N-0({Fhq@tz_CS_-dw(A8fYL`4{}Ll&UQ(n-iq-AOhAkL_PT zy7-_VBBF6HbR{gx#SSW?S&6@if0Z&0QnUTo%PVd?RSoZbk{6DlvP7SnFUJs9>h(Ck z*<~b&yL3pt#Wwf7>ovCcf3^fo2Ldq#TiHxeA>{qX1Lev1D=p#De!ell^hxH_gcR{=KQ>S4jq%k+^k8 zq0Q-jJ=E~fyFU*}TaCu54J-|BJqP97QR}L!5XL?^HT8Nn(<0A;`al85$j1SR2NvdN zs8uJY_q?}Xc&!dCCImL{{<;A(taL~9Y~_*^#|*1B8aM1$0hrmV4w|dx#HqGe295nt zV1PTh2KM+&H-Ua~+OAfo>lUuicr6kFyW7w1k1053d@4ZeA9 z{FUkDN*ai=W8n;0(qKti$lwl1M`^K>ldC&2w?RKlfjLMDKxFymq9~^}8J_H0lamE$ zA@a|dpn?fVoNlp!GHcZ1(mDfl8c2F~y(~kBZt=<{s3-wE(A%HWtRK!07w@W=XAJD1MQYD+qD{4IphL2Ehl^FqMo^~(f0*)Q8DF~Z#;M33yG z-20uS{D=sON*jYiIMi=boXEz;X3)Nvph!16dgAn$8}>5CUw?ym{ULZ+OiT>G2ZXS& zurMzU3}tc9UglJi2DLTNlPyl5dmP+j@2>7O+pi9CH2{U)g|!?$HHzVWqZtQm=Rhz` zajkLOqQLz1j|~DJ^wSyiASLLvpjx$fxGljE`R^VB#7pV} zA(ceFR@x61Jp5Xd1zX&Gnd6mAe?NInym0W6g3=kN%n$%N$!UB|Xw3EduP_ZdWU%gu z6jh(&|zu>Mu$fC@U1xlFTmuhKnbsrn;{`%iP&bvYMLA(wN*y7{M= zA!+DoBKeR|Lxx$uZF>S8Mi8{p`3oHp_@^owh&}RW+I9}o zVbCY>&8w?B2X`wx4rrlJ#f+e%14F*8y0ax-5aKv8XEd}SpkmZqGHH3Z6Asy)PwMFAB<0wgr0u1x%{|+urgIP^+3TT@(6jTv1()Q9N?dxF1$!w7K&Tvf-D(C2|9yz9E~y8D&1eZ1biUz zND0}qI`8gWAy#xmg@Hg+eDvn@?x9i4#%a*Tf(1Q5>92{F4S}l8Cvc55;_l>$W!l)U zi|>HNhw9)vmK$}8E#{{AAnJ@eEMJ?=Ffpf2VUubUScms08>+<)HOzTy&5$IOhe+e3Pc!he;CJAvP;XU7%F6^I(WrQx z0<>$9cm{f~b?~)82baKwqH2#b@|i*er8Letu0|9j*rAuJE=e$SKiV-Z7>K*V4?(i5^=E+X);dY4QONY0%j#=Dv%HHRpjsC`{V-hk`8|nF!{y#@S)sJL?WXlZ z(ldEft5W6X{VihPN#*Xxf9g;rqcrXSn^TIJ9u4`EU@ zhX)`Cru$7r29XsE7BKAuMJ4U*O`X04dUL?;`Cbz}qZUpeOr_m*fys#ip2pt?08bQ< zx90ZLAqR;x&UN`p_ou5AStJEQWt!|JnCRXdTV(=4Tjt9@5n40g_DwAc(aBE^6f~!S zszhB~O>O;?u3(EG1mSL+kJkm|fmyd82HUVnbRwx?ksqnZ(=gwE=FCthsc0nvK}pmR zTA&@&-mky!rrJF)7sUrKS8KaxNTict<2afg!YEq}{ij)O|%WNxQ%oISg~ENKj324h~l7y)}a1>Oc-sNU1lnfTq^FA`B#v+CE=DWP4> z^YJ2aamGJ=z!QyCI=)4qdi0Y4=&v7z!&KO!?`um#ySCzN?qH*FeD&*#F9_m!6pet6 zB?g{@JSW3r)a5Q-7&L7;3i^pEdK8Igc z-*nGv%Rx(*A1*Aff?Qo-)R!qHC_rBqWVu$Az<_AO3-`r1F?4V1H@6w2Bu1N@5mb=F zW?o+2@$p*unVw5&tv_5Lg_&PzpTp2@9igCe4Z_428XATig2z8A6hW~Fd11Bws6tyr zo1tG+f(o=`&?_(yXwcpaxW&>M?F!YRiJ1%sTOA!8{$-B*&}n;@SLyz|q~|heZH2B- z)y%i`GoK9&bM0GUT9EW*Ae2|H%u1E_dm|eL&}>qUXB`-R25lTj+1Y$NDe7~T=7yjU zmZ+;XV3d?H`qyuNz}g3LkgCsAfpR+NFXk&5UOG($Y4Bam?i(5~|D&Y%6Mg7q;Ia+} z&H0F+{gw3c%%9M84N~Kn~y_kY`0@g3*<;wYXU~s*48#gMs_7g zD`tVYuE2XQP3>dRnrWFy&7in<|x2a&%i~7Q1AB7$EvA6 z)VhHcu3^{L*QI!x=HufO(^`Aplux>}dp-O$C*i)K>cK${aV>eQZSp=3JCPxi=HL1G zpxsNUdqa6d41z2`!PX{Ges7#)`aOm&r^vwV2}DRwntJ)ikB7;6xy*`S2R{YlbU(I=8<%qT48eIOsWz>bOP53K!Z-gyOK^nbi;e(_3 z__+)Acfdk@5QpDJ_xQ<8h14UB2K#8zg_g&RF<<}8&CT^F2mc*vl1~%*<_g(PzpGoR z208cON^{X%aG3!U%E`-HrK62i4+QA7B9kTrF09zj4opl%TZkr{fQ~ml(4`3xTLJrr znWMhM@gRJBC(vxYP<8i&`tHh7#c0BmOA`czG65EW%(j;bFuFoRmu5JaXR*=D|9JQN z_wP-wJ99y!BIKa_^y$;+GiT1IhXDLI0oO80wBggHzDeCi;t~=^r3tJHY+zUh7l1Mz zGcz;wD)-d~VtEzQ&0w|_u=jwpxywyct^-P+VVDb7&-djyS$owJ7A3-55wt^KD%j4u z!{gSCy`N19dbvo_imIS6-3c1@)gR8yL>?y*#I3;PCY`sn2SI(P%KZXc$pf>)RG4=v zD2J7om-l>~i%NG&Y*Orn0=fX?ggL9FA81tC%xj#3N*JTtJ~%o$N?i{A`(^4)_oE-# zu(gaJ<52Y*q6xB&=xc)dV`*ZyenvHaOEADOG>Mu}v+SvmH zngBlRb}lZCq;=fgKo0XE{5sHVL`pgg!-VfJPg8QI)6{o87&H!w`6xhNDT%&uLl;f2 zK4^D<5ELqXT{21SRp&hKk0u$6C#Zvm$nwUi&##r=OfqoMTm_?ks`^i?NACr%JWkMy zcpL$F=&A5Z0Y*rXv|%c_`_XYGj2dI+A0}mAI(%|2sZ%Y+@hPlGh@1X1xJYnpO>=|? zzRzAEjq2zcoRQyUrQu*m>)cMft)zc8;MPwkG@96W*N4bnqKgvw=hE!F3P{@B)%E>LgV;%uAD(nU&{9TI{=32ldS~}K0V^H_re!}3&xq2_{sEk6 zQ>=Ejlp4UfJc0^`3MU4m{9tDX53aP#0Wx%U?Ljez_b8dV_<`hWK>ixDay$aiv-$@gZt2IZ$L$_@aNIvlfZ|WCINPpHawSr zW_W#>Tlcw?eAp_`&bJNJoOGEt;N_-^(Y5DoE$OT@d+Zj4gKr2bQ0ukj34>|*I5`6+w<2Sm3>U(IQ8;vx(3zl@yU`r1w$tw+arzA? zjN1VFI>G7+z6%1##|}n*?u9bkchYKoEo*G|Q-jq`UdfT+ra#f1EH;6{>B$(Fuso5^ zE)#~UngBjX`NQBJ<>Mfhyi6I9j|I6?YvwBNt| z`}_u%UM@aNDoNiF&=e{oC-<6*mv^rdbh)cnuRIly2OMAk7ign{R%+)W=6wh!l5Eij zyS(r!Ng&a?cYnQ8)0TH=miIEpDwYh-@VUujZFnNvcWa4_jC*l zVKVW$^&3x9W5b5gywjIJy9uZXw}4P5T0a->#ZI%AI^xD?f4fRN2!i0#q~8m`Odoj@ zzz7lW@Rot`>aMR?g7c}$Xy*tVdnL)XWEWl z_3LX_k_=tQhJYm**Q^fMfl}(m2cS=#xu$M>LA1D>Zr`KP0F`y)K35{0M-MHClrS!7 zb*t}y(hJOrJs%69J@>?SqndxX*D{fo`s8sB?pT zm_?;chFq#N0Jwaw8m3P&uY|$Z?lDUt1C*i~6dA_i`UJ!LwuMVU|1vVVh zZUr8l-3nZe1ZutDW6gVP6_Iw6x`F zQrZk0zN?(gD$CxUt6ZQ0bJS0s80{w6OP4mbGBan)xU=9y2Jp)zdb=VHo&vZL;Eego z0GcTx6;gjJ-7FqjajtNa=Zv{qG0Fk*Qhk99OxSwgV(s(s7J|$Lpk)j6P+WZ4I+I`` zBF9c2xk4K$FvSqrdXlVrI%E^qd_}0=Iy@r_2B|p6___(E+SQczx&8zxlTvV*>>%aG zP>DrhWyK)MsM4mm+(Q3U0V`-l=(Eu8vnXT*i4Ud%($^WW&?h#<7T{9Ktpm{dlWFpP zaIdfa@CuE*R%WNVIYWfjgNx?05$2#DqsBy}o`ojjck4{Atq4ma2YqDswex-b0sve{&1<*LV(1RN7`zkEt#^ecz%L4ckk^c^mS{OV`aiN(PX7P^ literal 0 HcmV?d00001 diff --git a/js/main-page.js b/js/main-page.js index 39ceb00..125cd2f 100644 --- a/js/main-page.js +++ b/js/main-page.js @@ -36,11 +36,11 @@ function populateUsersList(users){ let userProfilePicture=document.createElement('img'); let username=document.createElement('h3'); let lastMessage=document.createElement('p'); - let onlineBadge=document.createElement('p'); + let onlineBadge=document.createElement('h4'); let isGroup=users[i].participants!==undefined; - onlineBadge.textContent='⦿'; + onlineBadge.textContent='•'; onlineBadge.style.color='green'; if(users[i].isOnline===true && isGroup===false){ @@ -50,7 +50,7 @@ function populateUsersList(users){ onlineBadge.style.display='none'; } - userProfilePicture.src=users[i].profilePicture||'../assets/images/profile-icon.png'; + userProfilePicture.src=users[i].profilePicture||'../assets/images/icons/image.png'; username.textContent=isGroup?users[i].name :users[i].username; lastMessage.textContent='Last message placeholder'; @@ -238,7 +238,7 @@ function main(){ let groups=LocalStorageService.getGroups(); let currentUser=SessionManager.getUser(); users=users.filter(user=>user.id!==currentUser.id); - groups=groups.filter(group=>group.participants.includes(currentUser.id)); + groups=groups.filter(group=>group.participants.includes(currentUser.username)); window.addEventListener('storage',function(event){ diff --git a/pages/main.html b/pages/main.html index f3a7a6c..94daedc 100644 --- a/pages/main.html +++ b/pages/main.html @@ -2,6 +2,7 @@ Main | LocalChat +
@@ -9,20 +10,23 @@
-
- chatee profile picture -

+
+ chatee profile picture +

@@ -61,7 +61,7 @@
- send-icon + send-icon
diff --git a/styles/main-page.css b/styles/main-page.css index c0ed43b..6bea527 100644 --- a/styles/main-page.css +++ b/styles/main-page.css @@ -4,23 +4,33 @@ font-family: Arial, Helvetica, sans-serif; } +html{ + height: 100%; +} + body{ display: flex; flex-direction: row; + height: 100vh; + overflow-x: hidden; } nav{ flex:0.6; background-color: #f5f5f5; + height: 100vh; + overflow-y: auto; } main{ flex: 1; + height: 100vh; } aside{ flex:1; + height: 100vh; } #text-logo{ @@ -78,6 +88,8 @@ input{ padding: 10px; border-bottom-left-radius: 6px; border-top-left-radius: 6px; + width: 100%; + overflow: hidden; } @@ -113,6 +125,7 @@ input{ flex-direction: column; height: 65px; border-radius: 6px; + position: relative; } #users-list li p{ @@ -145,6 +158,12 @@ input{ } +main{ + display: flex; + flex-direction: column; + background-color: #f5f5f5; +} + #users-list li img{ width: 50px; height: 50px; @@ -153,3 +172,89 @@ input{ } +#chatee-info{ + display: flex; + justify-content: start; + flex-direction: column; + margin-left: 10px; + background-color: white; + +} + +#messages-box{ + margin-top: 30px; + justify-content: center; + text-align: center; + overflow-y: scroll; +} + +#message-container{ + margin-top: auto; + justify-content:space-between ; + background-color: white; + display: flex; + margin-left: 10px; + margin-right: 10px; + margin-bottom: 10px; + border-radius: 6px; + align-items: center; +} + +#message-send{ + height: 30px; + width: 30px; + margin: 10px; +} + +#no-messages{ + font-weight: bold; + color: #cdcdcd; +} + +#chatee-profile-picture{ + height: 55px; + width: 55px; +} + +#chatee-name{ + color:#636262; + margin-top: 5px; + margin-left: 8px; + position: absolute; + margin-top: 7px; + margin-left: 70px; + font-size: 20px; +} + +#chatee-status{ + position: absolute; + margin-top: 33px; + margin-left: 70px; + font-size: 13px; +} + + +#message-tile{ + background-color: rgb(244, 107, 107); + text-align: left; + border-radius: 8px; + margin-left: 10px; + margin-right: 20%; + padding-left: 10px; + padding-top: 10px; + list-style-type: none; + margin-bottom: 15px; +} + +#message-tile-text{ + color: white; +} + +#message-date{ + color:#eeeeee; + margin-top: 10px; + text-align: end; + font-size: 13px; + margin-right: 10px; + padding-bottom: 10px; +} \ No newline at end of file From 69e9a50f1c0d1a9c98e401404038a5708212c9ae Mon Sep 17 00:00:00 2001 From: Welcome Date: Thu, 12 Feb 2026 16:30:20 +0200 Subject: [PATCH 21/21] added user profile edit styling --- js/main-page.js | 21 ++++++++ pages/main.html | 35 ++++++++----- styles/main-page.css | 116 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 158 insertions(+), 14 deletions(-) diff --git a/js/main-page.js b/js/main-page.js index 74eaa31..88b89b4 100644 --- a/js/main-page.js +++ b/js/main-page.js @@ -206,6 +206,7 @@ function applyFilters(){ //This is a nice to have, implement if there's time } + function updateProfile(){ let username=document.getElementById('username-input').value; let password=document.getElementById('password-input').value; @@ -223,7 +224,21 @@ function createGroup(){ } +function showUserProfile(){ + let userProfile=document.getElementById('current-user'); + let chateeProfile=document.getElementById('chatee'); + + userProfile.style.display='inline'; + chateeProfile.style.display='none'; +} +function showChateeProfile(){ + let userProfile=document.getElementById('current-user'); + let chateeProfile=document.getElementById('chatee'); + + userProfile.style.display='none'; + chateeProfile.style.display='inline'; +} function main(){ @@ -239,6 +254,12 @@ function main(){ let addGroup=document.getElementById('add-group-icon'); addGroup.addEventListener('click',()=>createGroup()); + let userProfile=document.getElementById('profile-icon'); + userProfile.addEventListener('click',()=>showUserProfile()); + + let chateeProfile=document.getElementById('chatee-info'); + chateeProfile.addEventListener('click',()=>showChateeProfile()); + let users=LocalStorageService.getUsers(); let groups=LocalStorageService.getGroups(); let currentUser=SessionManager.getUser(); diff --git a/pages/main.html b/pages/main.html index 090e844..f0bf54d 100644 --- a/pages/main.html +++ b/pages/main.html @@ -68,27 +68,36 @@