0% found this document useful (0 votes)
98 views

Minor Project Report

This document is a project report for a web application called "Web Meet Up" submitted by Mayank. It discusses developing a blood donation management system to automate the existing manual process. The report outlines the objectives, existing system, proposed system, modules, user interface, benefits, limitations, requirements analysis, technologies used, user classes, system design including use case diagram, data flow diagram, data dictionary, coding, testing, security, and future scope. The aim is to develop a computerized system for blood donation management that allows for secure, reliable and easy access to stored data.

Uploaded by

parteek singhal
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
98 views

Minor Project Report

This document is a project report for a web application called "Web Meet Up" submitted by Mayank. It discusses developing a blood donation management system to automate the existing manual process. The report outlines the objectives, existing system, proposed system, modules, user interface, benefits, limitations, requirements analysis, technologies used, user classes, system design including use case diagram, data flow diagram, data dictionary, coding, testing, security, and future scope. The aim is to develop a computerized system for blood donation management that allows for secure, reliable and easy access to stored data.

Uploaded by

parteek singhal
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 82

 

   PROJECT REPORT 
ON 
“WEB MEET UP” 
 
Submitted in partial fulfillment of the 
Requirement for the award of the degree of 
 
BACHELOR OF COMPUTER APPLICATION 
 

 
 
                      Submitted To: -               Submitted By:- 
                      Mrs. Shaliee Bhatia                             MAYANK 

                      VSIT,VIPS                                           Enroll no. – 02117702019 


                                                   BCA – 5(A) 
 
(Batch: 2016-2019) 
Vivekananda Institute of Professional Studies 
(Affiliated to Guru Gobind Singh Indraprastha University) 

CERTIFICATE 
 
This is to certify that I Mayank of BCA 5th Semester from Vivekananda Institute of
Professional Studies, Delhi has presented this project work entitled “WEB MEET UP”, a
blood donation management web application in partial fulfillment of the requirements for the
award of the degree of Bachelor of Computer Applications under our supervision and
guidance. 
ACKNOWLEDGEMENT 
It is our proud privilege to express our profound gratitude to the entire management of
Vivekananda Institute of Professional Studies and teachers of the institute for providing us
with the opportunity to avail the excellent facilities and infrastructure. The knowledge and
values inculcated have proved to be of immense help at the very start of my career. Special
thanks to Hon’ble Founder, Vivekananda Institute of Professional Studies, Delhi for having
provided us an excellent infrastructure at VSIT. 
I am grateful to Prof. (Dr.) Supriya Madan (Dean, VSIT), and Mrs. Shaliee Bhatia for their
astute guidance, constant encouragement and sincere support for this project work. 
Sincere thanks to all my family members, seniors and friends for their support and assistance
throughout the project. 

ABSTRACT 
 
The purpose of Web meet upis to automate the existing manual system by the help of
computerized equipment and full-fledged computer software, fulfilling their requirements, so
that their valuable data/information can be stored for a longer period with easy accessing and
manipulation of the same. The required software and hardware are easily available and easy
to work with. Web meet up, as described above, can lead to error free, secure, reliable and
fast management system. It can assist the user to concentrate on their other activities rather to
concentrate on the record keeping. Thus it will help organization in better utilization of
resources. The organization can maintain computerized records without redundant entries.
That means that one need not be distracted by information that is not relevant, while being
able to reach the information. The aim is to automate its existing manual system by the help
of computerized equipment and full-fledged computer software, fulfilling their requirements,
so that their valuable data/information can be stored for a longer period with easy accessing
and manipulation of the same. Basically the project describes how to manage for good
performance and better services for the clients. 
 
 
 
 
 
 
 
TABLE OF CONTENTS 
CHAPTER – 1 INTRODUCTION                                                                                      9 
       1.1 OBJECTIVE                                                                                                            10 
       1.2 EXISTING SYSTEM                                                                                              11 
       1.3 PROPOSED SYSTEM                                                                                            11 
       1.4 MODULE                                                                                                                 12 
       1.5 USER INTERFACE                                                                                                13 
       1.6 BENEFITS                                                                                                                13 
       1.7 LIMITATIONS                                                                                                        14 
CHAPTER – 2 REQUIREMENT ANALYSIS                                                                  16 
       2.1 ANALYSIS                                                                                                               16 
       2.2 FEASIBILITY STUDY                                                                                           17 
       2.3 TECHNOLOGIES                                                                                                   19 
       2.4 TOOLS USED                                                                                                          19 
       2.5 USER AND SYSTEM REQUIREMENTS                                                            20 
       2.6 OPERATING ENVIRONMENT                                                                           22 
       2.7 USER CLASSES                                                                                                      23 
       2.8 DESIGN CONSTRAINTS                                                                                      23 
         2.9 SYSTEM FEATURES                                                                                          23 
CHAPTER – 3 DESIGN OF THE SYSTEM                                                                     27 
        3.1 USE CASE DIAGRAM                                                                                          27 
        3.2 DATA FLOW DIAGRAM (DFD)                                                                         30 
        3.4 DATA DICTIONARY                                                                                          
38 
CHAPTER – 4 CODE                                                                                                       
42 
        4.1 IMPLEMENTATION AND CODING                                                             
42 
        4.2TESTING                                                                                                                
178              
        4.3 TEST RESULTS                                                                                                
189 
        4.4 SECURITY                                                                                                              
200             
        4.5 LIMITATIONS OF THE PROJECT                                                                    
205 
CONCLUSION                                                                                                                      
207 
        5.1 CONCLUSION                                                                                                        
207 
        5.2 FUTURE SCOPE OF THE PROJECT                                                                 
208 
BIBLIOGRAPHY                                                                                                                  
209 
                                                                                     
  
 
 
 
 
 
 
S.NO.                            FIGURES                                           PAGE
NO. 
2.                Fig 2.2.9 Non Functional Requirements                                                       25 
3.                Fig 3.1 Use case Diagram                                                                               29  
                   Fig 3.2.1 Process Notations                                                                            32 
                   Fig 3.2.2 Data Store Notations                                                                       32 
                   Fig 3.2.3 External Entity Notations                                                               32 
                   Fig 3.2.4 Data Flow Notations                                                                        32 
                   Fig 3.2.5 Zero Level DFD                                                                               33 
                   Fig 3.2.6 First Level DFD                                                                               34 
                   Fig 3.2.7 Second Level DFD                                                                           34 
                   Fig 3.3.1 Entity                                                                                                36 
                   Fig 3.3.2 Attribute                                                                                           36 
                   Fig 3.3.3 Relationship                                                                                     37 
                   Fig 3.3.4 ER Diagram                                                                                     37 
                   3.4 Blood Inventory Table                                                                              39 
                   3.4 Donor’s Table                                                                                            40 
                   3.4 Handover Request’s Table                                                                       40 
                   3.4 Request’s Table                                                                                         41 
                   3.4 User’s Table                                                                                               41 
4.                Fig 4.3.1 Login Page                                                                                        189 
                   Fig 4.3.2 Home Page                                                                                        190 
                   Fig 4.3.3 Donor’s Page                                                                                    191 
                   Fig 4.3.5 Donor’s Quantity Page                                                                     
193 
                   Fig 4.3.6 Donation’s Form                                                                               
194 
                   Fig 4.3.7 Request Page                                                                                     
195 
                   Fig 4.3.8 Request Form                                                                                    
196 
                   Fig 4.3.9 Handover Page                                                                                  
197 
                   Fig 4.3.10 User Page                                                                                         
198 
                   Fig 4.3.11 User Form                                                                                        
199 
 
INTRODUCTION 
• Web meet-up is a website which is specifically designed to allow users to talk to
strangers. It works by randomly matching users to talk one-to-one using either
text or video. 
• It is anonymous to use, with no account registration.
• The purpose of this website is to make a web application using React-js.
• This web app is consisted of video camera, chat bar, voice recognition.
• The project helped in gaining practical knowledge on several topics like
designing web pages using ReactJS library, usage of express to create backend
server, designing of web applications and management of database using Stripe
API.

.  
1.1 OBJECTIVE 
• Web meet-up is a website which is specifically designed to allow users to talk to strangers. It
works by randomly matching users to talk one-to-one using either text or video. 

• It is anonymous to use, with no account registration.

CHAPTER – 2 
 
REQUIREMENT ANALYSIS 
Before we begin a new system it is important to study the system that will be improved or
replaced (if there is one).We need to analyze how this system uses hardware, software,
network and the people resources to convert data resources, such as transaction data, into
information products, such as reports and displays. Thus, we should document how the
information system activities of input, processing, output, storage and control are
accomplished. 
  
2.1 ANALYSIS STUDY 
1. Open Communication Environment: 
It provides a good way of communication between the user (customer) and the admin of the
system. The potential customer gets to see a wide variety of products available to him. He
may order the products which he desires to buy and later on give a feedback regarding the
selected item and the admin can reply to that feedback. Which leads to an healthy
communication between the user and the manager. 
2. Lower Installation Charges: 
We neither require any high configuration systems for smooth running of server program, nor
do we require any high configuration systems for smooth running of a client program. This
application is designed with an ease to support any ordinary system having a internet
connection. At the server the charges are only for setting up the LAN connections but not the
systems.   
3. Secured and Reliable: 
The messages that travel across the LAN are enclosed in the form of TCP packets which are a
secured form of data transfer that is most widely used across the globe. So, the private
sessions would be done in a secured form without a third-party interface. 
4. Simple to use and Easy to Understand: 
The coding of this application is a tedious job. But the client and server modules are enclosed
in servlet and jsp pages. The user only needs a web browser to start interpreting the coding
done in these pages.   
5. Platform Independent 
Since the project is done completely in java, it also executes main properties of language. The
given application is platform independent. So, the client systems may have vista, Linux, Mac
or any other operating system, but they can connect to server easily without any dependencies
of OS. 
2.2 FEASIBILITY STUDY 
Feasibility Study is the test of the System proposal according to its workability, impact on the
current System, ability to meet the needs of the current users and effective use of the
resources. 
Its main objective is not to solve the problem, but to acquire its s cope. It focuses on
following: 
• Meet user requirements 
• Best utilization of available resources 
• Develop a cost effective System 
• Develop a technically feasible System  
There are three aspects in the feasibility study: 
• Technical Feasibility 
• Economical Feasibility 
• Operational Feasibility 
 
2.2.1 TECHNICAL FEASIBILITY 
Issues to be studied are, whether the work for the project will be done with current
equipment, existing S/W technology and available personnel? If the new technology is
required, then what is the likelihood that it can be developed? 
This software is technically feasible. The primary technical requirement includes the
availability of Windows 7 or higher version of operating Systems installed in the network.
MySQL is also required which was already installed. To develop programs NetBeans 8.1 or
higher was required which was also available. Reliability, access power and data
security was also available. Thus, through all the ends technical feasibility was met. 
 
2.2.2 ECONOMICAL FEASIBILITY 
Issues to be studied are, whether the new System is cost effective or not? he benefits in the
form of reduced cost? 
This software is economically feasible. As the hardware was installed from quite beginning,
the cost on project of hardware is low. Similarly, the software loaded for this project was
used for many other applications. The software cost was under budget. As student trainees
were developing the application, there were no major personnel costs associated. 
Moreover, the technical requirements were already available so there was no further
expenditure for buying software packages. 
 
 
2.2.3 OPERATIONAL FEASIBILITY 
 
Issues to be studied are, is there sufficient support for management and users? Is the current
method acceptable to users? Will the proposed system cause any harm? 
This software is operationally feasible. This application provides the necessary information to
the user such as how to enter the information regarding different operations performed on the
database. The application was planned in such a way that no prior knowledge was required to
go through the various operations. The user just needed to have the basic knowledge of
computers. 
 
2.3 TECHNOLOGIES 
Languages -  HTML, CSS, JAVASCRIPT, PHP
BOOTSTRAP  
RDBMS - MySQL 
Web Server - Apache Tomcat 8.5 
 
2.4 TOOLS USED 
Editor Used - VISUAL STUDIO CODE 
Operating System - Windows 8, 10 
Processor - X86 Compatible processor with 2.25 GHz Clock speed 
 
 
 
 
2.5 USER AND SYSTEM REQUIREMENTS 
2.5.1 OBJECTIVE  
The main objective of this specification is to support the automated tracking of blood
products from the initial ordering of a blood transfusion for a patient, through to the taking of
a blood sample for cross matching, to administration of a blood transfusion and subsequent
updates to care records. To allow the probable recipients to make search and match the
volunteer donors, and make request for the blood.  
2.5.2 INTRODUCTION  
Blood sales and blood purchase are entered and maintained in this project. Blood stock
reports, sales reports and blood purchase reports are managed in this project. It will help us to
find the blood group with its most efficient time to take care of the blood and it is more
easy to hand over the blood to the hospitals to help people to get blood on time. This all thing
is been stored and been seen in this Web meet up. To help more people trying best to do so. 
2.5.3 PURPOSE  
Blood Bank Management Software is designed & suitable for several Blood Bank either
operating as individual organization or part of Hospital. It covers all Blood banking process
from Donor recruitment, donor management, mobile sessions, component preparation,
screening covering all tests, blood stock inventory maintenance, patient registration, cross
matching, patient issues etc. 
2.5.4 INTENDED USER 
Anybody can use this BBMS to Donor as well as who need blood e.g., Public, Hospitals,
Blood Banks, etc. 
 
2.5.5 PROJECT SCOPE  
The scope of the specification includes the following scenarios: Routine blood transfusion;
Transfusion for special requirements (for example, cytomegalovirus (CMV) negative blood,
irradiated blood or antigen negative blood); Emergency issue of blood; Management of
returned and unused blood units. 
2.5.6 LIMITATIONS END 
 User’s will not be able to get the information about the availability of the blood in the bank
