update,
This commit is contained in:
0
hk1234566/.env.docker
Normal file
0
hk1234566/.env.docker
Normal file
0
hk1234566/SQL/Assessment1/.gitkeep
Normal file
0
hk1234566/SQL/Assessment1/.gitkeep
Normal file
8
hk1234566/SQL/Assessment1/Combat.csv
Normal file
8
hk1234566/SQL/Assessment1/Combat.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
BattleDate,BattleNo,Attacker,Defender,Weapon,Result,Damage
|
||||
15-May-23,5481,Calvin,SneakySue,Axe,Hit,87
|
||||
15-May-23,5481,SneakySue,Calvin,Dagger,Miss,0
|
||||
15-May-23,5481,Calvin,SneakySue,Axe,Hit,94
|
||||
15-May-23,5481,SneakySue,Calvin,Dagger,Parry,0
|
||||
15-May-23,5481,Calvin,SneakySue,Axe ,Hit,78
|
||||
15-May-23,5481,SneakySue,Calvin,Dagger,Hit,14
|
||||
15-May-23,5481,Calvin,SneakySue,Axe,Victory,112
|
|
8
hk1234566/SQL/Assessment1/Customers.csv
Normal file
8
hk1234566/SQL/Assessment1/Customers.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
Account_Number,Forename,surname,e-mail_Address,Character_CreationDate,Character_Expiry_Date,Character_Name,Character_Type,Level,ExperiencePoints,Max_Health,Health,AttackinScore,DefenceScore,StealthScore,ManaScore,Money_bank,Money_wallet
|
||||
15468336,Jones,Susan,sj56@gmail.com,02-Jan-2022,,juju97,Warrior,12,12475,1000,996,85,23,17,,4273.95,351
|
||||
15468336,Jones,Susan,sj56@gmail.com,15-Mar-2022,,SneakySue,Thief,7,7201,900,856,37,12,56,,11730.34,295
|
||||
15468336,Jones,Susan,sj56@gmail.com,14-Jul-2022,19-Aug-2022,DarkMage,Mage,3,2012,250,250,12,17,9,21,0,0
|
||||
35482956,Turker,Uraz,u.turker@lancaster.ac.uk,05-Mar-2022,,Uraz-The-Magnificent,Mage,34,34925,1200,1094,34,49,21,64,11397,700
|
||||
54387937,Schmidt,Johan,jjs46@hotmail.com,08-Jan2023,,SpacemanSpiff,Mage,3,1085,250,227,9,19,8,31,548,102
|
||||
64345236,Ricki,Boswell-Challand,r.boswell-challand@lancaster.ac.uk,24-Apr-2022,,Calvin,Merchant,18,21765,950,950,54,53,36,,34950,3705
|
||||
64345236,Ricki,Boswell-Challand,r.boswell-challand@lancaster.ac.uk,13-May2022,,Hobbes,Warrior,95,95678,1500,1500,88,79,84,,0,0
|
|
230
hk1234566/SQL/Assessment1/ER.html
Normal file
230
hk1234566/SQL/Assessment1/ER.html
Normal file
@@ -0,0 +1,230 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
startOnLoad: true
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="mermaid">
|
||||
---
|
||||
title: Order example
|
||||
---
|
||||
erDiagram
|
||||
CUSTOMER |o--o{ Warrior : Own
|
||||
CUSTOMER |o--o{ Thief : Own
|
||||
CUSTOMER |o--o{ Mage : Own
|
||||
CUSTOMER |o--o{ Merchant : Own
|
||||
|
||||
ITEMS |o--o{ Warrior : Own
|
||||
ITEMS |o--o{ Thief : Own
|
||||
ITEMS |o--o{ Mage : Own
|
||||
ITEMS |o--o{ Merchant : Own
|
||||
|
||||
Warrior }o--o{ COMBAT : Attack
|
||||
Thief }o--o{ COMBAT : Attack
|
||||
Mage }o--o{ COMBAT : Attack
|
||||
Merchant }o--o{ COMBAT : Attack
|
||||
|
||||
Warrior }o--o{ COMBAT : Defense
|
||||
Thief }o--o{ COMBAT : Defense
|
||||
Mage }o--o{ COMBAT : Defense
|
||||
Merchant }o--o{ COMBAT : Defense
|
||||
|
||||
COMBAT }o--o{ BATTLE : Own
|
||||
|
||||
CUSTOMER {
|
||||
string AccountNumber PK
|
||||
string e-mail_Address
|
||||
string Forename
|
||||
string surname
|
||||
}
|
||||
|
||||
Merchant {
|
||||
int AccountNumber FK
|
||||
string CharacterCreationDate
|
||||
string CharacterExpiryDate
|
||||
string CharacterName
|
||||
string CharacterType
|
||||
string Level
|
||||
string ExperiencePoints
|
||||
string MaxHealth
|
||||
string Health
|
||||
string AttackinScore
|
||||
string DefenceScore
|
||||
string StealthScore
|
||||
string ManaScore
|
||||
string MoneyBank
|
||||
string MoneyWallet
|
||||
}
|
||||
|
||||
Mage {
|
||||
int AccountNumber FK
|
||||
string CharacterCreationDate
|
||||
string CharacterExpiryDate
|
||||
string CharacterName
|
||||
string CharacterType
|
||||
string Level
|
||||
string ExperiencePoints
|
||||
string MaxHealth
|
||||
string Health
|
||||
string AttackinScore
|
||||
string DefenceScore
|
||||
string StealthScore
|
||||
string ManaScore
|
||||
string MoneyBank
|
||||
string MoneyWallet
|
||||
}
|
||||
|
||||
Thief {
|
||||
int AccountNumber FK
|
||||
string CharacterCreationDate
|
||||
string CharacterExpiryDate
|
||||
string CharacterName
|
||||
string CharacterType
|
||||
string Level
|
||||
string ExperiencePoints
|
||||
string MaxHealth
|
||||
string Health
|
||||
string AttackinScore
|
||||
string DefenceScore
|
||||
string StealthScore
|
||||
string ManaScore
|
||||
string MoneyBank
|
||||
string MoneyWallet
|
||||
}
|
||||
|
||||
Warrior {
|
||||
int AccountNumber FK
|
||||
string CharacterCreationDate
|
||||
string CharacterExpiryDate
|
||||
string CharacterName
|
||||
string CharacterType
|
||||
string Level
|
||||
string ExperiencePoints
|
||||
string MaxHealth
|
||||
string Health
|
||||
string AttackinScore
|
||||
string DefenceScore
|
||||
string StealthScore
|
||||
string ManaScore
|
||||
string MoneyBank
|
||||
string MoneyWallet
|
||||
}
|
||||
|
||||
Score {
|
||||
int characterKey FK
|
||||
string ManaScore
|
||||
string StealthScore
|
||||
string DefenceScore
|
||||
string AttackInScore
|
||||
}
|
||||
|
||||
COMBAT {
|
||||
int AccountNumber_CharacterName FK
|
||||
string BattleDate
|
||||
string BattleNo
|
||||
string Attacker
|
||||
string Defender
|
||||
string Weapon
|
||||
string Result
|
||||
string Damage
|
||||
}
|
||||
|
||||
ITEMS {
|
||||
string Character
|
||||
string Item
|
||||
string Item_Type
|
||||
string WeaponType
|
||||
string Range
|
||||
string Price
|
||||
string Quantity
|
||||
string DefendScore
|
||||
string AttackScore
|
||||
string HealingScore
|
||||
string ManaScore
|
||||
string SingleUse
|
||||
string wearable
|
||||
string worn
|
||||
string BodyPart
|
||||
string Equipped
|
||||
}
|
||||
|
||||
ARMOUR {
|
||||
string Price
|
||||
string Quantity
|
||||
string DefendScore
|
||||
string SingleUse
|
||||
string wearable
|
||||
string worn
|
||||
string BodyPart
|
||||
string Equipped
|
||||
}
|
||||
|
||||
ARTEFACT {
|
||||
string Price
|
||||
string Quantity
|
||||
string DefendScore
|
||||
string AttackScore
|
||||
string ManaScore
|
||||
string SingleUse
|
||||
string wearable
|
||||
string Equipped
|
||||
}
|
||||
|
||||
CLOTHING {
|
||||
string Price
|
||||
string Quantity
|
||||
string DefendScore
|
||||
string ManaScore
|
||||
string SingleUse
|
||||
string wearable
|
||||
string worn
|
||||
string BodyPart
|
||||
string Equipped
|
||||
}
|
||||
|
||||
FOOD {
|
||||
string Price
|
||||
string Quantity
|
||||
string HealingScore
|
||||
string SingleUse
|
||||
string wearable
|
||||
string worn
|
||||
string Equipped
|
||||
}
|
||||
|
||||
WEAPON {
|
||||
string WeaponType
|
||||
string Range
|
||||
string Price
|
||||
string Quantity
|
||||
string DefendScore
|
||||
string AttackScore
|
||||
string HealingScore
|
||||
string SingleUse
|
||||
string wearable
|
||||
string Equipped
|
||||
}
|
||||
|
||||
BATTLE {
|
||||
string BattleDate
|
||||
string BattleNo
|
||||
}
|
||||
|
||||
COMBAT {
|
||||
string Attacker FK
|
||||
string Defender FK
|
||||
string Weapon
|
||||
string Result
|
||||
string Damage
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
26
hk1234566/SQL/Assessment1/ER/dot2.bat
Normal file
26
hk1234566/SQL/Assessment1/ER/dot2.bat
Normal file
@@ -0,0 +1,26 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
|
||||
if [%2] equ [] (
|
||||
echo dot2 ext dotfile
|
||||
exit /b
|
||||
)
|
||||
|
||||
set extension=%1
|
||||
set dotFile=%2
|
||||
set dotFile_=%~n2%
|
||||
|
||||
if not exist %dotFile% (
|
||||
echo %dotFile% does not exist
|
||||
exit /b
|
||||
)
|
||||
|
||||
dot -T%extension% -o%dotFile_%.%extension% %dotFile%
|
||||
|
||||
if %errorlevel% neq 0 (
|
||||
echo ErrorLevel: %errorlevel%
|
||||
exit /b
|
||||
)
|
||||
|
||||
@REM start %dotFile_%.%extension%
|
63
hk1234566/SQL/Assessment1/ER/helloworld copy.dot
Normal file
63
hk1234566/SQL/Assessment1/ER/helloworld copy.dot
Normal file
@@ -0,0 +1,63 @@
|
||||
graph ER {
|
||||
size="15,15"
|
||||
fontname="Helvetica,Arial,sans-serif"
|
||||
node [fontname="Helvetica,Arial,sans-serif", fontsize=10;]
|
||||
edge [fontname="Helvetica,Arial,sans-serif"]
|
||||
layout=neato
|
||||
|
||||
node [shape=triangle,color=red]; "ISA";
|
||||
node [shape=box, color=black]; course; institute; student; Customers;
|
||||
|
||||
node [shape=box, color=black]; Customers;
|
||||
node [shape=ellipse]; AccountNumber; EMailAddress; Name; Forename; Surname;
|
||||
node [shape=ellipse]; {node [label="Name"] name0; name1; name2;}
|
||||
|
||||
Customers -- AccountNumber [len=2.0];
|
||||
Customers -- EMailAddress [len=1.0];
|
||||
Customers -- name0 [len=1.0];
|
||||
Name -- Forename [len=1.5];
|
||||
Name -- Surname [len=1.0];
|
||||
|
||||
node [shape=box,color=black, peripheries=2]; "Characters";
|
||||
node [shape=ellipse, peripheries=1]; AccountNumber; Forename; surname; EMailAddress; CharacterCreationDate; CharacterExpiryDate; CharacterName; CharacterType; Level; ExperiencePoints; MaxHealth; Health; AttackinScore; DefenceScore; StealthScore; ManaScore; Moneybank; Moneywallet;
|
||||
Characters -- Level [len=2.0];
|
||||
Characters -- Type [len=2.0];
|
||||
Characters -- Name [len=2.0];
|
||||
Characters -- MaxHealth [len=2.0];
|
||||
Characters -- StealthScore [len=2.0];
|
||||
Characters -- ExperiencePoints [len=2.0];
|
||||
Characters -- DefenceScore [len=2.0];
|
||||
Characters -- MoneyBank [len=2.0];
|
||||
Characters -- AttackInScore [len=2.0];
|
||||
Characters -- MoneyWallet [len=2.0];
|
||||
Characters -- Health [len=2.0];
|
||||
Characters -- ManaScore [len=2.0];
|
||||
Characters -- Date [len=2.0];
|
||||
Date -- Creation [len=2.0];
|
||||
Date -- Expiry [len=2.0];
|
||||
Date -- BillDuration [len=2.0];
|
||||
|
||||
|
||||
node [shape=ellipse]; {node [label="name"] name0; name1; name2;} code; grade; number;
|
||||
node [shape=diamond,color=black, peripheries=2]; "C-I"; "S-C"; "S-I";
|
||||
node [shape=box,color=black, peripheries=2]; "RECT2";
|
||||
node [shape=ellipse,color=black, peripheries=2]; "ellipse2";
|
||||
|
||||
RECT2 -- ellipse2 [label="n",len=3.00, color="black:white:black"];
|
||||
|
||||
name0 -- course;
|
||||
code -- course;
|
||||
course -- "C-I" [label="n",len=1.00];
|
||||
"C-I" -- institute [label="1",len=1.00];
|
||||
institute -- name1;
|
||||
institute -- "S-I" [label="1",len=1.00];
|
||||
"S-I" -- student [label="n",len=1.00];
|
||||
student -- grade;
|
||||
student -- name2;
|
||||
student -- number;
|
||||
student -- "S-C" [label="m",len=1.00];
|
||||
"S-C" -- course [label="n",len=1.00];
|
||||
|
||||
label = "\n\nEntity Relation Diagram\ndrawn by NEATO";
|
||||
fontsize=10;
|
||||
}
|
27
hk1234566/SQL/Assessment1/ER/helloworld.dot
Normal file
27
hk1234566/SQL/Assessment1/ER/helloworld.dot
Normal file
@@ -0,0 +1,27 @@
|
||||
graph ER {
|
||||
|
||||
fontname="Helvetica,Arial,sans-serif"
|
||||
node [fontname="Helvetica,Arial,sans-serif", fontsize=10]
|
||||
edge [fontname="Helvetica,Arial,sans-serif"]
|
||||
layout=neato
|
||||
node [shape=box]; course; institute; student;
|
||||
node [shape=ellipse]; {node [label="name"] name0; name1; name2;}
|
||||
code; grade; number;
|
||||
node [shape=diamond,style=filled,color=lightgrey]; "C-I"; "S-C"; "S-I";
|
||||
|
||||
name0 -- course;
|
||||
code -- course;
|
||||
course -- "C-I" [label="n",len=1.00];
|
||||
"C-I" -- institute [label="1",len=1.00];
|
||||
institute -- name1;
|
||||
institute -- "S-I" [label="1",len=1.00];
|
||||
"S-I" -- student [label="n",len=1.00];
|
||||
student -- grade;
|
||||
student -- name2;
|
||||
student -- number;
|
||||
student -- "S-C" [label="m",len=1.00];
|
||||
"S-C" -- course [label="n",len=1.00];
|
||||
|
||||
label = "\n\nEntity Relation Diagram\ndrawn by NEATO";
|
||||
fontsize=20;
|
||||
}
|
BIN
hk1234566/SQL/Assessment1/ER/helloworld.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/ER/helloworld.png
(Stored with Git LFS)
Normal file
Binary file not shown.
12
hk1234566/SQL/Assessment1/ER/index.html
Normal file
12
hk1234566/SQL/Assessment1/ER/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<img src="helloworld.png" />
|
||||
</body>
|
||||
</html>
|
15
hk1234566/SQL/Assessment1/Items.csv
Normal file
15
hk1234566/SQL/Assessment1/Items.csv
Normal file
@@ -0,0 +1,15 @@
|
||||
Character,Item,Item_Type,WeaponType,Range,Price,Quantity,DefendScore,AttackScore,HealingScore,ManaScore,SingleUse,wearable,worn,BodyPart,Equipped
|
||||
juju97,breastplate,Armour,,,290,1,18,,,,0,1,1,torso,0
|
||||
Uraz-The-Magnificent,Wizard's Staff,Artefact,,,3500,1,0,0,,37,0,,,,1
|
||||
SpacemanSpiff,Transmogrifier,Artefact,,,54000,1,,,,500,0,0,,,1
|
||||
Uraz-The-Magnificent,Wizard's Robe,Clothing,,,2000,1,10,,,,,1,1,torso,0
|
||||
juju97,Tunic,Clothing,,,5,1,1,0,,,0,1,1,torso,
|
||||
juju97,Cloak of Invisibility,Clothing,,,4500,1,,,,75,,1,0,torso,
|
||||
Uraz-The-Magnificent,Apple,Food,,,1,1,,,10,,1,,,,0
|
||||
juju97,Bread,Food,,,0.75,3,,,8,,1,,,,0
|
||||
SpacemanSpiff,Can of Tuna,Food,,,3,4,,,15,,1,0,,,1
|
||||
Uraz-The-Magnificent,Cheese,Food,,,6,10,,,12,,1,0,0,,0
|
||||
juju97,Broadsword,Weapon,Melee,,175,1,,24,,,0,0,,,1
|
||||
juju97,slingshot,Weapon,Projectile,30,50,1,,13,,,0,0,,,0
|
||||
SneakySue,Dagger,Weapon,Melee,,12,1,1,10,0,,0,0,,,1
|
||||
Calvin,Axe,Weapon,Melee,,80,1,,,,,,,,,1
|
|
BIN
hk1234566/SQL/Assessment1/docs/Coursework_Updated.pdf
Normal file
BIN
hk1234566/SQL/Assessment1/docs/Coursework_Updated.pdf
Normal file
Binary file not shown.
1
hk1234566/SQL/Assessment1/docs/ERD.xml
Normal file
1
hk1234566/SQL/Assessment1/docs/ERD.xml
Normal file
File diff suppressed because one or more lines are too long
BIN
hk1234566/SQL/Assessment1/docs/ER_for_characters.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/docs/ER_for_characters.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/docs/ER_for_combat.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/docs/ER_for_combat.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/docs/ER_for_customers.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/docs/ER_for_customers.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/docs/ER_for_items.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/docs/ER_for_items.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/docs/ER_overview.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/docs/ER_overview.png
(Stored with Git LFS)
Normal file
Binary file not shown.
92
hk1234566/SQL/Assessment1/docs/draft.md
Normal file
92
hk1234566/SQL/Assessment1/docs/draft.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# ER and attributes for combat
|
||||
|
||||

|
||||
|
||||
### Entity
|
||||
A Battle has a Battle Number (the primary key) and Date(BattleDate) attribute.
|
||||
|
||||
A Combat has a Damage, Weapon and a Result attribute.
|
||||
|
||||
### Relationship: Involved (battle)
|
||||
A combat must have battle involved.
|
||||
|
||||
A battle will contain at least on combat.
|
||||
|
||||
### Relationship: Involved (Attacker / Defender)
|
||||
A combat must have at least 1 characters involved.
|
||||
|
||||
A Characters may contain empty combat history
|
||||
|
||||
# ER and attributes for characters
|
||||
|
||||

|
||||
|
||||
### Entity
|
||||
|
||||
A Characters has a Name(key), Type, Level, ExperiencePoints, MaxHealth, Health, AttackInScore, DefenceScore, StealthScore, ManaScore, MoneyBank MoneyWallet attribute.
|
||||
|
||||
|
||||
### Relationship: OwnedBy
|
||||
A character must owned by one player
|
||||
|
||||
A player may have many characters
|
||||
|
||||
### Relationship: OwnItems
|
||||
An Items must owned by one character
|
||||
|
||||
A character may have many Items
|
||||
|
||||
If a character is deleted from the game server, the items will be deleted
|
||||
|
||||
### Relationship: Involved
|
||||
|
||||
A Combat (either attacker/defender) must owned by one character
|
||||
|
||||
A character may involved in many combats
|
||||
|
||||
If a character is deleted from the game server, the combat will be deleted
|
||||
|
||||
|
||||
# ER and attributes for customers/players
|
||||
|
||||

|
||||
|
||||
|
||||
## Entity set
|
||||
|
||||
A customers has a AccountNumber(key), Name and EMailAddress attribute.
|
||||
|
||||
Name is a Multi-valued attribute containing Forename and Surname.
|
||||
|
||||
## Relationship Owned By
|
||||
|
||||
A Characters must owned by one character
|
||||
|
||||
A customers/player may have many character
|
||||
|
||||
If a customer/player is deleted from the game server, the characters will be deleted
|
||||
|
||||
# ER and attributes for items/inventory
|
||||
|
||||

|
||||
|
||||
## Entity set
|
||||
|
||||
A Items has a ItemName, ItemType, WeaponType, Quantity, Range, SingleUse, Price, Equipped, BodyPart, Wearable, Worn attribute
|
||||
|
||||
A Score is a Multi-valued attribute containing ManaScore, DefendScore and AttackScore.
|
||||
|
||||
A ItemKey is an key to indicate the specific item
|
||||
|
||||
## Relationship OwnedItems
|
||||
|
||||
A Items must owned by one character
|
||||
|
||||
A character may have many items
|
||||
|
||||
If a character is deleted from the game server, the Items will be deleted
|
||||
|
||||
|
||||
# Overview of ERs
|
||||
|
||||

|
BIN
hk1234566/SQL/Assessment1/docs/output1.odt
Normal file
BIN
hk1234566/SQL/Assessment1/docs/output1.odt
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/docs/output1.pdf
Normal file
BIN
hk1234566/SQL/Assessment1/docs/output1.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/docs/output2.odt
Normal file
BIN
hk1234566/SQL/Assessment1/docs/output2.odt
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/docs/output2.pdf
Normal file
BIN
hk1234566/SQL/Assessment1/docs/output2.pdf
Normal file
Binary file not shown.
85
hk1234566/SQL/Assessment1/fields.md
Normal file
85
hk1234566/SQL/Assessment1/fields.md
Normal file
@@ -0,0 +1,85 @@
|
||||
Players(customers)
|
||||
- requirements:
|
||||
- A player must have at least one character (Characters_owned)
|
||||
- can create a new character or
|
||||
- deactivate one they no longer wish to play
|
||||
- Once a player unsubscribed from the game, the character is also removed from the system.
|
||||
- A player will be billed at the end of a calendar month
|
||||
- for all active characters for any part of that month.
|
||||
|
||||
- fields:
|
||||
- Account_Number(pk)
|
||||
- Forename
|
||||
- surname
|
||||
- e-mail_Address
|
||||
- Characters_owned(1 to many to characters)
|
||||
|
||||
Characters
|
||||
- requirements:
|
||||
- Characters have combat info (see Combat.csv)
|
||||
|
||||
- fields:
|
||||
- Name(Character_Name)
|
||||
- Type(Character_Type)
|
||||
- Level
|
||||
- ExperiencePoints
|
||||
- Max_Health
|
||||
- Health
|
||||
- AttackInScore
|
||||
- DefenceScore
|
||||
- StealthScore
|
||||
- ManaScore
|
||||
- MoneyBank
|
||||
- MoneyWallet
|
||||
- OwnedBy (many to 1 to players)
|
||||
- Items (1 to Many to items table)
|
||||
- CombatInvolved (1 to many to Combat table / Battle)
|
||||
- CreationDate(Character_CreationDate)
|
||||
- ExpiryDate(Character_Expiry_Date)
|
||||
|
||||
Inventory(Items)
|
||||
- for the various weapons and armour a character may possess
|
||||
- Weapons:
|
||||
- range
|
||||
- damage points.
|
||||
- Armours:
|
||||
- defence score
|
||||
- worn on a speciÞc body part.
|
||||
- Supplies:
|
||||
- healing score,
|
||||
- mana score
|
||||
- if consumed increase the character’s life score by that amount (after which time the character will possess one fewer of that type of item)
|
||||
|
||||
- fields:
|
||||
- ItemsKey(pk)
|
||||
- Item_Name(Item)
|
||||
- Item_Type
|
||||
- WeaponType
|
||||
- Range
|
||||
- Price
|
||||
- Quantity
|
||||
- DefendScore
|
||||
- AttackScore
|
||||
- HealingScore
|
||||
- ManaScore
|
||||
- SingleUse
|
||||
- wearable
|
||||
- worn
|
||||
- BodyPart
|
||||
- Equipped
|
||||
- Character (many to 1 to character / Items)
|
||||
|
||||
Combat:
|
||||
- requirements:
|
||||
- \# of kills
|
||||
- KIA’s(Killed in action)
|
||||
- victories
|
||||
|
||||
- fields:
|
||||
- BattleNo(pk)
|
||||
- BattleDate
|
||||
- Attacker(many to 1 -> characters)
|
||||
- Defender(many to 1 -> characters)
|
||||
- Weapon
|
||||
- Result
|
||||
- Damage
|
29
hk1234566/SQL/Assessment1/notes.md
Normal file
29
hk1234566/SQL/Assessment1/notes.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# notes.md
|
||||
|
||||

|
||||
|
||||
Your ERD should handle the following rules as a minimum but please use your
|
||||
imagination to provide further rules:
|
||||
a) A player must have at least one character and can create a new character or
|
||||
deactivate one they no longer wish to play at any time. Once a player
|
||||
unsubscribed from the game, the character is also removed from the system.
|
||||
b) A player will be billed at the end of a calendar month for all active characters
|
||||
for any part of that month.
|
||||
c) A character can possess any number of inventory items (see Inventories.csv):
|
||||
a. Weapons: have a range, damage points.
|
||||
b. Armours: has a defence score and is worn on a speci c body part.
|
||||
c. Supplies: have a healing score, mana score and if consumed increase the character’s life score by that amount (after which time the character will possess one fewer of that type of item)
|
||||
d) Characters have combat info (see Combat.csv)
|
||||
|
||||
|
||||
|
||||
1. Your initial E-R diagram (WEEK 8 – 30%)
|
||||
You will provide two outputs:
|
||||
|
||||
1) An English paragraph given in a PDF Þle that describes your personal ERD and
|
||||
2) your ERD (embedded in the PDF Þle). We will assess your ERD by reading your paragraph.
|
||||
You will receive full mark if your paragraph matches to your ERD.
|
||||
Otherwise we will reduce your marks based on the following rules:
|
||||
a) For each participation constraint fault (-1.5%).
|
||||
b) For each multiplicity fault (-1.5%).
|
||||
c) For each notation/Symbol fault (-1.5%).
|
19
hk1234566/SQL/Assessment1/requirements.md
Normal file
19
hk1234566/SQL/Assessment1/requirements.md
Normal file
@@ -0,0 +1,19 @@
|
||||
In the followings we will provide you some requirements,
|
||||
however we will expect you to exceed these expectations. You will need to demonstrate these in three milestones:
|
||||
|
||||
MILESTONES
|
||||
1) Design and develop an Entity-Relationship Diagram (ERD) that models the following
|
||||
key entities:
|
||||
a) Customers/Players.
|
||||
b) Characters.
|
||||
c) Inventory for the various weapons and armour a character may possess.
|
||||
d) Combat activities (#of kills, KIA’s, victories, etc.).
|
||||
|
||||
Your ERD should handle the following rules as a minimum but please use your imagination to provide further rules:
|
||||
a) A player must have at least one character and can create a new character or deactivate one they no longer wish to play at any time. Once a player unsubscribed from the game, the character is also removed from the system.
|
||||
b) A player will be billed at the end of a calendar month for all active characters for any part of that month.
|
||||
c) A character can possess any number of inventory items (see Inventories.csv):
|
||||
a. Weapons: have a range, damage points.
|
||||
b. Armours: has a defence score and is worn on a speciÞc body part.
|
||||
c. Supplies: have a healing score, mana score and if consumed increase the character’s life score by that amount (after which time the character will possess one fewer of that type of item)
|
||||
d) Characters have combat info (see Combat.csv)
|
1
hk1234566/SQL/Assessment1/test.dot
Normal file
1
hk1234566/SQL/Assessment1/test.dot
Normal file
@@ -0,0 +1 @@
|
||||
digraph G {Hello->World}
|
105
hk1234566/SQL/Assessment1/test_graphviz.html
Normal file
105
hk1234566/SQL/Assessment1/test_graphviz.html
Normal file
@@ -0,0 +1,105 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script charset="utf-8" type="text/javascript" src="live.bc.js" ></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css" integrity="sha256-9mbkOfVho3ZPXfM7W8sV2SndrGDuh7wuyLjtsWeTI1Q=" crossorigin="anonymous" />
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.js" integrity="sha256-qs5p0BFSqSvrstBxPvex+zdyrzcyGdHNeNmAirO2zc0=" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tonsky/FiraCode@1.207/distr/fira_code.css">
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
<title>ovenMPST IDE</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/iblize/dist/iblize.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/2.1.2/viz.js" integrity="sha256-8RHyK+AFzq9iXwbFo2unqidwPbwHU5FFWe3RwkcVtuU=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/viz.js/2.1.2/full.render.js" integrity="sha256-Ogqs510LFnekr9o7OLdpelaaAmNss9egQRTyzCqV2NQ=" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
function getProtocolName() {
|
||||
var ele = document.getElementsByName('protocol_choice');
|
||||
for(i = 0; i < ele.length; i++) {
|
||||
if(ele[i].checked) return ele[i].value.trim();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function getOutputFormat() {
|
||||
var ele = document.getElementById('output_format');
|
||||
var ret = ele.value;
|
||||
return ret;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="ui fixed menu">
|
||||
<div class="ui container">
|
||||
<a href="https://nuscr.dev/oven/" class="header item">
|
||||
<img class="logo" src="ovenMPST.png">
|
||||
OvenMPST
|
||||
</a>
|
||||
<!-- <a href="docs" class="item">Documentation</a> -->
|
||||
<a href="https://github.com/nuscr/oven" target="_blank" rel="noopener noreferrer" class="item">GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui main container">
|
||||
<h1 class="ui header">
|
||||
<img src="ovenMPST.png" alt="Logo" />
|
||||
OvenMPST IDE
|
||||
</h1>
|
||||
|
||||
<div class="ui grid">
|
||||
<div class="eight wide column">
|
||||
<h2>Global protocol</h2>
|
||||
<div rows="30" id="protocol-textarea" default="Enter text..."></div>
|
||||
<script>
|
||||
// use selector
|
||||
const iblize = new Iblize("#protocol-textarea", {
|
||||
language: "html",
|
||||
lineNumber: true,
|
||||
theme: "iblize-light",
|
||||
// etc
|
||||
});
|
||||
to1 = window.setTimeout(() => console.log("empty timer."), 1);
|
||||
to2 = window.setTimeout(() => console.log("empty timer."), 1);
|
||||
|
||||
function clear_and_parse () {
|
||||
ovenInterface.clear(1); ovenInterface.parse(1);
|
||||
}
|
||||
|
||||
iblize.onUpdate((value) => {
|
||||
window.clearTimeout(to1);
|
||||
to1 = window.setTimeout(clear_and_parse, 100);
|
||||
window.clearTimeout(to2);
|
||||
to2 = window.setTimeout(()=> ovenInterface.render(1), 1000);
|
||||
|
||||
});
|
||||
</script>
|
||||
<br />
|
||||
<select required class="ui dropdown" id="examples">
|
||||
<option value="" disabled selected hidden>Load an example</option>
|
||||
</select>
|
||||
<select required class="ui dropdown" id="output_format">
|
||||
<option value="graph" selected>Show graph</option>
|
||||
<option value="dot">Show graphviz dot file</option>
|
||||
</select>
|
||||
<button class="ui button" id="button">Analyse</button>
|
||||
</div>
|
||||
<div class="eight wide column" id="output">
|
||||
</div>
|
||||
<div class="ui negative message" id="errorbox" hidden></div>
|
||||
<div class="sixteen wide column">
|
||||
<h2> Global Machine </h2>
|
||||
<!-- remove the unused ones -->
|
||||
<div id="result"></div>
|
||||
<pre id="projected"/></pre>
|
||||
<div id="efsm" style="overflow: scroll;"></div>
|
||||
</div>
|
||||
<div class = "sixteen wide column">
|
||||
<h2>Local Projections </h2>
|
||||
<div id="local">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
519
hk1234566/SQL/Assessment1/update3/.$ERD-Page-2.drawio.xml.bkp
Normal file
519
hk1234566/SQL/Assessment1/update3/.$ERD-Page-2.drawio.xml.bkp
Normal file
@@ -0,0 +1,519 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mxfile host="app.diagrams.net" modified="2023-03-09T04:41:02.806Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36" etag="qIToQRhJueHNQSkVaT_3" version="20.8.5" type="device">
|
||||
<diagram id="gbh2_RjxMlchc6C8Ck6F" name="Page-2">
|
||||
<mxGraphModel dx="1052" dy="1885" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1654" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-129" value="N" style="endArrow=none;html=1;rounded=0;strokeWidth=2;fontSize=14;entryX=0.025;entryY=0.499;entryDx=0;entryDy=0;shape=link;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryPerimeter=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-19" target="W42QqZGia2SB_BN2uIFJ-8" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="584" y="-546.75" as="sourcePoint" />
|
||||
<mxPoint x="639" y="-546.75" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-1" value="Customers" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=2;fontSize=14;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="746.5" y="-937" width="135" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-2" value="" style="group" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="774" y="-722" width="80" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-3" value="" style="rhombus;whiteSpace=wrap;html=1;" parent="W42QqZGia2SB_BN2uIFJ-2" vertex="1">
|
||||
<mxGeometry width="80" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-4" value="Owned<br style="border-color: var(--border-color); padding: 0px; margin: 0px;"><span style="">By</span>" style="rhombus;whiteSpace=wrap;html=1;" parent="W42QqZGia2SB_BN2uIFJ-2" vertex="1">
|
||||
<mxGeometry x="10" y="10" width="60" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-5" value="N" style="endArrow=none;html=1;rounded=0;exitX=0.505;exitY=1.027;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;strokeWidth=2;shape=link;fontSize=14;exitPerimeter=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-3" target="W42QqZGia2SB_BN2uIFJ-15" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="1049" y="-596.25" as="sourcePoint" />
|
||||
<mxPoint x="1099" y="-646.25" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-7" value="" style="group" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="594" y="-590" width="115" height="83.75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-8" value="" style="rhombus;whiteSpace=wrap;html=1;" parent="W42QqZGia2SB_BN2uIFJ-7" vertex="1">
|
||||
<mxGeometry width="115" height="83.75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-9" value="Own<br>Items" style="rhombus;whiteSpace=wrap;html=1;" parent="W42QqZGia2SB_BN2uIFJ-7" vertex="1">
|
||||
<mxGeometry x="14.375" y="10.46875" width="86.25" height="62.8125" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-11" value="Involved<br>(battle)" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="989" y="-346.25" width="80" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-12" value="M" style="endArrow=none;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=2;fontSize=14;shape=link;" parent="1" source="W42QqZGia2SB_BN2uIFJ-11" target="W42QqZGia2SB_BN2uIFJ-22" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="899" y="-58.379999999999995" as="sourcePoint" />
|
||||
<mxPoint x="867.5" y="-30.129999999999995" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-13" value="N" style="endArrow=none;html=1;rounded=0;strokeWidth=2;fontSize=14;entryX=0;entryY=0.5;entryDx=0;entryDy=0;shape=link;" parent="1" target="W42QqZGia2SB_BN2uIFJ-11" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="934" y="-306.25" as="sourcePoint" />
|
||||
<mxPoint x="897.5" y="-94.13" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-14" value="" style="group" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="764" y="-581.25" width="100" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-15" value="Characters" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=2;fontSize=14;" parent="W42QqZGia2SB_BN2uIFJ-14" vertex="1">
|
||||
<mxGeometry width="100" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-16" value="Characters" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=2;fontSize=14;" parent="W42QqZGia2SB_BN2uIFJ-14" vertex="1">
|
||||
<mxGeometry x="10" y="10" width="80" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-17" value="" style="group" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="414" y="-572.65" width="88.72" height="52.8" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-18" value="Items" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=2;fontSize=14;" parent="W42QqZGia2SB_BN2uIFJ-17" vertex="1">
|
||||
<mxGeometry width="88.72" height="52.79999999999999" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-19" value="Items" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=2;fontSize=14;" parent="W42QqZGia2SB_BN2uIFJ-17" vertex="1">
|
||||
<mxGeometry x="6.571851851851852" y="6.700507614213197" width="76.41749333333334" height="39.398984771573595" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-20" value="1" style="endArrow=none;html=1;rounded=0;entryX=0;entryY=0.471;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=2;fontSize=14;entryPerimeter=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-8" target="W42QqZGia2SB_BN2uIFJ-15" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="624" y="-456.25" as="sourcePoint" />
|
||||
<mxPoint x="674" y="-506.25" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-21" value="" style="group" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="1124" y="-329.43999999999994" width="92.5" height="47.129999999999995" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-22" value="Battle" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=2;fontSize=14;" parent="W42QqZGia2SB_BN2uIFJ-21" vertex="1">
|
||||
<mxGeometry width="92.5" height="47.13" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-23" value="Battle" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=2;fontSize=14;" parent="W42QqZGia2SB_BN2uIFJ-21" vertex="1">
|
||||
<mxGeometry x="8.75" y="6.059999999999945" width="75" height="35.75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-24" value="" style="group" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="844" y="-336.25" width="90" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-25" value="Combat" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=2;fontSize=14;" parent="W42QqZGia2SB_BN2uIFJ-24" vertex="1">
|
||||
<mxGeometry width="90" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-26" value="Combat" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=2;fontSize=14;" parent="W42QqZGia2SB_BN2uIFJ-24" vertex="1">
|
||||
<mxGeometry x="7.5" y="12.120000000000005" width="75" height="36.5" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-27" value="Involved<br>(battle)" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="994" y="-341.25" width="70" height="70" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-28" value="BattleDate" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="1261.5" y="-298.37" width="78.75" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-29" value="" style="endArrow=none;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeWidth=2;fontSize=14;entryX=0.017;entryY=0.591;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" target="W42QqZGia2SB_BN2uIFJ-28" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="1216.5" y="-300.3699999999999" as="sourcePoint" />
|
||||
<mxPoint x="1311.505" y="-304.22575000000006" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-30" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=2;fontSize=14;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1.004;exitY=0.394;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" target="W42QqZGia2SB_BN2uIFJ-113" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="1216.5" y="-304.3699999999999" as="sourcePoint" />
|
||||
<mxPoint x="1278.7800000000002" y="-309.4399999999998" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-31" value="Weapon" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="894" y="-207" width="75" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-32" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=3;entryX=0.395;entryY=1.023;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-31" target="W42QqZGia2SB_BN2uIFJ-25" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="437" y="-53" as="sourcePoint" />
|
||||
<mxPoint x="623" y="-262" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-33" value="Result" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="799" y="-207" width="75" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-34" value="" style="endArrow=none;html=1;rounded=0;exitX=0.63;exitY=0.051;exitDx=0;exitDy=0;strokeWidth=3;exitPerimeter=0;entryX=0.13;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-33" target="W42QqZGia2SB_BN2uIFJ-25" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="757" y="-271.25" as="sourcePoint" />
|
||||
<mxPoint x="854" y="-278" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-35" value="Damage" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="989" y="-207" width="75" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-36" value="" style="endArrow=none;html=1;rounded=0;exitX=0.431;exitY=0.014;exitDx=0;exitDy=0;strokeWidth=3;exitPerimeter=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-35" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="937" y="-291.25" as="sourcePoint" />
|
||||
<mxPoint x="914" y="-277" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-38" value="SingleUse" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="329" y="-700.0000000000001" width="90" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-169" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=1;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-39" target="W42QqZGia2SB_BN2uIFJ-141" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-39" value="ManaScore" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="509" y="-230" width="90" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-159" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-41" target="W42QqZGia2SB_BN2uIFJ-38" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="414" y="-676" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="419" y="-676" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-41" value="Quantity" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="494" y="-700" width="95" height="48" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-153" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-43" target="W42QqZGia2SB_BN2uIFJ-130" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="464" y="-612" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-43" value="Price" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="329" y="-637.0000000000001" width="90" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-170" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-45" target="W42QqZGia2SB_BN2uIFJ-142" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-45" value="Range" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="44" y="-437" width="90" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-163" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=1;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-47" target="W42QqZGia2SB_BN2uIFJ-142" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-47" value="WeaponType" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="104" y="-369.12" width="90" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-161" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=1;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-49" target="W42QqZGia2SB_BN2uIFJ-141" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-49" value="ItemType" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="329" y="-240.32" width="90" height="48" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-165" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-53" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="414" y="-740" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-53" value="Equipped" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="494" y="-765" width="92.5" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-164" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-55" target="W42QqZGia2SB_BN2uIFJ-141" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-55" value="BodyPart" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="414" y="-207" width="90" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-57" value="Worn" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="409" y="-830" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-59" value="Wearable" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="329" y="-764" width="90" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-171" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-62" target="W42QqZGia2SB_BN2uIFJ-143" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-62" value="HealingScore" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="584" y="-333.55999999999995" width="100" height="51.25" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-168" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=1;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-63" target="W42QqZGia2SB_BN2uIFJ-142" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-63" value="AttackScore" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="314" y="-370" width="90" height="50.88" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-167" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-66" target="W42QqZGia2SB_BN2uIFJ-142" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-66" value="DefendScore" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="214" y="-336.25" width="90" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-68" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-69" target="W42QqZGia2SB_BN2uIFJ-1" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="994" y="-877" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-69" value="Account_Number" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;fontStyle=4" parent="1" vertex="1">
|
||||
<mxGeometry x="914" y="-967" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-70" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-71" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="994" y="-877" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="1124" y="-877" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-71" value="Name" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1089" y="-957" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-72" value="Forename" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1116.5" y="-1030" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-73" value="Surname" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1195" y="-980" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-74" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=3;" parent="1" source="W42QqZGia2SB_BN2uIFJ-72" target="W42QqZGia2SB_BN2uIFJ-71" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="1392" y="-897" as="sourcePoint" />
|
||||
<mxPoint x="1420" y="-827" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-75" value="" style="endArrow=none;html=1;rounded=0;strokeWidth=3;entryX=0.013;entryY=0.532;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-73" target="W42QqZGia2SB_BN2uIFJ-71" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="1208" y="-864" as="sourcePoint" />
|
||||
<mxPoint x="1243" y="-845" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-76" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-77" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="884" y="-877" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="895" y="-1007" />
|
||||
<mxPoint x="895" y="-877" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-77" value="EMailAddress" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="944" y="-1040" width="130" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-78" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-79" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="914" y="-534" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="994" y="-534" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-79" value="Type" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="959" y="-484" width="70" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-80" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.632;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-81" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="914" y="-534" />
|
||||
</Array>
|
||||
<mxPoint x="864.0000000000005" y="-534.0100000000002" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-81" value="Level" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="879" y="-484" width="70" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-82" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-83" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="864.0000000000005" y="-534" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="1182" y="-534" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-83" value="ExperiencePoints" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1101.5" y="-619.65" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-84" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-85" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="865" y="-534" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="1084" y="-534" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-85" value="MaxHealth" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1015" y="-674" width="160" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-86" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-87" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1364" y="-534" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="1409" y="-534" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-87" value="Health" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1359" y="-434" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-88" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-89" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1154" y="-534" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="1335" y="-534" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-89" value="AttackInScore" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1275" y="-479" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-90" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-91" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1039" y="-534" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="1205" y="-534" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-91" value="DefenceScore" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1161.5" y="-484" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-92" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-93" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="864" y="-534" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="1095" y="-534" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-93" value="StealthScore" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1045" y="-484" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-95" value="ManaScore" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1424" y="-484" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-96" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-97" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1194" y="-534" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="1290" y="-534" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-97" value="MoneyBank" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1234" y="-689" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-98" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-99" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1284" y="-534" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="1364" y="-534" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-99" value="MoneyWallet" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1314" y="-639" width="100" height="50" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-178" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.605;entryY=-0.016;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-100" target="W42QqZGia2SB_BN2uIFJ-119" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-100" value="Creation" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1469" y="-703.5" width="70" height="42" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-179" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=1;entryY=0;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-101" target="W42QqZGia2SB_BN2uIFJ-119" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-101" value="Expiry" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;" parent="1" vertex="1">
|
||||
<mxGeometry x="1543.5" y="-695.5" width="66.5" height="37" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-122" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.302;entryY=0.053;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-102" target="W42QqZGia2SB_BN2uIFJ-119" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="1456" y="-677.5" />
|
||||
<mxPoint x="1456" y="-650.5" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-102" value="BillDuration" style="ellipse;whiteSpace=wrap;html=1;fontSize=14;strokeWidth=3;direction=west;dashed=1;dashPattern=1 1;" parent="1" vertex="1">
|
||||
<mxGeometry x="1414" y="-751.5" width="85" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-106" value="" style="group" parent="1" vertex="1" connectable="0">
|
||||
<mxGeometry x="762.72" y="-463.25" width="76" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-107" value="" style="rhombus;whiteSpace=wrap;html=1;" parent="W42QqZGia2SB_BN2uIFJ-106" vertex="1">
|
||||
<mxGeometry width="76" height="75" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-108" value="Attacker/ Defender" style="rhombus;whiteSpace=wrap;html=1;" parent="W42QqZGia2SB_BN2uIFJ-106" vertex="1">
|
||||
<mxGeometry x="2.111111111111111" y="3.2522727272727145" width="71.77777777777777" height="68.50227272727273" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-109" value="M" style="endArrow=none;html=1;rounded=0;strokeWidth=2;edgeStyle=orthogonalEdgeStyle;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.369;entryY=0.993;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-107" target="W42QqZGia2SB_BN2uIFJ-15" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="855" y="-447" as="sourcePoint" />
|
||||
<mxPoint x="934" y="-497" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-110" value="N" style="endArrow=none;html=1;rounded=0;strokeWidth=2;shape=link;edgeStyle=orthogonalEdgeStyle;exitX=-0.011;exitY=0.349;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-25" target="W42QqZGia2SB_BN2uIFJ-107" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="854" y="-382" as="sourcePoint" />
|
||||
<mxPoint x="904" y="-432" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-111" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-112" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="973.5" y="-534" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="994" y="-534" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-112" value="<span style="border-bottom: 1px dotted">Name</span>" style="ellipse;whiteSpace=wrap;html=1;align=center;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="944" y="-597" width="100" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-113" value="<span style="border-bottom: 1px dotted">BattleNo</span>" style="ellipse;whiteSpace=wrap;html=1;align=center;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="1275" y="-359.12" width="100" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-190" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=1;exitDx=0;exitDy=0;endArrow=none;endFill=0;jumpStyle=none;jumpSize=6;" parent="1" source="W42QqZGia2SB_BN2uIFJ-119" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="1404" y="-530" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-119" value="Date" style="ellipse;whiteSpace=wrap;html=1;align=center;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="1424" y="-621.65" width="100" height="59.65" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-140" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-128" target="W42QqZGia2SB_BN2uIFJ-141" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="459" y="-394.75" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-128" value="ISA" style="verticalLabelPosition=middle;verticalAlign=middle;html=1;shape=mxgraph.basic.acute_triangle;dx=0.5;strokeWidth=3;labelPosition=center;align=center;" parent="1" vertex="1">
|
||||
<mxGeometry x="414" y="-470" width="90" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-130" value="<span style="border-bottom: 1px dotted">ItemName</span>" style="ellipse;whiteSpace=wrap;html=1;align=center;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="494" y="-632" width="100" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-141" value="Wear" style="shape=ext;margin=3;double=1;whiteSpace=wrap;html=1;align=center;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="409" y="-310" width="100" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-145" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-142" target="W42QqZGia2SB_BN2uIFJ-128" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-142" value="Weapon" style="shape=ext;margin=3;double=1;whiteSpace=wrap;html=1;align=center;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="214" y="-428.25" width="100" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-144" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-143" target="W42QqZGia2SB_BN2uIFJ-128" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-143" value="Food" style="shape=ext;margin=3;double=1;whiteSpace=wrap;html=1;align=center;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="584" y="-428.25" width="100" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-146" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=45;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-18" target="W42QqZGia2SB_BN2uIFJ-128" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-160" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-18" target="W42QqZGia2SB_BN2uIFJ-57" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="458" y="-790" as="targetPoint" />
|
||||
<mxPoint x="459" y="-580" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-173" value="1" style="endArrow=none;html=1;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;strokeWidth=2;fontSize=14;" parent="1" source="W42QqZGia2SB_BN2uIFJ-1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="691.5000000000005" y="-763.845" as="sourcePoint" />
|
||||
<mxPoint x="814" y="-720" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-187" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0;exitDx=45;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-174" target="W42QqZGia2SB_BN2uIFJ-184" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-174" value="ISA" style="verticalLabelPosition=middle;verticalAlign=middle;html=1;shape=mxgraph.basic.acute_triangle;dx=0.5;strokeWidth=3;labelPosition=center;align=center;" parent="1" vertex="1">
|
||||
<mxGeometry x="873" y="-679" width="90" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-180" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-15" target="W42QqZGia2SB_BN2uIFJ-174" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-189" style="edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;endArrow=none;endFill=0;" parent="1" source="W42QqZGia2SB_BN2uIFJ-184" target="W42QqZGia2SB_BN2uIFJ-188" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-184" value="Mage" style="shape=ext;margin=3;double=1;whiteSpace=wrap;html=1;align=center;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="919" y="-751.5" width="100" height="41.5" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="W42QqZGia2SB_BN2uIFJ-188" value="ManaScore" style="ellipse;whiteSpace=wrap;html=1;align=center;strokeWidth=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="1054" y="-799" width="100" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
1
hk1234566/SQL/Assessment1/update3/.$ERD.xml.bkp
Normal file
1
hk1234566/SQL/Assessment1/update3/.$ERD.xml.bkp
Normal file
File diff suppressed because one or more lines are too long
BIN
hk1234566/SQL/Assessment1/update3/ERD-Page-2.drawio.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/update3/ERD-Page-2.drawio.png
(Stored with Git LFS)
Normal file
Binary file not shown.
1
hk1234566/SQL/Assessment1/update3/ERD-Page-2.drawio.xml
Normal file
1
hk1234566/SQL/Assessment1/update3/ERD-Page-2.drawio.xml
Normal file
File diff suppressed because one or more lines are too long
BIN
hk1234566/SQL/Assessment1/update3/ERD-characters.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/update3/ERD-characters.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/update3/ERD-combat.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/update3/ERD-combat.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/update3/ERD-items-1.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/update3/ERD-items-1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/update3/ERD-items-2.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/update3/ERD-items-2.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/update3/ERD-items.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/update3/ERD-items.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/update3/ERD-overview.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment1/update3/ERD-overview.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/update3/ERD.pdf
Normal file
BIN
hk1234566/SQL/Assessment1/update3/ERD.pdf
Normal file
Binary file not shown.
1
hk1234566/SQL/Assessment1/update3/ERD.xml
Normal file
1
hk1234566/SQL/Assessment1/update3/ERD.xml
Normal file
File diff suppressed because one or more lines are too long
BIN
hk1234566/SQL/Assessment1/update3/output1.odt
Normal file
BIN
hk1234566/SQL/Assessment1/update3/output1.odt
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/update3/output1.pdf
Normal file
BIN
hk1234566/SQL/Assessment1/update3/output1.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/update3/output2.odt
Normal file
BIN
hk1234566/SQL/Assessment1/update3/output2.odt
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment1/update3/output2.pdf
Normal file
BIN
hk1234566/SQL/Assessment1/update3/output2.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment2/1NF-example.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment2/1NF-example.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment2/2NF-example.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment2/2NF-example.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment2/3NF-example.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment2/3NF-example.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment2/4NF-example.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment2/4NF-example.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment2/5NF-example.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment2/5NF-example.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Assessment2/first-normal-form.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment2/first-normal-form.png
(Stored with Git LFS)
Normal file
Binary file not shown.
30
hk1234566/SQL/Assessment2/notes.md
Normal file
30
hk1234566/SQL/Assessment2/notes.md
Normal file
@@ -0,0 +1,30 @@
|
||||
2) Write relational schema and integrity constraints for your relations. Provide the relevant SQL DDL statements to implement your ERD.
|
||||
a) Pay careful attention to your choice of datatypes and consistency.
|
||||
b) Consider referential integrity and nullable/not nullable attributes.
|
||||
c) Make comment on the Normalisation level of your schemas.
|
||||
d) Providing relational algebra statements is a bonus.
|
||||
|
||||
Assessment:
|
||||
2. SQL DDL (30%)
|
||||
You will provide a PDF Þle that contains your
|
||||
Relational Schemas (RS),
|
||||
Integrity Constraints (IC),
|
||||
i.e.:
|
||||
```
|
||||
Mec_Repair(MID:integer, Name:string, Brand:string),
|
||||
ICs: MID (Primary key), Brand (Foreign key referencing Car)
|
||||
Normalisation reports: i.e. 3NF
|
||||
DDL statements:
|
||||
Car(Brand:string, weight:integer),
|
||||
ICs: Brand (Primary key)
|
||||
Normalisation reports: i.e. 3NF
|
||||
DDL statements:
|
||||
```
|
||||
Normalisation reports for each RSs and
|
||||
the DDL statements written in SQL.
|
||||
|
||||
You will receive full mark if your RS and ICs matches with your ERD. Otherwise, you we will reduce your mark based on the followings:
|
||||
a) Typo for SQL code -2pts.
|
||||
b) Reporting wrong Normalisation level -5pts.
|
||||
c) IC mismatch from ERD to ICs or from ICs to DDL -10 pts.
|
||||
d) Providing Relational Algebra statements (Bonus 10 pts)
|
BIN
hk1234566/SQL/Assessment2/second-nromal-form.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/Assessment2/second-nromal-form.png
(Stored with Git LFS)
Normal file
Binary file not shown.
7
hk1234566/SQL/Assessment3/notes.md
Normal file
7
hk1234566/SQL/Assessment3/notes.md
Normal file
@@ -0,0 +1,7 @@
|
||||
3. Java Library and SQL queries (40%)
|
||||
You will provide a java library that reads CSV Þle and builds required tables and answers the queries given above. You will receive full mark if your library successfully accomplishes these tasks. Otherwise we will reduce your mark according to the following rules:
|
||||
a) Not compiles -100pts.
|
||||
b) Compiles but cannot populate tables -50pts.
|
||||
c) Cannot read CSV Þles but reads from other Þle format and populates tables - 0pts.
|
||||
d) SQL Integrity Constraint warning, error while populating -10pts.
|
||||
e) Failed to retrieve the answer for a query -10pts.
|
8
hk1234566/SQL/Combat.csv
Normal file
8
hk1234566/SQL/Combat.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
BattleDate,BattleNo,Attacker,Defender,Weapon,Result,Damage
|
||||
15-May-23,5481,Calvin,SneakySue,Axe,Hit,87
|
||||
15-May-23,5481,SneakySue,Calvin,Dagger,Miss,0
|
||||
15-May-23,5481,Calvin,SneakySue,Axe,Hit,94
|
||||
15-May-23,5481,SneakySue,Calvin,Dagger,Parry,0
|
||||
15-May-23,5481,Calvin,SneakySue,Axe ,Hit,78
|
||||
15-May-23,5481,SneakySue,Calvin,Dagger,Hit,14
|
||||
15-May-23,5481,Calvin,SneakySue,Axe,Victory,112
|
|
BIN
hk1234566/SQL/Coursework (1).pdf
Normal file
BIN
hk1234566/SQL/Coursework (1).pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/Coursework_Updated.pdf
Normal file
BIN
hk1234566/SQL/Coursework_Updated.pdf
Normal file
Binary file not shown.
8
hk1234566/SQL/Customers.csv
Normal file
8
hk1234566/SQL/Customers.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
Account_Number,Forename,surname,e-mail_Address,Character_CreationDate,Character_Expiry_Date,Character_Name,Character_Type,Level,ExperiencePoints,Max_Health,Health,AttackinScore,DefenceScore,StealthScore,ManaScore,Money_bank,Money_wallet
|
||||
15468336,Jones,Susan,sj56@gmail.com,02-Jan-2022,,juju97,Warrior,12,12475,1000,996,85,23,17,,4273.95,351.00
|
||||
35482956,Turker,Uraz,u.turker@lancaster.ac.uk,05-Mar-2022,,Uraz-The-Magnificent,Mage,34,34925,1200,1094,34,49,21,64,11397.00,700.00
|
||||
64345236,Ricki,Boswell-Challand,r.boswell-challand@lancaster.ac.uk,24-Apr-2022,,Calvin,Merchant,18,21765,950,950,54,53,36,,34950.00,3705.00
|
||||
64345236,Ricki,Boswell-Challand,r.boswell-challand@lancaster.ac.uk,13-May2022,,Hobbes,Warrior,95,95678,1500,1500,88,79,84,,0,0
|
||||
15468336,Jones,Susan,sj56@gmail.com,15-Mar-2022,,SneakySue,Thief,7,7201,900,856,37,12,56,,11730.34,295.00
|
||||
54387937,Schmidt,Johan,jjs46@hotmail.com,08-Jan2023,,SpacemanSpiff,Mage,3,1085,250,227,09,19,8,31,548.00,102.00
|
||||
15468336,Jones,Susan,sj56@gmail.com,14-Jul-2022,19-Aug-2022,DarkMage,Mage,3,2012,250,250,12,17,9,21,0.00,0.00
|
|
15
hk1234566/SQL/Items.csv
Normal file
15
hk1234566/SQL/Items.csv
Normal file
@@ -0,0 +1,15 @@
|
||||
Character,Item,Item_Type,WeaponType,Range,Price,Quantity,DefendScore,AttackScore,HealingScore,ManaScore,SingleUse,wearable,worn,BodyPart,Equipped
|
||||
juju97,Broadsword,Weapon,Melee,,175,1,,24,,,0,0,,,1
|
||||
juju97,breastplate,Armour,,,290,1,18,,,,0,1,1,torso,0
|
||||
juju97,slingshot,Weapon,Projectile,30,50,1,,13,,,0,0,,,0
|
||||
Uraz-The-Magnificent,Wizard's Staff,Artefact,,,3500,1,0,0,,37,0,,,,1
|
||||
Uraz-The-Magnificent,Wizard's Robe,Clothing,,,2000,1,10,,,,,1,1,torso,0
|
||||
juju97,Tunic,Clothing,,,5,1,1,0,,,0,1,1,torso,
|
||||
Uraz-The-Magnificent,Apple,Food,,,1,1,,,10,,1,,,,0
|
||||
juju97,Bread,Food,,,0.75,3,,,8,,1,,,,0
|
||||
SneakySue,Dagger,Weapon,Melee,,12,1,1,10,0,,0,0,,,1
|
||||
SpacemanSpiff,Transmogrifier,Artefact,,,54000,1,,,,500,0,0,,,1
|
||||
SpacemanSpiff,Can of Tuna,Food,,,3,4,,,15,,1,0,,,1
|
||||
Calvin,Axe,Weapon,Melee,,80,1,,,,,,,,,1
|
||||
juju97,Cloak of Invisibility,Clothing,,,4500,1,,,,75,,1,0,torso,
|
||||
Uraz-The-Magnificent,Cheese,Food,,,6,10,,,12,,1,0,0,,0
|
|
BIN
hk1234566/SQL/SCC201_Database/1.SCC201WEEK1.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/1.SCC201WEEK1.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/2.SCC201WEEK2.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/2.SCC201WEEK2.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/3.SCC201WEEK3.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/3.SCC201WEEK3.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/4.SCC201WEEK4.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/4.SCC201WEEK4.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/5.SCC201WEEK5.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/5.SCC201WEEK5.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/6.SCC201WEEK6.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/6.SCC201WEEK6.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/CSS 201 Lab Week 1-Answers.docx
Normal file
BIN
hk1234566/SQL/SCC201_Database/CSS 201 Lab Week 1-Answers.docx
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/CSS 201 Lab Week 2-Solution.jpeg
Normal file
BIN
hk1234566/SQL/SCC201_Database/CSS 201 Lab Week 2-Solution.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
BIN
hk1234566/SQL/SCC201_Database/CSS 201 Lab Week 2.docx
Normal file
BIN
hk1234566/SQL/SCC201_Database/CSS 201 Lab Week 2.docx
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/Coursework.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/Coursework.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/SCC 201 Lab Week 3_Solutions.docx
Normal file
BIN
hk1234566/SQL/SCC201_Database/SCC 201 Lab Week 3_Solutions.docx
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/SCC 201 Lab Week 4_Solutions.docx
Normal file
BIN
hk1234566/SQL/SCC201_Database/SCC 201 Lab Week 4_Solutions.docx
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
https://sqliteonline.com/
|
Binary file not shown.
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/Week 5 Lab Material.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/Week 5 Lab Material.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/Week 5 Lab-Solutions.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/Week 5 Lab-Solutions.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/Week 6 Lab Material.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/Week 6 Lab Material.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/Week 6 Lab-Solutions.pdf
Normal file
BIN
hk1234566/SQL/SCC201_Database/Week 6 Lab-Solutions.pdf
Normal file
Binary file not shown.
BIN
hk1234566/SQL/SCC201_Database/useful/Screenshot from 2023-03-05 16-16-48.png
(Stored with Git LFS)
Normal file
BIN
hk1234566/SQL/SCC201_Database/useful/Screenshot from 2023-03-05 16-16-48.png
(Stored with Git LFS)
Normal file
Binary file not shown.
42
hk1234566/SQL/notes.md
Normal file
42
hk1234566/SQL/notes.md
Normal file
@@ -0,0 +1,42 @@
|
||||
Players.csv - The main player and character data Þle, which contains player character definitions, with customer and billing data.
|
||||
Items.csv - Character inventory of weapons.
|
||||
Combat.csv - Records the activity and results of battles between players.
|
||||
|
||||
1. Your initial E-R diagram (WEEK 8 – 30%)
|
||||
You will provide two outputs:
|
||||
|
||||
1) An English paragraph given in a PDF Þle that describes your personal ERD and
|
||||
2) your ERD (embedded in the PDF Þle). We will assess your ERD by reading your paragraph.
|
||||
You will receive full mark if your paragraph matches to your ERD.
|
||||
Otherwise we will reduce your marks based on the following rules:
|
||||
a) For each participation constraint fault (-1.5%).
|
||||
b) For each multiplicity fault (-1.5%).
|
||||
c) For each notation/Symbol fault (-1.5%).
|
||||
|
||||
2. SQL DDL ( WEEK 9 – 30%)
|
||||
You will provide a PDF Þle that contains your
|
||||
Relational Schemas (RS),
|
||||
Integrity Constraints (IC),
|
||||
Normalisation reports for each RSs and
|
||||
the DDL statements written in SQL.
|
||||
|
||||
You will receive full mark if
|
||||
your RS and ICs matches with your ERD.
|
||||
Otherwise, you we will reduce your mark based on the followings:
|
||||
a) For each typo for SQL code (-0.6%).
|
||||
b) Reporting wrong(or none) Normalisation level (for each table -1.5%).
|
||||
c) For each IC mismatch (from ERD to ICs) and (from ICs to DDL) (-3%).
|
||||
|
||||
3. Java Library and SQL queries (WEEK 10 – 40%)
|
||||
You will provide a PDF Þle that contains the English versions of your queries.
|
||||
You will also provide a java library that reads CSV Þle and
|
||||
builds required tables and answers the queries you provided.
|
||||
You will receive full mark if your library successfully accomplishes these tasks.
|
||||
|
||||
Otherwise we will reduce your mark according to the following rules:
|
||||
a) Not compiles (-40%).
|
||||
b) Compiles but cannot populate tables (-20%).
|
||||
c) Cannot read CSV Þles but read from other Þle format and populates tables (-0%).
|
||||
d) For each SQL warning, error (-3%).
|
||||
e) For each failed query (-3%).
|
||||
f) Providing Relational Algebra statements (for each query) (+3%)
|
7
hk1234566/gitUpdate.bat
Normal file
7
hk1234566/gitUpdate.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
git status .
|
||||
|
||||
@pause
|
||||
|
||||
git add .
|
||||
git commit -m"update hk1234566,"
|
||||
start git push
|
15
hk1234566/meta.md
Normal file
15
hk1234566/meta.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
tags: [python, wireshark, networking, javascript, SQL, "SCC 212"]
|
||||
---
|
||||
|
||||
# hk1234566
|
||||
|
||||
## balance history
|
||||
|
||||
### quotation
|
||||
|
||||
佢份問題總共有五個部份(其中有兩個部份比分)
|
||||
我諗我會報 HKD 250
|
||||
如果合意的話麻煩您比埋 NetworkApplications.py 呢個 file 我好嘛
|
||||
|
||||
唔該先 😊
|
13
hk1234566/package.json
Normal file
13
hk1234566/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "hk1234566",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"gitUpdate": "git add . && git commit -m\"update hk1234566,\" && git push"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
685
hk1234566/python_networking/NetworkApplications_working.py
Normal file
685
hk1234566/python_networking/NetworkApplications_working.py
Normal file
@@ -0,0 +1,685 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
|
||||
|
||||
######
|
||||
|
||||
import argparse
|
||||
|
||||
import socket
|
||||
|
||||
import os
|
||||
|
||||
import sys
|
||||
|
||||
import struct
|
||||
|
||||
import time
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def setupArgumentParser() -> argparse.Namespace:
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
|
||||
description='A collection of Network Applications developed for SCC.203.')
|
||||
|
||||
parser.set_defaults(func=ICMPPing, hostname='lancaster.ac.uk')
|
||||
|
||||
subparsers = parser.add_subparsers(help='sub-command help')
|
||||
|
||||
|
||||
|
||||
parser_p = subparsers.add_parser('ping', aliases=['p'], help='run ping')
|
||||
|
||||
parser_p.add_argument('hostname', type=str, help='host to ping towards')
|
||||
|
||||
parser_p.add_argument('count', nargs='?', type=int,
|
||||
|
||||
help='number of times to ping the host before stopping')
|
||||
|
||||
parser_p.add_argument('timeout', nargs='?',
|
||||
|
||||
type=int,
|
||||
|
||||
help='maximum timeout before considering request lost')
|
||||
|
||||
parser_p.set_defaults(func=ICMPPing)
|
||||
|
||||
|
||||
|
||||
parser_t = subparsers.add_parser('traceroute', aliases=['t'],
|
||||
|
||||
help='run traceroute')
|
||||
|
||||
parser_t.add_argument('hostname', type=str, help='host to traceroute towards')
|
||||
|
||||
parser_t.add_argument('timeout', nargs='?', type=int,
|
||||
|
||||
help='maximum timeout before considering request lost')
|
||||
|
||||
parser_t.add_argument('protocol', nargs='?', type=str,
|
||||
|
||||
help='protocol to send request with (UDP/ICMP)')
|
||||
|
||||
parser_t.set_defaults(func=Traceroute)
|
||||
|
||||
|
||||
|
||||
parser_w = subparsers.add_parser('web', aliases=['w'], help='run web server')
|
||||
|
||||
parser_w.set_defaults(port=8080)
|
||||
|
||||
parser_w.add_argument('port', type=int, nargs='?',
|
||||
|
||||
help='port number to start web server listening on')
|
||||
|
||||
parser_w.set_defaults(func=WebServer)
|
||||
|
||||
|
||||
|
||||
parser_x = subparsers.add_parser('proxy', aliases=['x'], help='run proxy')
|
||||
|
||||
parser_x.set_defaults(port=8000)
|
||||
|
||||
parser_x.add_argument('port', type=int, nargs='?',
|
||||
|
||||
help='port number to start web server listening on')
|
||||
|
||||
parser_x.set_defaults(func=Proxy)
|
||||
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class NetworkApplication:
|
||||
|
||||
|
||||
|
||||
def checksum(self, dataToChecksum: str) -> str:
|
||||
|
||||
csum = 0
|
||||
|
||||
countTo = (len(dataToChecksum) // 2) * 2
|
||||
|
||||
count = 0
|
||||
|
||||
|
||||
|
||||
while count < countTo:
|
||||
|
||||
thisVal = dataToChecksum[count+1] * 256 + dataToChecksum[count]
|
||||
|
||||
csum = csum + thisVal
|
||||
|
||||
csum = csum & 0xffffffff
|
||||
|
||||
count = count + 2
|
||||
|
||||
|
||||
|
||||
if countTo < len(dataToChecksum):
|
||||
|
||||
csum = csum + dataToChecksum[len(dataToChecksum) - 1]
|
||||
|
||||
csum = csum & 0xffffffff
|
||||
|
||||
|
||||
|
||||
csum = (csum >> 16) + (csum & 0xffff)
|
||||
|
||||
csum = csum + (csum >> 16)
|
||||
|
||||
answer = ~csum
|
||||
|
||||
answer = answer & 0xffff
|
||||
|
||||
answer = answer >> 8 | (answer << 8 & 0xff00)
|
||||
|
||||
answer = socket.htons(answer)
|
||||
|
||||
return answer
|
||||
|
||||
|
||||
|
||||
def printOneResult(self, destinationAddress: str, packetLength:
|
||||
|
||||
int, time: float, ttl: int, destinationHostname=''):
|
||||
|
||||
|
||||
|
||||
if destinationHostname:
|
||||
|
||||
print("%d bytes from %s (%s):ttl=%d time=%.2f ms" % (packetLength, destinationHostname, destinationAddress, ttl, time))
|
||||
|
||||
else:
|
||||
|
||||
print("%d bytes from %s: ttl=%dtime=%.2f ms" % (packetLength, destinationAddress, ttl, time))
|
||||
|
||||
|
||||
|
||||
def printAdditionalDetails(self, packetLoss=0.0, minimumDelay=0.0,averageDelay=0.0, maximumDelay=0.0):
|
||||
|
||||
print("%.2f%% packet loss" % (packetLoss))
|
||||
|
||||
if minimumDelay > 0 and averageDelay > 0 and maximumDelay > 0:
|
||||
|
||||
print("rtt min/avg/max = %.2f/%.2f/%.2fms" % (minimumDelay, averageDelay, maximumDelay))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ICMPPing(NetworkApplication):
|
||||
|
||||
|
||||
|
||||
def receiveOnePing(self, icmpSocket, destinationAddress, ID,timeout):
|
||||
|
||||
# 1. Wait for the socket to receive a reply
|
||||
|
||||
timeLeft = timeout/1000
|
||||
|
||||
select = 0
|
||||
|
||||
startedSelect = time.time()
|
||||
|
||||
whatReady = select.select([icmpSocket],[],[],timeLeft)
|
||||
|
||||
howLongInSelect =(time.time() - startedSelect)
|
||||
|
||||
|
||||
|
||||
# 2. Once received, record time of receipt, otherwise, handle a timeout
|
||||
|
||||
if whatReady[0] == []:#timeout
|
||||
|
||||
return None
|
||||
|
||||
|
||||
|
||||
timeLeft = timeLeft - howLongInSelect
|
||||
|
||||
if timeLeft <= 0:
|
||||
|
||||
return None
|
||||
|
||||
|
||||
|
||||
recPacket, addr = icmpSocket.recvfrom(ICMP_MAX_RECV)
|
||||
|
||||
timeRecieved = time.time()
|
||||
|
||||
icmpHeader = recPacket[20:28]
|
||||
|
||||
|
||||
|
||||
# 3. Compare the time of receipt to time of sending, producing the total network delay
|
||||
|
||||
timeSent = self.sendOnePing(icmpSocket, destinationAddress, 111)
|
||||
|
||||
Delay = timeRecieved - timeSent
|
||||
|
||||
|
||||
|
||||
# 4. Unpack the packet header for useful information, including the ID
|
||||
|
||||
icmpType,icmpCode,icmpChecksum,icmpPacketID,icmpSeqNumber = struct.unpack("bbHHh",icmpHeader)
|
||||
|
||||
|
||||
|
||||
# 5. Check that the ID matches between the request and reply
|
||||
|
||||
|
||||
|
||||
# 6. Return total network delay
|
||||
|
||||
if(icmpPacketID == ID):
|
||||
|
||||
return addr[0].Delay
|
||||
|
||||
|
||||
|
||||
else:
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
def sendOnePing(self, icmpSocket, destinationAddress, ID):
|
||||
|
||||
# 1. Build ICMP header
|
||||
|
||||
Type = 8
|
||||
|
||||
code = 0
|
||||
|
||||
chksum = 0
|
||||
|
||||
seq = 1
|
||||
|
||||
data = "data"
|
||||
|
||||
icmpHeader = struct.pack("bbHHh", Type, code,chksum, ID,seq)
|
||||
|
||||
|
||||
|
||||
# 2. Checksum ICMP packet using given function
|
||||
|
||||
real_chksum = self.checksum(icmpHeader)
|
||||
|
||||
|
||||
|
||||
# 3. Insert checksum into packet
|
||||
|
||||
icmpheader = struct.pack("bbHHh", type,code,real_chksum,ID,seq)
|
||||
|
||||
packet = icmpHeader
|
||||
|
||||
|
||||
|
||||
# 4. Send packet using socket
|
||||
|
||||
icmpSocket.sendto(packet, (destinationAddress,1) ) #double check this //run with wireshark
|
||||
|
||||
|
||||
|
||||
# 5. Record time of sending
|
||||
|
||||
sent_time = time.time()
|
||||
|
||||
return sent_time
|
||||
|
||||
|
||||
|
||||
def doOnePing(self, destinationAddress, timeout):
|
||||
|
||||
# 1. Create ICMP socket
|
||||
|
||||
ICMP_CODE = socket.getprotobyname("icmp") #Translate an Internet protocol name (for example, 'icmp') to a constant suitable for passing as the (optional) third argument to the socket() function.
|
||||
|
||||
icmpSocket = socket.socket(socket.AF_INET,socket.SOCK_RAW, ICMP_CODE)
|
||||
|
||||
|
||||
|
||||
# 2. Call sendOnePing function
|
||||
|
||||
timeSent = self.sendOnePing(icmpSocket, destinationAddress, 111)
|
||||
|
||||
|
||||
|
||||
# 3. Call receiveOnePing function
|
||||
|
||||
AddressAndDelay = self.receiveOnePing(icmpSocket, destinationAddress, 111, 1000,timeSent)
|
||||
|
||||
|
||||
|
||||
# 4. Close ICMP socket
|
||||
|
||||
icmpSocket.close()
|
||||
|
||||
|
||||
|
||||
# 5. Return total network delay
|
||||
|
||||
return AddressAndDelay[0], AddressAndDelay[1]
|
||||
|
||||
|
||||
|
||||
def __init__(self, args):
|
||||
|
||||
print('Ping to: %s...' % (args.hostname))
|
||||
|
||||
# 1. Look up hostname, resolving it to an IP address
|
||||
|
||||
ip_address = socket.gethostbyname(args.hostname)
|
||||
|
||||
|
||||
|
||||
# 2. Call doOnePing function approximately every second
|
||||
|
||||
while True:
|
||||
|
||||
time.sleep(1)
|
||||
testVariable = args.timeout
|
||||
print("testing:", testVariable)
|
||||
recAddressAndDelay = self.doOnePing(ip_address, testVariable, 1)
|
||||
|
||||
|
||||
|
||||
# 3. Print out the returned delay (and other relevant details) using the printOneResult method
|
||||
|
||||
self.printOneResult(ip_address, 50, recAddressAndDelay[1]*1000,150)
|
||||
|
||||
#Example use of printOneResult - complete as appropriate
|
||||
|
||||
# 4. Continue this process until stopped - would this be a loop? and when should we stop?
|
||||
|
||||
|
||||
|
||||
class Traceroute(NetworkApplication):
|
||||
|
||||
|
||||
|
||||
def __init__(self, args):
|
||||
|
||||
#
|
||||
|
||||
# Please ensure you print each result using the printOneResult method!
|
||||
|
||||
print('Traceroute to: %s...' % (args.hostname))
|
||||
|
||||
# 1. Look up hostname, resolving it to an IP address
|
||||
|
||||
ip_address = socket.gethostbyname(args.hostname)
|
||||
|
||||
# 2. Call PingOneNode function approximately every second
|
||||
|
||||
while True:
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
nodalDelay = self.pingOneNode(ip_address,args.timeout,1)
|
||||
|
||||
# 4. Continue this process until stopped - until ICMP = 0
|
||||
|
||||
if ICMP == 0:
|
||||
|
||||
break
|
||||
|
||||
# 3. Print out the returned delay (and other relevant details) using the printOneResult method
|
||||
|
||||
self.printOneResult(ip_address, 50, nodalDelay[1]*1000,150) #check this don't think its right
|
||||
|
||||
|
||||
|
||||
def pingOneNode():
|
||||
|
||||
# 1. Create ICMP socket
|
||||
|
||||
ICMP_CODE = socket.getprotobyname("icmp") #Translate an Internet protocol name (for example, 'icmp') to a constant suitable for passing as the (optional) third argument to the socket() function.
|
||||
|
||||
icmpSocket = socket.socket(socket.AF_INET,socket.SOCK_RAW, ICMP_CODE)
|
||||
|
||||
# 2. Call sendNodePing function
|
||||
|
||||
timeSent = self.sendNodePing(icmpSocket, destinationAddress, 111)
|
||||
|
||||
# 3. Call recieveNodePing function
|
||||
|
||||
AddressAndDelay = self.recieveNodePing(icmpSocket, destinationAddress, 111, 1000,timeSent)
|
||||
|
||||
# 4. Close ICMP socket
|
||||
|
||||
icmpSocket.close()
|
||||
|
||||
# 5. Return total network delay- add up all the nodes
|
||||
|
||||
for x in Nodes:
|
||||
|
||||
TotalDelay = (AddressAndDelay[x] + AddressAndDelay[x +1])
|
||||
|
||||
if x == "numberOfNodes":
|
||||
|
||||
break
|
||||
|
||||
return TotalDelay
|
||||
|
||||
|
||||
|
||||
def sendNodePing():
|
||||
|
||||
# 1. Build ICMP header
|
||||
|
||||
Type = 8
|
||||
|
||||
code = 0
|
||||
|
||||
chksum = 0
|
||||
|
||||
seq = 1
|
||||
|
||||
data = "data"
|
||||
|
||||
icmpHeader = struct.pack("bbHHh", Type, code,chksum, ID,seq)
|
||||
|
||||
# 2. Checksum ICMP packet using given function
|
||||
|
||||
real_chksum = self.checksum(icmpHeader)
|
||||
|
||||
# 3. Insert checksum into packet
|
||||
|
||||
icmpheader = struct.pack("bbHHh", type,code,real_chksum,ID,seq)
|
||||
|
||||
packet = icmpHeader
|
||||
|
||||
# 4. Send packet using socket
|
||||
|
||||
icmpSocket.sendto(packet, (destinationAddress,1) ) #double check this //run with wireshark
|
||||
|
||||
# 5. Record time of sending
|
||||
|
||||
sentTime = time.time()
|
||||
|
||||
return sentTime
|
||||
|
||||
|
||||
|
||||
def recieveNodePing():
|
||||
|
||||
# 1. Wait for the socket to receive a reply- TTL = 0
|
||||
|
||||
timeLeft = timeout/1000
|
||||
|
||||
select = 0
|
||||
|
||||
startedSelect = time.time()
|
||||
|
||||
whatReady = select.select([icmpSocket],[],[],timeLeft)
|
||||
|
||||
howLongInSelect =(time.time() - startedSelect)
|
||||
|
||||
|
||||
|
||||
# 2. Once received, record time of receipt, otherwise, handle a timeout
|
||||
|
||||
if TTL != 0:#timeout
|
||||
|
||||
return None
|
||||
|
||||
timeLeft = timeLeft - howLongInSelect
|
||||
|
||||
if TTL == 0:
|
||||
|
||||
recPacket, addr = icmpSocket.recvfrom(ICMP_MAX_RECV)
|
||||
|
||||
timeRecieved = time.time()
|
||||
|
||||
icmpHeader = recPacket[20:28]
|
||||
|
||||
return timeLeft
|
||||
|
||||
|
||||
|
||||
# 3. Compare the time of receipt to time of sending, producing the total network delay
|
||||
|
||||
timeSent = self.sendNodePing(icmpSocket, destinationAddress, 111)
|
||||
|
||||
Delay = timeRecieved - timeSent
|
||||
|
||||
|
||||
|
||||
# 4. Unpack the packet header for useful information, including the ID
|
||||
|
||||
icmpType,icmpCode,icmpChecksum,icmpPacketID,icmpSeqNumber = struct.unpack("bbHHh",icmpHeader)
|
||||
|
||||
|
||||
|
||||
# 5. Check that the ID matches between the request and reply
|
||||
|
||||
# 6. Return total network delay
|
||||
|
||||
if(icmpPacketID == ID):
|
||||
|
||||
return pingOneNode.TotalDelay
|
||||
|
||||
else:
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class WebServer(NetworkApplication):
|
||||
|
||||
|
||||
|
||||
def handleRequest(tcpSocket):
|
||||
|
||||
# 1. Receive request message from the client on connection socket
|
||||
|
||||
bufferSize = tcpSocket.CMSG_SPACE(4) #IPv4 address is 4 bytes in length
|
||||
|
||||
requestMessage = tcpSocket.recvmsg(bufferSize[0,[0]])
|
||||
|
||||
# 2. Extract the path of the requested object from the message (second part of the HTTP header)
|
||||
|
||||
file = requestMessage.unpack_from(format, buffer, offset=1) #returns a tuple
|
||||
|
||||
# 3. Read the corresponding file from disk
|
||||
|
||||
socket.sendfile(file, offset=0, count=None)
|
||||
|
||||
# 4. Store in temporary buffer
|
||||
|
||||
buffer = socket.makefile(mode='r', buffering=None, encoding=None,errors=None, newline=None)
|
||||
|
||||
struct.pack_into(format, self.buffer, 0, file)
|
||||
|
||||
# 5. Send the correct HTTP response error
|
||||
|
||||
# 6. Send the content of the file to the socket
|
||||
|
||||
tcpSocket.recvmsg(bufferSize[0, 0])
|
||||
|
||||
# 7. Close the connection socket
|
||||
|
||||
tcpSocket.close()
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def __init__(self, args):
|
||||
|
||||
print('Web Server starting on port: %i...' % (args.port))
|
||||
|
||||
# 1. Create server socket
|
||||
|
||||
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
print("creating server socket")
|
||||
|
||||
# 2. Bind the server socket to server address and server port
|
||||
|
||||
serverSocket.bind((socket.gethostname(), 80))
|
||||
|
||||
print("binding socket")
|
||||
|
||||
# 3. Continuously listen for connections to server socket
|
||||
|
||||
serverSocket.listen(5)
|
||||
|
||||
# 4. When a connection is accepted, call handleRequest function, passing new connection socket (see https://docs.python.org/3/library/socket.html#socket.socket.accept)
|
||||
|
||||
newSocket = socket.accept()
|
||||
|
||||
while True:
|
||||
|
||||
handleRequest(newSocket)
|
||||
|
||||
print("calling handleRequest")
|
||||
|
||||
# 5. Close server socket
|
||||
|
||||
serverSocket.close()
|
||||
|
||||
|
||||
|
||||
class Proxy(NetworkApplication):
|
||||
|
||||
|
||||
|
||||
def __init__(self, args):
|
||||
|
||||
print('Web Proxy starting on port: %i...' % (args.port))
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
args = setupArgumentParser()
|
||||
|
||||
args.func(args)
|
||||
|
||||
# 1. Receive request message from the client on connection socket
|
||||
# IPv4 address is 4 bytes in length
|
||||
bufferSize = connectionSocket.CMSG_SPACE(4)
|
||||
requestMessage = connectionSocket.recvmsg(bufferSize[0, [0]])
|
||||
# 2. Extract the path of the requested object from the message (second part of the HTTP header)
|
||||
file = requestMessage.unpack_from( format, buffer, offset = 1) # returns a tuple
|
||||
# 2. send HTTP request for object to proxy server
|
||||
httpRequest= ("GET /" + file + " HTTP/1.1\r\n\r\n")
|
||||
connectionSocket.send(httpRequest.encode())
|
||||
#connctionSocket.send("HTTP/1.1 200 OK\r\n\r\n")
|
||||
print("Request message sent")
|
||||
# 3. proxy server checks to see if copy of object is stored locally- calls class localObject
|
||||
filename= requestMessage.split()[1]
|
||||
try:
|
||||
isObjectLocal=open(filename[1:], "r") # open file in text mode
|
||||
# 1. if it does, the proxy server returns the object within a HTTP response message to the client browser
|
||||
# 3. Read the corresponding file from disk
|
||||
socket.sendfile(object, offset = 0, count =None)
|
||||
#send via HTTP response message to client Browser
|
||||
|
||||
except isObjectLocal == "false":
|
||||
# 2. if it doesn’t, the proxy server opens a TCP connection to the origin server:
|
||||
proxySocket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# bind the socket to a public host, and a well-known port
|
||||
proxySocket.bind((socket.gethostname(), 80))
|
||||
#sends HTTP request for object
|
||||
proxySocket.send(httpRequest.encode())
|
||||
#origin server recieves request
|
||||
connectionSocket.recvmessage(httpRequest.encode())
|
||||
# 4. proxy server sends HTTP request for the object into the cache-to-server TCP connection
|
||||
|
||||
# 5. origin server receives request
|
||||
|
||||
# 6. origin server sends object to proxy server within a HTTP response
|
||||
|
||||
# 7. proxy server receives the object
|
||||
object= serverSocket.recvmsg(bufferSize[0, 0])
|
||||
|
||||
# 8. proxy server stores copy in its local storage
|
||||
|
||||
# 9. proxy server sends copy -in HTTP response message- to client browser over TCP connection
|
||||
|
||||
# proxy server checks to see if copy of object is stored locally
|
||||
|
0
hk1234566/python_networking/new/.env.docker
Normal file
0
hk1234566/python_networking/new/.env.docker
Normal file
2
hk1234566/python_networking/new/.pylintrc
Normal file
2
hk1234566/python_networking/new/.pylintrc
Normal file
@@ -0,0 +1,2 @@
|
||||
[FORMAT]
|
||||
max-line-length=180
|
587
hk1234566/python_networking/new/NetworkApplications-full.py
Normal file
587
hk1234566/python_networking/new/NetworkApplications-full.py
Normal file
@@ -0,0 +1,587 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
import argparse
|
||||
import socket
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
import time
|
||||
import random
|
||||
import traceback # useful for exception handling
|
||||
import threading
|
||||
|
||||
from pprint import pprint
|
||||
|
||||
|
||||
# config
|
||||
INCOMING_BUFFER = 1024
|
||||
OUTGOING_BUFFER = INCOMING_BUFFER * 10
|
||||
ICMP_TYPE = 8
|
||||
|
||||
|
||||
def setupArgumentParser() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description='A collection of Network Applications developed for SCC.203.')
|
||||
parser.set_defaults(func=ICMPPing, hostname='lancaster.ac.uk')
|
||||
subparsers = parser.add_subparsers(help='sub-command help')
|
||||
|
||||
parser_p = subparsers.add_parser('ping', aliases=['p'], help='run ping')
|
||||
parser_p.set_defaults(timeout=4)
|
||||
parser_p.add_argument('hostname', type=str, help='host to ping towards')
|
||||
parser_p.add_argument(
|
||||
'--count',
|
||||
'-c',
|
||||
nargs='?',
|
||||
type=int,
|
||||
help='number of times to ping the host before stopping')
|
||||
parser_p.add_argument(
|
||||
'--timeout',
|
||||
'-t',
|
||||
nargs='?',
|
||||
type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_p.set_defaults(func=ICMPPing)
|
||||
|
||||
parser_t = subparsers.add_parser('traceroute', aliases=['t'],
|
||||
help='run traceroute')
|
||||
parser_t.set_defaults(timeout=4, protocol='icmp')
|
||||
parser_t.add_argument(
|
||||
'hostname',
|
||||
type=str,
|
||||
help='host to traceroute towards')
|
||||
parser_t.add_argument(
|
||||
'--timeout',
|
||||
'-t',
|
||||
nargs='?',
|
||||
type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_t.add_argument('--protocol', '-p', nargs='?', type=str,
|
||||
help='protocol to send request with (UDP/ICMP)')
|
||||
parser_t.set_defaults(func=Traceroute)
|
||||
|
||||
parser_pt = subparsers.add_parser('paris-traceroute', aliases=['pt'],
|
||||
help='run paris-traceroute')
|
||||
parser_pt.set_defaults(timeout=4, protocol='icmp')
|
||||
parser_pt.add_argument(
|
||||
'hostname',
|
||||
type=str,
|
||||
help='host to traceroute towards')
|
||||
parser_pt.add_argument(
|
||||
'--timeout',
|
||||
'-t',
|
||||
nargs='?',
|
||||
type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_pt.add_argument('--protocol', '-p', nargs='?', type=str,
|
||||
help='protocol to send request with (UDP/ICMP)')
|
||||
parser_pt.set_defaults(func=ParisTraceroute)
|
||||
|
||||
parser_w = subparsers.add_parser(
|
||||
'web', aliases=['w'], help='run web server')
|
||||
parser_w.set_defaults(port=8080)
|
||||
parser_w.add_argument('--port', '-p', type=int, nargs='?',
|
||||
help='port number to start web server listening on')
|
||||
parser_w.set_defaults(func=WebServer)
|
||||
|
||||
parser_x = subparsers.add_parser('proxy', aliases=['x'], help='run proxy')
|
||||
parser_x.set_defaults(port=8000)
|
||||
parser_x.add_argument('--port', '-p', type=int, nargs='?',
|
||||
help='port number to start web server listening on')
|
||||
parser_x.set_defaults(func=Proxy)
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
class NetworkApplication:
|
||||
|
||||
def checksum(self, dataToChecksum: str) -> str:
|
||||
csum = 0
|
||||
countTo = (len(dataToChecksum) // 2) * 2
|
||||
count = 0
|
||||
|
||||
while count < countTo:
|
||||
thisVal = dataToChecksum[count + 1] * 256 + dataToChecksum[count]
|
||||
csum = csum + thisVal
|
||||
csum = csum & 0xffffffff
|
||||
count = count + 2
|
||||
|
||||
if countTo < len(dataToChecksum):
|
||||
csum = csum + dataToChecksum[len(dataToChecksum) - 1]
|
||||
csum = csum & 0xffffffff
|
||||
|
||||
csum = (csum >> 16) + (csum & 0xffff)
|
||||
csum = csum + (csum >> 16)
|
||||
answer = ~csum
|
||||
answer = answer & 0xffff
|
||||
answer = answer >> 8 | (answer << 8 & 0xff00)
|
||||
|
||||
answer = socket.htons(answer)
|
||||
|
||||
return answer
|
||||
|
||||
def printOneResult(
|
||||
self,
|
||||
destinationAddress: str,
|
||||
packetLength: int,
|
||||
time: float,
|
||||
ttl: int,
|
||||
destinationHostname=''):
|
||||
if destinationHostname:
|
||||
print(
|
||||
"%d bytes from %s (%s): ttl=%d time=%.2f ms" %
|
||||
(packetLength, destinationHostname, destinationAddress, ttl, time))
|
||||
else:
|
||||
print("%d bytes from %s: ttl=%d time=%.2f ms" %
|
||||
(packetLength, destinationAddress, ttl, time))
|
||||
|
||||
def printAdditionalDetails(
|
||||
self,
|
||||
packetLoss=0.0,
|
||||
minimumDelay=0.0,
|
||||
averageDelay=0.0,
|
||||
maximumDelay=0.0):
|
||||
print("%.2f%% packet loss" % (packetLoss))
|
||||
if minimumDelay > 0 and averageDelay > 0 and maximumDelay > 0:
|
||||
print("rtt min/avg/max = %.2f/%.2f/%.2f ms" %
|
||||
(minimumDelay, averageDelay, maximumDelay))
|
||||
|
||||
def printMultipleResults(
|
||||
self,
|
||||
ttl: int,
|
||||
destinationAddress: str,
|
||||
measurements: list,
|
||||
destinationHostname=''):
|
||||
latencies = ''
|
||||
noResponse = True
|
||||
for rtt in measurements:
|
||||
if rtt is not None:
|
||||
latencies += str(round(rtt, 3))
|
||||
latencies += ' ms '
|
||||
noResponse = False
|
||||
else:
|
||||
latencies += '* '
|
||||
|
||||
if noResponse is False:
|
||||
print(
|
||||
"%d %s (%s) %s" %
|
||||
(ttl,
|
||||
destinationHostname,
|
||||
destinationAddress,
|
||||
latencies))
|
||||
else:
|
||||
print("%d %s" % (ttl, latencies))
|
||||
|
||||
|
||||
class ICMPPing(NetworkApplication):
|
||||
# Task 1.1: ICMP Ping
|
||||
|
||||
def receiveOnePing(self, icmpSocket, destinationAddress, ID, timeout):
|
||||
# 1. Wait for the socket to receive a reply
|
||||
icmpSocket.settimeout(timeout)
|
||||
|
||||
try:
|
||||
reply, addr = icmpSocket.recvfrom(2048)
|
||||
except socket.timeout as msg:
|
||||
print("No data received from socket within timeout period. Message: " + str(msg))
|
||||
sys.exit(1)
|
||||
|
||||
# 2. Once received, record time of receipt, otherwise, handle a timeout
|
||||
recv_time = time.time()
|
||||
|
||||
# 4. Unpack the packet header for useful information, including the ID
|
||||
# icmp header of the received packet,
|
||||
# bottom of packet because of network byte-order
|
||||
# align offset to include the layer 2 encap = 14
|
||||
reply_size = struct.unpack(">H", reply[16 - 14:18 - 14])[0]
|
||||
reply_ttl = struct.unpack(">B", reply[22 - 14:23 - 14])[0]
|
||||
reply_id = struct.unpack(">B", reply[38 - 14:39 - 14])[0]
|
||||
|
||||
# 5. Check that the ID matches between the request and reply
|
||||
if reply_id != ID:
|
||||
print("Received packet ID not match")
|
||||
sys.exit(1)
|
||||
|
||||
# 6. Return recv time + packet size
|
||||
return (recv_time, reply_size, reply_ttl)
|
||||
|
||||
def sendOnePing(self, icmpSocket, destinationAddress, ID):
|
||||
# 1. Build ICMP header
|
||||
header = struct.pack('BBHHH', ICMP_TYPE, 0, 0, ID, 1)
|
||||
data = bytes("Task 1.1: ICMP Ping", 'utf-8')
|
||||
|
||||
# 2. Checksum ICMP packet using given function
|
||||
new_checksum = self.checksum(header + data)
|
||||
|
||||
# 3. Insert checksum into packet
|
||||
header = struct.pack('BBHHH', ICMP_TYPE, 0, new_checksum, ID, 1)
|
||||
packet = header + data
|
||||
|
||||
# 4. Send packet using socket
|
||||
while packet:
|
||||
sent = icmpSocket.sendto(packet, (destinationAddress, 1500)) # 1500 = Port number
|
||||
packet = packet[sent:]
|
||||
|
||||
# 5. Record time of sending
|
||||
sendTime = time.time()
|
||||
return sendTime
|
||||
|
||||
def doOnePing(self, destinationAddress, timeout):
|
||||
# 1. Create ICMP socket
|
||||
# Sends raw packets to ipv4 addresses
|
||||
new_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname('icmp'))
|
||||
ID = 1
|
||||
|
||||
# 2. Call sendOnePing function
|
||||
sendTime = self.sendOnePing(new_socket, destinationAddress, ID)
|
||||
|
||||
# 3. Call receiveOnePing function
|
||||
(recv_time, reply_len, reply_size) = self.receiveOnePing(new_socket, destinationAddress, ID, 1)
|
||||
|
||||
# 4. Close ICMP socket
|
||||
new_socket.close()
|
||||
|
||||
# 5. Return total network delay
|
||||
send_time_ms = sendTime * 1000
|
||||
recv_time_ms = recv_time * 1000
|
||||
|
||||
total_delay = recv_time_ms - send_time_ms
|
||||
|
||||
return (total_delay, reply_len, reply_size)
|
||||
|
||||
def __init__(self, args):
|
||||
print('Ping to: %s...' % (args.hostname))
|
||||
# 1. Look up hostname, resolving it to an IP address
|
||||
|
||||
# # 2. Call doOnePing function, approximately every second
|
||||
try:
|
||||
destinationAddress = socket.gethostbyname(args.hostname)
|
||||
|
||||
while True:
|
||||
(total_delay, reply_len, reply_size) = self.doOnePing(destinationAddress, 1)
|
||||
# 3. Print out the returned delay (and other relevant details) using the printOneResult method
|
||||
self.printOneResult(destinationAddress, reply_len, total_delay, reply_size, args.hostname)
|
||||
time.sleep(1)
|
||||
|
||||
# 4. Continue this process until stopped
|
||||
|
||||
except BaseException:
|
||||
print("Host name not recognised")
|
||||
|
||||
|
||||
class Traceroute(NetworkApplication):
|
||||
# Task 1.2: Traceroute
|
||||
|
||||
def __init__(self, args):
|
||||
# Please ensure you print each result using the printOneResult method!
|
||||
print('Traceroute to: %s...' % (args.hostname))
|
||||
|
||||
# Get IP of destination
|
||||
dest_address = socket.gethostbyname(args.hostname)
|
||||
|
||||
# init ttl_count_up
|
||||
ttl_count_up = 1
|
||||
while True:
|
||||
# Creates sockets
|
||||
recv_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
|
||||
send_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_ICMP)
|
||||
send_socket.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl_count_up)
|
||||
|
||||
# COnstruct and send packet
|
||||
header = struct.pack('BBHHH', ICMP_TYPE, 0, 0, 5, 1)
|
||||
data = "Task 1.2: Traceroute".encode()
|
||||
|
||||
# NOTE: the direction constrainted by checksum generating function, so the above BBHHH will not be modified
|
||||
new_checksum = self.checksum(header + data)
|
||||
header = struct.pack('BBHHH', ICMP_TYPE, 0, new_checksum, 5, 1)
|
||||
packet = header + data
|
||||
send_socket.sendto(packet, (dest_address, 1024 * 10))
|
||||
|
||||
send_time = time.time() # Record beginning time
|
||||
|
||||
# Loop until packet received
|
||||
run = True
|
||||
while run:
|
||||
recv_packet, address = recv_socket.recvfrom(1024 * 4)
|
||||
address = address[0]
|
||||
|
||||
run = False
|
||||
|
||||
send_socket.close()
|
||||
recv_socket.close()
|
||||
|
||||
recv_time = time.time()
|
||||
|
||||
# try best to resolv hostname
|
||||
try:
|
||||
hostname = socket.gethostbyaddr(address)[0]
|
||||
except BaseException:
|
||||
hostname = address
|
||||
|
||||
self.printOneResult(address, sys.getsizeof(packet), (recv_time - send_time) * 1000, ttl_count_up, hostname)
|
||||
ttl_count_up += 1
|
||||
|
||||
# dest reach, exit loop
|
||||
if address == dest_address:
|
||||
break
|
||||
|
||||
|
||||
|
||||
|
||||
class ParisTraceroute(NetworkApplication):
|
||||
# Task 1.3: Paris-Traceroute
|
||||
# A well-known limitation of trace route is that it may indicate a path that does not actually
|
||||
# exist in the presence of “load-balancers” in the network. Consider the example below where
|
||||
# a source host Src sends traceroute traffic to a destination host Dst.
|
||||
|
||||
def getIdentifier(self, checkSumWanted):
|
||||
return 0xf7ff - checkSumWanted
|
||||
|
||||
def __init__(self, args):
|
||||
|
||||
try:
|
||||
print('Paris-Traceroute to: %s...' % (args.hostname))
|
||||
|
||||
# Get IP of destination
|
||||
dest_ip = socket.gethostbyname(args.hostname)
|
||||
|
||||
ttl_count_up = 1
|
||||
# in paris-traceroute, use checksum as identifier
|
||||
check_sum_count_up = 1
|
||||
|
||||
while True:
|
||||
# Creates sockets
|
||||
recv_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
|
||||
send_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
|
||||
|
||||
# Limit ttl of socket
|
||||
send_socket.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl_count_up)
|
||||
|
||||
# COnstruct and send packet
|
||||
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
|
||||
header = struct.pack('!BBHHH', ICMP_TYPE, 0, 0, 0, 0)
|
||||
|
||||
# NOTE: the checksum acts as a identifier, get the apporiate identifier to get the wanted checksum
|
||||
# BE(big endian) used here
|
||||
# checked with opensource from https://paris-traceroute.net
|
||||
new_identifier = self.getIdentifier(check_sum_count_up)
|
||||
header = struct.pack('!BBHHH', ICMP_TYPE, 0, check_sum_count_up, new_identifier, 0)
|
||||
|
||||
packet = header
|
||||
send_socket.sendto(packet, (dest_ip, OUTGOING_BUFFER))
|
||||
|
||||
# jot down start time for diff
|
||||
start_time = time.time()
|
||||
|
||||
# Loop until packet received
|
||||
run = True
|
||||
while run:
|
||||
recv_packet, address = recv_socket.recvfrom(INCOMING_BUFFER)
|
||||
address = address[0]
|
||||
|
||||
run = False
|
||||
|
||||
# close socket after done
|
||||
send_socket.close()
|
||||
recv_socket.close()
|
||||
|
||||
recv_time = time.time()
|
||||
|
||||
# try best to resolv hostname
|
||||
try:
|
||||
try_res_hostname = socket.gethostbyaddr(address)[0]
|
||||
except BaseException:
|
||||
# bypass if cannot resolv hostname
|
||||
try_res_hostname = address
|
||||
|
||||
self.printOneResult(address, sys.getsizeof(packet), (recv_time - start_time) * 1000, ttl_count_up, try_res_hostname)
|
||||
ttl_count_up += 1
|
||||
check_sum_count_up += 1
|
||||
|
||||
# dest reach, exit loop
|
||||
if address == dest_ip:
|
||||
break
|
||||
|
||||
except BaseException as err:
|
||||
print('error occured', err)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class WebServer(NetworkApplication):
|
||||
|
||||
def handleRequest(self, tcpSocket):
|
||||
# 1. Receive request message from the client on connection socket
|
||||
getrequest = tcpSocket.recv(INCOMING_BUFFER).decode()
|
||||
print(getrequest)
|
||||
|
||||
# 2. Extract the path of the requested object from the message (second
|
||||
# part of the HTTP header)
|
||||
headers = getrequest.split('\n')
|
||||
filename = headers[0].split()[1]
|
||||
|
||||
try:
|
||||
# 3. Read the corresponding file from disk
|
||||
filetosend = open(filename.replace('/', ''))
|
||||
content = filetosend.read()
|
||||
filetosend.close()
|
||||
|
||||
# 4. Store in temporary buffer
|
||||
response = 'HTTP/1.0 200 OK\n\n' + content
|
||||
|
||||
# 5. Send the correct HTTP response error
|
||||
except FileNotFoundError:
|
||||
response = 'HTTP/1.0 404 NOT FOUND\n\nFile Not Found'
|
||||
|
||||
# 6. Send the content of the file to the socket
|
||||
tcpSocket.sendall(response.encode())
|
||||
|
||||
# 7. Close the connection socket
|
||||
tcpSocket.close()
|
||||
pass
|
||||
|
||||
def __init__(self, args):
|
||||
print('Web Server starting on port: %i...' % (args.port))
|
||||
# 1. Create server socket
|
||||
server_socket = socket.socket()
|
||||
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
# 2. Bind the server socket to server address and server port
|
||||
server_socket.bind(("127.0.0.1", args.port))
|
||||
|
||||
# 3. Continuously listen for connections to server socket
|
||||
server_socket.listen()
|
||||
|
||||
# 4. When a connection is accepted, call handleRequest function,
|
||||
# passing new connection socket
|
||||
# (see https://docs.python.org/3/library/socket.html#socket.socket.accept)
|
||||
run = True
|
||||
while run:
|
||||
client_socket, client_address = server_socket.accept()
|
||||
self.handleRequest(client_socket)
|
||||
|
||||
# 5. Close server socket
|
||||
server_socket.close()
|
||||
run = False
|
||||
|
||||
|
||||
|
||||
|
||||
class Proxy(NetworkApplication):
|
||||
# Task 2.2: Web Proxy
|
||||
# As with Task 2.1, there are a number of ways to test your Web Proxy. For example, to
|
||||
# generate requests using curl, we can use the following:
|
||||
# curl neverssl.com - -proxy 127.0.0.1: 8000
|
||||
# This assumes that the Web Proxy is running on the local machine and bound to port 8000.
|
||||
# In this case, the URL requested from the proxy is neverssl.com.
|
||||
def handleRequest(self, tcp_socket):
|
||||
dst_host = ''
|
||||
|
||||
# receive request from client
|
||||
full_req = tcp_socket.recv(INCOMING_BUFFER).decode('utf-8')
|
||||
# print("Full req =", full_req)
|
||||
|
||||
first_line = full_req.split('\r\n')[0]
|
||||
[http_action, full_url, http_ver] = first_line.split(' ')
|
||||
sainted_url = full_url.split('://')[1].replace('/', '')
|
||||
try_split_port = sainted_url.split(':')
|
||||
if (len(try_split_port) > 1):
|
||||
dst_host, dst_port = try_split_port
|
||||
else:
|
||||
dst_host = sainted_url
|
||||
dst_port = 80
|
||||
|
||||
try:
|
||||
# try convert to ip, if not emit gaierror
|
||||
dst_ip = socket.gethostbyname(dst_host)
|
||||
|
||||
# create new socket for sending request
|
||||
outgoing_req_socket = socket.socket(
|
||||
socket.AF_INET, socket.SOCK_STREAM)
|
||||
outgoing_req_socket.settimeout(2)
|
||||
|
||||
# connect to dst server
|
||||
outgoing_req_socket.connect((dst_ip, dst_port))
|
||||
|
||||
# forward request getting from proxy
|
||||
outgoing_req_socket.send(full_req.encode('utf-8'))
|
||||
# print("forwarded the request")
|
||||
|
||||
# receive data from the server
|
||||
while True:
|
||||
reply = outgoing_req_socket.recv(INCOMING_BUFFER)
|
||||
|
||||
if len(reply) > 0:
|
||||
# forward reply to originator
|
||||
tcp_socket.send(reply)
|
||||
|
||||
else:
|
||||
# buffer empty, forward reply done
|
||||
break
|
||||
|
||||
# close port
|
||||
outgoing_req_socket.close()
|
||||
|
||||
# handle cannot convert hostname to ip
|
||||
except socket.gaierror as msg:
|
||||
print("Couldn't convert domain to ip", dst_host, msg)
|
||||
|
||||
if tcp_socket:
|
||||
tcp_socket.close()
|
||||
sys.exit(1)
|
||||
|
||||
# handle socket timeout
|
||||
except socket.timeout:
|
||||
print("Connection timeout")
|
||||
if outgoing_req_socket:
|
||||
outgoing_req_socket.close()
|
||||
return
|
||||
|
||||
# final overflow for any error
|
||||
except socket.error as msg:
|
||||
print("Socket error:", msg)
|
||||
if outgoing_req_socket:
|
||||
outgoing_req_socket.close()
|
||||
if tcp_socket:
|
||||
tcp_socket.close()
|
||||
sys.exit(1)
|
||||
|
||||
def __init__(self, args):
|
||||
server_ip = '127.0.0.1'
|
||||
server_port = args.port
|
||||
print('Task 2.2: Web Proxy, starting on port: %i...' % (server_port))
|
||||
|
||||
# 1. Create server socket
|
||||
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
# 2. Bind the server socket to server address and server port
|
||||
server_socket.bind((server_ip, server_port))
|
||||
|
||||
# 3. Continuously listen for connections to server socket
|
||||
server_socket.listen(1)
|
||||
serving = True
|
||||
try:
|
||||
while serving:
|
||||
# 4. When a connection is accepted,
|
||||
# -> call handleIncomingRequest function,
|
||||
# -> passing new connection socket
|
||||
# (see https://docs.python.org/3/library/socket.html#socket.socket.accept)
|
||||
connection, address = server_socket.accept()
|
||||
self.handleRequest(connection)
|
||||
|
||||
except socket.error as msg:
|
||||
if server_socket:
|
||||
server_socket.close()
|
||||
print("Socket error:", msg)
|
||||
sys.exit(1)
|
||||
|
||||
finally:
|
||||
# 5. Close server socket
|
||||
if server_socket:
|
||||
server_socket.close()
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = setupArgumentParser()
|
||||
args.func(args)
|
587
hk1234566/python_networking/new/NetworkApplications.py
Normal file
587
hk1234566/python_networking/new/NetworkApplications.py
Normal file
@@ -0,0 +1,587 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
import argparse
|
||||
import socket
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
import time
|
||||
import random
|
||||
import traceback # useful for exception handling
|
||||
import threading
|
||||
|
||||
from pprint import pprint
|
||||
|
||||
|
||||
# config
|
||||
INCOMING_BUFFER = 1024
|
||||
OUTGOING_BUFFER = INCOMING_BUFFER * 10
|
||||
ICMP_TYPE = 8
|
||||
|
||||
|
||||
def setupArgumentParser() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description='A collection of Network Applications developed for SCC.203.')
|
||||
parser.set_defaults(func=ICMPPing, hostname='lancaster.ac.uk')
|
||||
subparsers = parser.add_subparsers(help='sub-command help')
|
||||
|
||||
parser_p = subparsers.add_parser('ping', aliases=['p'], help='run ping')
|
||||
parser_p.set_defaults(timeout=4)
|
||||
parser_p.add_argument('hostname', type=str, help='host to ping towards')
|
||||
parser_p.add_argument(
|
||||
'--count',
|
||||
'-c',
|
||||
nargs='?',
|
||||
type=int,
|
||||
help='number of times to ping the host before stopping')
|
||||
parser_p.add_argument(
|
||||
'--timeout',
|
||||
'-t',
|
||||
nargs='?',
|
||||
type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_p.set_defaults(func=ICMPPing)
|
||||
|
||||
parser_t = subparsers.add_parser('traceroute', aliases=['t'],
|
||||
help='run traceroute')
|
||||
parser_t.set_defaults(timeout=4, protocol='icmp')
|
||||
parser_t.add_argument(
|
||||
'hostname',
|
||||
type=str,
|
||||
help='host to traceroute towards')
|
||||
parser_t.add_argument(
|
||||
'--timeout',
|
||||
'-t',
|
||||
nargs='?',
|
||||
type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_t.add_argument('--protocol', '-p', nargs='?', type=str,
|
||||
help='protocol to send request with (UDP/ICMP)')
|
||||
parser_t.set_defaults(func=Traceroute)
|
||||
|
||||
parser_pt = subparsers.add_parser('paris-traceroute', aliases=['pt'],
|
||||
help='run paris-traceroute')
|
||||
parser_pt.set_defaults(timeout=4, protocol='icmp')
|
||||
parser_pt.add_argument(
|
||||
'hostname',
|
||||
type=str,
|
||||
help='host to traceroute towards')
|
||||
parser_pt.add_argument(
|
||||
'--timeout',
|
||||
'-t',
|
||||
nargs='?',
|
||||
type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_pt.add_argument('--protocol', '-p', nargs='?', type=str,
|
||||
help='protocol to send request with (UDP/ICMP)')
|
||||
parser_pt.set_defaults(func=ParisTraceroute)
|
||||
|
||||
parser_w = subparsers.add_parser(
|
||||
'web', aliases=['w'], help='run web server')
|
||||
parser_w.set_defaults(port=8080)
|
||||
parser_w.add_argument('--port', '-p', type=int, nargs='?',
|
||||
help='port number to start web server listening on')
|
||||
parser_w.set_defaults(func=WebServer)
|
||||
|
||||
parser_x = subparsers.add_parser('proxy', aliases=['x'], help='run proxy')
|
||||
parser_x.set_defaults(port=8000)
|
||||
parser_x.add_argument('--port', '-p', type=int, nargs='?',
|
||||
help='port number to start web server listening on')
|
||||
parser_x.set_defaults(func=Proxy)
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
class NetworkApplication:
|
||||
|
||||
def checksum(self, dataToChecksum: str) -> str:
|
||||
csum = 0
|
||||
countTo = (len(dataToChecksum) // 2) * 2
|
||||
count = 0
|
||||
|
||||
while count < countTo:
|
||||
thisVal = dataToChecksum[count + 1] * 256 + dataToChecksum[count]
|
||||
csum = csum + thisVal
|
||||
csum = csum & 0xffffffff
|
||||
count = count + 2
|
||||
|
||||
if countTo < len(dataToChecksum):
|
||||
csum = csum + dataToChecksum[len(dataToChecksum) - 1]
|
||||
csum = csum & 0xffffffff
|
||||
|
||||
csum = (csum >> 16) + (csum & 0xffff)
|
||||
csum = csum + (csum >> 16)
|
||||
answer = ~csum
|
||||
answer = answer & 0xffff
|
||||
answer = answer >> 8 | (answer << 8 & 0xff00)
|
||||
|
||||
answer = socket.htons(answer)
|
||||
|
||||
return answer
|
||||
|
||||
def printOneResult(
|
||||
self,
|
||||
destinationAddress: str,
|
||||
packetLength: int,
|
||||
time: float,
|
||||
ttl: int,
|
||||
destinationHostname=''):
|
||||
if destinationHostname:
|
||||
print(
|
||||
"%d bytes from %s (%s): ttl=%d time=%.2f ms" %
|
||||
(packetLength, destinationHostname, destinationAddress, ttl, time))
|
||||
else:
|
||||
print("%d bytes from %s: ttl=%d time=%.2f ms" %
|
||||
(packetLength, destinationAddress, ttl, time))
|
||||
|
||||
def printAdditionalDetails(
|
||||
self,
|
||||
packetLoss=0.0,
|
||||
minimumDelay=0.0,
|
||||
averageDelay=0.0,
|
||||
maximumDelay=0.0):
|
||||
print("%.2f%% packet loss" % (packetLoss))
|
||||
if minimumDelay > 0 and averageDelay > 0 and maximumDelay > 0:
|
||||
print("rtt min/avg/max = %.2f/%.2f/%.2f ms" %
|
||||
(minimumDelay, averageDelay, maximumDelay))
|
||||
|
||||
def printMultipleResults(
|
||||
self,
|
||||
ttl: int,
|
||||
destinationAddress: str,
|
||||
measurements: list,
|
||||
destinationHostname=''):
|
||||
latencies = ''
|
||||
noResponse = True
|
||||
for rtt in measurements:
|
||||
if rtt is not None:
|
||||
latencies += str(round(rtt, 3))
|
||||
latencies += ' ms '
|
||||
noResponse = False
|
||||
else:
|
||||
latencies += '* '
|
||||
|
||||
if noResponse is False:
|
||||
print(
|
||||
"%d %s (%s) %s" %
|
||||
(ttl,
|
||||
destinationHostname,
|
||||
destinationAddress,
|
||||
latencies))
|
||||
else:
|
||||
print("%d %s" % (ttl, latencies))
|
||||
|
||||
|
||||
class ICMPPing(NetworkApplication):
|
||||
# Task 1.1: ICMP Ping
|
||||
|
||||
def receiveOnePing(self, icmpSocket, destinationAddress, ID, timeout):
|
||||
# 1. Wait for the socket to receive a reply
|
||||
icmpSocket.settimeout(timeout)
|
||||
|
||||
try:
|
||||
reply, addr = icmpSocket.recvfrom(2048)
|
||||
except socket.timeout as msg:
|
||||
print("No data received from socket within timeout period. Message: " + str(msg))
|
||||
sys.exit(1)
|
||||
|
||||
# 2. Once received, record time of receipt, otherwise, handle a timeout
|
||||
recv_time = time.time()
|
||||
|
||||
# 4. Unpack the packet header for useful information, including the ID
|
||||
# icmp header of the received packet,
|
||||
# bottom of packet because of network byte-order
|
||||
# align offset to include the layer 2 encap = 14
|
||||
reply_size = struct.unpack(">H", reply[16 - 14:18 - 14])[0]
|
||||
reply_ttl = struct.unpack(">B", reply[22 - 14:23 - 14])[0]
|
||||
reply_id = struct.unpack(">B", reply[38 - 14:39 - 14])[0]
|
||||
|
||||
# 5. Check that the ID matches between the request and reply
|
||||
if reply_id != ID:
|
||||
print("Received packet ID not match")
|
||||
sys.exit(1)
|
||||
|
||||
# 6. Return recv time + packet size
|
||||
return (recv_time, reply_size, reply_ttl)
|
||||
|
||||
def sendOnePing(self, icmpSocket, destinationAddress, ID):
|
||||
# 1. Build ICMP header
|
||||
header = struct.pack('BBHHH', ICMP_TYPE, 0, 0, ID, 1)
|
||||
data = bytes("Task 1.1: ICMP Ping", 'utf-8')
|
||||
|
||||
# 2. Checksum ICMP packet using given function
|
||||
new_checksum = self.checksum(header + data)
|
||||
|
||||
# 3. Insert checksum into packet
|
||||
header = struct.pack('BBHHH', ICMP_TYPE, 0, new_checksum, ID, 1)
|
||||
packet = header + data
|
||||
|
||||
# 4. Send packet using socket
|
||||
while packet:
|
||||
sent = icmpSocket.sendto(packet, (destinationAddress, 1500)) # 1500 = Port number
|
||||
packet = packet[sent:]
|
||||
|
||||
# 5. Record time of sending
|
||||
sendTime = time.time()
|
||||
return sendTime
|
||||
|
||||
def doOnePing(self, destinationAddress, timeout):
|
||||
# 1. Create ICMP socket
|
||||
# Sends raw packets to ipv4 addresses
|
||||
new_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname('icmp'))
|
||||
ID = 1
|
||||
|
||||
# 2. Call sendOnePing function
|
||||
sendTime = self.sendOnePing(new_socket, destinationAddress, ID)
|
||||
|
||||
# 3. Call receiveOnePing function
|
||||
(recv_time, reply_len, reply_size) = self.receiveOnePing(new_socket, destinationAddress, ID, 1)
|
||||
|
||||
# 4. Close ICMP socket
|
||||
new_socket.close()
|
||||
|
||||
# 5. Return total network delay
|
||||
send_time_ms = sendTime * 1000
|
||||
recv_time_ms = recv_time * 1000
|
||||
|
||||
total_delay = recv_time_ms - send_time_ms
|
||||
|
||||
return (total_delay, reply_len, reply_size)
|
||||
|
||||
def __init__(self, args):
|
||||
print('Ping to: %s...' % (args.hostname))
|
||||
# 1. Look up hostname, resolving it to an IP address
|
||||
|
||||
# # 2. Call doOnePing function, approximately every second
|
||||
try:
|
||||
destinationAddress = socket.gethostbyname(args.hostname)
|
||||
|
||||
while True:
|
||||
(total_delay, reply_len, reply_size) = self.doOnePing(destinationAddress, 1)
|
||||
# 3. Print out the returned delay (and other relevant details) using the printOneResult method
|
||||
self.printOneResult(destinationAddress, reply_len, total_delay, reply_size, args.hostname)
|
||||
time.sleep(1)
|
||||
|
||||
# 4. Continue this process until stopped
|
||||
|
||||
except BaseException:
|
||||
print("Host name not recognised")
|
||||
|
||||
|
||||
class Traceroute(NetworkApplication):
|
||||
# Task 1.2: Traceroute
|
||||
|
||||
def __init__(self, args):
|
||||
# Please ensure you print each result using the printOneResult method!
|
||||
print('Traceroute to: %s...' % (args.hostname))
|
||||
|
||||
# Get IP of destination
|
||||
dest_address = socket.gethostbyname(args.hostname)
|
||||
|
||||
# init ttl_count_up
|
||||
ttl_count_up = 1
|
||||
while True:
|
||||
# Creates sockets
|
||||
recv_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
|
||||
send_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_ICMP)
|
||||
send_socket.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl_count_up)
|
||||
|
||||
# COnstruct and send packet
|
||||
header = struct.pack('BBHHH', ICMP_TYPE, 0, 0, 5, 1)
|
||||
data = "Task 1.2: Traceroute".encode()
|
||||
|
||||
# NOTE: the direction constrainted by checksum generating function, so the above BBHHH will not be modified
|
||||
new_checksum = self.checksum(header + data)
|
||||
header = struct.pack('BBHHH', ICMP_TYPE, 0, new_checksum, 5, 1)
|
||||
packet = header + data
|
||||
send_socket.sendto(packet, (dest_address, 1024 * 10))
|
||||
|
||||
send_time = time.time() # Record beginning time
|
||||
|
||||
# Loop until packet received
|
||||
run = True
|
||||
while run:
|
||||
recv_packet, address = recv_socket.recvfrom(1024 * 4)
|
||||
address = address[0]
|
||||
|
||||
run = False
|
||||
|
||||
send_socket.close()
|
||||
recv_socket.close()
|
||||
|
||||
recv_time = time.time()
|
||||
|
||||
# try best to resolv hostname
|
||||
try:
|
||||
hostname = socket.gethostbyaddr(address)[0]
|
||||
except BaseException:
|
||||
hostname = address
|
||||
|
||||
self.printOneResult(address, sys.getsizeof(packet), (recv_time - send_time) * 1000, ttl_count_up, hostname)
|
||||
ttl_count_up += 1
|
||||
|
||||
# dest reach, exit loop
|
||||
if address == dest_address:
|
||||
break
|
||||
|
||||
|
||||
|
||||
|
||||
class ParisTraceroute(NetworkApplication):
|
||||
# Task 1.3: Paris-Traceroute
|
||||
# A well-known limitation of trace route is that it may indicate a path that does not actually
|
||||
# exist in the presence of “load-balancers” in the network. Consider the example below where
|
||||
# a source host Src sends traceroute traffic to a destination host Dst.
|
||||
|
||||
def getIdentifier(self, checkSumWanted):
|
||||
return 0xf7ff - checkSumWanted
|
||||
|
||||
def __init__(self, args):
|
||||
|
||||
try:
|
||||
print('Paris-Traceroute to: %s...' % (args.hostname))
|
||||
|
||||
# Get IP of destination
|
||||
dest_ip = socket.gethostbyname(args.hostname)
|
||||
|
||||
ttl_count_up = 1
|
||||
# in paris-traceroute, use checksum as identifier
|
||||
check_sum_count_up = 1
|
||||
|
||||
while True:
|
||||
# Creates sockets
|
||||
recv_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
|
||||
send_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
|
||||
|
||||
# Limit ttl of socket
|
||||
send_socket.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl_count_up)
|
||||
|
||||
# COnstruct and send packet
|
||||
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
|
||||
header = struct.pack('!BBHHH', ICMP_TYPE, 0, 0, 0, 0)
|
||||
|
||||
# NOTE: the checksum acts as a identifier, get the apporiate identifier to get the wanted checksum
|
||||
# BE(big endian) used here
|
||||
# checked with opensource from https://paris-traceroute.net
|
||||
new_identifier = self.getIdentifier(check_sum_count_up)
|
||||
header = struct.pack('!BBHHH', ICMP_TYPE, 0, check_sum_count_up, new_identifier, 0)
|
||||
|
||||
packet = header
|
||||
send_socket.sendto(packet, (dest_ip, OUTGOING_BUFFER))
|
||||
|
||||
# jot down start time for diff
|
||||
start_time = time.time()
|
||||
|
||||
# Loop until packet received
|
||||
run = True
|
||||
while run:
|
||||
recv_packet, address = recv_socket.recvfrom(INCOMING_BUFFER)
|
||||
address = address[0]
|
||||
|
||||
run = False
|
||||
|
||||
# close socket after done
|
||||
send_socket.close()
|
||||
recv_socket.close()
|
||||
|
||||
recv_time = time.time()
|
||||
|
||||
# try best to resolv hostname
|
||||
try:
|
||||
try_res_hostname = socket.gethostbyaddr(address)[0]
|
||||
except BaseException:
|
||||
# bypass if cannot resolv hostname
|
||||
try_res_hostname = address
|
||||
|
||||
self.printOneResult(address, sys.getsizeof(packet), (recv_time - start_time) * 1000, ttl_count_up, try_res_hostname)
|
||||
ttl_count_up += 1
|
||||
check_sum_count_up += 1
|
||||
|
||||
# dest reach, exit loop
|
||||
if address == dest_ip:
|
||||
break
|
||||
|
||||
except BaseException as err:
|
||||
print('error occured', err)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class WebServer(NetworkApplication):
|
||||
|
||||
def handleRequest(self, tcpSocket):
|
||||
# 1. Receive request message from the client on connection socket
|
||||
getrequest = tcpSocket.recv(INCOMING_BUFFER).decode()
|
||||
print(getrequest)
|
||||
|
||||
# 2. Extract the path of the requested object from the message (second
|
||||
# part of the HTTP header)
|
||||
headers = getrequest.split('\n')
|
||||
filename = headers[0].split()[1]
|
||||
|
||||
try:
|
||||
# 3. Read the corresponding file from disk
|
||||
filetosend = open(filename.replace('/', ''))
|
||||
content = filetosend.read()
|
||||
filetosend.close()
|
||||
|
||||
# 4. Store in temporary buffer
|
||||
response = 'HTTP/1.0 200 OK\n\n' + content
|
||||
|
||||
# 5. Send the correct HTTP response error
|
||||
except FileNotFoundError:
|
||||
response = 'HTTP/1.0 404 NOT FOUND\n\nFile Not Found'
|
||||
|
||||
# 6. Send the content of the file to the socket
|
||||
tcpSocket.sendall(response.encode())
|
||||
|
||||
# 7. Close the connection socket
|
||||
tcpSocket.close()
|
||||
pass
|
||||
|
||||
def __init__(self, args):
|
||||
print('Web Server starting on port: %i...' % (args.port))
|
||||
# 1. Create server socket
|
||||
server_socket = socket.socket()
|
||||
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
# 2. Bind the server socket to server address and server port
|
||||
server_socket.bind(("127.0.0.1", args.port))
|
||||
|
||||
# 3. Continuously listen for connections to server socket
|
||||
server_socket.listen()
|
||||
|
||||
# 4. When a connection is accepted, call handleRequest function,
|
||||
# passing new connection socket
|
||||
# (see https://docs.python.org/3/library/socket.html#socket.socket.accept)
|
||||
run = True
|
||||
while run:
|
||||
client_socket, client_address = server_socket.accept()
|
||||
self.handleRequest(client_socket)
|
||||
|
||||
# 5. Close server socket
|
||||
server_socket.close()
|
||||
run = False
|
||||
|
||||
|
||||
|
||||
|
||||
class Proxy(NetworkApplication):
|
||||
# Task 2.2: Web Proxy
|
||||
# As with Task 2.1, there are a number of ways to test your Web Proxy. For example, to
|
||||
# generate requests using curl, we can use the following:
|
||||
# curl neverssl.com - -proxy 127.0.0.1: 8000
|
||||
# This assumes that the Web Proxy is running on the local machine and bound to port 8000.
|
||||
# In this case, the URL requested from the proxy is neverssl.com.
|
||||
def handleRequest(self, tcp_socket):
|
||||
dst_host = ''
|
||||
|
||||
# receive request from client
|
||||
full_req = tcp_socket.recv(INCOMING_BUFFER).decode('utf-8')
|
||||
# print("Full req =", full_req)
|
||||
|
||||
first_line = full_req.split('\r\n')[0]
|
||||
[http_action, full_url, http_ver] = first_line.split(' ')
|
||||
sainted_url = full_url.split('://')[1].replace('/', '')
|
||||
try_split_port = sainted_url.split(':')
|
||||
if (len(try_split_port) > 1):
|
||||
dst_host, dst_port = try_split_port
|
||||
else:
|
||||
dst_host = sainted_url
|
||||
dst_port = 80
|
||||
|
||||
try:
|
||||
# try convert to ip, if not emit gaierror
|
||||
dst_ip = socket.gethostbyname(dst_host)
|
||||
|
||||
# create new socket for sending request
|
||||
outgoing_req_socket = socket.socket(
|
||||
socket.AF_INET, socket.SOCK_STREAM)
|
||||
outgoing_req_socket.settimeout(2)
|
||||
|
||||
# connect to dst server
|
||||
outgoing_req_socket.connect((dst_ip, dst_port))
|
||||
|
||||
# forward request getting from proxy
|
||||
outgoing_req_socket.send(full_req.encode('utf-8'))
|
||||
# print("forwarded the request")
|
||||
|
||||
# receive data from the server
|
||||
while True:
|
||||
reply = outgoing_req_socket.recv(INCOMING_BUFFER)
|
||||
|
||||
if len(reply) > 0:
|
||||
# forward reply to originator
|
||||
tcp_socket.send(reply)
|
||||
|
||||
else:
|
||||
# buffer empty, forward reply done
|
||||
break
|
||||
|
||||
# close port
|
||||
outgoing_req_socket.close()
|
||||
|
||||
# handle cannot convert hostname to ip
|
||||
except socket.gaierror as msg:
|
||||
print("Couldn't convert domain to ip", dst_host, msg)
|
||||
|
||||
if tcp_socket:
|
||||
tcp_socket.close()
|
||||
sys.exit(1)
|
||||
|
||||
# handle socket timeout
|
||||
except socket.timeout:
|
||||
print("Connection timeout")
|
||||
if outgoing_req_socket:
|
||||
outgoing_req_socket.close()
|
||||
return
|
||||
|
||||
# final overflow for any error
|
||||
except socket.error as msg:
|
||||
print("Socket error:", msg)
|
||||
if outgoing_req_socket:
|
||||
outgoing_req_socket.close()
|
||||
if tcp_socket:
|
||||
tcp_socket.close()
|
||||
sys.exit(1)
|
||||
|
||||
def __init__(self, args):
|
||||
server_ip = '127.0.0.1'
|
||||
server_port = args.port
|
||||
print('Task 2.2: Web Proxy, starting on port: %i...' % (server_port))
|
||||
|
||||
# 1. Create server socket
|
||||
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
# 2. Bind the server socket to server address and server port
|
||||
server_socket.bind((server_ip, server_port))
|
||||
|
||||
# 3. Continuously listen for connections to server socket
|
||||
server_socket.listen(1)
|
||||
serving = True
|
||||
try:
|
||||
while serving:
|
||||
# 4. When a connection is accepted,
|
||||
# -> call handleIncomingRequest function,
|
||||
# -> passing new connection socket
|
||||
# (see https://docs.python.org/3/library/socket.html#socket.socket.accept)
|
||||
connection, address = server_socket.accept()
|
||||
self.handleRequest(connection)
|
||||
|
||||
except socket.error as msg:
|
||||
if server_socket:
|
||||
server_socket.close()
|
||||
print("Socket error:", msg)
|
||||
sys.exit(1)
|
||||
|
||||
finally:
|
||||
# 5. Close server socket
|
||||
if server_socket:
|
||||
server_socket.close()
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = setupArgumentParser()
|
||||
args.func(args)
|
197
hk1234566/python_networking/new/NetworkApplications_original.py
Normal file
197
hk1234566/python_networking/new/NetworkApplications_original.py
Normal file
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
import argparse
|
||||
import socket
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
import time
|
||||
import random
|
||||
import traceback # useful for exception handling
|
||||
import threading
|
||||
|
||||
def setupArgumentParser() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description='A collection of Network Applications developed for SCC.203.')
|
||||
parser.set_defaults(func=ICMPPing, hostname='lancaster.ac.uk')
|
||||
subparsers = parser.add_subparsers(help='sub-command help')
|
||||
|
||||
parser_p = subparsers.add_parser('ping', aliases=['p'], help='run ping')
|
||||
parser_p.set_defaults(timeout=4)
|
||||
parser_p.add_argument('hostname', type=str, help='host to ping towards')
|
||||
parser_p.add_argument('--count', '-c', nargs='?', type=int,
|
||||
help='number of times to ping the host before stopping')
|
||||
parser_p.add_argument('--timeout', '-t', nargs='?',
|
||||
type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_p.set_defaults(func=ICMPPing)
|
||||
|
||||
parser_t = subparsers.add_parser('traceroute', aliases=['t'],
|
||||
help='run traceroute')
|
||||
parser_t.set_defaults(timeout=4, protocol='icmp')
|
||||
parser_t.add_argument('hostname', type=str, help='host to traceroute towards')
|
||||
parser_t.add_argument('--timeout', '-t', nargs='?', type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_t.add_argument('--protocol', '-p', nargs='?', type=str,
|
||||
help='protocol to send request with (UDP/ICMP)')
|
||||
parser_t.set_defaults(func=Traceroute)
|
||||
|
||||
parser_pt = subparsers.add_parser('paris-traceroute', aliases=['pt'],
|
||||
help='run paris-traceroute')
|
||||
parser_pt.set_defaults(timeout=4, protocol='icmp')
|
||||
parser_pt.add_argument('hostname', type=str, help='host to traceroute towards')
|
||||
parser_pt.add_argument('--timeout', '-t', nargs='?', type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_pt.add_argument('--protocol', '-p', nargs='?', type=str,
|
||||
help='protocol to send request with (UDP/ICMP)')
|
||||
parser_pt.set_defaults(func=ParisTraceroute)
|
||||
|
||||
parser_w = subparsers.add_parser('web', aliases=['w'], help='run web server')
|
||||
parser_w.set_defaults(port=8080)
|
||||
parser_w.add_argument('--port', '-p', type=int, nargs='?',
|
||||
help='port number to start web server listening on')
|
||||
parser_w.set_defaults(func=WebServer)
|
||||
|
||||
parser_x = subparsers.add_parser('proxy', aliases=['x'], help='run proxy')
|
||||
parser_x.set_defaults(port=8000)
|
||||
parser_x.add_argument('--port', '-p', type=int, nargs='?',
|
||||
help='port number to start web server listening on')
|
||||
parser_x.set_defaults(func=Proxy)
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
class NetworkApplication:
|
||||
|
||||
def checksum(self, dataToChecksum: str) -> str:
|
||||
csum = 0
|
||||
countTo = (len(dataToChecksum) // 2) * 2
|
||||
count = 0
|
||||
|
||||
while count < countTo:
|
||||
thisVal = dataToChecksum[count+1] * 256 + dataToChecksum[count]
|
||||
csum = csum + thisVal
|
||||
csum = csum & 0xffffffff
|
||||
count = count + 2
|
||||
|
||||
if countTo < len(dataToChecksum):
|
||||
csum = csum + dataToChecksum[len(dataToChecksum) - 1]
|
||||
csum = csum & 0xffffffff
|
||||
|
||||
csum = (csum >> 16) + (csum & 0xffff)
|
||||
csum = csum + (csum >> 16)
|
||||
answer = ~csum
|
||||
answer = answer & 0xffff
|
||||
answer = answer >> 8 | (answer << 8 & 0xff00)
|
||||
|
||||
answer = socket.htons(answer)
|
||||
|
||||
return answer
|
||||
|
||||
def printOneResult(self, destinationAddress: str, packetLength: int, time: float, ttl: int, destinationHostname=''):
|
||||
if destinationHostname:
|
||||
print("%d bytes from %s (%s): ttl=%d time=%.2f ms" % (packetLength, destinationHostname, destinationAddress, ttl, time))
|
||||
else:
|
||||
print("%d bytes from %s: ttl=%d time=%.2f ms" % (packetLength, destinationAddress, ttl, time))
|
||||
|
||||
def printAdditionalDetails(self, packetLoss=0.0, minimumDelay=0.0, averageDelay=0.0, maximumDelay=0.0):
|
||||
print("%.2f%% packet loss" % (packetLoss))
|
||||
if minimumDelay > 0 and averageDelay > 0 and maximumDelay > 0:
|
||||
print("rtt min/avg/max = %.2f/%.2f/%.2f ms" % (minimumDelay, averageDelay, maximumDelay))
|
||||
|
||||
def printMultipleResults(self, ttl: int, destinationAddress: str, measurements: list, destinationHostname=''):
|
||||
latencies = ''
|
||||
noResponse = True
|
||||
for rtt in measurements:
|
||||
if rtt is not None:
|
||||
latencies += str(round(rtt, 3))
|
||||
latencies += ' ms '
|
||||
noResponse = False
|
||||
else:
|
||||
latencies += '* '
|
||||
|
||||
if noResponse is False:
|
||||
print("%d %s (%s) %s" % (ttl, destinationHostname, destinationAddress, latencies))
|
||||
else:
|
||||
print("%d %s" % (ttl, latencies))
|
||||
|
||||
class ICMPPing(NetworkApplication):
|
||||
|
||||
def receiveOnePing(self, icmpSocket, destinationAddress, ID, timeout):
|
||||
# 1. Wait for the socket to receive a reply
|
||||
# 2. Once received, record time of receipt, otherwise, handle a timeout
|
||||
# 3. Compare the time of receipt to time of sending, producing the total network delay
|
||||
# 4. Unpack the packet header for useful information, including the ID
|
||||
# 5. Check that the ID matches between the request and reply
|
||||
# 6. Return total network delay
|
||||
pass
|
||||
|
||||
def sendOnePing(self, icmpSocket, destinationAddress, ID):
|
||||
# 1. Build ICMP header
|
||||
# 2. Checksum ICMP packet using given function
|
||||
# 3. Insert checksum into packet
|
||||
# 4. Send packet using socket
|
||||
# 5. Record time of sending
|
||||
pass
|
||||
|
||||
def doOnePing(self, destinationAddress, timeout):
|
||||
# 1. Create ICMP socket
|
||||
# 2. Call sendOnePing function
|
||||
# 3. Call receiveOnePing function
|
||||
# 4. Close ICMP socket
|
||||
# 5. Return total network delay
|
||||
pass
|
||||
|
||||
def __init__(self, args):
|
||||
print('Ping to: %s...' % (args.hostname))
|
||||
# 1. Look up hostname, resolving it to an IP address
|
||||
# 2. Call doOnePing function, approximately every second
|
||||
# 3. Print out the returned delay (and other relevant details) using the printOneResult method
|
||||
self.printOneResult('1.1.1.1', 50, 20.0, 150) # Example use of printOneResult - complete as appropriate
|
||||
# 4. Continue this process until stopped
|
||||
|
||||
|
||||
class Traceroute(NetworkApplication):
|
||||
|
||||
def __init__(self, args):
|
||||
# Please ensure you print each result using the printOneResult method!
|
||||
print('Traceroute to: %s...' % (args.hostname))
|
||||
|
||||
class ParisTraceroute(NetworkApplication):
|
||||
|
||||
def __init__(self, args):
|
||||
# Please ensure you print each result using the printOneResult method!
|
||||
print('Paris-Traceroute to: %s...' % (args.hostname))
|
||||
|
||||
class WebServer(NetworkApplication):
|
||||
|
||||
def handleRequest(tcpSocket):
|
||||
# 1. Receive request message from the client on connection socket
|
||||
# 2. Extract the path of the requested object from the message (second part of the HTTP header)
|
||||
# 3. Read the corresponding file from disk
|
||||
# 4. Store in temporary buffer
|
||||
# 5. Send the correct HTTP response error
|
||||
# 6. Send the content of the file to the socket
|
||||
# 7. Close the connection socket
|
||||
pass
|
||||
|
||||
def __init__(self, args):
|
||||
print('Web Server starting on port: %i...' % (args.port))
|
||||
# 1. Create server socket
|
||||
# 2. Bind the server socket to server address and server port
|
||||
# 3. Continuously listen for connections to server socket
|
||||
# 4. When a connection is accepted, call handleRequest function, passing new connection socket (see https://docs.python.org/3/library/socket.html#socket.socket.accept)
|
||||
# 5. Close server socket
|
||||
|
||||
|
||||
class Proxy(NetworkApplication):
|
||||
|
||||
def __init__(self, args):
|
||||
print('Web Proxy starting on port: %i...' % (args.port))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = setupArgumentParser()
|
||||
args.func(args)
|
17
hk1234566/python_networking/new/build.sh
Normal file
17
hk1234566/python_networking/new/build.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
rm -rf _temp/*
|
||||
rm -rf delivery.zip
|
||||
|
||||
mkdir -p _temp
|
||||
|
||||
set -ex
|
||||
|
||||
cp NetworkApplications.py _temp/NetworkApplications.py
|
||||
cp test.sh _temp/test.sh
|
||||
|
||||
pushd _temp
|
||||
7za a -tzip ../delivery.zip *
|
||||
popd
|
||||
|
||||
rm -rf _temp
|
5
hk1234566/python_networking/new/format.sh
Normal file
5
hk1234566/python_networking/new/format.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
autopep8 --max-line-length 160 --in-place --aggressive --aggressive NetworkApplications.py
|
12
hk1234566/python_networking/new/index.html
Normal file
12
hk1234566/python_networking/new/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
helloworld
|
||||
</body>
|
||||
</html>
|
5
hk1234566/python_networking/new/notes.md
Normal file
5
hk1234566/python_networking/new/notes.md
Normal file
@@ -0,0 +1,5 @@
|
||||
https://www.ietf.org/rfc/rfc792.txt
|
||||
https://realpython.com/python-sockets/
|
||||
|
||||
https://lwn.net/Articles/422330/
|
||||
https://fasionchan.com/network/icmp/ping-py/
|
31
hk1234566/python_networking/new/test.sh
Normal file
31
hk1234566/python_networking/new/test.sh
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
# python ./NetworkApplications.py -h
|
||||
|
||||
# test web
|
||||
# python ./NetworkApplications.py w
|
||||
# curl http://localhost:8080/index.html
|
||||
|
||||
# test ParisTraceroute
|
||||
# sudo su
|
||||
# python ./NetworkApplications.py pt www.google.com
|
||||
|
||||
# test ping
|
||||
# python ./NetworkApplications.py p www.google.com
|
||||
|
||||
# test traceroute
|
||||
# traceroute -I www.google.com
|
||||
# paris-traceroute -I www.google.com
|
||||
# python ./NetworkApplications.py t www.google.com
|
||||
|
||||
# test proxy
|
||||
# python ./NetworkApplications.py x
|
||||
# curl neverssl.com --proxy 127.0.0.1:8000
|
||||
# curl http://neverssl.com --proxy 127.0.0.1:8000
|
||||
# curl https://neverssl.com:443 --proxy 127.0.0.1:8000
|
||||
|
||||
# utils
|
||||
# gethostbyname
|
||||
# python ./NetworkApplications.py p localhost
|
8
hk1234566/python_networking/new/test_proxy.sh
Normal file
8
hk1234566/python_networking/new/test_proxy.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
curl http://neverssl.com:80 --proxy 127.0.0.1:8000
|
||||
# curl http://neverssl.com --proxy 127.0.0.1:8000
|
||||
# curl http://neverssl.com:8080 --proxy 127.0.0.1:8000
|
||||
# curl neverssl.com --proxy 127.0.0.1:8000
|
409
hk1234566/python_networking/sample1.py
Normal file
409
hk1234566/python_networking/sample1.py
Normal file
@@ -0,0 +1,409 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
######
|
||||
import argparse
|
||||
import socket
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
import time
|
||||
|
||||
|
||||
def setupArgumentParser() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description='A collection of Network Applications developed for SCC.203.')
|
||||
parser.set_defaults(func=ICMPPing, hostname='lancaster.ac.uk')
|
||||
subparsers = parser.add_subparsers(help='sub-command help')
|
||||
|
||||
parser_p = subparsers.add_parser(
|
||||
'ping', aliases=['p'], help='run ping')
|
||||
parser_p.add_argument('hostname', type=str,
|
||||
help='host to ping towards')
|
||||
parser_p.add_argument('count', nargs='?', type=int,
|
||||
help='number of times to ping the host before stopping')
|
||||
parser_p.add_argument('timeout', nargs='?',
|
||||
type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_p.set_defaults(func=ICMPPing)
|
||||
|
||||
parser_t = subparsers.add_parser('traceroute', aliases=['t'],
|
||||
help='run traceroute')
|
||||
parser_t.add_argument('hostname', type=str,
|
||||
help='host to traceroute towards')
|
||||
parser_t.add_argument('timeout', nargs='?', type=int,
|
||||
help='maximum timeout before considering request lost')
|
||||
parser_t.add_argument('protocol', nargs='?', type=str,
|
||||
help='protocol to send request with (UDP/ICMP)')
|
||||
parser_t.set_defaults(func=Traceroute)
|
||||
|
||||
parser_w = subparsers.add_parser(
|
||||
'web', aliases=['w'], help='run web server')
|
||||
parser_w.set_defaults(port=8080)
|
||||
parser_w.add_argument('port', type=int, nargs='?',
|
||||
help='port number to start web server listening on')
|
||||
parser_w.set_defaults(func=WebServer)
|
||||
|
||||
parser_x = subparsers.add_parser(
|
||||
'proxy', aliases=['x'], help='run proxy')
|
||||
parser_x.set_defaults(port=8000)
|
||||
parser_x.add_argument('port', type=int, nargs='?',
|
||||
help='port number to start web server listening on')
|
||||
parser_x.set_defaults(func=Proxy)
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
class NetworkApplication:
|
||||
|
||||
def checksum(self, dataToChecksum: str) -> str:
|
||||
csum = 0
|
||||
countTo = (len(dataToChecksum) // 2) * 2
|
||||
count = 0
|
||||
|
||||
while count < countTo:
|
||||
thisVal = dataToChecksum[count+1] * 256 + dataToChecksum[count]
|
||||
csum = csum + thisVal
|
||||
csum = csum & 0xffffffff
|
||||
count = count + 2
|
||||
|
||||
if countTo < len(dataToChecksum):
|
||||
csum = csum + dataToChecksum[len(dataToChecksum) - 1]
|
||||
csum = csum & 0xffffffff
|
||||
|
||||
csum = (csum >> 16) + (csum & 0xffff)
|
||||
csum = csum + (csum >> 16)
|
||||
answer = ~csum
|
||||
answer = answer & 0xffff
|
||||
answer = answer >> 8 | (answer << 8 & 0xff00)
|
||||
answer = socket.htons(answer)
|
||||
return answer
|
||||
|
||||
def printOneResult(self, destinationAddress: str, packetLength: int, time: float, ttl: int, destinationHostname=''):
|
||||
|
||||
if destinationHostname:
|
||||
print("%d bytes from %s (%s):ttl=%d time=%.2f ms" % (
|
||||
packetLength, destinationHostname, destinationAddress, ttl, time))
|
||||
else:
|
||||
print("%d bytes from %s: ttl=%dtime=%.2f ms" %
|
||||
(packetLength, destinationAddress, ttl, time))
|
||||
|
||||
def printAdditionalDetails(self, packetLoss=0.0, minimumDelay=0.0, averageDelay=0.0, maximumDelay=0.0):
|
||||
print("%.2f%% packet loss" % (packetLoss))
|
||||
if minimumDelay > 0 and averageDelay > 0 and maximumDelay > 0:
|
||||
print("rtt min/avg/max = %.2f/%.2f/%.2fms" %
|
||||
(minimumDelay, averageDelay, maximumDelay))
|
||||
|
||||
|
||||
class ICMPPing(NetworkApplication):
|
||||
|
||||
def receiveOnePing(self, icmpSocket, destinationAddress, ID, timeout):
|
||||
|
||||
# 1. Wait for the socket to receive a reply. #2. Once received, record time of receipt, otherwise, handle a timeout
|
||||
try:
|
||||
timeRecieved = time.time()
|
||||
information, address = icmpSocket.recvfrom(1024)
|
||||
timeSent = information.split()[2]
|
||||
|
||||
# 3. Compare the time of receipt to time of sending, producing the total network delay
|
||||
timeSent= self.sendOnePing(icmpSocket, destinationAddress, 111)
|
||||
totalNetworkDelay = (timeRecieved*1000) - timeSent
|
||||
|
||||
# 4. Unpack the packet header for useful information, including the ID
|
||||
icmpType, icmpCode, icmpChecksum, icmpPacketID, icmpSeqNumber = struct.unpack("bbHHh", icmpHeader)
|
||||
|
||||
# 5. Check that the ID matches between the request and reply AND THEN 6. Return total network delay
|
||||
if(icmpPacketID == self.ID):
|
||||
return totalNetworkDelay
|
||||
|
||||
else:
|
||||
return 0
|
||||
|
||||
except timeout: # No response received, print the timeout message
|
||||
print("Request timed out")
|
||||
|
||||
|
||||
|
||||
def sendOnePing(self, icmpSocket, destinationAddress, ID):
|
||||
# 1. Build ICMP header
|
||||
icmpHeader=struct.pack("bbHHh", 8, 0, 0, ID, 1)
|
||||
|
||||
# 2. Checksum ICMP packet using given function
|
||||
icmpChecksum = self.checksum(icmpHeader)
|
||||
|
||||
# 3. Insert checksum into packet
|
||||
icmpHeader = struct.pack("bbHHh", 8, 0, icmpChecksum, ID, 1)
|
||||
|
||||
# 4. Send packet using socket- double check this //run with wireshark
|
||||
icmpSocket.sendto(icmpHeader, (destinationAddress, 1))
|
||||
|
||||
# 5. Record time of sending
|
||||
timeSent=time.time()
|
||||
return timeSent
|
||||
|
||||
def doOnePing(self, destinationAddress, timeout):
|
||||
# 1. Create ICMP socket
|
||||
# Translate an Internet protocol name (for example, 'icmp') to a constant suitable for passing as the (optional) third argument to the socket() function.
|
||||
icmp_proto = socket.getprotobyname("icmp") #debugging
|
||||
icmpSocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp_proto)
|
||||
#icmpSocket = socket.socket(socket.AF_INET,socket.SOCK_RAW, socket.IPPROTO_ICMP)
|
||||
|
||||
# 2. Call sendOnePing function
|
||||
timeSent = self.sendOnePing(icmpSocket, destinationAddress, 111)
|
||||
|
||||
# 3. Call receiveOnePing function
|
||||
networkDelay = self.receiveOnePing(icmpSocket, destinationAddress, 111, 1000, timeSent)
|
||||
|
||||
# 4. Close ICMP socket
|
||||
icmpSocket.close()
|
||||
|
||||
# 5. Return total network delay
|
||||
return networkDelay
|
||||
|
||||
def __init__(self, args):
|
||||
print('Ping to: %s...' % (args.hostname))
|
||||
# 1. Look up hostname, resolving it to an IP address
|
||||
ipAddress = socket.gethostbyname(args.hostname)
|
||||
|
||||
# 2. Call doOnePing function approximately every second
|
||||
while True:
|
||||
time.sleep(1)
|
||||
debuggingTimeout = args.timeout
|
||||
print("testing:", ipAddress, debuggingTimeout)
|
||||
returnedDelay = self.doOnePing(ipAddress, debuggingTimeout)
|
||||
# 3. Print out the returned delay (and other relevant details) using the printOneResult method
|
||||
self.printOneResult(ipAddress, 50, returnedDelay, 150)
|
||||
#Example use of printOneResult - complete as appropriate
|
||||
# 4. Continue this process until stopped - did this through the while True
|
||||
|
||||
|
||||
class Traceroute(NetworkApplication):
|
||||
|
||||
def __init__(self, args):
|
||||
#
|
||||
# Please ensure you print each result using the printOneResult method!
|
||||
print('Traceroute to: %s...' % (args.hostname))
|
||||
# 1. Look up hostname, resolving it to an IP address
|
||||
ipAddress= socket.gethostbyname(args.hostname)
|
||||
numberofNodes= 0 # create variable and initialise
|
||||
# 2. Call PingOneNode function approximately every second
|
||||
while True:
|
||||
time.sleep(1)
|
||||
#nodalDelay = self.pingOneNode(ipAddress, args.timeout, 1)
|
||||
|
||||
nodalDelay = self.pingOneNode()
|
||||
self.printOneResult(ipAddress, 50, nodalDelay[1]*1000, 150)
|
||||
numberofNodes = numberofNodes + 1 # increments number of nodes
|
||||
|
||||
# 4. Continue this process until stopped - until ICMP = 0
|
||||
if self.ICMP_CODE == 0:
|
||||
break
|
||||
# 3. Print out the returned delay (and other relevant details) using the printOneResult method
|
||||
# check this don't think its right
|
||||
self.printOneResult(ipAddress, 50, nodalDelay[1]*1000, 150)
|
||||
|
||||
def pingOneNode(self):
|
||||
# 1. Create ICMP socket
|
||||
icmp_proto = socket.getprotobyname("icmp") #debugging
|
||||
icmpSocket= socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp_proto)
|
||||
# 2. Call sendNodePing function
|
||||
timeSent= self.sendNodePing(icmpSocket, self.ipAddress, 111)
|
||||
# 3. Call recieveNodePing function
|
||||
networkDelay= self.recieveNodePing(icmpSocket, self.ipAddress, 111, 1000, timeSent)
|
||||
# 4. Close ICMP socket
|
||||
icmpSocket.close()
|
||||
# 5. Return total network delay- add up all the nodes
|
||||
x = 0
|
||||
for x in self.numberOfNodes:
|
||||
totalDelay = (networkDelay[x] + networkDelay[x + 1])
|
||||
x = x + 1
|
||||
if x == self.numberOfNodes:
|
||||
break
|
||||
return totalDelay
|
||||
|
||||
def sendNodePing(icmpSocket):
|
||||
# 1. Build ICMP header
|
||||
icmpHeader= struct.pack("bbHHh", 8, 0, 0, ID, 1)
|
||||
# 2. Checksum ICMP packet using given function
|
||||
icmpChecksum= self.checksum(icmpHeader)
|
||||
# 3. Insert checksum into packet
|
||||
packetHeader= struct.pack("bbHHh", 8, 0, icmpChecksum, ID, 1)
|
||||
packet= packetHeader
|
||||
# 4. Send packet using socket
|
||||
# double check this //run with wireshark
|
||||
icmpSocket.sendto(packet, (self.icmpAddress, 1))
|
||||
# 5. Record time of sending
|
||||
sentTime= time.time()
|
||||
return sentTime
|
||||
|
||||
def recieveNodePing(icmpSocket):
|
||||
# 1. Wait for the socket to receive a reply- TTL = 0
|
||||
sentTime= time.time()
|
||||
## Set the TTL for messages to 1 so they do not go past the local network segment
|
||||
#TTL = socket.recvmessage()
|
||||
|
||||
TTL = struct.pack('b', 1)
|
||||
icmpSocket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, TTL)
|
||||
# 2. Once received, record time of receipt, otherwise, handle a timeout
|
||||
try: # TTL == 0
|
||||
timeRecieved = time.time()
|
||||
# 3. Compare the time of receipt to time of sending, producing the total network delay- did when calculated RTT?
|
||||
totalNetworkDelay = (timeRecieved * 1000) - sentTime
|
||||
# 4. Unpack the packet header for useful information, including the ID
|
||||
icmpType, icmpCode, icmpChecksum, icmpPacketID, icmpSeqNumber= struct.unpack("bbHHh", icmpHeader)
|
||||
# 5. Check that the ID matches between the request and reply and # 6. Return total network delay
|
||||
if(icmpPacketID == self.ID):
|
||||
return totalNetworkDelay
|
||||
else:
|
||||
return 0
|
||||
|
||||
except TTL != 0: #if nothing is recieved, handle a timeout
|
||||
print("TTL is 0 - socket has not recieved a reply")
|
||||
return None
|
||||
|
||||
|
||||
|
||||
class WebServer(NetworkApplication):
|
||||
|
||||
def handleRequest(tcpSocket):
|
||||
# 1. Receive request message from the client on connection (tcp?) socket
|
||||
tcpSocket = serverSocket.accept() # acceptrequest
|
||||
bufferSize = tcpSocket.CMSG_SPACE(4) # IPv4 address is 4 bytes in length - calculates the size of the buffer that should be allocated for receiving the ancillary data.
|
||||
#recieve message in buffer size allocated
|
||||
requestMessage = tcpSocket.recvmsg(bufferSize[0, [0]])
|
||||
# 2. Extract the path of the requested object from the message (second part of the HTTP header)
|
||||
file = requestMessage.unpack_from(bufferSize) # returns a tuple
|
||||
# 3. Read the corresponding file from disk
|
||||
socket.sendfile(file)
|
||||
# 4. Store in temporary buffer
|
||||
tempBuffer = socket.makefile( mode = 'r', buffering =None, encoding=None, errors=None, newline=None)
|
||||
tempFile = struct.pack_into(format, self.tempBuffer, 0, file)
|
||||
# 5. Send the correct HTTP response error
|
||||
httpResponseError= ("HTTP/1.1 404 Not Found\r\n")
|
||||
tcpSocket.sendmsg(httpResponseError)
|
||||
# 6. Send the content of the file to the socket
|
||||
tcpSocket.recvmsg(bufferSize[0, 0])
|
||||
# 7. Close the connection socket
|
||||
tcpSocket.close()
|
||||
pass
|
||||
|
||||
def __init__(self, args):
|
||||
print('Web Server starting on port: %i...' % (args.port))
|
||||
# 1. Create server socket
|
||||
serverSocket= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
print("creating server socket")
|
||||
# 2. Bind the server socket to server address and server port
|
||||
#serverSocket.bind((socket.gethostname(), 80))
|
||||
serverSocket.bind((sys.argv[1],80))
|
||||
print("binding socket")
|
||||
# 3. Continuously listen for connections to server socket
|
||||
serverSocket.listen(5)
|
||||
# 4. When a connection is accepted, call handleRequest function, passing new connection socket (see https://docs.python.org/3/library/socket.html#socket.socket.accept)
|
||||
newSocket= socket.accept()
|
||||
while True:
|
||||
handleRequest(newSocket)
|
||||
print("calling handleRequest")
|
||||
# 5. Close server socket
|
||||
serverSocket.close()
|
||||
|
||||
|
||||
class Proxy(NetworkApplication):
|
||||
|
||||
def __init__(self, args):
|
||||
print('Web Proxy starting on port: %i...' % (args.port))
|
||||
|
||||
#if __name__ == "__main__":
|
||||
# args=setupArgumentParser()
|
||||
# args.func(args)
|
||||
|
||||
#1. create server socket and listen - connectionless socket: used to establish a TCP connection with the HTTP server
|
||||
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
#2. Bind the server socket to server address and server port
|
||||
serverSocket.bind((socket.gethostname(), 80))
|
||||
#serverSocket.bind(('', args.port))
|
||||
#serverSocket.bind((sys.argv[1],80))
|
||||
print("binding socket")
|
||||
serverSocket.listen(5)
|
||||
#3. create proxy
|
||||
proxySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
proxySocket.bind((socket.gethostname(), args.port))
|
||||
# become a server socket
|
||||
proxySocket.listen(5)
|
||||
#4. Continuously listen for connections to server socket and proxy
|
||||
#5. When a connection is accepted, call handleRequest function, passing new connection socket (?)
|
||||
while 1:
|
||||
connectionSocket, addr = serverSocket.accept() # accept TCP connection from client
|
||||
with serverSocket.accept()[0] as connectionSocket: #pass new connection socket
|
||||
print("recieved connection from ", addr)
|
||||
handleRequest(proxySocket)
|
||||
print("calling handleRequest")
|
||||
# 5. Close server socket?
|
||||
serverSocket.close()
|
||||
|
||||
|
||||
def handleRequest(connectionSocket):
|
||||
#1. Receive request message from the client on connection socket
|
||||
# IPv4 address is 4 bytes in length
|
||||
bufferSize = connectionSocket.CMSG_SPACE(4)
|
||||
requestMessage = connectionSocket.recvmsg(bufferSize[0, [0]])
|
||||
#2. forward to proxy
|
||||
proxySocket.recvmsg(requestMessage)
|
||||
#3. proxy extracts the path of the requested object from the message (second part of the HTTP header)
|
||||
file = requestMessage.unpack_from( format, buffer, offset = 1) # returns a tuple
|
||||
filename= requestMessage.split()[1]
|
||||
#4. Read the corresponding file from disk: proxy server checks to see if object is stored locally
|
||||
try:
|
||||
fileOpen = open(filename[1:], "r") # open file in text mode
|
||||
outputdata = fileOpen.readlines()
|
||||
isObjectLocal == True
|
||||
# 1. if it does, the proxy server returns the object within a HTTP response message to the client browser
|
||||
httpResponse= ("GET /" + file + " HTTP/1.1\r\n\r\n")
|
||||
# 3. Read the corresponding file from disk
|
||||
socket.sendfile(object, offset = 0, count =None)
|
||||
#send via HTTP response message to client Browser
|
||||
|
||||
except IOError:
|
||||
if isObjectLocal == False:
|
||||
# 2. if it doesn’t, the proxy server opens a TCP connection to the origin server??
|
||||
originIP = serverSocket.gethostbyname(args.hostname)
|
||||
proxySocket.connect(originIP, port)
|
||||
# proxySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# bind the socket to a public host, and a well-known port
|
||||
# proxySocket.bind((socket.gethostname(), 80))
|
||||
#sends HTTP request for object
|
||||
httpRequest= ("GET /" + file + " HTTP/1.1\r\n\r\n")
|
||||
proxySocket.send(httpRequest.encode())
|
||||
#origin server recieves request
|
||||
connectionSocket.recvmessage(httpRequest.encode())
|
||||
|
||||
#5. Store in temporary buffer
|
||||
hostn = filename.split('/')[0].replace("www.","",1)
|
||||
connectionSocket.connect((hostn,80))
|
||||
# Create a temporary file on this socket
|
||||
tempObject = proxySocket.makefile('r', 0)
|
||||
tempObject.write("GET "+"http://" + filename + " HTTP/1.0\n\n")
|
||||
|
||||
#6. Send the correct HTTP response error
|
||||
httpRequest= ("GET /" + file + " HTTP/1.1\r\n\r\n")
|
||||
connectionSocket.send(httpRequest.encode())
|
||||
#connctionSocket.send("HTTP/1.1 200 OK\r\n\r\n")
|
||||
print("Request message sent")
|
||||
#7. send content to webserver
|
||||
object = connectionSocket.send(bufferSize[0, 0])
|
||||
serverSocket.recvmsg(object)
|
||||
#8. Send the content of the file to the socket
|
||||
|
||||
#9. Close the connection socket
|
||||
connectionSocket.close()
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args= setupArgumentParser()
|
||||
args.func(args)
|
||||
|
||||
def main():
|
||||
print("running")
|
||||
NetworkApplication()
|
BIN
hk1234566/python_networking/scc_203_practical_1_master.pdf
Normal file
BIN
hk1234566/python_networking/scc_203_practical_1_master.pdf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user