of which he/she donated. Only the Admin has all right to edit the things in the End User’s
Profile.  
2.5.7 OVERALL DESCRIPTION 
Product Prospective  
• To provide a means for the blood bank to publicize and advertise blood
donation programs.  
• To provide an efficient donor and blood stock management functions to the
blood bank by recording the donor and blood details.  
• To improve the efficiency of blood stock management by alerting the blood
bank staffs when the blood quantity is below it par level or when the blood stock has
expired.  
• To provide pure blood with no wastages blood is been collected in different
types of packs.  
• They are double, triple, and triple (AS), quadruple pack. 
• To provide synchronized and centralized donor and blood stock database.  
• To provide immediate storage and retrieval of data and information. 
 
Product Features  
Login Interface  
User should enter the valid username and password to get access to its profile. 
Donor Profile  
User will be able to see its Account No. , 
The receipts of the blood donated to the bank, Donation to the Bank, Need of the
Blood to the Bank and Request for Blood. 
  
2.6 OPERATING ENVIRONMENT 
Operating system :  
Processor  -  X86 Compatible processor with 2.25 GHz Clock speed 
RAM         -  4GB  or more. 
Hard disk   - 50 GB or more. 
Monitor     - VGA/SVGA. 
Keyboard  - 104 Keys. 
Mouse - 2 buttons/ 3 buttons.  
Operating System - Windows8.1/10. 
 
2.7 USER CLASSES  
System Owner: The Blood Bank System Users: 
Administrators: has full privilege on the system's functions  
Public: can view the blood donation events and donate or can make requests for donation
(Donor and Recipients fall under this category). 
 
2.8 DESIGN CONSTRAINTS  
GUI will be only in English. 
2.9 SYSTEM FEATURES  
2.9.1 FUNCTIONAL REQUIREMENTS 
Login the system provides security features through username-password matching where
only authorized user can access the system with different authorization level. 
Admin  
Input:-Username, Password  
Output: - Invalid or Update Blood Details, logout Donor Profile Registration This allows
healthy public to register as volunteer donor. 
  
Blood Stock Management  
The blood bank staffs can manage the blood stock starting from the blood collection, to blood
screening, processing, storage, transference and transfusion through this system. Each process
or work-flow can be traced from the database. The system will also raise alert to the staff
whenever the blood quantity is below its par level or when the blood in stock has expired.
Donor/Recipient Management The records of all donors/recipient and their history are kept in
one centralized database and thus reducing duplicate data in the database. The record of
donation is maintained by the system. 
 Input:-Blood Type 
Output:-No. of Blood Bottle Available. 
2.9.2 NON FUNCTIONAL REQUIREMENTS  
Availability 
 The system should be available at all times, meaning the user can access it using application.
In case of a of a hardware failure or database corruption, a replacement page will be
shown. Also in case of a hardware failure or database corruption, backups of the database
should be retrieved from the application data folder and saved by the administrator. It means
24 x 7 availability. 
Security 
The system use SSL (secured socket layer) in all transactions that include any confidential
customer information. The system must automatically log out all customers after a period of
inactivity. 
Performance  
The system is interactive and the delays involved are less. When connecting to the server the
delay is based editing on the distance of the 2 systems and the configuration between them so
there is high probability that there will be or not a successful connection in less than 20
seconds for sake of good communication.  
Reliability  
As the system provide the right tools for problem solving it is made in such a way that the
system is reliable in its operations and for securing the sensitive details. 

Advantages: 
 Easy to understand and implement. Testing in each phase. Documentation Available after
each phase. Most Suitable for single projects where work products are well defined and their
functioning is understood.  
 
Disadvantages : 
Once detecting error at any face it may be required that the precede subsidy faces may
change. Very difficult to manage changes b/w the phases there are possibility of blocking
which can slow down the productivity and efficiency of the process. Risk is not addressed in
this mode. 
Advantage of Model in this System  
• Easy to Understand It is the basic model of all models.  
• Errors are detected after each Phase of Development.  
            • It is Single and Small Project. 
 
 
 
 
 
 
 
 
 
CHAPTER – 3 
 
DESIGN OF THE SYSTEM 
3.1 USE CASE DIAGRAM 
 
A use case diagram is a way to summarize details of a system and the users within that
system. It is generally shown as a graphic depiction of interactions among different elements
in a system. Use case diagrams will specify the events in a system and how those events flow,
however, use case diagram does not describe how those events are implemented. 
A use case is a methodology used in system analysis to identify, clarify, and organize system
requirements. In this context, the term "system" refers to something being developed or
operated, such as a mail-order product sales and service Web site. Use case diagrams are
employed in UML (Unified Modeling Language), a standard notation for the modeling of
real-world objects and systems. There are a number of benefits with having a use case
diagram over similar diagrams such as flowcharts. 
Its is Composed of: 
Actor: 
 Someone interacts with use case (system function). 
 Named by noun. 
 Actor plays a role in the business 
 Similar to the concept of user, but a user can play different roles. 
 Use Case: 
 System function (process - automated or manual) 
Named by verb + Noun (or Noun Phrase). 
i.e. Do something 
 Each Actor must be linked to a use case, while some use cases may not
be linked to actors. 
 Communication link: 
 The participation of an actor in a use case is shown by connecting an
actor to a use case by a solid link. 
 Actors may be connected to use cases by associations, indicating that
the actor and the use case communicate with one another using messages. 

3.2 DATA FLOW DIAGRAM (DFD) 


Data flow diagrams are used to graphically represent the flow of data in a business
information system. DFD describes the processes that are involved in a system to transfer
data from the input to the file storage and reports generation. 
Data flow diagrams can be divided into logical and physical. The logical data flow diagram
describes flow of data through a system to perform certain functionality of a business. The
physical data flow diagram describes the implementation of the logical data flow. 
DFD graphically representing the functions, or processes, which capture, manipulate, store,
and distribute data between a system and its environment and between components of a
system. The visual representation makes it a good communication tool between User and
System designer. Structure of DFD allows starting from a broad overview and expand it to a
hierarchy of detailed diagrams. DFD has often been used due to the following reasons: 
• Logical information flow of the system 
• Determination of physical system construction requirements 
• Simplicity of notation 
• Establishment of manual and automated systems requirements. 
The diagrams are: 
Graphical, eliminating thousands of words; 
• Logical representations, modelling ‘WHAT’ a System does, rather than physical
models showing ‘HOW’ it does it; 
• Hierarchical, showing System s at any level of detail; and Jargon less, allowing user
understanding and reviewing. 
The goal of data flow diagramming is to have a commonly understood model of a System.
The diagrams are the basis of structured System’s analysis. Data flow diagrams are supported
by other techniques of structured System s analysis such as data structure diagrams, data
dictionaries, and procedure-representing techniques such as decision tables, decision trees,
and structured English. 
The objective of Data flow diagrams is avoiding the cost of user/developer misunderstanding
of a System, resulting in a need to redo System’s or in not using the System. 
Having to start documentation from scratch when the physical System changes since the
logical System, ‘WHAT’ gets done, often remains the same when technology changes. 
It helps in removing inefficiencies of System because a System gets "computerized" before it
gets "Systematized". Also helps enabling to evaluate System project boundaries or degree of
automation, resulting in a project of inappropriate scope. 
3.2.1 DFD SYMBOLS 
In the DFD, there are four symbols shown in figure below: 
Ø A Square defines a source (originator) or destination of data pipeline through which
information flows. 
Ø An Arrow identifies data flow data in motion. It is a pipeline through which
information flows. 
Ø A Circle or a "bubble" (some people use an oval bubble) represents a process that
transforms incoming data flow into outgoing data flow. 
Ø An Open rectangle is a data store - data at rest, or a temporary repository of data. 
 
 
3.2 DATA FLOW DIAGRAM (DFD) 
Data flow diagrams are used to graphically represent the flow of data in a business
information system. DFD describes the processes that are involved in a system to transfer
data from the input to the file storage and reports generation. 
Data flow diagrams can be divided into logical and physical. The logical data flow diagram
describes flow of data through a system to perform certain functionality of a business. The
physical data flow diagram describes the implementation of the logical data flow. 
DFD graphically representing the functions, or processes, which capture, manipulate, store,
and distribute data between a system and its environment and between components of a
system. The visual representation makes it a good communication tool between User and
System designer. Structure of DFD allows starting from a broad overview and expand it to a
hierarchy of detailed diagrams. DFD has often been used due to the following reasons: 
• Logical information flow of the system 
• Determination of physical system construction requirements 
• Simplicity of notation 
• Establishment of manual and automated systems requirements. 
The diagrams are: 
Graphical, eliminating thousands of words; 
• Logical representations, modelling ‘WHAT’ a System does, rather than physical
models showing ‘HOW’ it does it; 
• Hierarchical, showing System s at any level of detail; and Jargon less, allowing user
understanding and reviewing. 
The goal of data flow diagramming is to have a commonly understood model of a System.
The diagrams are the basis of structured System’s analysis. Data flow diagrams are supported
by other techniques of structured System s analysis such as data structure diagrams, data
dictionaries, and procedure-representing techniques such as decision tables, decision trees,
and structured English. 
The objective of Data flow diagrams is avoiding the cost of user/developer misunderstanding
of a System, resulting in a need to redo System’s or in not using the System. 
Having to start documentation from scratch when the physical System changes since the
logical System, ‘WHAT’ gets done, often remains the same when technology changes. 
It helps in removing inefficiencies of System because a System gets "computerized" before it
gets "Systematized". Also helps enabling to evaluate System project boundaries or degree of
automation, resulting in a project of inappropriate scope. 
3.2.1 DFD SYMBOLS 
In the DFD, there are four symbols shown in figure below: 
Ø A Square defines a source (originator) or destination of data pipeline through which
information flows. 
Ø An Arrow identifies data flow data in motion. It is a pipeline through which
information flows. 
Ø A Circle or a "bubble" (some people use an oval bubble) represents a process that
transforms incoming data flow into outgoing data flow. 
Ø An Open rectangle is a data store - data at rest, or a temporary repository of data. 
 
 
3.3 ENTITY RELATIONSHIP DIAGRAM ( ER
DIAGRAM ) 
 
ER Diagram stands for Entity Relationship Diagram, also known as ERD is a diagram that
displays the relationship of entity sets stored in a database. In other words, ER diagrams help
to explain the logical structure of databases. ER diagrams are created based on three basic
concepts: entities, attributes and relationships. 
  
ER Diagrams contain different symbols that use rectangles to represent entities, ovals to
define attributes and diamond shapes to represent relationships. 
At first look, an ER diagram looks very similar to the flowchart. However, ER Diagram
includes many specialized symbols, and its meanings make this model unique. The purpose
of ER Diagram is to represent the entity framework infrastructure.  
ER model helps to systematically analyze data requirements to produce a well-designed
database. The ER Model represents real-world entities and the relationships between them.
Creating  
an ER Model in DBMS is considered as a best practice before implementing your database 
In software engineering an entity relationship model diagram (E-R model diagram) is a data
model for describing a database in an abstract way. An ER diagram shows the relationship
among entity sets. An entity set is a group of similar entities and these entities can have
attributes. In terms of DBMS, an entity is a table or attribute of a table in database, so by
showing relationship among tables and their attributes, ER diagram shows the complete
logical structure of a database. It is widely used to develop an initial design of a database. It
describes data as a collection of entities, relationship and attributes. 
E-R Diagram are composed of: 
a) ENTITY: 
An entity is an object or component of data. An entity is represented as rectangle in an ER
diagram. 

 
Fig 3.3.1 
 
 
b) ATTRIBUTE: 
An attribute describes the property of an entity. An attribute is represented as Oval in an ER
diagram. There are four types of attributes: 
Ø Key attribute 
Ø Composite attribute 
Ø Multivalued attribute 
Ø Derived attribute 
3.4 DATA DICTIONARY 
A Data Dictionary is a collection of names, definitions, and attributes about dat
a elements that are being used or captured in a database, information system,
or part of a research project. It describes the meanings and purposes of
data elements within the context of a project, and provides guidance
on interpretation, accepted meanings and representation. A Data Dictionary
also provides metadata about data elements. The metadata included in 
A Data Dictionary can assist in defining the scope and characteristics of data
elements, as well the rules for their usage and application. 
Data Dictionaries are useful for a number of reasons. In short, they: 
 Assist in avoiding data inconsistencies across a project. 
 Help define conventions that are to be used across a project. 
 Provide consistency in the collection and use of data across multiple members
of a research team. 
 Make data easier to analyse. 
 Enforce the use of Data Standards. 
 
 
CHAPTER – 4   
 
CODE 
 
1. IMPLEMENTATION AND CODING 
 
export const callType = {
    CHAT_PERSONAL_CODE: "CHAT_PERSONAL_CODE",
    VIDEO_PERSONAL_CODE: "VIDEO_PERSONAL_CODE",
    CHAT_STRANGER: "CHAT_STRANGER",
    VIDEO_STRANGER: "VIDEO_STRANGER",
}

export const preOfferAnswer = {


    CALLEE_NOT_FOUND: "CALLEE_NOT_FOUND",
    CALL_ACCEPTED: "CALL_ACCEPTED",
    CALL_REJECTED: "CALL_REJECTED",
    CALL_UNAVAILABLE: "CALL_UNAVAILABLE",
}

export const webRTCSignaling = {


    OFFER: "OFFER",
    ANSWER: "ANSWER",
    ICE_CANDIDATE: "ICE_CANDIDATE",
}

export const callState = {


    CALL_AVAILABLE: "CALL_AVAILABLE",
    CALL_UNAVAILABLE: "CALL_UNAVAILABLE",
    CALL_AVAILABLE_ONLY_CHAT: "CALL_AVAILABLE_ONLY_CHAT",
}
export const getIncomingCallType = (callerTypeInfo, acceptCallHandler,
rejectCallHandler) => {
    // console.log("call dialog box :" + callerTypeInfo);

    const dialogContent = getDialogBox(`Incoming ${callerTypeInfo} call`);


    const dialog = dialogContent.parentElement;

    const imageContainer = getDialogImageContainer();


    dialogContent.appendChild(imageContainer);

    const buttonContainer = document.createElement("div");


    buttonContainer.classList.add("dialog_button_container");
    dialogContent.appendChild(buttonContainer);

    const acceptCallButton = getAcceptCallButton();


    buttonContainer.appendChild(acceptCallButton);

    const rejectCallButton = getRejectCallButton();


    buttonContainer.appendChild(rejectCallButton);

    acceptCallButton.addEventListener("click", () => {
        acceptCallHandler();
    })

    rejectCallButton.addEventListener("click", () => {
        rejectCallHandler();
    })

    return dialog;
}

export const getCallingDialog = (callingDialogRejectCallHandler) => {


    // console.log("calling dialog box");

    const dialogContent = getDialogBox("Calling. . .");


    const dialog = dialogContent.parentElement;

    const imageContainer = getDialogImageContainer()


    dialogContent.appendChild(imageContainer);

    const buttonContainer = document.createElement("div");


    buttonContainer.classList.add("dialog_button_container");
    dialogContent.appendChild(buttonContainer);

    const hangUpCallButton = getRejectCallButton();


    buttonContainer.appendChild(hangUpCallButton);

    hangUpCallButton.addEventListener("click",
callingDialogRejectCallHandler);

    return dialog;
}

export const getInfoDialog = (dialogTitle, dialogDescription) => {


    // console.log("Info call dialog box");

    const dialogContent = getDialogBox(dialogTitle);


    const dialog = dialogContent.parentElement;

    const imageContainer = getDialogImageContainer()


    dialogContent.appendChild(imageContainer);

    const description = document.createElement('div');


    description.classList.add("dialog_description");
    description.innerHTML = dialogDescription;
    dialogContent.appendChild(description);

    return dialog;
}

const getDialogImageContainer = () => {


    const imageContainer = document.createElement("div");
    imageContainer.classList.add("dialog_image_container");
    const image = document.createElement("img");
    const avatarImagePath = "../utils/images/dialogAvatar.png"
    image.src = avatarImagePath;
    imageContainer.appendChild(image);
    return imageContainer;
}

const getRejectCallButton = () => {


    const rejectCallButton = document.createElement("button");
    rejectCallButton.classList.add("dialog_reject_call_button");
    const rejectCallImage = document.createElement("img");
    const rejectCallImagePath = "../utils/images/rejectCall.png";
    rejectCallImage.src = rejectCallImagePath;
    rejectCallButton.appendChild(rejectCallImage);
    return rejectCallButton;
}

const getAcceptCallButton = () => {


    const acceptCallButton = document.createElement("button");
    acceptCallButton.classList.add("dialog_accept_call_button");
    const acceptCallImage = document.createElement("img");
    const acceptCallImagePath = "../utils/images/acceptCall.png";
    acceptCallImage.src = acceptCallImagePath;
    acceptCallButton.appendChild(acceptCallImage);
    return acceptCallButton;
}

const getDialogBox = (dialogTitle) => {


    const dialog = document.createElement("div");
    dialog.classList.add("dialog_wrapper");
    const dialogContent = document.createElement("div");
    dialogContent.classList.add("dialog_content");
    dialog.appendChild(dialogContent);

    const title = document.createElement("p");


    title.classList.add("dialog_title");
    title.innerHTML = dialogTitle;
    dialogContent.appendChild(title);
    return dialogContent;
}

export const getMessage = (message, isRight) => {


    const messageContainer = document.createElement("div");
    let constainerClass = isRight ? "message_right_container" :
"message_left_container";
    messageContainer.classList.add(constainerClass);
    const messageParagraph = document.createElement("div");
    let paragraphClass = isRight ? "message_right_paragraph" :
"message_left_paragraph";
    messageParagraph.classList.add(paragraphClass);
    messageParagraph.innerHTML = message;
    messageContainer.appendChild(messageParagraph);

    return messageContainer;
}
import * as store from "./store.js";
import * as wss from "./wss.js";    //connection file
import * as webRTCHandler from "./webRTCHandler.js";
import * as constants from "./constants.js";
import * as ui from "./ui.js";
import * as recordingUtils from "./recordingUtils.js";
import * as strangerUtils from "./strangerUtils.js";

// initialization of socket.io connection


const socket = io("/");
wss.registerSocketEvents(socket);
webRTCHandler.getLocalPreview() //set local video to local video container
// register event listner for personalCode copy button
const personalCodeCopyButton =
document.getElementById("personal_code_copy_button");
personalCodeCopyButton.addEventListener("click", () => {
  const personalCode = store.getState().socketId;
  navigator.clipboard && navigator.clipboard.writeText(personalCode);
})

// register event listeners for connection call_buttons


const personalCodeChatButton =
document.getElementById("personal_code_chat_button");
const personalCodeVideoButton =
document.getElementById("personal_code_video_button");

personalCodeChatButton.addEventListener("click", () => {
  const calleePersonalCode =
document.getElementById("personal_code_input").value;
  const callType = constants.callType.CHAT_PERSONAL_CODE;

  webRTCHandler.sendPreOffer(callType, calleePersonalCode);
})

personalCodeVideoButton.addEventListener("click", () => {
  const calleePersonalCode =
document.getElementById("personal_code_input").value;
  const callType = constants.callType.VIDEO_PERSONAL_CODE;

  webRTCHandler.sendPreOffer(callType, calleePersonalCode);
})

//Add event listners for Stranger buttons


const strangerChatButton = document.getElementById("stranger_chat_button");
strangerChatButton.addEventListener("click", () => {
  //TODO
 
strangerUtils.getStrangerSocketIdAndConnect(constants.callType.CHAT_STRANGER);
});

const strangerVideoButton = document.getElementById("stranger_video_button");


strangerVideoButton.addEventListener("click", () => {
  // TODO
 
strangerUtils.getStrangerSocketIdAndConnect(constants.callType.VIDEO_STRANGER)
;
})

//register event for allow connection from strangers


const checkbox = document.getElementById("allow_strangers_checkbox");
checkbox.addEventListener("click", () => {
  const checkboxState = store.getState().allowConnectionsFromStrangers;
  ui.updateStrangerCheckBox(!checkboxState);
  store.setAllowConnectionsFromStrangers(!checkboxState);
  strangerUtils.changeStrangerConnectionStatus(!checkboxState);
});

// event listener for video call buttons


const micButton = document.getElementById("mic_button");
micButton.addEventListener("click", () => {
  const { localStream } = store.getState();
  const auditTrack = localStream.getAudioTracks()[0];
  auditTrack.enabled = !auditTrack.enabled;   //toggle audio track
  ui.updateMicButton(auditTrack.enabled);
})

const cameraButton = document.getElementById("camera_button");


cameraButton.addEventListener("click", () => {
  const { localStream } = store.getState();
  const videoTrack = localStream.getVideoTracks()[0];
  videoTrack.enabled = !videoTrack.enabled;
  ui.updateCameraButton(videoTrack.enabled);
})

const switchForScreenSharingButton =
document.getElementById("screen_sharing_button");
switchForScreenSharingButton.addEventListener("click", () => {
  const { screenSharingActive } = store.getState();
  webRTCHandler.switchBetweenCameraAndScreenSharing(screenSharingActive);
})

//messenger
const newMessageInput = document.getElementById("new_message_input");

const sendMessage = () => {


  // console.log("Chat Occured");
  let message = newMessageInput.value;
  if(!!newMessageInput.value.trim()){
    webRTCHandler.sendMessageUsingDataChannel(message);
    ui.appendMessage(message, true);
  }
  newMessageInput.value = "";
}

newMessageInput.addEventListener("keydown", (event) => {


  const key = event.key;
  if(key === "Enter") {
    sendMessage();
  }
})

const sendMessageButton = document.getElementById("send_message_button");


sendMessageButton.addEventListener("click", sendMessage);

//recording
const startRecordingButton =
document.getElementById("start_recording_button");
startRecordingButton.addEventListener("click", () => {
  recordingUtils.startRecording();
  ui.showRecordingPanel();
})

const stopRecordingButton = document.getElementById("stop_recording_button");


stopRecordingButton.addEventListener("click", () => {
  recordingUtils.stopRecording();
  ui.hideRecordingPanel();
})

const pauseRecordingButton =
document.getElementById("pause_recording_button");
pauseRecordingButton.addEventListener("click", () => {
  recordingUtils.pauseRecording();
  ui.switchBetweenRecordingButtons(true);
});

const resumeRecordingButton =
document.getElementById("resume_recording_button");
resumeRecordingButton.addEventListener("click", () => {
  recordingUtils.resumeRecording();
  ui.switchBetweenRecordingButtons(false);
});

//hang up

const hangUpButton = document.getElementById("hang_up_button");


hangUpButton.addEventListener("click", () => {
  webRTCHandler.handleHangUp();
});

const hangUpChatButton = document.getElementById("finish_chat_call_button");


hangUpChatButton.addEventListener("click", () => {
  webRTCHandler.handleHangUp();
});

import * as store from "./store.js";


let mediaRecorder;
let recordedChunks = [];

const vp9Codec = "video/webm; codecs=vp=9";


const videoOptions = { mimeType: vp9Codec };

export const startRecording = () => {


    // console.log("startRecording-recordingUtils")
    const remoteStream = store.getState().remoteStream;

    if (MediaRecorder.isTypeSupported(vp9Codec)) {
        mediaRecorder = new MediaRecorder(remoteStream, videoOptions);
    } else {
        mediaRecorder = new MediaRecorder(remoteStream);
    }

    mediaRecorder.ondataavailable = handleDataAvailable; //will be called when


recording is finished
    mediaRecorder.start();
}

export const pauseRecording = () => {


    // console.log("pauseRecording-recordingUtils")
    mediaRecorder.pause();
}

export const resumeRecording = () => {


    // console.log("resumeRecording-recordingUtils")
    mediaRecorder.resume();
}

export const stopRecording = () => {


    // console.log("stopRecording-recordingUtils")
    mediaRecorder.stop();
}

const downloadRecordedVideo = () => {


    // console.log("downloadRecordedVideo-recordingUtils")
    const blob = new Blob(recordedChunks, { type: 'video/webm' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    document.body.appendChild(a);
    a.style = "display: none;"
    a.href = url;
    a.download = "recording.webm";
    a.click();
    window.URL.revokeObjectURL(url);
}
export const handleDataAvailable = (event) => {
    // console.log("handleDataAvailable-recordingUtils")
    if (event.data.size > 0) {
        recordedChunks.push(event.data);
        downloadRecordedVideo();
    }
}
import * as constants from "./constants.js";

//initial state
let state = {
    socketId: null,
    localStream: null,
    remoteStream: null,
    screenSharingStream: null,
    allowConnectionsFromStrangers: false,
    screenSharingActive: false,
    callState: constants.callState.CALL_AVAILABLE_ONLY_CHAT,
}

const setStateField = (field, value) => {


    if (!state.hasOwnProperty(field)) {
        throw new Error("state does not have property " + field);
    }
    state[field] = value;
    // console.log("Updated State: ", state);
}

export const setSocketId = (socketId) => {


    setStateField("socketId", socketId);
}

export const setLocalStream = (localStream) => {


    setStateField("localStream", localStream);
}

export const setRemoteStream = (remoteStream) => {


    setStateField("remoteStream", remoteStream);
}

export const setScreenSharingStream = (screenSharingStream) => {


    setStateField("screenSharingStream", screenSharingStream);
}

export const setAllowConnectionsFromStrangers =


(allowConnectionsFromStrangers) => {
    setStateField("allowConnectionsFromStrangers",
allowConnectionsFromStrangers)
}

export const setScreenSharingActive = (screenSharingActive) => {


    setStateField("screenSharingActive", screenSharingActive);
}

export const setCallState = (callState) => {


    setStateField("callState", callState);  
}

export const getState = () => {


    return state;
}

let connectedUserDetails = {
    callType: null,
    socketId: null,
}

export const setConnectedUserDetails = (data) => {


    if(data == null) {
        connectedUserDetails = {
            callType: null,
            socketId: null,
        }
    }else {
        connectedUserDetails.callType = data.callType ? data.callType :
connectedUserDetails.callType;
        connectedUserDetails.socketId = data.socketId ? data.socketId :
connectedUserDetails.socketId;
    }
}

export const getConnectedUserDetails = () => {


    return connectedUserDetails;
}

import * as wss from "./wss.js";


import * as webRTCHandler from "./webRTCHandler.js";
import * as ui from "./ui.js";

let strangerCallType;

export const changeStrangerConnectionStatus = (status) => {


    const data = { status };
    wss.changeStrangerConnectionStatus(data);
}

export const getStrangerSocketIdAndConnect = (callType) => {


    strangerCallType = callType;
    wss.getStrangerSocketId();
}

export const connectWithStranger = (data) => {


    // console.log(data.randomStrangerSocketId);
    if (data.randomStrangerSocketId) {
        webRTCHandler.sendPreOffer(strangerCallType,
data.randomStrangerSocketId);
    } else {
        // no stranger is available for connection
        ui.showNoStrangerAvailableDialogue();
    }
}
import * as constants from "./constants.js";
import * as elements from "./elements.js";

export const updatePersonalCode = (personalCode) => {


    const personalCodeParagraph =
document.getElementById("personal_code_paragraph");
    personalCodeParagraph.innerHTML = personalCode;
}

export const updateLocalVideo = (stream) => {


    const localVideo = document.getElementById("local_video");
    localVideo.srcObject = stream;

    localVideo.addEventListener("loadedmetadata", () => {
        localVideo.play();
    })
}

//buttons with which we can make video calls


export const showVideoCallButtons = () => {
    const personalCodeVideoButton =
document.getElementById("personal_code_video_button");
    const strangerVideoButton =
document.getElementById("stranger_video_button");

    showElement(personalCodeVideoButton);
    showElement(strangerVideoButton);
}

export const updateRemoteStream = (stream) => {


    const remoteVideo = document.getElementById("remote_video");
    remoteVideo.srcObject = stream;

    remoteVideo.addEventListener("loadedmetadata", () => {
        remoteVideo.play();
    })
}

//Incoming call pop up


export const showIncomingCallDialog = (callType, acceptCallHandler,
rejectCallHandler) => {
    const callerTypeInfo = callType ===
constants.callType.CHAT_PERSONAL_CODE ? "chat" : "video";
    const incomingCallDialog = elements.getIncomingCallType(callerTypeInfo,
acceptCallHandler, rejectCallHandler);

    // remove all dialog inside html dialog element


    const dialogHTML = document.getElementById("dialog");
    dialogHTML.querySelectorAll("*").forEach(dialog => dialog.remove());

    dialogHTML.appendChild(incomingCallDialog);
}

export const showCallingDialog = (callingDialogRejectCallHandler) => {


    const callingDialog =
elements.getCallingDialog(callingDialogRejectCallHandler);

    // remove all dialog inside html dialog element


    removeAllDialogs();

    const dialogHTML = document.getElementById("dialog");


    dialogHTML.appendChild(callingDialog);
}

export const removeAllDialogs = () => {


    // remove all dialog inside html dialog element
    const dialogHTML = document.getElementById("dialog");
    dialogHTML.querySelectorAll("*").forEach(dialog => dialog.remove());
}

export const showNoStrangerAvailableDialogue = () => {


    const infoDialog = elements.getInfoDialog("No Stranger Available", "Please
try again later");
    if (infoDialog) {
        const dialog = document.getElementById("dialog");
        dialog.appendChild(infoDialog);

        setTimeout(removeAllDialogs, 4000);
    }
}

export const showInfoDialog = (preOfferAnswer) => {


    let infoDialog;

    switch (preOfferAnswer) {
        case constants.preOfferAnswer.CALL_ACCEPTED:
            // show the dialog that call is accepted by the callee
            infoDialog = elements.getInfoDialog("Call accepted", "Callee
accepted your call");
            break;
        case constants.preOfferAnswer.CALL_REJECTED:
            // show the dialog that call is accepted by the callee
            infoDialog = elements.getInfoDialog("Call rejected", "Callee
rejected your call");
            break;
        case constants.preOfferAnswer.CALL_UNAVAILABLE:
            // show the dialog that callee is not able to connect
            infoDialog = elements.getInfoDialog("Call is not possible",
"Probably callee is busy. Please try again later");
            break;
        case constants.preOfferAnswer.CALLEE_NOT_FOUND:
            // show the dialog that callee has not been found
            infoDialog = elements.getInfoDialog("Callee not found", "Please
check personal code");
            break;
    }

    if (infoDialog) {
        const dialog = document.getElementById("dialog");
        dialog.appendChild(infoDialog);

        setTimeout(removeAllDialogs, 4000);
    }
}

export const showCallElements = (callType) => {


    switch (callType) {
        case constants.callType.CHAT_PERSONAL_CODE:
            showChatCallElements();
            break;
        case constants.callType.CHAT_STRANGER:
            showChatCallElements();
            break;
        case constants.callType.VIDEO_PERSONAL_CODE:
            showVideoCallElements();
            break;
        case constants.callType.VIDEO_STRANGER:
            showVideoCallElements();
            break;
    }
}

const showChatCallElements = () => {


    const finishConnectionChatButtonContainer =
document.getElementById("finish_chat_button_container");
    showElement(finishConnectionChatButtonContainer);

    const newMessageContainer = document.getElementById("new_message");


    showElement(newMessageContainer);

    disableDashboard();
}

const showVideoCallElements = () => {


    const callButtons = document.getElementById("call_buttons");
    showElement(callButtons);

    const placeHolder = document.getElementById("video_placeholder");


    hideElement(placeHolder);

    const remoteVideo = document.getElementById("remote_video");


    showElement(remoteVideo);

    const newMessageContainer = document.getElementById("new_message");


    showElement(newMessageContainer);

    disableDashboard();
}

// ui call buttons

const micOnImgSrc = "../utils/images/mic.png"


const micOffImgSrc = "../utils/images/micOff.png"
export const updateMicButton = (micActive) => {
    const micButtonImage = document.getElementById("mic_button_image");
    micButtonImage.src = micActive ? micOnImgSrc : micOffImgSrc;
}

const cameraOnImgSrc = "../utils/images/camera.png";


const cameraOffImgSrc = "../utils/images/cameraOff.png";
export const updateCameraButton = (cameraActive) => {
    const cameraButtonImage = document.getElementById("camera_button_image");
    cameraButtonImage.src = cameraActive ? cameraOnImgSrc : cameraOffImgSrc;
}
//ui after hang up
export const updateUIAfterHangUp = (callType) => {
    enableDashboard();

    //hide the call buttons


    if (callType === constants.callType.VIDEO_PERSONAL_CODE || callType ===
constants.callType.VIDEO_STRANGER) {
        const callButtons = document.getElementById("call_buttons");
        hideElement(callButtons);
    } else { //chat buttons
        const chatCallButtons =
document.getElementById("finish_chat_button_container");
        hideElement(chatCallButtons);
    }

    const newMessageInput = document.getElementById("new_message");


    hideElement(newMessageInput);
    clearMessage();

    updateMicButton(false);
    updateCameraButton(false);

    //hide remoteVideo and show placeHolder


    const remoteVideo = document.getElementById("remote_video");
    hideElement(remoteVideo);

    const placeHolder = document.getElementById("video_placeholder");


    showElement(placeHolder);

    removeAllDialogs(); // call dialogue


}

export const updateStrangerCheckBox = (allowConnections) => {


    const checkboxImg =
document.getElementById("allow_strangers_checkbox_image");
    allowConnections ? showElement(checkboxImg) : hideElement(checkboxImg);
}

// ui helper functions
const disableDashboard = () => {
    const dashboardBlocker = document.getElementById("dashboard_blur");
    if (dashboardBlocker.classList.contains("display_none")) {
        dashboardBlocker.classList.remove("display_none")
    }
}

// block panel
const enableDashboard = () => {
    const dashboardBlocker = document.getElementById("dashboard_blur");
    if (!dashboardBlocker.classList.contains("display_none")) {
        dashboardBlocker.classList.add("display_none")
    }
}

const hideElement = (element) => {


    if (!element.classList.contains("display_none")) {
        element.classList.add("display_none")
    }
}

const showElement = (element) => {


    if (element.classList.contains("display_none")) {
        element.classList.remove("display_none")
    }
}

//ui messages
export const appendMessage = (message, isRight = false) => {
    const messagesContainer = document.getElementById("messages_container");
    const messageElement = elements.getMessage(message, isRight);
    messagesContainer.appendChild(messageElement);
}

export const clearMessage = () => {


    const messageContainer = document.getElementById("messages_container");
    messageContainer.querySelectorAll("*").forEach(n => n.remove());
}

// recording
export const showRecordingPanel = () => {
    const recordingButtons =
document.getElementById("video_recording_buttons");
    showElement(recordingButtons);

    // hide start recording button if active


    const startRecordingButton =
document.getElementById("start_recording_button");
    hideElement(startRecordingButton);
}

export const hideRecordingPanel = () => {


    const recordingButtons =
document.getElementById("video_recording_buttons");
    hideElement(recordingButtons);

    // show start recording button


    const startRecordingButton =
document.getElementById("start_recording_button");
    showElement(startRecordingButton);
}

export const switchBetweenRecordingButtons = (showResumeButton = false) => {


    // console.log("switchBetweenRecordingButtons-ui")
    const pauseRecordingButton =
document.getElementById("pause_recording_button");
    const resumeRecordingButton =
document.getElementById("resume_recording_button");

    if (showResumeButton) {
        showElement(resumeRecordingButton);
        hideElement(pauseRecordingButton);
    } else {
        showElement(pauseRecordingButton);
        hideElement(resumeRecordingButton);
    }
}
import * as wss from "./wss.js";
import * as constants from "./constants.js";
import * as ui from "./ui.js";
import * as store from "./store.js";

const defaultConstraints = {
  audio: true,
  video: true
}

let peerConnection;
let dataChannel;

const configuration = {
  iceServers: [
    {
      urls: "stun:stun.l.google.com:13902"
    },
  ]
}

const createPeerConnection = () => {


  peerConnection = new RTCPeerConnection(configuration);

  dataChannel = peerConnection.createDataChannel("chat"); //label to our


dataChanel = chat

  peerConnection.ondatachannel = (event) => {


    const dataChannel = event.channel;

    dataChannel.onopen = () => {
      // console.log("Peer connection is ready to recieve data channel
messages");
    }

    dataChannel.onmessage = (event) => {


      // console.log("messages received");
      const message = JSON.parse(event.data);
      ui.appendMessage(message, false);
      // console.log(message);
    }
  }

  // getting ice candidate from stun server


  peerConnection.onicecandidate = (event) => {
    // console.log("getting ice candidate from stun server");
    if (event.candidate) {
      // send our ice candidate to other user
      // console.log("sending ice candidate", event.candidate);
      wss.sendDataUsingWebRTCSignaling({
        connectedUserSocketId: store.getConnectedUserDetails().socketId,
        type: constants.webRTCSignaling.ICE_CANDIDATE,
        candidate: event.candidate,
      })
    }
  }

  // this will occur when ice candidates are exchanged succesfully


  peerConnection.onconnectionstatechange = (event) => {
    if (peerConnection.connectionState == "connected") {
      console.log("Successfully connected with other peer");
    }
  }

  //recieving tracks
  const remoteStream = new MediaStream();
  store.setRemoteStream(remoteStream);
  ui.updateRemoteStream(remoteStream);

  peerConnection.ontrack = (event) => {


    remoteStream.addTrack(event.track);
  }

  // add our stream to peer connection


  if ([constants.callType.VIDEO_PERSONAL_CODE,
constants.callType.VIDEO_STRANGER].some(callType =>
    callType === store.getConnectedUserDetails().callType
  )) {
    const localStream = store.getState().localStream;

    for (const track of localStream.getTracks()) {


      peerConnection.addTrack(track, localStream);
    }
  }
}

export const getLocalPreview = () => {


  navigator.mediaDevices.getUserMedia(defaultConstraints).then((stream) => {
    ui.updateLocalVideo(stream);
    ui.showVideoCallButtons(); //if local video available, add video call
buttons
    store.setCallState(constants.callState.CALL_AVAILABLE); //if local video
available change call state to video call;
    store.setLocalStream(stream);
  }).catch((error) => {
    console.log("Error occured when trying to get access to camera");
    // console.log(error);
  })
}

export const sendMessageUsingDataChannel = (messaage) => {


  const stringifiedMessage = JSON.stringify(messaage);
  dataChannel.send(stringifiedMessage);
}

export const sendPreOffer = (callType, calleePersonalCode) => {


  store.setConnectedUserDetails({
    callType,
    socketId: calleePersonalCode,
  })

  if (callType === constants.callType.CHAT_PERSONAL_CODE || callType ===


constants.callType.VIDEO_PERSONAL_CODE) {
    let data = { callType, calleePersonalCode };
    ui.showCallingDialog(callingDialogRejectCallHandler);
    store.setCallState(constants.callState.CALL_UNAVAILABLE); // when we are
making the call request we are unavialable
    wss.sendPreOffer(data);
  }

  if (callType === constants.callType.CHAT_STRANGER || callType ===


constants.callType.VIDEO_STRANGER) {
    let data = { callType, calleePersonalCode };
    //directly make call, no pop up
    store.setCallState(constants.callState.CALL_UNAVAILABLE); // when we are
making the call request we are unavialable
    wss.sendPreOffer(data);
  }

};

//call is coming, we have to handle it


export const handlePreOffer = (data) => {
  let { callType, callerPersonalCode } = data;

  if (checkCallPossibility(callType) == false) {
    return sendPreOfferAnswer(constants.preOfferAnswer.CALL_UNAVAILABLE,
callerPersonalCode);
  }

  store.setConnectedUserDetails({
    callType,
    socketId: callerPersonalCode,
  });

  if (callType === constants.callType.CHAT_PERSONAL_CODE || callType ===


constants.callType.VIDEO_PERSONAL_CODE) {
    ui.showIncomingCallDialog(callType, acceptCallHandler, rejectCallHandler);
  }

  if (callType === constants.callType.CHAT_STRANGER || callType ===


constants.callType.VIDEO_STRANGER) {
    //directly accept calls, no pop-up request
    acceptCallHandler();
  }
}

const acceptCallHandler = () => {


  // console.log("call accepted");
  sendPreOfferAnswer(constants.preOfferAnswer.CALL_ACCEPTED);
  ui.showCallElements(store.getConnectedUserDetails().callType); //show call
elment buttons based on call type
  store.setCallState(constants.callState.CALL_UNAVAILABLE); // when we accept
the call request we become unavialable for others
  createPeerConnection();
}

const rejectCallHandler = () => {


  // console.log("call rejected");
  sendPreOfferAnswer(constants.preOfferAnswer.CALL_REJECTED);
  store.setConnectedUserDetails(null); //reset connected user details
}
const callingDialogRejectCallHandler = () => {
  // console.log("rejecting the call");
  const data = { connectedUserSocketId:
store.getConnectedUserDetails().socketId };

  wss.sendUserHangedUp(data); //same as hang up functionality


  closePeerConnectionAndResetState();
}

const sendPreOfferAnswer = (preOfferAnswer, callerSocketId = null) => {


  const callerPersonalCode = callerSocketId ? callerSocketId :
store.getConnectedUserDetails().socketId;
  let data = { callerPersonalCode, preOfferAnswer }

  ui.removeAllDialogs(); // remove all dialog inside html dialog element


  wss.sendPreOfferAnswer(data);
}

export const handlePreOfferAnswer = (data) => {


  let { preOfferAnswer, calleePersonalCode } = data;
  // console.log(preOfferAnswer + " from " + calleePersonalCode);
  ui.removeAllDialogs(); // remove all dialog inside html dialog element

  switch (preOfferAnswer) {
    case constants.preOfferAnswer.CALL_ACCEPTED:
      ui.showCallElements(store.getConnectedUserDetails().callType); //show
call elment buttons based on call type
      createPeerConnection();
      sendWebRTCOffer();
      // show the dialog that call is accepted by the callee
      break;
    case constants.preOfferAnswer.CALL_REJECTED:
      ui.showInfoDialog(preOfferAnswer);
      // show the dialog that call is accepted by the callee
      setIncomingCallAvailable();
      break;
    case constants.preOfferAnswer.CALL_UNAVAILABLE:
      ui.showInfoDialog(preOfferAnswer);
      // show the dialog that callee is not able to connect
      setIncomingCallAvailable();
      break;
    case constants.preOfferAnswer.CALLEE_NOT_FOUND:
      ui.showInfoDialog(preOfferAnswer);
      // show the dialog that callee has not been found
      setIncomingCallAvailable();
      break;
  }
}

const sendWebRTCOffer = async () => {


  const offer = await peerConnection.createOffer(); //our sdp information
  await peerConnection.setLocalDescription(offer); //save sdp information in
local

  wss.sendDataUsingWebRTCSignaling({
    connectedUserSocketId: store.getConnectedUserDetails().socketId,
    type: constants.webRTCSignaling.OFFER,
    offer: offer,   // offer = {sdp, type}
  });
}

export const handleWebRTCOffer = async (data) => {


  // console.log("webRTC offer came");
  await peerConnection.setRemoteDescription(data.offer);

  const answer = await peerConnection.createAnswer();


  await peerConnection.setLocalDescription(answer);

  wss.sendDataUsingWebRTCSignaling({
    connectedUserSocketId: store.getConnectedUserDetails().socketId,
    type: constants.webRTCSignaling.ANSWER,
    answer: answer,
  })
}

export const handleWebRTCAnswer = async (data) => {


  // console.log("handling webRTC answer");
  await peerConnection.setRemoteDescription(data.answer);
}

export const handleWebRTCCandidate = async (data) => {


  try {
    await peerConnection.addIceCandidate(data.candidate);
  } catch (err) {
    console.log("error occured when trying to add recieved ice candidate",
err);
  }
}

export const switchBetweenCameraAndScreenSharing = async (screenSharingActive)


=> {
  try {
    let newStream;
    if (screenSharingActive) {
      const { localStream } = store.getState();
      store.getState().screenSharingStream.getTracks().forEach(track =>
track.stop()); //stop stream from sharing
      newStream = localStream;
    } else {
      // console.log("switching for screen sharing");
      const screenSharingStream = await
navigator.mediaDevices.getDisplayMedia({ video: true });
      store.setScreenSharingStream(screenSharingStream);
      newStream = screenSharingStream;
    }

    //replace track which sender is sending


    const senders = peerConnection.getSenders();
    const sender = senders.find(sender => {
      return sender.track.kind === newStream.getVideoTracks()[0].kind;
    })

    if (sender) {
      sender.replaceTrack(newStream.getVideoTracks()[0]);
    }
    ui.updateLocalVideo(newStream); //update local video with new stream
    store.setScreenSharingActive(!screenSharingActive);
  } catch (err) {
    console.log("error occured when trying to switch screen sharing stream",
err)
  }
}

//hang up

export const handleHangUp = () => {


  // console.log("finshing the call");
  const data = { connectedUserSocketId:
store.getConnectedUserDetails().socketId };

  wss.sendUserHangedUp(data);
  closePeerConnectionAndResetState();
}

export const handleConnectedUserHangedUp = () => {


  // console.log("connected peer hanged up");
  closePeerConnectionAndResetState();
}

const closePeerConnectionAndResetState = () => {


  if (peerConnection) {
    peerConnection.close();
    peerConnection = null;
  }

  //active mic and camera


  const { callType } = store.getConnectedUserDetails();
  if (callType === constants.callType.VIDEO_PERSONAL_CODE || callType ===
constants.callType.VIDEO_STRANGER) {
    store.getState().localStream.getVideoTracks()[0].enabled = true;
    store.getState().localStream.getAudioTracks()[0].enabled = true;
  }

  ui.updateUIAfterHangUp(callType);
  setIncomingCallAvailable();
  store.setConnectedUserDetails(null); //to reset connected user state
};

const checkCallPossibility = (callType) => {


  const callState = store.getState().callState;

  if (callState === constants.callState.CALL_AVAILABLE) return true;

  if ((callType === constants.callType.VIDEO_PERSONAL_CODE || callType ===


constants.callType.VIDEO_STRANGER) && (callState ===
constants.callState.CALL_AVAILABLE_ONLY_CHAT)) {
    //if some one calls for video and this person is only available for chat
    return false;
  }

  return false;
}

const setIncomingCallAvailable = () => {


  const localStream = store.getState().localStream;

  if (localStream) {
    store.setCallState(constants.callState.CALL_AVAILABLE);
  } else {
    store.setCallState(constants.callState.CALL_AVAILABLE_ONLY_CHAT);
  }
}
import * as store from "./store.js";
import * as ui from "./ui.js";
import * as webRTCHandler from "./webRTCHandler.js";
import * as constants from "./constants.js";
import * as strangerUtils from "./strangerUtils.js";

let socketIO = null

// listen to server
export const registerSocketEvents = (socket) => {
    socketIO = socket;

    socket.on("connect", () => {            //When Socket connected


        console.log("succesfully connected to socket.io server");
        store.setSocketId(socket.id);       // set socketId on state of user
        ui.updatePersonalCode(socket.id);   //set personalCode on UI
    });

    socket.on("pre-offer", (data) => {


        webRTCHandler.handlePreOffer(data)
    })

    // listens to the answer (accept or reject) from callee


    socket.on("pre-offer-answer", (data) => {
        webRTCHandler.handlePreOfferAnswer(data)
    })

    socket.on("user-hanged-up", () => {
        webRTCHandler.handleConnectedUserHangedUp();
    });

    socket.on("webRTC-signaling", (data) => {


        switch (data.type) {
            case constants.webRTCSignaling.OFFER:
                webRTCHandler.handleWebRTCOffer(data)
                break;
            case constants.webRTCSignaling.ANSWER:
                webRTCHandler.handleWebRTCAnswer(data)
                break;
            case constants.webRTCSignaling.ICE_CANDIDATE:
                webRTCHandler.handleWebRTCCandidate(data)
                break;
        }
    })

    socket.on("stranger-socket-id", (data) => {


        strangerUtils.connectWithStranger(data);
    })
}

export const sendPreOffer = (data) => {


    socketIO.emit("pre-offer", data);
}

export const sendPreOfferAnswer = (data) => {


    socketIO.emit("pre-offer-answer", data);
}
export const sendDataUsingWebRTCSignaling = (data) => {
    socketIO.emit("webRTC-signaling", data);
}

//hang up
export const sendUserHangedUp = (data) => {
    socketIO.emit("user-hanged-up", data);
}

export const changeStrangerConnectionStatus = (data) => {


    socketIO.emit("stranger-connection-status", data);
};

export const getStrangerSocketId = () => {


    socketIO.emit("get-stranger-socket-id");
}
<html>
    <head>
        <title>Meet the strangers</title>
        <link rel='stylesheet' href='./css/style.css'>
    </head>
    <body>
        <div class='main_container'>
        <div class='dashboard_container'>
            <div class='logo_container'>
                <img src='./utils/images/logo.png'></img>
            </div>
            <div>
                <div class='description_container'>
                    <p class='description_container_paragraph'>
                        Talk with other user by passing his personal code or
talk with strangers!
                    </p>
                </div>
                <div class='personal_code_container'>
                    <div class='personal_code_title_container'>
                        <p class='personal_code_title_paragraph'>
                            Your personal code
                        </p>
                    </div>
                    <div class="personal_code_value_container">
                        <p class='personal_code_value_paragraph'
id='personal_code_paragraph'>Code Not Available</p>
                        <button class='personal_code_copy_button'
id='personal_code_copy_button'>
                            <img src='./utils/images/copyButton.png'></img>
                        </button>
                    </div>
                </div>
                </div>
                <div class='personal_code_connecting_container'>
                    <p class='personal_code_connecting_paragraph'>Personal
Code</p>
                    <div class='personal_code_connecting_input_container'>
                        <input class='personal_code_input'
id='personal_code_input'></input>
                    </div>
                    <div class='personal_code_connecting_buttons_container'>
                        <button class='connecting_button'
id='personal_code_chat_button'>
                            <img src='./utils/images/chatButton.png'
class='connecting_buttons_image'></img>
                        </button>
                        <button class='connecting_button display_none'
id='personal_code_video_button'>
                            <img src='./utils/images/videoButton.png'
class='connecting_buttons_image'></img>
                        </button>
                    </div>
                </div>
                <div class='stranger_connecting_container'>
                    <p class='stranger_title_container'>Stranger</p>
                    <div class='stranger_buttons_container'>
                        <button class='connecting_button'
id='stranger_chat_button'>
                            <img src='/utils/images/chatButton.png'
class='connecting_buttons_image'></img>
                        </button>
                        <button class='connecting_button display_none'
id='stranger_video_button'>
                            <img src='/utils/images/videoButton.png'
class='connecting_buttons_image'></img>
                        </button>
                    </div>
                </div>
                <div class='checkbox_container'>
                    <div class='checkbox_connection'
id='allow_strangers_checkbox'>
                        <img id='allow_strangers_checkbox_image'
class='display_none' src='./utils/images/check.png'></img>
                    </div>
                    <p class='checkbox_container_paragraph'>Allow connection
from strangers</p>
                </div>
                <div class='dashboard_blur display_none'
id='dashboard_blur'></div>
            </div>
        <div class='call_container'>
            <div class='videos_container'>
                <div id='video_placeholder' class='videos_placeholder'>
                    <img src='./utils/images/logo.png'></img>
                </div>
                <video class='remote_video display_none' autoplay
id='remote_video'></video>
                <div class='local_video_container'>
                    <video class='local_video' id='local_video' muted
autoplay></video>
                </div>
                <div class='call_buttons_container display_none'
id='call_buttons'>
                    <button class='call_button_small' id='mic_button'>
                        <img src='./utils/images/mic.png'
id='mic_button_image'></img>
                    </button>
                    <button class='call_button_small' id='camera_button'>
                        <img src='./utils/images/camera.png'
id='camera_button_image'></img>
                    </button>
                    <button class='call_button_large' id='hang_up_button'>
                        <img src='./utils/images/hangUp.png'></img>
                    </button>
                    <button class='call_button_small'
id='screen_sharing_button'>
                        <img
src='./utils/images/switchCameraScreenSharing.png'></img>
                    </button>
                    <button class='call_button_small'
id='start_recording_button'>
                        <img src='./utils/images/recordingStart.png'></img>
                    </button>
                </div>
                <div class='finish_chat_button_container display_none'
id='finish_chat_button_container'>
                    <button class='call_button_large'
id='finish_chat_call_button'>
                        <img src='./utils/images/hangUp.png'></img>
                    </button>
                </div>
                <div class='video_recording_buttons_container display_none'
id='video_recording_buttons'>
                    <button id='pause_recording_button'>
                        <img src='./utils/images/pause.png'></img>
                    </button>
                    <button id='resume_recording_button' class='display_none'>
                        <img src='./utils/images/resume.png'></img>
                    </button>
                    <button id='stop_recording_button'>
                        Stop recording
                    </button>
                </div>
            </div>
        </div>
        <div class='messenger_container'>
            <div class='messages_container' id='messages_container'></div>
            <div class='new_message_container display_none' id='new_message'>
                <input class='new_message_input' id='new_message_input'
type='text' placeholder="Type your message..."></input>
                <button class='send_message_button' id='send_message_button'>
                    <img class='send_message_button_image'
src='./utils/images/sendMessageButton.png'></image>
                </button>
            </div>
        </div>
        <div id='dialog'></div>    
        </div>
        <script src='/socket.io/socket.io.js'></script>
        <script src='./js/elements.js' type='module'></script>
        <script src='./js/constants.js' type='module'></script>
        <script src='./js/ui.js' type='module'></script>
        <script src='./js/wss.js' type='module'></script>
        <script src='./js/store.js' type='module'></script>
        <script src='./js/recordingUtils.js' type='module'></script>
        <script src='./js/webRTCHandler.js' type='module'></script>
        <script src='./js/strangerUtils.js' type='module'></script>
        <script src='./js/main.js' type='module'></script>
    </body>
</html>
const express = require('express');
const http = require('http');

const PORT = process.env.PORT || 3000;

const app = express();


const server = http.createServer(app);
const io = require('socket.io')(server);    //io is my websocket server

app.use(express.static("public"));

app.get("/", (req, res) => {


    res.sendFile(__dirname + "public/index.html");
})

//to store the socket.id of user


let connectedPeers = [];

// for strangers
let connectedPeerStrangers = [];

// when an connection is established


io.on("connection", (socket) => {
    // socket is basically a connection between user and webSocket server
    console.log("User connected on socket.io server");
    console.log(socket.id);
    connectedPeers.push(socket.id);

    // listening to pre-offer emit event


    socket.on("pre-offer", (data) => {
        const { callType, calleePersonalCode } = data;
        const callerPersonalCode = socket.id;

        //secondary user exist ?


        const connectedPeer = connectedPeers.find(peerSocketId => {
            return peerSocketId === calleePersonalCode;
        })

        // emit pre-offer to secondary user if he exists


        if (connectedPeer) {
            let data = { callType, callerPersonalCode };
            io.to(calleePersonalCode).emit("pre-offer", data);
        } else {
            //else send caller info that callee not found
            let data = {
                preOfferAnswer: "CALLEE_NOT_FOUND", calleePersonalCode
            };
            io.to(callerPersonalCode).emit("pre-offer-answer", data);
        }
    })

    socket.on("pre-offer-answer", (data) => {


        const { preOfferAnswer, callerPersonalCode } = data;
        const calleePersonalCode = socket.id;

        //caller/primary user exist ?


        const connectedPeer = connectedPeers.find(peerSocketId => {
            return peerSocketId === callerPersonalCode;
        })

        // emit pre-offer to primary user if he exists


        if (connectedPeer) {
            let data = { preOfferAnswer, calleePersonalCode }
            io.to(callerPersonalCode).emit("pre-offer-answer", data);
        }

    })

    socket.on("webRTC-signaling", (data) => {


        const { connectedUserSocketId } = data;

        const connectedPeer = connectedPeers.find(peerSocketId => {


            return peerSocketId === connectedUserSocketId;
        })

        // emit pre-offer to primary user if he exists


        if (connectedPeer) {
            io.to(connectedUserSocketId).emit("webRTC-signaling", data);
        }
    })

    socket.on("user-hanged-up", (data) => {


        const { connectedUserSocketId } = data;

        const connectedPeer = connectedPeers.find(peerSocketId => {


            return peerSocketId === connectedUserSocketId;
        })

        // emit hang up offer to other user if he exists


        if (connectedPeer) {
            io.to(connectedUserSocketId).emit("user-hanged-up");
        }
    })

    socket.on("stranger-connection-status", (data) => {


        const { status } = data;

        if(status) { //accepting stranger connections


            connectedPeerStrangers.push(socket.id);
        }else { //else remove from stranger DB
            connectedPeerStrangers =
connectedPeerStrangers.filter(peerSocketId => peerSocketId !== socket.id);
        }
    });

    socket.on("get-stranger-socket-id", () => {
        let randomStrangerSocketId;
        let filteredConnectedPeerStrangers =
connectedPeerStrangers.filter(peerSocketId => peerSocketId !== socket.id);
       
        if(filteredConnectedPeerStrangers.length > 0) {
            let index = Math.floor(Math.random() *
filteredConnectedPeerStrangers.length);
            randomStrangerSocketId = filteredConnectedPeerStrangers[index];
        }else {
            randomStrangerSocketId = null;
        }

        const data = { randomStrangerSocketId };

        io.to(socket.id).emit("stranger-socket-id", data);
    });

    // user disconnected
    socket.on("disconnect", () => {
        console.log("User disconnected");
        connectedPeers = connectedPeers.filter(peerSocketId => peerSocketId !
== socket.id);
        console.log("total users online : " + connectedPeers.length);
    });
})

server.listen(PORT, () => {
    console.log(`server is running on port: ${PORT}`);
});

{
  "name": "meet-up",
  "version": "1.0.0",
  "lockfileVersion": 2,
  "requires": true,
  "packages": {
    "": {
      "name": "meet-up",
      "version": "1.0.0",
      "license": "ISC",
      "dependencies": {
        "express": "^4.17.1",
        "socket.io": "^4.1.3"
      }
    },
    "node_modules/@types/component-emitter": {
      "version": "1.2.10",
      "resolved":
"https://registry.npmjs.org/@types/component-emitter/-/component-emitter-
1.2.10.tgz",
      "integrity": "sha512-
bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1
+HWMbFhg=="
    },
    "node_modules/@types/cookie": {
      "version": "0.4.1",
      "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-
0.4.1.tgz",
      "integrity":
"sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwN
QaRfXCun0+KbWY7Q=="
    },
    "node_modules/@types/cors": {
      "version": "2.8.12",
      "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
      "integrity":
"sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr
1NE2lNNFhp0lEThw=="
    },
    "node_modules/@types/node": {
      "version": "16.3.1",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.1.tgz",
      "integrity":
"sha512-N87VuQi7HEeRJkhzovao/JviiqKjDKMVKxKMfUvSKw+MbkbW8R0nA3fi/MQhhlxV2fQ+2R
eM+/Nt4efdrJx3zA=="
    },
    "node_modules/accepts": {
      "version": "1.3.7",
      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
      "integrity":
"sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh
1hOxNgIf5bv7dQpA==",
      "dependencies": {
        "mime-types": "~2.1.24",
        "negotiator": "0.6.2"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/array-flatten": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-
1.1.1.tgz",
      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
    },
    "node_modules/base64-arraybuffer": {
      "version": "0.1.4",
      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-
arraybuffer-0.1.4.tgz",
      "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=",
      "engines": {
        "node": ">= 0.6.0"
      }
    },
    "node_modules/base64id": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
      "integrity":
"sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/
WyEg3lsuyw4GHlPZHog==",
      "engines": {
        "node": "^4.5.0 || >= 5.9"
      }
    },
    "node_modules/body-parser": {
      "version": "1.19.0",
      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-
1.19.0.tgz",
      "integrity": "sha512-
dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+r
gzifNCsw==",
      "dependencies": {
        "bytes": "3.1.0",
        "content-type": "~1.0.4",
        "debug": "2.6.9",
        "depd": "~1.1.2",
        "http-errors": "1.7.2",
        "iconv-lite": "0.4.24",
        "on-finished": "~2.3.0",
        "qs": "6.7.0",
        "raw-body": "2.4.0",
        "type-is": "~1.6.17"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/bytes": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
      "integrity": "sha512-
zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcV
zfVTI2Dg==",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/component-emitter": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/component-emitter/-/component-
emitter-1.3.0.tgz",
      "integrity":
"sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBu
E0QYoB90YdfatsRg=="
    },
    "node_modules/content-disposition": {
      "version": "0.5.3",
      "resolved": "https://registry.npmjs.org/content-disposition/-/content-
disposition-0.5.3.tgz",
      "integrity": "sha512-
ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcW
ng8z1z0g==",
      "dependencies": {
        "safe-buffer": "5.1.2"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/content-type": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/content-type/-/content-type-
1.0.4.tgz",
      "integrity":
"sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/
tvIG/tUc9mOUJiPBhPXA==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/cookie": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
      "integrity":
"sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/
W6ZaPDOUbnjOt/99w66zk+l1Xg==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/cookie-signature": {
      "version": "1.0.6",
      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-
signature-1.0.6.tgz",
      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
    },
    "node_modules/cors": {
      "version": "2.8.5",
      "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
      "integrity":
"sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q
4n6GHQ9cDtxv/P6g==",
      "dependencies": {
        "object-assign": "^4",
        "vary": "^1"
      },
      "engines": {
        "node": ">= 0.10"
      }
    },
    "node_modules/debug": {
      "version": "2.6.9",
      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
      "integrity": "sha512-
bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/
E7AdgFBVeAPVMNcKGsHMA==",
      "dependencies": {
        "ms": "2.0.0"
      }
    },
    "node_modules/depd": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/destroy": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
    },
    "node_modules/ee-first": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
    },
    "node_modules/encodeurl": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-
1.0.2.tgz",
      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/engine.io": {
      "version": "5.1.1",
      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-
5.1.1.tgz",
      "integrity":
"sha512-aMWot7H5aC8L4/T8qMYbLdvKlZOdJTH54FxfdFunTGvhMx1BHkJOntWArsVfgAZVwAO9LC
2sryPWRcEeUzCe5w==",
      "dependencies": {
        "accepts": "~1.3.4",
        "base64id": "2.0.0",
        "cookie": "~0.4.1",
        "cors": "~2.8.5",
        "debug": "~4.3.1",
        "engine.io-parser": "~4.0.0",
        "ws": "~7.4.2"
      },
      "engines": {
        "node": ">=10.0.0"
      }
    },
    "node_modules/engine.io-parser": {
      "version": "4.0.2",
      "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-
parser-4.0.2.tgz",
      "integrity":
"sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/
MqJdZbUjW97JU72iYg==",
      "dependencies": {
        "base64-arraybuffer": "0.1.4"
      },
      "engines": {
        "node": ">=8.0.0"
      }
    },
    "node_modules/engine.io/node_modules/cookie": {
      "version": "0.4.1",
      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
      "integrity":
"sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF
8zELf3dFNl/kxkUA==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/engine.io/node_modules/debug": {
      "version": "4.3.2",
      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
      "integrity":
"sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0
xV7M0cCO6P/O0Xhw==",
      "dependencies": {
        "ms": "2.1.2"
      },
      "engines": {
        "node": ">=6.0"
      },
      "peerDependenciesMeta": {
        "supports-color": {
          "optional": true
        }
      }
    },
    "node_modules/engine.io/node_modules/ms": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
      "integrity": "sha512-
sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvb
s1PEaH2w=="
    },
    "node_modules/escape-html": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-
1.0.3.tgz",
      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
    },
    "node_modules/etag": {
      "version": "1.8.1",
      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/express": {
      "version": "4.17.1",
      "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
      "integrity":
"sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUV
qgb27xlEMXTnYt4g==",
      "dependencies": {
        "accepts": "~1.3.7",
        "array-flatten": "1.1.1",
        "body-parser": "1.19.0",
        "content-disposition": "0.5.3",
        "content-type": "~1.0.4",
        "cookie": "0.4.0",
        "cookie-signature": "1.0.6",
        "debug": "2.6.9",
        "depd": "~1.1.2",
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "etag": "~1.8.1",
        "finalhandler": "~1.1.2",
        "fresh": "0.5.2",
        "merge-descriptors": "1.0.1",
        "methods": "~1.1.2",
        "on-finished": "~2.3.0",
        "parseurl": "~1.3.3",
        "path-to-regexp": "0.1.7",
        "proxy-addr": "~2.0.5",
        "qs": "6.7.0",
        "range-parser": "~1.2.1",
        "safe-buffer": "5.1.2",
        "send": "0.17.1",
        "serve-static": "1.14.1",
        "setprototypeof": "1.1.1",
        "statuses": "~1.5.0",
        "type-is": "~1.6.18",
        "utils-merge": "1.0.1",
        "vary": "~1.1.2"
      },
      "engines": {
        "node": ">= 0.10.0"
      }
    },
    "node_modules/finalhandler": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-
1.1.2.tgz",
      "integrity": "sha512-
aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsB
g6z0zsWA==",
      "dependencies": {
        "debug": "2.6.9",
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "on-finished": "~2.3.0",
        "parseurl": "~1.3.3",
        "statuses": "~1.5.0",
        "unpipe": "~1.0.0"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/forwarded": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-
0.2.0.tgz",
      "integrity": "sha512-
buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/
Nt6MT9aYow==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/fresh": {
      "version": "0.5.2",
      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/http-errors": {
      "version": "1.7.2",
      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-
1.7.2.tgz",
      "integrity":
"sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ
5plg63TvGfRSDCRg==",
      "dependencies": {
        "depd": "~1.1.2",
        "inherits": "2.0.3",
        "setprototypeof": "1.1.1",
        "statuses": ">= 1.5.0 < 2",
        "toidentifier": "1.0.0"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/iconv-lite": {
      "version": "0.4.24",
      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-
0.4.24.tgz",
      "integrity": "sha512-
v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bE
qdpj8/rA==",
      "dependencies": {
        "safer-buffer": ">= 2.1.2 < 3"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/inherits": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
    },
    "node_modules/ipaddr.js": {
      "version": "1.9.1",
      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-
1.9.1.tgz",
      "integrity":
"sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/
w18ZlXSHBYXiYUPO3g==",
      "engines": {
        "node": ">= 0.10"
      }
    },
    "node_modules/media-typer": {
      "version": "0.3.0",
      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-
0.3.0.tgz",
      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/merge-descriptors": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-
descriptors-1.0.1.tgz",
      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
    },
    "node_modules/methods": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/mime": {
      "version": "1.6.0",
      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
      "integrity": "sha512-
x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFR
srswaQeg==",
      "bin": {
        "mime": "cli.js"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/mime-db": {
      "version": "1.48.0",
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
      "integrity": "sha512-
FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUS
q1yzslJQ==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/mime-types": {
      "version": "2.1.31",
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-
2.1.31.tgz",
      "integrity": "sha512-
XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/
MOcsDgpilPOPg==",
      "dependencies": {
        "mime-db": "1.48.0"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/ms": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
    },
    "node_modules/negotiator": {
      "version": "0.6.2",
      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-
0.6.2.tgz",
      "integrity":
"sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7m
um2AUqDidoKqcTOw==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/object-assign": {
      "version": "4.1.1",
      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-
4.1.1.tgz",
      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/on-finished": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-
2.3.0.tgz",
      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
      "dependencies": {
        "ee-first": "1.1.1"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/parseurl": {
      "version": "1.3.3",
      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
      "integrity":
"sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fH
ynXi9NYO4nWOL+qQ==",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/path-to-regexp": {
      "version": "0.1.7",
      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-
0.1.7.tgz",
      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
    },
    "node_modules/proxy-addr": {
      "version": "2.0.7",
      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-
2.0.7.tgz",
      "integrity":
"sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/
gJEdZU7KMraoK1+XYAg==",
      "dependencies": {
        "forwarded": "0.2.0",
        "ipaddr.js": "1.9.1"
      },
      "engines": {
        "node": ">= 0.10"
      }
    },
    "node_modules/qs": {
      "version": "6.7.0",
      "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
      "integrity":
"sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIG
tV0XeCirBtpDrTyQ==",
      "engines": {
        "node": ">=0.6"
      }
    },
    "node_modules/range-parser": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-
1.2.1.tgz",
      "integrity": "sha512-
Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/
GTl5agOwSg==",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/raw-body": {
      "version": "2.4.0",
      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
      "integrity":
"sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8
ipEDoiH70ySUJP3Q==",
      "dependencies": {
        "bytes": "3.1.0",
        "http-errors": "1.7.2",
        "iconv-lite": "0.4.24",
        "unpipe": "1.0.0"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/safe-buffer": {
      "version": "5.1.2",
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-
5.1.2.tgz",
      "integrity":
"sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt
8ud/wPtojys4G6+g=="
    },
    "node_modules/safer-buffer": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-
2.1.2.tgz",
      "integrity": "sha512-
YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbw
qcQriUtg=="
    },
    "node_modules/send": {
      "version": "0.17.1",
      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
      "integrity": "sha512-
BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3
V4fT9sAg==",
      "dependencies": {
        "debug": "2.6.9",
        "depd": "~1.1.2",
        "destroy": "~1.0.4",
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "etag": "~1.8.1",
        "fresh": "0.5.2",
        "http-errors": "~1.7.2",
        "mime": "1.6.0",
        "ms": "2.1.1",
        "on-finished": "~2.3.0",
        "range-parser": "~1.2.1",
        "statuses": "~1.5.0"
      },
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/send/node_modules/ms": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
      "integrity":
"sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/
FpnYaD/kOWhYQvyg=="
    },
    "node_modules/serve-static": {
      "version": "1.14.1",
      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-
1.14.1.tgz",
      "integrity":
"sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecp
Zs+3mW+XbQZu9QCg==",
      "dependencies": {
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "parseurl": "~1.3.3",
        "send": "0.17.1"
      },
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/setprototypeof": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-
1.1.1.tgz",
      "integrity": "sha512-
JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lq
VRYP2OAw=="
    },
    "node_modules/socket.io": {
      "version": "4.1.3",
      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-
4.1.3.tgz",
      "integrity": "sha512-
tLkaY13RcO4nIRh1K2hT5iuotfTaIQw7cVIe0FUykN3SuQi0cm7ALxuyT5/
CtDswOMWUzMGTibxYNx/gU7In+Q==",
      "dependencies": {
        "@types/cookie": "^0.4.0",
        "@types/cors": "^2.8.10",
        "@types/node": ">=10.0.0",
        "accepts": "~1.3.4",
        "base64id": "~2.0.0",
        "debug": "~4.3.1",
        "engine.io": "~5.1.1",
        "socket.io-adapter": "~2.3.1",
        "socket.io-parser": "~4.0.4"
      },
      "engines": {
        "node": ">=10.0.0"
      }
    },
    "node_modules/socket.io-adapter": {
      "version": "2.3.1",
      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-
adapter-2.3.1.tgz",
      "integrity": "sha512-
8cVkRxI8Nt2wadkY6u60Y4rpW3ejA1rxgcK2JuyIhmF+RMNpTy1QRtkHIDUOf3B4HlQwakMsWbKftM
v/71VMmw=="
    },
    "node_modules/socket.io-parser": {
      "version": "4.0.4",
      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-
parser-4.0.4.tgz",
      "integrity":
"sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/
8R5ygK7jAR6t028/z+7295g==",
      "dependencies": {
        "@types/component-emitter": "^1.2.10",
        "component-emitter": "~1.3.0",
        "debug": "~4.3.1"
      },
      "engines": {
        "node": ">=10.0.0"
      }
    },
    "node_modules/socket.io-parser/node_modules/debug": {
      "version": "4.3.2",
      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
      "integrity":
"sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0
xV7M0cCO6P/O0Xhw==",
      "dependencies": {
        "ms": "2.1.2"
      },
      "engines": {
        "node": ">=6.0"
      },
      "peerDependenciesMeta": {
        "supports-color": {
          "optional": true
        }
      }
    },
    "node_modules/socket.io-parser/node_modules/ms": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
      "integrity": "sha512-
sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvb
s1PEaH2w=="
    },
    "node_modules/socket.io/node_modules/debug": {
      "version": "4.3.2",
      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
      "integrity":
"sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0
xV7M0cCO6P/O0Xhw==",
      "dependencies": {
        "ms": "2.1.2"
      },
      "engines": {
        "node": ">=6.0"
      },
      "peerDependenciesMeta": {
        "supports-color": {
          "optional": true
        }
      }
    },
    "node_modules/socket.io/node_modules/ms": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
      "integrity": "sha512-
sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvb
s1PEaH2w=="
    },
    "node_modules/statuses": {
      "version": "1.5.0",
      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/toidentifier": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-
1.0.0.tgz",
      "integrity":
"sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJl
n5FNQDRrxj3YcbVw==",
      "engines": {
        "node": ">=0.6"
      }
    },
    "node_modules/type-is": {
      "version": "1.6.18",
      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
      "integrity": "sha512-
TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm
06XQBy8g==",
      "dependencies": {
        "media-typer": "0.3.0",
        "mime-types": "~2.1.24"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/unpipe": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/utils-merge": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-
1.0.1.tgz",
      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
      "engines": {
        "node": ">= 0.4.0"
      }
    },
    "node_modules/vary": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/ws": {
      "version": "7.4.6",
      "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
      "integrity":
"sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCY
QNUnfWdXta/Yu85A==",
      "engines": {
        "node": ">=8.3.0"
      },
      "peerDependencies": {
        "bufferutil": "^4.0.1",
        "utf-8-validate": "^5.0.2"
      },
      "peerDependenciesMeta": {
        "bufferutil": {
          "optional": true
        },
        "utf-8-validate": {
          "optional": true
        }
      }
    }
  },
  "dependencies": {
    "@types/component-emitter": {
      "version": "1.2.10",
      "resolved":
"https://registry.npmjs.org/@types/component-emitter/-/component-emitter-
1.2.10.tgz",
      "integrity": "sha512-
bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1
+HWMbFhg=="
    },
    "@types/cookie": {
      "version": "0.4.1",
      "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-
0.4.1.tgz",
      "integrity":
"sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwN
QaRfXCun0+KbWY7Q=="
    },
    "@types/cors": {
      "version": "2.8.12",
      "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz",
      "integrity":
"sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr
1NE2lNNFhp0lEThw=="
    },
    "@types/node": {
      "version": "16.3.1",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.1.tgz",
      "integrity":
"sha512-N87VuQi7HEeRJkhzovao/JviiqKjDKMVKxKMfUvSKw+MbkbW8R0nA3fi/MQhhlxV2fQ+2R
eM+/Nt4efdrJx3zA=="
    },
    "accepts": {
      "version": "1.3.7",
      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
      "integrity":
"sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh
1hOxNgIf5bv7dQpA==",
      "requires": {
        "mime-types": "~2.1.24",
        "negotiator": "0.6.2"
      }
    },
    "array-flatten": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-
1.1.1.tgz",
      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
    },
    "base64-arraybuffer": {
      "version": "0.1.4",
      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-
arraybuffer-0.1.4.tgz",
      "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI="
    },
    "base64id": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
      "integrity":
"sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/
WyEg3lsuyw4GHlPZHog=="
    },
    "body-parser": {
      "version": "1.19.0",
      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-
1.19.0.tgz",
      "integrity": "sha512-
dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+r
gzifNCsw==",
      "requires": {
        "bytes": "3.1.0",
        "content-type": "~1.0.4",
        "debug": "2.6.9",
        "depd": "~1.1.2",
        "http-errors": "1.7.2",
        "iconv-lite": "0.4.24",
        "on-finished": "~2.3.0",
        "qs": "6.7.0",
        "raw-body": "2.4.0",
        "type-is": "~1.6.17"
      }
    },
    "bytes": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
      "integrity": "sha512-
zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcV
zfVTI2Dg=="
    },
    "component-emitter": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/component-emitter/-/component-
emitter-1.3.0.tgz",
      "integrity":
"sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBu
E0QYoB90YdfatsRg=="
    },
    "content-disposition": {
      "version": "0.5.3",
      "resolved": "https://registry.npmjs.org/content-disposition/-/content-
disposition-0.5.3.tgz",
      "integrity": "sha512-
ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcW
ng8z1z0g==",
      "requires": {
        "safe-buffer": "5.1.2"
      }
    },
    "content-type": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/content-type/-/content-type-
1.0.4.tgz",
      "integrity":
"sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/
tvIG/tUc9mOUJiPBhPXA=="
    },
    "cookie": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
      "integrity":
"sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/
W6ZaPDOUbnjOt/99w66zk+l1Xg=="
    },
    "cookie-signature": {
      "version": "1.0.6",
      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-
signature-1.0.6.tgz",
      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
    },
    "cors": {
      "version": "2.8.5",
      "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
      "integrity":
"sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q
4n6GHQ9cDtxv/P6g==",
      "requires": {
        "object-assign": "^4",
        "vary": "^1"
      }
    },
    "debug": {
      "version": "2.6.9",
      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
      "integrity": "sha512-
bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/
E7AdgFBVeAPVMNcKGsHMA==",
      "requires": {
        "ms": "2.0.0"
      }
    },
    "depd": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
    },
    "destroy": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
    },
    "ee-first": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
    },
    "encodeurl": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-
1.0.2.tgz",
      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
    },
    "engine.io": {
      "version": "5.1.1",
      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-
5.1.1.tgz",
      "integrity":
"sha512-aMWot7H5aC8L4/T8qMYbLdvKlZOdJTH54FxfdFunTGvhMx1BHkJOntWArsVfgAZVwAO9LC
2sryPWRcEeUzCe5w==",
      "requires": {
        "accepts": "~1.3.4",
        "base64id": "2.0.0",
        "cookie": "~0.4.1",
        "cors": "~2.8.5",
        "debug": "~4.3.1",
        "engine.io-parser": "~4.0.0",
        "ws": "~7.4.2"
      },
      "dependencies": {
        "cookie": {
          "version": "0.4.1",
          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
          "integrity":
"sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF
8zELf3dFNl/kxkUA=="
        },
        "debug": {
          "version": "4.3.2",
          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
          "integrity":
"sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0
xV7M0cCO6P/O0Xhw==",
          "requires": {
            "ms": "2.1.2"
          }
        },
        "ms": {
          "version": "2.1.2",
          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
          "integrity": "sha512-
sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvb
s1PEaH2w=="
        }
      }
    },
    "engine.io-parser": {
      "version": "4.0.2",
      "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-
parser-4.0.2.tgz",
      "integrity":
"sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/
MqJdZbUjW97JU72iYg==",
      "requires": {
        "base64-arraybuffer": "0.1.4"
      }
    },
    "escape-html": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-
1.0.3.tgz",
      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
    },
    "etag": {
      "version": "1.8.1",
      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
    },
    "express": {
      "version": "4.17.1",
      "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
      "integrity":
"sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUV
qgb27xlEMXTnYt4g==",
      "requires": {
        "accepts": "~1.3.7",
        "array-flatten": "1.1.1",
        "body-parser": "1.19.0",
        "content-disposition": "0.5.3",
        "content-type": "~1.0.4",
        "cookie": "0.4.0",
        "cookie-signature": "1.0.6",
        "debug": "2.6.9",
        "depd": "~1.1.2",
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "etag": "~1.8.1",
        "finalhandler": "~1.1.2",
        "fresh": "0.5.2",
        "merge-descriptors": "1.0.1",
        "methods": "~1.1.2",
        "on-finished": "~2.3.0",
        "parseurl": "~1.3.3",
        "path-to-regexp": "0.1.7",
        "proxy-addr": "~2.0.5",
        "qs": "6.7.0",
        "range-parser": "~1.2.1",
        "safe-buffer": "5.1.2",
        "send": "0.17.1",
        "serve-static": "1.14.1",
        "setprototypeof": "1.1.1",
        "statuses": "~1.5.0",
        "type-is": "~1.6.18",
        "utils-merge": "1.0.1",
        "vary": "~1.1.2"
      }
    },
    "finalhandler": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-
1.1.2.tgz",
      "integrity": "sha512-
aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsB
g6z0zsWA==",
      "requires": {
        "debug": "2.6.9",
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "on-finished": "~2.3.0",
        "parseurl": "~1.3.3",
        "statuses": "~1.5.0",
        "unpipe": "~1.0.0"
      }
    },
    "forwarded": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-
0.2.0.tgz",
      "integrity": "sha512-
buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/
Nt6MT9aYow=="
    },
    "fresh": {
      "version": "0.5.2",
      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
    },
    "http-errors": {
      "version": "1.7.2",
      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-
1.7.2.tgz",
      "integrity":
"sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ
5plg63TvGfRSDCRg==",
      "requires": {
        "depd": "~1.1.2",
        "inherits": "2.0.3",
        "setprototypeof": "1.1.1",
        "statuses": ">= 1.5.0 < 2",
        "toidentifier": "1.0.0"
      }
    },
    "iconv-lite": {
      "version": "0.4.24",
      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-
0.4.24.tgz",
      "integrity": "sha512-
v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bE
qdpj8/rA==",
      "requires": {
        "safer-buffer": ">= 2.1.2 < 3"
      }
    },
    "inherits": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
    },
    "ipaddr.js": {
      "version": "1.9.1",
      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-
1.9.1.tgz",
      "integrity":
"sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/
w18ZlXSHBYXiYUPO3g=="
    },
    "media-typer": {
      "version": "0.3.0",
      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-
0.3.0.tgz",
      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
    },
    "merge-descriptors": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-
descriptors-1.0.1.tgz",
      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
    },
    "methods": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
    },
    "mime": {
      "version": "1.6.0",
      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
      "integrity": "sha512-
x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFR
srswaQeg=="
    },
    "mime-db": {
      "version": "1.48.0",
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz",
      "integrity": "sha512-
FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUS
q1yzslJQ=="
    },
    "mime-types": {
      "version": "2.1.31",
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-
2.1.31.tgz",
      "integrity": "sha512-
XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/
MOcsDgpilPOPg==",
      "requires": {
        "mime-db": "1.48.0"
      }
    },
    "ms": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
    },
    "negotiator": {
      "version": "0.6.2",
      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-
0.6.2.tgz",
      "integrity":
"sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7m
um2AUqDidoKqcTOw=="
    },
    "object-assign": {
      "version": "4.1.1",
      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-
4.1.1.tgz",
      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
    },
    "on-finished": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-
2.3.0.tgz",
      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
      "requires": {
        "ee-first": "1.1.1"
      }
    },
    "parseurl": {
      "version": "1.3.3",
      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
      "integrity":
"sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fH
ynXi9NYO4nWOL+qQ=="
    },
    "path-to-regexp": {
      "version": "0.1.7",
      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-
0.1.7.tgz",
      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
    },
    "proxy-addr": {
      "version": "2.0.7",
      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-
2.0.7.tgz",
      "integrity":
"sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/
gJEdZU7KMraoK1+XYAg==",
      "requires": {
        "forwarded": "0.2.0",
        "ipaddr.js": "1.9.1"
      }
    },
    "qs": {
      "version": "6.7.0",
      "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
      "integrity":
"sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIG
tV0XeCirBtpDrTyQ=="
    },
    "range-parser": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-
1.2.1.tgz",
      "integrity": "sha512-
Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/
GTl5agOwSg=="
    },
    "raw-body": {
      "version": "2.4.0",
      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
      "integrity":
"sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8
ipEDoiH70ySUJP3Q==",
      "requires": {
        "bytes": "3.1.0",
        "http-errors": "1.7.2",
        "iconv-lite": "0.4.24",
        "unpipe": "1.0.0"
      }
    },
    "safe-buffer": {
      "version": "5.1.2",
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-
5.1.2.tgz",
      "integrity":
"sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt
8ud/wPtojys4G6+g=="
    },
    "safer-buffer": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-
2.1.2.tgz",
      "integrity": "sha512-
YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbw
qcQriUtg=="
    },
    "send": {
      "version": "0.17.1",
      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
      "integrity": "sha512-
BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3
V4fT9sAg==",
      "requires": {
        "debug": "2.6.9",
        "depd": "~1.1.2",
        "destroy": "~1.0.4",
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "etag": "~1.8.1",
        "fresh": "0.5.2",
        "http-errors": "~1.7.2",
        "mime": "1.6.0",
        "ms": "2.1.1",
        "on-finished": "~2.3.0",
        "range-parser": "~1.2.1",
        "statuses": "~1.5.0"
      },
      "dependencies": {
        "ms": {
          "version": "2.1.1",
          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
          "integrity":
"sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/
FpnYaD/kOWhYQvyg=="
        }
      }
    },
    "serve-static": {
      "version": "1.14.1",
      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-
1.14.1.tgz",
      "integrity":
"sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecp
Zs+3mW+XbQZu9QCg==",
      "requires": {
        "encodeurl": "~1.0.2",
        "escape-html": "~1.0.3",
        "parseurl": "~1.3.3",
        "send": "0.17.1"
      }
    },
    "setprototypeof": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-
1.1.1.tgz",
      "integrity": "sha512-
JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lq
VRYP2OAw=="
    },
    "socket.io": {
      "version": "4.1.3",
      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-
4.1.3.tgz",
      "integrity": "sha512-
tLkaY13RcO4nIRh1K2hT5iuotfTaIQw7cVIe0FUykN3SuQi0cm7ALxuyT5/
CtDswOMWUzMGTibxYNx/gU7In+Q==",
      "requires": {
        "@types/cookie": "^0.4.0",
        "@types/cors": "^2.8.10",
        "@types/node": ">=10.0.0",
        "accepts": "~1.3.4",
        "base64id": "~2.0.0",
        "debug": "~4.3.1",
        "engine.io": "~5.1.1",
        "socket.io-adapter": "~2.3.1",
        "socket.io-parser": "~4.0.4"
      },
      "dependencies": {
        "debug": {
          "version": "4.3.2",
          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
          "integrity":
"sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0
xV7M0cCO6P/O0Xhw==",
          "requires": {
            "ms": "2.1.2"
          }
        },
        "ms": {
          "version": "2.1.2",
          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
          "integrity": "sha512-
sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvb
s1PEaH2w=="
        }
      }
    },
    "socket.io-adapter": {
      "version": "2.3.1",
      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-
adapter-2.3.1.tgz",
      "integrity": "sha512-
8cVkRxI8Nt2wadkY6u60Y4rpW3ejA1rxgcK2JuyIhmF+RMNpTy1QRtkHIDUOf3B4HlQwakMsWbKftM
v/71VMmw=="
    },
    "socket.io-parser": {
      "version": "4.0.4",
      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-
parser-4.0.4.tgz",
      "integrity":
"sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/
8R5ygK7jAR6t028/z+7295g==",
      "requires": {
        "@types/component-emitter": "^1.2.10",
        "component-emitter": "~1.3.0",
        "debug": "~4.3.1"
      },
      "dependencies": {
        "debug": {
          "version": "4.3.2",
          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
          "integrity":
"sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0
xV7M0cCO6P/O0Xhw==",
          "requires": {
            "ms": "2.1.2"
          }
        },
        "ms": {
          "version": "2.1.2",
          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
          "integrity": "sha512-
sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvb
s1PEaH2w=="
        }
      }
    },
    "statuses": {
      "version": "1.5.0",
      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
    },
    "toidentifier": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-
1.0.0.tgz",
      "integrity":
"sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJl
n5FNQDRrxj3YcbVw=="
    },
    "type-is": {
      "version": "1.6.18",
      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
      "integrity": "sha512-
TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm
06XQBy8g==",
      "requires": {
        "media-typer": "0.3.0",
        "mime-types": "~2.1.24"
      }
    },
    "unpipe": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
    },
    "utils-merge": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-
1.0.1.tgz",
      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
    },
    "vary": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
    },
    "ws": {
      "version": "7.4.6",
      "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
      "integrity":
"sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCY
QNUnfWdXta/Yu85A==",
      "requires": {}
    }
  }
}

{
  "name": "meet-up",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js"
  },
  "keywords": [],
  "author": "Abhinav",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "socket.io": "^4.1.3"
  }
}

4.4 SECURITY 
As computers and other digital devices have become essential to business
and commerce, they have also increasingly
become a target for attacks. In order for a company or an individual to use a
computing device with confidence, they must first be assured that the device is
not compromised in any way and that all communications will be secure. In this
chapter, we will review the
fundamental concepts of information System s security and
discuss some of the measures that can be taken to mitigate security threats. We
will begin with an
overview focusing on how organizations can stay secure. Several different meas
ures that a company can take to improve security will be discussed. We will then
follow up by reviewing security precautions that individuals can take in order to
secure their personal computing environment. 
The Information Security Triad: Confidentiality, Integrity,
Availability (CIA) 
 Confidentiality 
When protecting information, we want to be able to restrict access to
those who are allowed to see it; everyone else should be disallowed from
learning anything about its contents. This is the essence of confidentiality.
For example, federal law requires that universities restrict access to
private student information. The university must be sure that only those who
are authorized have access to view the grade records. 
 Integrity 
Integrity is the assurance that the information being accessed has not
been altered and truly represents what is intended. Just as a person with
integrity means what he or she says and can be trusted to consistently represent
the truth, information integrity means information truly represents its
intended meaning. Information can lose its integrity through malicious intent,
such as when someone who is not authorized makes a change to
intentionally misrepresent something. An example of this would be when a
hacker is hired to go into the university’s System and change a grade. 
Integrity can also be lost unintentionally, such as when a computer
power surge corrupts a file or someone authorized to make a change
accidentally deletes a file or enters incorrect information. 
 
Information availability is the third part of the CIA triad. Availability
means that information can be accessed and modified by anyone authorized to d
o so in an appropriate timeframe. Depending on the type of
information, appropriate timeframe can mean different things. For example, a
stock trader needs information to be available immediately, while a sales person
may be happy to get sales numbers for the day in a report the next morning. 
Companies such as Amazon.com will require their servers to be
available twenty-four hours a day, seven days a week. Other companies may not
suffer if their web servers are down for a few minutes once in a while. 
 Tools for Information Security 
In order to ensure the confidentiality, integrity, and availability of information, o
rganizations can choose from a variety of tools. Each of these tools can
be utilized as part of an overall information-security policy. 
 Authentication: 
Authentication can be accomplished by identifying someone through one
or more of three factors: something they know, something they have,
or something they are. For example, the most common form of
authentication today is the user ID and password. In this case, the authentication
is done by confirming something that the user knows (their ID and password).
But this form of authentication is easy to compromise (see sidebar) and
stronger forms of authentication are sometimes needed. Identifying someone
only by something they have, such as
a key or a card, can also be problematic. When that identifying token is lost or
stolen, the identity can be easily stolen. The final factor, something you are, is
much harder to compromise. This
factor identifies a user through the use of a physical characteristic, such as an
eye-scan or fingerprint. Identifying someone through their physical characteristi
cs is called biometrics. 
A more secure way to authenticate a user is to do multi-factor authentication. By
combining two or more of the factors listed above, it becomes much more diffic
ult for someone to misrepresent themselves. 
 Access Control 
Once a user has been authenticated, the next step is to ensure that they can only
access the information resources that are appropriate. This is
done through the use of access control. Access control determines which users a
re authorized to read, modify, add, and/or delete information. Several
different access control models exist. Here we will discuss two: the access
control list (ACL) and role-based access control (RBAC). 
For each information resource that an organization wishes to manage, a list of
users who have the ability to take specific actions can be created. This is an
access control list, or ACL. For each user, specific capabilities are assigned,
such as read, write, delete, or add. Only users with
those capabilities are allowed to perform those functions. If a user is not on the l
ist, they have no ability to even know that the information resource exists. 
ACLs are simple to understand and maintain. However, they have
several drawbacks. The primary drawback is that each information resource
is managed separately, so if a security administrator wanted to add or remove
a user to a large set of information resources, it would be quite difficult. And as
the number of users and resources increase, ACLs become harder to maintain.
This has led to an improved method of access control, called role- based access
control, or RBAC. With RBAC, instead of giving specific users access rights to
an information resource, users are assigned to roles and then those roles are
assigned the access. This allows the administrators to manage users and roles
separately, simplifying administration and, by extension, improving security. 
 Encryption 
Many times, an organization needs to transmit information over the Internet or
transfer it on external media such as a CD or flash drive. In these cases, even
with proper authentication and access control, it is possible for an unauthorized
person to get access to the data. Encryption is a process of encoding data upon
its transmission or storage so that only authorized individuals can read it. This
encoding is accomplished by a computer program, which encodes the plain
text that needs to be transmitted; then the recipient receives the cipher text and
decodes it (decryption). In order for this to work, the sender and receiver need
to agree on the method of encoding so that both parties can communicate
properly. Both parties share the encryption key, enabling them to encode and
decode each other’s messages. This is called symmetric key encryption. This
type of encryption is problematic because the key is available
in two different places. 
An alternative to symmetric key encryption is public key encryption.
In public key encryption, two keys are used:
a public key and a private key. To send an encrypted message, you obtain the
public key, encode the message, and send it. The recipient then uses the private
key to decode it. The public key can be given to anyone who wishes
to send the recipient a message. 
Each user simply needs one private key and one public key in order to
secure messages. The private key is necessary in order to decrypt something
sent with the public key. 
 
4.5 LIMITATIONS OF THE PROJECT 
Limitation of Project on Web meet upAlthough I have put my best efforts to make the
software flexible, easy to operate but limitations cannot be ruled out even by me.  

 • The transactions are executed in on-line mode, hence off-line data for Donor, Blood
Stock capture and modification is not possible.  
• Off-line reports of Blood Bank, Blood Cell, Donor cannot be generated due to batch
mode execution.. 
1. DOCUMENTATION: 
It is time consuming and requires expertise in creating good documentation from view
point of top administrators users. 
 
2. MANUALS: 
Various manuals are to be prepared such as user manuals, System manuals etc. It needs
time, human labor and are subject to change drastically as the technology changes 
3. ONLINE HELP: 
One needs to provide online help to various users so that all the features of the software
can be properly understood by the user. 
 
4. COMPLEXITY: 
It is time consuming to manage and debug all the modules one by one. 
 
 
 
 
 
 
 
 
 
CONSLUSION 
 
5.1 CONCLUSION 
Now a day’s there is a big demand of different types of applications, which is because IT has
become the main part of our New World. There is a big need of different applications. People
want application for every specific task from work to entertainment. I have developed
this php application “WEEB MEET UP” which works easy on any given web browser. 
The application has been tested on platform of php and found to be working as per the given
criteria. It can be safely concluded that the application possesses a highly efficient UI system
and is working properly and meeting to all the requirements of the user. The application gives
the user maximum flexibility in the types of touch and other device movements.  
        Secondly, I take this opportunity to express my sense of indebtedness and gratitude to all
those people who helped us in completing this project and implementation .  This project and
implementation has contributed a lot to my knowledge that has proved to be a value addition
for me. 
 
 
 
 
5.2 FUTURE SCOPE OF THE PROJECT 
In a nutshell, it can be summarized that the future scope of the project circles around
maintaining information regarding:  
• We can add printer in future.  
• We can give more advance software for Web meet upincluding more facilities  
• We will host the platform on online servers to make it accessible worldwide 
 • Integrate multiple load balancers to distribute the loads of the system  
• Create the master and slave database structure to reduce the overload of the database
queries  
• Implement the backup mechanism for taking backup of codebase and database on
regular basis on different servers The above mentioned points are the enhancements
which can be done to increase the applicability and usage of this project.  
Here we can maintain the records of Blood Bank and Blood Group. Also, as it can be
seen that now-a-days the players are versatile, i.e. so there is a scope for introducing a
method to maintain the Web meet up. 
 
 
 
 
BIBLIOGRAPHY 
 
1. IGNOU books 
2. www.youtube.com 
3. www.google.com 
4. www.wikkipedia.com 
5. www.tutorialspoint.com 
 

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy