Compare commits

19 Commits

Author SHA1 Message Date
858bfef1bb Change how the text menu works. It is somewhat behind in that it does
not have all the same old functionality, but it uses menuitems now.
This will allow us to much-better utilize the textwindows.
2024-06-14 16:01:41 -05:00
deb5f29cee Changed some spaces to tabs. Happened automatically. 2024-06-11 09:22:13 -05:00
9aa26b82c6 make drawshape work better 2024-06-06 14:16:01 -07:00
726bafe580 Change drawshape to be drawhighlight as we pass it a highlight. 2024-06-06 13:59:59 -07:00
80c1abd5fe Trying to add a .editorconfig file for the Visual Studio editor. Visual
Studio keeps messing up the crlf.  Since I will mainly host this from a
Linux server, I want it to be just lf.
2024-06-03 15:41:16 -07:00
5ce6dc6d3e Moved actionStruct to be a class. Better that way 2024-05-31 17:12:00 -07:00
bf2e281c40 Use the translated version of the puzzle description. 2024-05-17 16:06:03 -06:00
98733d1ad5 Get basic problem translations. Ping only for now 2024-05-17 15:37:31 -06:00
0859bffc23 Put a selection-box around an item if we clicked on something 2024-05-17 10:33:33 -06:00
9be833dd2c Brought over the language strings from edunetworkbuilder and functions
for making language translation work.
2024-05-17 10:06:07 -06:00
0e9a6d1a15 Fixed a bug where clicking on a line would change how things were
viewed.  It turned out to be a rather bizarre bug based off of !== null
not working properly.
2024-05-16 12:13:41 -06:00
3e902cba95 Devices with problems properly have red background 2024-05-15 17:06:48 -06:00
77b034f845 Highlight items that have problems. 2024-05-10 15:03:52 -06:00
f3ed276ca9 Fixed not clearing the old highlights when we moused-off something. 2024-05-10 11:23:10 -06:00
7b57cbe97a Changing the highlight system to something that works for more cases.
We will highlight devices with problems and other things.
2024-05-10 11:00:42 -06:00
ee0a3f9255 Visual Studio complained about some of my tags in the index.html. So I
cleaned up what it was complaining about.
2024-05-10 09:22:50 -06:00
a19cb99b9d Getting it so we can click on devices. Mainly figuring stuff out.
Committing now because I am about to drive off and I want to have the
code-base up to date before I travel.
2024-04-30 17:38:31 -05:00
6119432875 Added lines to separate out portions of the screen. Also, I think ui.js
updated its crlfs.
2024-04-30 11:14:23 -05:00
84685e3bd4 Added a thumbs-up image to be used in a bit. Saw the visual studio
editor was madly messing up crlf and whatnot.  Changed it to be lf since
that is what we had started with.
2024-04-30 10:58:44 -05:00
12 changed files with 9892 additions and 239 deletions

4
Web/.editorconfig Normal file
View File

@ -0,0 +1,4 @@
root = true
[*]
end_of_line = lf

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
Web/img/thumb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -25,12 +25,13 @@
</form> </form>
--> -->
<canvas id='MainCanvas' width='700 ' height='400' style="border:1px solid #000000;"> <canvas id='MainCanvas' width='700 ' height='400' style="border:1px solid #000000;"></canvas>
<script src="allpuzzles.js"></script> <script src="allpuzzles.js"></script>
<script src="selectmenu.js"></script> <script src="selectmenu.js"></script>
<script src="network.js"></script> <script src="network.js"></script>
<script src="textwindow.js"></script> <script src="textwindow.js"></script>
<script src="language.js"></script>
<script src="ui.js"></script> <script src="ui.js"></script>
</body> </body>
</html> </html>

3995
Web/language.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,10 @@
//This file contains the information about the puzzle (network) //This file contains the information about the puzzle (network)
//Each puzzle is stored in the allpuzzles variable. We need to select one and use it //Each puzzle is stored in the allpuzzles variable. We need to select one and use it
//We define this here, even though it is used primarily in the UI. We define its values here
var ui_helplevel = 0;
var puzzle=networkFromName("Level0-Ping"); var puzzle=networkFromName("Level0-Ping");
//var puzzle=networkFromName("Level0-NeedsLink"); //var puzzle=networkFromName("Level0-NeedsLink");
//var puzzle=networkFromName("Level0_NetworkLoop"); //var puzzle=networkFromName("Level0_NetworkLoop");
@ -26,32 +30,126 @@ function switchPuzzle(target)
function networkFromName(what) function networkFromName(what)
{ {
let index=0; let index=0;
while (index < allpuzzles.length) { while (index < allpuzzles.length) {
//console.log(allpuzzles[index].EduNetworkBuilder.Network.name); //console.log(allpuzzles[index].EduNetworkBuilder.Network.name);
if(allpuzzles[index].EduNetworkBuilder.Network.name == what) if(allpuzzles[index].EduNetworkBuilder.Network.name == what)
{ {
console.log("Found " + what + " at index " + index); console.log("Found " + what + " at index " + index);
return structuredClone(allpuzzles[index].EduNetworkBuilder.Network); return networkFromIndex(index);
} }
index++; index++;
} }
} }
function networkFromIndex(what) function networkFromIndex(what)
{ {
if(typeof(what)==="number" && what >= 0 && what < allpuzzles.length){ if(typeof(what)==="number" && what >= 0 && what < allpuzzles.length){
return structuredClone(allpuzzles[what].EduNetworkBuilder.Network); var newitem = structuredClone(allpuzzles[what].EduNetworkBuilder.Network);
console.log("It is an array:" + Array.isArray(newitem.nettest));
if (!Array.isArray(newitem.nettest)) {
var oneitem = newitem.nettest; //this is an object
newitem.nettest = [];
newitem.nettest.push(oneitem); //make it an one-item array.
}
//Set the help level to be whatever we need
if (newitem.startinghelplevel == "full") ui_helplevel = 3;
if (newitem.startinghelplevel == "hints") ui_helplevel = 2;
if (newitem.startinghelplevel == "basic") ui_helplevel = 1;
if (newitem.startinghelplevel == "none") ui_helplevel = 0;
console.log("Starting help level = " + ui_helplevel + " from " + newitem.startinghelplevel);
return newitem;
} }
return null; return null;
} }
function deviceHasProblem(Device) {
var hostname = Device.hostname;
//console.log("Looking for tests on " + hostname + " and have: " + puzzle.nettest.length)
for (var index = 0; index < puzzle.nettest.length; index++) {
//console.log("Found test: " + JSON.stringify(puzzle.nettest));
if (puzzle.nettest[index].shost == hostname) {
if (puzzle.nettest[index].solved == null) {
//It has not yet been solved.
//console.log("Found problem on device: " + hostname);
return true;
}
}
}
return false;
}
function problemString(nettest) {
if (nettest == null) return "";
//The structure of a nettest
//"shost": "pc0",
//"dhost": "laptop0",
//"thetest": "SuccessfullyPings"
//if (ui_helplevel == 0) setStatus("There is a disturbance in the force. Guessing...");
//if (ui_helplevel == 1) setStatus("Service check detected a problem.");
//if (ui_helplevel == 2) setStatus("Someone submitted a trouble ticket.");
//if (ui_helplevel == 3) setStatus("Interviewed users for detailed info.");
switch (nettest.thetest) {
case "DHCPServerEnabled":
case "DeviceBlowsUpWithPower":
case "DeviceIsFrozen":
case "DeviceNeedsUPS":
case "FailedPing":
case "HelpRequest":
case "LockAll":
case "LockLocation":
case "LockNic":
case "LockVLANNames":
case "LockVLANsOnHost":
case "NeedsDefaultGW":
case "NeedsLinkToDevice":
case "NeedsLocalIPTo":
case "NeedsRouteToNet":
case "NeedsTaggedVLAN":
case "ReadContextHelp":
break;
case "SuccessfullyPings":
//level 0 is handled elsewhere
if (ui_helplevel == 2) return translator.getStr("NT_TstDiscriptPing");
if (ui_helplevel == 3) return translator.getStr("NT_TstDiscriptPing2") + nettest.dhost;
case "SuccessfullyPingsWithoutLoop":
case "SuccessfullyTraceroutes":
break;
}
return "";
}
function returnProblemStrings(Device) {
var hostname = Device.hostname;
var errors = [];
//console.log("Looking for tests on " + hostname + " and have: " + puzzle.nettest.length)
for (var index = 0; index < puzzle.nettest.length; index++) {
//console.log("Found test: " + JSON.stringify(puzzle.nettest));
if (puzzle.nettest[index].shost == hostname) {
if (puzzle.nettest[index].solved == null) {
//It has not yet been solved.
var error = problemString(puzzle.nettest[index]);
//console.log("We got a problem string:" + JSON.stringify(error));
if (error != "");
errors.push(error);
}
}
}
return errors;
}
function networkNamesMatchingText(textToMatch) function networkNamesMatchingText(textToMatch)
{ {
var list = []; var list = [];
var re = new RegExp(textToMatch); var re = new RegExp(textToMatch);
let index=0; let index=0;
while (index < allpuzzles.length) { while (index < allpuzzles.length) {
//console.log(allpuzzles[index].EduNetworkBuilder.Network.name); //console.log(allpuzzles[index].EduNetworkBuilder.Network.name);
if(re.test(allpuzzles[index].EduNetworkBuilder.Network.name)) if(re.test(allpuzzles[index].EduNetworkBuilder.Network.name))
{ {
@ -59,32 +157,32 @@ function networkNamesMatchingText(textToMatch)
list.push(allpuzzles[index].EduNetworkBuilder.Network.name); list.push(allpuzzles[index].EduNetworkBuilder.Network.name);
} }
index++; index++;
} }
return list; return list;
} }
function deviceFromName(what) function deviceFromName(what)
{ {
if (puzzle == null) return null; //If the puzzle has not been set, return a null if (puzzle == null) return null; //If the puzzle has not been set, return a null
let index=0; let index=0;
while (index < puzzle.device.length) { while (index < puzzle.device.length) {
if (puzzle.device[index].hostname == what) return puzzle.device[index]; //return the device that matches if (puzzle.device[index].hostname == what) return puzzle.device[index]; //return the device that matches
index++; index++;
} }
return null; //No match. return a null value return null; //No match. return a null value
} }
function deviceFromID(what) function deviceFromID(what)
{ {
if (puzzle == null) return null; //If the puzzle has not been set, return a null if (puzzle == null) return null; //If the puzzle has not been set, return a null
let index=0; let index=0;
while (index < puzzle.device.length) { while (index < puzzle.device.length) {
if (puzzle.device[index].uniqueidentifier == what) return puzzle.device[index]; //return the device that matches if (puzzle.device[index].uniqueidentifier == what) return puzzle.device[index]; //return the device that matches
index++; index++;
} }
return null; //No match. return a null value return null; //No match. return a null value
} }
//return a list of all the ip addresses a device has //return a list of all the ip addresses a device has
@ -121,7 +219,7 @@ function ipsFromInterface(what, nictype) {
}; };
ipaddresses.push(one); ipaddresses.push(one);
//console.log("found an ip object: " + JSON.stringify(one) + " " + nictype); //console.log("found an ip object: " + JSON.stringify(one) + " " + nictype);
} }
return ipaddresses; return ipaddresses;
} }

View File

@ -0,0 +1,40 @@
#!/usr/bin/perl
opendir(Dir, "Resources") || die "Can't open Resources directory: $!\n";
@files = grep(/edustrings/,readdir(Dir));
closedir(Dir);
open ($outfile, '>', "language.js") or die $!;
print($outfile "language = {\n");
foreach $file (@files) {
$lang = $file;
$lang =~ s/edustrings.//;
$lang =~ s/.json//;
print($outfile " $lang : {\n");
open my $info, "Resources/$file" or die "Could not open $file: $!";
while( my $line = <$info>) {
chomp($line);
if ( $line =~ /name": "(.*)",$/)
{
print($outfile " $1 : {");
}
if ( $line =~ /value": "(.*)",$/)
{
print($outfile "$line\n");
}
if ( $line =~ /value": "(.*)"$/) #if there is no comment
{
print($outfile "$line\n },\n");
}
if ( $line =~ /comment": "(.*)"$/)
{
print($outfile " $line\n },\n");
}
}
print($outfile " },\n"); #End the language file;
}
print($outfile "];\n"); #End the language variable definition
close($outfile);

View File

@ -0,0 +1,25 @@
#!/bin/bash
#
# Convert the EduNetworkBuilder language files into json
# Run this from the web directory, and make sure to have xq installed
if which xq >/dev/null; then
if [ -d Resources -a -d EduResources/languages ]; then
for a in EduResources/languages/*.resx; do
c=$a;
if [ $a = "EduResources/languages/edustrings.resx" ]; then
c="edustrings.en.resx"
fi
b=$(basename $c | sed 's/.resx/\.json/');
#if [ ! -e Resources/languages/$b ]; then
echo $b
xq '.root.data' $a |sed 's/\@name/name/' | grep -v 'xml:space' > Resources/$b
#fi
done
else
echo "You must be in the web directory of the EduNetworkBuilder git repo for this to work"
fi
else
echo "xq must be installed. This comes with the jq program"
echo "jq is used for working with json files and xq is the counterpart"
echo "that converts xml to json."
fi

View File

@ -17,7 +17,7 @@ var menuItemSize=50;
function InitializeSelectMenu() { function InitializeSelectMenu() {
cachedSelectMenuCanvas = document.createElement('canvas'); cachedSelectMenuCanvas = document.createElement('canvas');
cachedSelectMenuCanvas.width = menuItemSize; cachedSelectMenuCanvas.width = menuItemSize;
console.log("length= " + selectMenuNames.length); //console.log("length= " + selectMenuNames.length);
cachedSelectMenuCanvas.height = menuItemSize * selectMenuNames.length; cachedSelectMenuCanvas.height = menuItemSize * selectMenuNames.length;
var cSMCctx = cachedSelectMenuCanvas.getContext('2d'); var cSMCctx = cachedSelectMenuCanvas.getContext('2d');
var starty = 0; var starty = 0;
@ -32,19 +32,19 @@ function InitializeSelectMenu() {
function drawSelectMenu() function drawSelectMenu()
{ {
//console.log("Printing on main canvass"); //console.log("Printing on main canvass");
MainCanvas_ctx.fillStyle = maincanvasBackground; MainCanvas_ctx.fillStyle = maincanvasBackground;
MainCanvas_ctx.fillRect(0, 0, menuItemSize, MainCanvas.height); MainCanvas_ctx.fillRect(0, 0, menuItemSize, MainCanvas.height);
if (selectedMenuYOffset < 0) selectedMenuYOffset = 0; if (selectedMenuYOffset < 0) selectedMenuYOffset = 0;
if (cachedSelectMenuCanvas == null) InitializeSelectMenu();//initialize it if not done yet if (cachedSelectMenuCanvas == null) InitializeSelectMenu();//initialize it if not done yet
if(selectedMenuYOffset + MainCanvas.height > cachedSelectMenuCanvas.height) selectedMenuYOffset = cachedSelectMenuCanvas.height -MainCanvas.height; if(selectedMenuYOffset + MainCanvas.height > cachedSelectMenuCanvas.height) selectedMenuYOffset = cachedSelectMenuCanvas.height -MainCanvas.height;
MainCanvas_ctx.drawImage(cachedSelectMenuCanvas,0,selectedMenuYOffset,50,MainCanvas.height,0,0,50,MainCanvas.height); MainCanvas_ctx.drawImage(cachedSelectMenuCanvas,0,selectedMenuYOffset,50,MainCanvas.height,0,0,50,MainCanvas.height);
let index = selectMenuNames.indexOf(selectedMenuItemName); let index = selectMenuNames.indexOf(selectedMenuItemName);
if(index > -1) if(index > -1)
{ {
//We have a selected menu item //We have a selected menu item
const cachedSelectMenuCanvasOverlay = document.createElement('canvas'); const cachedSelectMenuCanvasOverlay = document.createElement('canvas');
let boxwidth=3; let boxwidth=3;
@ -59,60 +59,60 @@ function drawSelectMenu()
overlay.stroke(); overlay.stroke();
MainCanvas_ctx.drawImage(cachedSelectMenuCanvasOverlay,0,selectedMenuYOffset,50,MainCanvas.height,0,0,50,MainCanvas.height); MainCanvas_ctx.drawImage(cachedSelectMenuCanvasOverlay,0,selectedMenuYOffset,50,MainCanvas.height,0,0,50,MainCanvas.height);
//console.log("drawing select box around 0," + ty + " -> " + menuItemSize); //console.log("drawing select box around 0," + ty + " -> " + menuItemSize);
} }
//Now, if we have more to the top or bottom, draw the arrows showing as much //Now, if we have more to the top or bottom, draw the arrows showing as much
if(selectedMenuYOffset > (menuItemSize / 2)) if(selectedMenuYOffset > (menuItemSize / 2))
{ {
//We have one item above us. Draw the arrow //We have one item above us. Draw the arrow
//console.log("Drawing up arrow"); //console.log("Drawing up arrow");
MainCanvas_ctx.drawImage(imageFromName("ArrowUp"),0,0,50,25); MainCanvas_ctx.drawImage(imageFromName("ArrowUp"),0,0,50,25);
} }
//Now, if we have more to the top or bottom, draw the arrows showing as much //Now, if we have more to the top or bottom, draw the arrows showing as much
if(selectedMenuYOffset + (MainCanvas.height + 25) < cachedSelectMenuCanvas.height) if(selectedMenuYOffset + (MainCanvas.height + 25) < cachedSelectMenuCanvas.height)
{ {
//We have one item below us. Draw the arrow //We have one item below us. Draw the arrow
//console.log("Drawing down arrow"); //console.log("Drawing down arrow");
MainCanvas_ctx.drawImage(imageFromName("ArrowDown"),0,MainCanvas.height - 25,50,25); MainCanvas_ctx.drawImage(imageFromName("ArrowDown"),0,MainCanvas.height - 25,50,25);
} }
} }
function SelectMenu_handleMouseDown(evt) function SelectMenu_handleMouseDown(evt)
{ {
mouseDownLocation = copyLocation(evt); mouseDownLocation = copyLocation(evt);
mouseIsDown=true; mouseIsDown=true;
} }
function SelectMenu_handleMouseUp(evt) function SelectMenu_handleMouseUp(evt)
{ {
mouseIsDown=false; mouseIsDown=false;
//console.log("mouseup"); //console.log("mouseup");
//See if we have a mouse click //See if we have a mouse click
let deltaX = Math.abs(evt.pageX - mouseDownLocation.pageX); let deltaX = Math.abs(evt.pageX - mouseDownLocation.pageX);
let deltaY = Math.abs(evt.pageY - mouseDownLocation.pageY); let deltaY = Math.abs(evt.pageY - mouseDownLocation.pageY);
//console.log("delta " + deltaX + "," + deltaY); //console.log("delta " + deltaX + "," + deltaY);
if(deltaY < 3 && deltaX <3) if(deltaY < 3 && deltaX <3)
{ {
//We did not move much. Assume click //We did not move much. Assume click
if(evt.pageX <= menuItemSize && !mouseDidMovement) if(evt.pageX <= menuItemSize && !mouseDidMovement)
{ {
//We are in the item select menu. //We are in the item select menu.
let actualMenuLocation = selectedMenuYOffset + evt.pageY; let actualMenuLocation = selectedMenuYOffset + evt.pageY;
let newitemindex = Math.floor( actualMenuLocation / menuItemSize); let newitemindex = Math.floor( actualMenuLocation / menuItemSize);
console.log("clicked on item " + selectMenuNames[newitemindex]); console.log("clicked on item " + selectMenuNames[newitemindex]);
selectedMenuItemName = selectMenuNames[newitemindex]; selectedMenuItemName = selectMenuNames[newitemindex];
drawSelectMenu(); drawSelectMenu();
} }
} }
mouseDidMovement=false; //reset it after we raise the button mouseDidMovement=false; //reset it after we raise the button
} }
function SelectMenu_handleMouseMove(evt) function SelectMenu_handleMouseMove(evt)
{ {
if(mouseIsDown) if(mouseIsDown)
{ {
let deltaX = evt.pageX - mouseDownLocation.pageX; let deltaX = evt.pageX - mouseDownLocation.pageX;
let deltaY = evt.pageY - mouseDownLocation.pageY; let deltaY = evt.pageY - mouseDownLocation.pageY;
if(isNaN(deltaY)) deltaY=0; if(isNaN(deltaY)) deltaY=0;
@ -123,7 +123,7 @@ function SelectMenu_handleMouseMove(evt)
mouseDownLocation = copyLocation(evt); //reset the pointer mouseDownLocation = copyLocation(evt); //reset the pointer
drawSelectMenu(); drawSelectMenu();
mouseDidMovement=true; mouseDidMovement=true;
} }
} }
function copyLocation({ pageX, pageY }) { function copyLocation({ pageX, pageY }) {

View File

@ -19,9 +19,9 @@ var cachedTextMenuCanvas = null;
//Print the textmenu //Print the textmenu
function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1) function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
{ {
//It would be nice to print it on top of whatever is currently there. //It would be nice to print it on top of whatever is currently there.
//But we will do that later. //But we will do that later.
PrintScreen(0); //Print the network, then we can lay over it PrintScreen(0); //Print the network, then we can lay over it
if(cachedTextMenuCanvas == null) if(cachedTextMenuCanvas == null)
{ {
@ -34,8 +34,8 @@ function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
var rect; var rect;
//Fill in the background //Fill in the background
cTMCctx.fillStyle = tmWindowBackground; cTMCctx.fillStyle = tmWindowBackground;
cTMCctx.fillRect(0,0, cachedTextMenuCanvas.width, cachedTextMenuCanvas.height); cTMCctx.fillRect(0,0, cachedTextMenuCanvas.width, cachedTextMenuCanvas.height);
//Put the X there so we can click on it //Put the X there so we can click on it
rect = makeRectangle(cachedTextMenuCanvas.width - tmScrollBarWidth, 0, tmScrollBarWidth, tmMenuBarHight, tmOutsideXMargin, tmOutsideYMargin); rect = makeRectangle(cachedTextMenuCanvas.width - tmScrollBarWidth, 0, tmScrollBarWidth, tmMenuBarHight, tmOutsideXMargin, tmOutsideYMargin);
@ -49,7 +49,7 @@ function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
//Put the X there so we can click on it //Put the X there so we can click on it
cTMCctx.drawImage(imageFromName("ArrowDown"),cachedTextMenuCanvas.width - tmScrollBarWidth,cachedTextMenuCanvas.height - tmMenuBarHight,tmScrollBarWidth,tmMenuBarHight); cTMCctx.drawImage(imageFromName("ArrowDown"),cachedTextMenuCanvas.width - tmScrollBarWidth,cachedTextMenuCanvas.height - tmMenuBarHight,tmScrollBarWidth,tmMenuBarHight);
//Create and Draw the menu bar //Create and Draw the menu bar
cTMCctx.beginPath(); cTMCctx.beginPath();
cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth,0); cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth,0);
cTMCctx.lineTo(cachedTextMenuCanvas.width - tmScrollBarWidth,cachedTextMenuCanvas.height); cTMCctx.lineTo(cachedTextMenuCanvas.width - tmScrollBarWidth,cachedTextMenuCanvas.height);
@ -125,9 +125,9 @@ function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
//Write the text canvas on the main canvas. If we are scrolled up or down, do that. //Write the text canvas on the main canvas. If we are scrolled up or down, do that.
cTMCctx.drawImage(cachedTextMenuTextCanvas,0,0); cTMCctx.drawImage(cachedTextMenuTextCanvas,0,0);
//create and Draw the scroll-bar on the side //create and Draw the scroll-bar on the side
//Then make the text if we have not done so //Then make the text if we have not done so
//Finally print on top of the main canvas //Finally print on top of the main canvas
MainCanvas_ctx.globalAlpha = 0.9; //some transparancy MainCanvas_ctx.globalAlpha = 0.9; //some transparancy
MainCanvas_ctx.drawImage(cachedTextMenuCanvas,tmOutsideXMargin, tmOutsideYMargin) MainCanvas_ctx.drawImage(cachedTextMenuCanvas,tmOutsideXMargin, tmOutsideYMargin)
MainCanvas_ctx.globalAlpha = 1; //reset transparancy MainCanvas_ctx.globalAlpha = 1; //reset transparancy
@ -135,28 +135,28 @@ function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
function fragmentTextIntoLines(ctx, text, maxWidth) { function fragmentTextIntoLines(ctx, text, maxWidth) {
var words = text.split(" "); var words = text.split(" ");
var lines = []; var lines = [];
var currentLine = words[0]; var currentLine = words[0];
for (var i = 1; i < words.length; i++) { for (var i = 1; i < words.length; i++) {
var word = words[i]; var word = words[i];
var width = ctx.measureText(currentLine + " " + word).width; var width = ctx.measureText(currentLine + " " + word).width;
if (width < maxWidth) { if (width < maxWidth) {
currentLine += " " + word; currentLine += " " + word;
} else { } else {
lines.push(currentLine); lines.push(currentLine);
currentLine = word; currentLine = word;
} }
} }
lines.push(currentLine); lines.push(currentLine);
return lines; return lines;
} }
function TextWindow_handleMouseUp(evt) function TextWindow_handleMouseUp(evt)
{ {
console.log("TextWindow Mouse Up"); console.log("TextWindow Mouse Up");
//If we get here, it is a mouse-click event. See if we are on the X //If we get here, it is a mouse-click event. See if we are on the X
if(mouseDownLocation.pageX + tmScrollBarWidth >= cachedTextMenuCanvas.width - tmScrollBarWidth) if(mouseDownLocation.pageX + tmScrollBarWidth >= cachedTextMenuCanvas.width - tmScrollBarWidth)
{ {
console.log("TextWindow Mouse Up - X fits"); console.log("TextWindow Mouse Up - X fits");
@ -188,7 +188,7 @@ function TextWindow_handleMouseUp(evt)
} }
} }
} }
mouseDidMovement=false; //reset it after we raise the button mouseDidMovement=false; //reset it after we raise the button
} }
function textwindow_XClick(point, object) { function textwindow_XClick(point, object) {
@ -208,18 +208,202 @@ function PrintPuzzleSelectMenu(level=0)
{ {
var levellist=networkNamesMatchingText("Level"+level); var levellist=networkNamesMatchingText("Level"+level);
//console.log("list is this long: " + levellist.length); //console.log("list is this long: " + levellist.length);
textMenuPrint(levellist, -1, tmLastHighlightedIndex); //textMenuPrint(levellist, -1, tmLastHighlightedIndex);
tmPuzzleSelectMenuLevel=level; //tmPuzzleSelectMenuLevel=level;
//
var local_menuitems = [];
for (var i = 1; i < levellist.length; i++) {
var item = new menuitem(null, levellist[i], levellist[i], null, null, textMenu_PuzzleClick)
local_menuitems.push(item);
}
var local_menu = new menuclass(null);
local_menu.items = local_menuitems;
menuPrint(local_menu);
} }
function textMenu_PuzzleClick(text, name, source, dest) {
//If we get here, someone clicked on a puzzle name. Select it and move on
//We are in puzzle-select mode and clicked somewhere.
//if (text == null) { } //!== does not work properly
//else {
// console.log("Clicked on puzzle: " + text);
// uiMode = 1;
// switchPuzzle(text);
//}
}
function textMenu_HandleMouseMove(evt) function textMenu_HandleMouseMove(evt)
{ {
var highlighted_index = Math.floor(((evt.pageY - tmOutsideYMargin) - (tmTextHeight/3)) / tmTextHeight); //var highlighted_index = Math.floor(((evt.pageY - tmOutsideYMargin) - (tmTextHeight/3)) / tmTextHeight);
if(tmLastHighlightedIndex != highlighted_index) //if(tmLastHighlightedIndex != highlighted_index)
{ //{
//the index has changed // //the index has changed
console.log("index = " + highlighted_index); // console.log("index = " + highlighted_index);
tmLastHighlightedIndex = highlighted_index; // tmLastHighlightedIndex = highlighted_index;
PrintPuzzleSelectMenu(tmPuzzleSelectMenuLevel); // PrintPuzzleSelectMenu(tmPuzzleSelectMenuLevel);
//}
}
class menuitem {
constructor(rectangle, shownText, payloadName = null, payloadSource = null, payloadDest = null, clickFunc=null) {
this.rectangle = rectangle
this.shownText = shownText
this.payloadName = payloadName //The command, such as 'delete', 'power-on', 'ping', etc
this.payloadSource = payloadSource //The link, device, or original item.
this.payloadDest = payloadDest //The destination device, etc. Often null unless we are pinging or tracert
this.clickFunc = clickFunc
} }
} }
//Our menuclass will have a menu. We need to be able to have cascading menus (one on top of the other)
//so we can return to a past menu if we have moved on to a child menu.
class menuclass {
constructor(sourceItem) {
this.SourceItem = sourceItem
this.hmargin = 10 //horizontal margin on both left and right
this.vmargin = 10 //virtical margin on both top and bottom
this.backcolor = "grey" //The background color
this.font = "20px serif" //font and size
this.textcolor = "black" //Font color
this.items = [] //An array of menuitems
this.TextYGap = 3; //The gap to add to the size
}
}
function menuPrint(menu, menutop = 0, highlightedindex = -1) {
//the menu is the menuclass that holds everything
//menutop is the top=most item. If we scroll up and down, this changes.
//highlighted index is the item that has been moused-over. When this changes, re-draw the menu
PrintScreen(0); //Print the network, then we can lay over it
//This menu covers the entire place.
cachedTextMenuCanvas = document.createElement('canvas');
cachedTextMenuCanvas.width = MainCanvas.width - (tmOutsideXMargin * 2);
cachedTextMenuCanvas.height = MainCanvas.height - (tmOutsideYMargin * 2);
//Get the context
var cTMCctx = cachedTextMenuCanvas.getContext('2d');
var tw_rect;
var tw_width=0; //the width of the menu alltogether
var tw_height=0; //the height of the menu alltogether
var tw_itemHeight=0; //the height of both the font and margin spacing
var tw_rect; //the rectangle we end up using
//We need to figure out the size of the menu.
//Do we have an item to print? If so, add that at top
if (menu.SourceItem == null) {
//!== null does not work right
}
else {
tw_height = imageSize + 10;
}
var tw_startY = tw_height;
//Calculate the size of each text line
//Add spacing. If we are larger than the alloted space, add arrows at top and bottom
//Then we can fill in the area based on all of this.
cTMCctx.strokeStyle = menu.textcolor;
cTMCctx.font = menu.font;
var metrics = cTMCctx.measureText("test");
var yHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent + menu.TextYGap; //the hight of the default font and gap
var tw_TextHeight = yHeight; //store it for use
var maxWidth = 0;
//determine max width (width of longest text line)
for (var index = 0; index < menu.items.length; index++) {
var tmetrics = cTMCctx.measureText(menu.items[index].shownText);
var xWidth = tmetrics.width;
if (xWidth > maxWidth) maxWidth = xWidth;
}
maxWidth = maxWidth + 20 + menu.hmargin;
if (maxWidth > cachedTextMenuCanvas.width) maxWidth = cachedTextMenuCanvas.width;
tw_width = maxWidth;
//determine height (if we have more items than fit, figure out what will fit)
tw_height += menu.items.length * yHeight;
if(tw_height > cachedTextMenuCanvas.height) tw_height = cachedTextMenuCanvas.height;
//Now that we have the width and height, center it
var x = (cachedTextMenuCanvas.width - tw_width) / 2;
var y = (cachedTextMenuCanvas.height - tw_height) / 2;
//make a rectangle of the correct size
//Use that rectangle to place the closing X at the top
tw_rect = makeRectangle(x, y, tw_width, tw_height);
//fill in the whole thing with white and opaque
drawshape("square", makeRectangle(0, 0, cachedTextMenuCanvas.width, cachedTextMenuCanvas.height), "white", .5, cTMCctx);
//Fill in the background, nearly fully but showing a very little behind
drawshape("square", tw_rect, menu.backcolor, .9, cTMCctx);
//Put the X there so we can click on it
rect = makeRectangle(cachedTextMenuCanvas.width - tmScrollBarWidth, y, tmScrollBarWidth, tmMenuBarHight, tmOutsideXMargin, tmOutsideYMargin);
cTMCctx.drawImage(imageFromName("x"), rect.sx, rect.sy, rect.deltax, rect.deltay);
registerActionStruct("square", rect, null, textwindow_XClick);
//Put the UpArrow there so we can click on it
cTMCctx.drawImage(imageFromName("ArrowUp"), cachedTextMenuCanvas.width - tmScrollBarWidth, tmMenuBarHight, tmScrollBarWidth, tmMenuBarHight);
//Put the DownArrow there so we can click on it
cTMCctx.drawImage(imageFromName("ArrowDown"), cachedTextMenuCanvas.width - tmScrollBarWidth, cachedTextMenuCanvas.height - tmMenuBarHight, tmScrollBarWidth, tmMenuBarHight);
//Create and Draw the menu bar
cTMCctx.beginPath();
cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth, 0);
cTMCctx.lineTo(cachedTextMenuCanvas.width - tmScrollBarWidth, cachedTextMenuCanvas.height);
cTMCctx.strokeStyle = "white";
cTMCctx.stroke();
//horizontal line under the X
cTMCctx.beginPath();
cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth, tmMenuBarHight);
cTMCctx.lineTo(cachedTextMenuCanvas.width, tmMenuBarHight);
cTMCctx.strokeStyle = "white";
cTMCctx.stroke();
var oldfill = cTMCctx.fillStyle;
var oldstroke = cTMCctx.strokeStyle;
cTMCctx.font = menu.font;
cTMCctx.fillStyle = menu.textcolor;
cTMCctx.strokeStyle = menu.textcolor;
for (var index = menutop; index < menu.items.length; index++) {
var ty = tw_startY + (tw_TextHeight * (index - menutop));
//x is already defined
cTMCctx.fillText(menu.items[index].shownText, x, ty);
metrics = cTMCctx.measureText(menu.items[index].shownText);
var trect = makeRectangle(x + 20, ty, metrics.width, tw_TextHeight);
menu.items[index].rectangle = trect;
registerActionStruct("square", trect, menu.items[index], puzzle_clickOn, null, generic_mouseoverHighlight);
}
cTMCctx.fillStyle = oldfill;
cTMCctx.strokeStyle = oldstroke;
MainCanvas_ctx.globalAlpha = 0.9; //some transparancy
MainCanvas_ctx.drawImage(cachedTextMenuCanvas, tmOutsideXMargin, tmOutsideYMargin)
MainCanvas_ctx.globalAlpha = 1; //reset transparancy
}
function puzzle_clickOn(point, actionrec) {
console.log("clicking on puzzle:" + actionrec.theObject.shownText);
uiMode = 1;
switchPuzzle(actionrec.theObject.shownText);
}

588
Web/ui.js
View File

@ -8,11 +8,16 @@ var mouseIsDown=false;
var mouseDownLocation; var mouseDownLocation;
var mouseDidMovement=false; var mouseDidMovement=false;
var imageSize=40; var imageSize=40;
var small_button_size = 20; var small_button_size = 25;
var uiDeviceInfoLevel = 1; //What do we display when we look at the network var uiDeviceInfoLevel = 1; //What do we display when we look at the network
var uiActions = [];//a list of things on the screen we can click on or process. var uiActions = [];//a list of things on the screen we can click on or process.
var ui_highlightRect = null; var ui_highlightRect = null;
var ui_selectRect = null;
var ui_HadHighlight = false; var ui_HadHighlight = false;
var ui_status_height = 25;
var ui_StatusText = "";
var ui_HighlightArray = [];
var translator = new Language("en");
//The user interface mode. 0=network, 1=network information, 2=puzzle-selection menu //The user interface mode. 0=network, 1=network information, 2=puzzle-selection menu
var uiMode=1; var uiMode=1;
@ -29,7 +34,7 @@ const imageCollection = loadImages(
"tablet", "tree", "vidimage", "tablet", "tree", "vidimage",
"wap", "wbridge", "wrepeater", "wap", "wbridge", "wrepeater",
"wrouter", "x", "info", "menu", "wrouter", "x", "info", "menu",
"eye", "queryuser", "eye", "queryuser", "thumb",
], ],
["img/ArrowUp.png", "img/ArrowDown.png", "img/Animations.png", ["img/ArrowUp.png", "img/ArrowDown.png", "img/Animations.png",
"img/BurnMark.png", "img/cellphone.png", "img/Circle.png", "img/BurnMark.png", "img/cellphone.png", "img/Circle.png",
@ -42,92 +47,75 @@ const imageCollection = loadImages(
"img/VidImage.png", "img/WAP.png", "img/WBridge.png", "img/VidImage.png", "img/WAP.png", "img/WBridge.png",
"img/WRepeater.png", "img/WRouter.png", "img/X.png", "img/WRepeater.png", "img/WRouter.png", "img/X.png",
"img/info.png", "img/menu.png", "img/eye.png", "img/info.png", "img/menu.png", "img/eye.png",
"img/menu.png", "img/queryuser.png", "img/thumb.png",
], ],
InitializeGameMenu // this is called when all images have loaded. InitializeGameMenu // this is called when all images have loaded.
); );
var menuItemSize=50; var menuItemSize=50;
function loadImages(names, files, onAllLoaded) { function loadImages(names, files, onAllLoaded) {
var i = 0, numLoading = names.length; var i = 0, numLoading = names.length;
const onload = () => --numLoading === 0 && onAllLoaded(); const onload = () => --numLoading === 0 && onAllLoaded();
const images = {}; const images = {};
while (i < names.length) { while (i < names.length) {
const img = images[names[i]] = new Image; const img = images[names[i]] = new Image;
img.src = files[i++]; img.src = files[i++];
img.onload = onload; img.onload = onload;
} }
return images; return images;
} }
function imageFromName(name) function imageFromName(name)
{ {
return imageCollection[name]; return imageCollection[name];
} }
function InitializeGameMenu() function InitializeGameMenu()
{ {
console.log("Initializing"); console.log("Initializing");
MainCanvas.addEventListener("touchstart", handleTouchStart); MainCanvas.addEventListener("touchstart", handleTouchStart);
MainCanvas.addEventListener("touchend", handleTouchEnd); MainCanvas.addEventListener("touchend", handleTouchEnd);
MainCanvas.addEventListener("touchcancel", handleTouchCancel); MainCanvas.addEventListener("touchcancel", handleTouchCancel);
MainCanvas.addEventListener("touchmove", handleTouchMove); MainCanvas.addEventListener("touchmove", handleTouchMove);
MainCanvas.addEventListener('mousedown',handleMouseDown); MainCanvas.addEventListener('mousedown',handleMouseDown);
MainCanvas.addEventListener('mouseup',handleMouseUp); MainCanvas.addEventListener('mouseup',handleMouseUp);
MainCanvas.addEventListener('mousemove',handleMouseMove); MainCanvas.addEventListener('mousemove',handleMouseMove);
//MainCanvas_ctx.drawImage(imageCollection['router'],100,100,50,50); //MainCanvas_ctx.drawImage(imageCollection['router'],100,100,50,50);
//MainCanvas_ctx.drawImage(imageCollection['firewall'],150,150,50,50); //MainCanvas_ctx.drawImage(imageCollection['firewall'],150,150,50,50);
InitializeSelectMenu(); InitializeSelectMenu();
//It should be printed //It should be printed
PrintScreen(); PrintScreen();
} }
//Print the screen. Figure out what needs to be printed based on the mode //Print the screen. Figure out what needs to be printed based on the mode
function PrintScreen(WhatPassedIn=-1) function PrintScreen(WhatPassedIn=-1)
{ {
//allow us to override what is printed //allow us to override what is printed
var what=uiMode; var what=uiMode;
if(WhatPassedIn >=0) what=WhatPassedIn; if(WhatPassedIn >=0) what=WhatPassedIn;
//Clear out any old ActionStructs. They will get filled in as we print the screen. //Clear out any old ActionStructs. They will get filled in as we print the screen.
clearActionStructs(); clearActionStructs();
console.log("PrintingScreen for mode: " + what); //console.log("PrintingScreen for mode: " + what);
var rect; var rect;
if(what == 0) if(what == 0)
{ {
//The network drawing mode. Print the network //The network drawing mode. Print the network
//Clear the old screen //Clear the old screen
MainCanvas_ctx.fillStyle = maincanvasBackground; MainCanvas_ctx.fillStyle = maincanvasBackground;
MainCanvas_ctx.fillRect(0, 0, MainCanvas.width, MainCanvas.height); MainCanvas_ctx.fillRect(0, 0, MainCanvas.width, MainCanvas.height);
//Do any highlight we need to //Check for device highlights
if (ui_highlightRect !== null) { checkDevicesForIssues();
//console.log("trying to highlight something: " + JSON.stringify(ui_highlightRect));
MainCanvas_ctx.fillStyle = "white"; //print highlights. If we have mouseover highlights, note that.
MainCanvas_ctx.globalAlpha = 0.3; //mostly transparent if (printHighlights("mouseover") > 0) ui_HadHighlight = true;
if (ui_highlightRect.shapeText == "square")
MainCanvas_ctx.fillRect(ui_highlightRect.sx, ui_highlightRect.sy, ui_highlightRect.deltax, ui_highlightRect.deltay);
else if (ui_highlightRect.shapeText == "line") {
var oldWidth = MainCanvas_ctx.lineWidth;
MainCanvas_ctx.lineWidth += 4;
MainCanvas_ctx.strokeStyle = "white";
MainCanvas_ctx.beginPath();
MainCanvas_ctx.moveTo(ui_highlightRect.sx, ui_highlightRect.sy);
MainCanvas_ctx.lineTo(ui_highlightRect.dx, ui_highlightRect.dy);
MainCanvas_ctx.stroke();
MainCanvas_ctx.lineWidth = oldWidth;
MainCanvas_ctx.strokeStyle = "black";
}
MainCanvas_ctx.globalAlpha = 1.0; //reset
MainCanvas_ctx.fillStyle = "black"; //reset
ui_HadHighlight = true;
}
else ui_HadHighlight = false; else ui_HadHighlight = false;
//Draw the puzzle-select button //Draw the puzzle-select button
@ -146,6 +134,56 @@ function PrintScreen(WhatPassedIn=-1)
MainCanvas_ctx.drawImage(imageFromName("eye"), rect.sx, rect.sy, rect.deltax, rect.deltay); MainCanvas_ctx.drawImage(imageFromName("eye"), rect.sx, rect.sy, rect.deltax, rect.deltay);
registerActionStruct("square", rect, null, ui_eyeLeftClick, null, generic_mouseoverHighlight); registerActionStruct("square", rect, null, ui_eyeLeftClick, null, generic_mouseoverHighlight);
//Draw the help-level select button
rect = makeRectangle(MainCanvas.width - small_button_size, small_button_size * 3, small_button_size, small_button_size);
//Put any coloring behind the query-user image
var tmp_queryhighlight = null;
if (ui_helplevel == 0) tmp_queryhighlight = returnHighlightShape("square", rect, "red", "none", 0.3);
if (ui_helplevel == 1) tmp_queryhighlight = returnHighlightShape("square", rect, "orange", "none", 0.3);
if (ui_helplevel == 2) tmp_queryhighlight = returnHighlightShape("square", rect, "yellow", "none", 0.3);
if (ui_helplevel == 3) tmp_queryhighlight = returnHighlightShape("square", rect, "green", "none", 0.3);
if (tmp_queryhighlight == null) { }
else drawhighlight(tmp_queryhighlight);
MainCanvas_ctx.drawImage(imageFromName("queryuser"), rect.sx, rect.sy, rect.deltax, rect.deltay);
registerActionStruct("square", rect, null, ui_queryuserLeftClick, null, generic_mouseoverHighlight);
//Draw simple lines to show boundaries
//Select menu separation
MainCanvas_ctx.lineWidth = 2;
MainCanvas_ctx.strokeStyle = "white";
MainCanvas_ctx.beginPath();
MainCanvas_ctx.moveTo(menuItemSize, 0); //top side
MainCanvas_ctx.lineTo(menuItemSize, MainCanvas.height); //Bottom
MainCanvas_ctx.stroke();
//Right-side menu separator
MainCanvas_ctx.beginPath();
MainCanvas_ctx.moveTo(MainCanvas.width - small_button_size, 0); //top side
MainCanvas_ctx.lineTo(MainCanvas.width - small_button_size, MainCanvas.height - ui_status_height); //Bottom
MainCanvas_ctx.stroke();
//Status Bar separator
MainCanvas_ctx.beginPath();
MainCanvas_ctx.moveTo(menuItemSize, MainCanvas.height - ui_status_height); //top side
MainCanvas_ctx.lineTo(MainCanvas.width, MainCanvas.height - ui_status_height); //Bottom
MainCanvas_ctx.stroke();
var statustext = puzzle.name + ": " + ui_StatusText;
printLeftJustifiedText(MainCanvas_ctx, statustext, menuItemSize + 5, (MainCanvas.height - ui_status_height) + 7);
MainCanvas_ctx.strokeStyle = "black";
if (ui_selectRect == null) { }
else {
//console.log("We have something selected.");
var tmp_select = returnHighlightShape("selectbox", ui_selectRect, "green", "none", 0.8);
drawhighlight(tmp_select);
}
drawSelectMenu(); drawSelectMenu();
PrintAllNetworkLinks(); PrintAllNetworkLinks();
PrintAllNetworkDevices(); PrintAllNetworkDevices();
@ -153,7 +191,8 @@ function PrintScreen(WhatPassedIn=-1)
else if(what == 1) //PuzzleDescription/Info else if(what == 1) //PuzzleDescription/Info
{ {
//Display the text about the puzzle //Display the text about the puzzle
textMenuPrint(puzzle.en_message); console.log("Using language: " + ui_language);
textMenuPrint(eval('puzzle.' + ui_language + '_message'));
} }
else if(what == 2) //PuzzleSelect else if(what == 2) //PuzzleSelect
{ {
@ -164,33 +203,33 @@ function PrintScreen(WhatPassedIn=-1)
function handleTouchStart(evt) function handleTouchStart(evt)
{ {
handleMouseDown(copyLocation(evt)); handleMouseDown(copyLocation(evt));
} }
function handleTouchEnd(evt) function handleTouchEnd(evt)
{ {
handleMouseUp(copyLocation(evt)); handleMouseUp(copyLocation(evt));
} }
function handleTouchCancel(evt) function handleTouchCancel(evt)
{ {
evt.preventDefault(); evt.preventDefault();
console.log("canceling touch"); console.log("canceling touch");
} }
function handleTouchMove(evt) function handleTouchMove(evt)
{ {
//evt.preventDefault(); //evt.preventDefault();
if(evt.touches.length > 0) if(evt.touches.length > 0)
{ {
handleMouseMove(copyLocation(evt.touches[0])); handleMouseMove(copyLocation(evt.touches[0]));
} else{ } else{
//console.log("not enough touches"); //console.log("not enough touches");
} }
//console.log("moving touch"); //console.log("moving touch");
} }
function handleMouseDown(evt) function handleMouseDown(evt)
{ {
mouseDownLocation = copyLocation(evt); mouseDownLocation = copyLocation(evt);
mouseIsDown=true; mouseIsDown=true;
//console.log("mousedown"); //console.log("mousedown");
if(uiMode==0) SelectMenu_handleMouseDown(mouseDownLocation); if(uiMode==0) SelectMenu_handleMouseDown(mouseDownLocation);
} }
@ -199,9 +238,10 @@ function CheckForActions(actionPoint, action) {
var checkit = false; var checkit = false;
var inside = false; var inside = false;
for (var index = 0; index < uiActions.length; index++) { for (var index = 0; index < uiActions.length; index++) {
if (action == "leftclick" && uiActions[index].funcLeftClick !== null) checkit = true; checkit = true;
if (action == "rightclick" && uiActions[index].funcRightClick !== null) checkit = true; if (action == "leftclick" && uiActions[index].funcLeftClick == null) checkit = false;
if (action == "mouseover" && uiActions[index].funcMouseover !== null) checkit = true; if (action == "rightclick" && uiActions[index].funcRightClick == null) checkit = false;
if (action == "mouseover" && uiActions[index].funcMouseover == null) checkit = false;
checklocation = uiActions[index]; checklocation = uiActions[index];
var point = newPointFromPair(actionPoint.pageX - checklocation.shapePoints.offsetx, actionPoint.pageY - checklocation.shapePoints.offsety); var point = newPointFromPair(actionPoint.pageX - checklocation.shapePoints.offsetx, actionPoint.pageY - checklocation.shapePoints.offsety);
if (checkit) { if (checkit) {
@ -229,14 +269,16 @@ function CheckForActions(actionPoint, action) {
//console.log("Is inside"); //console.log("Is inside");
switch (action) { switch (action) {
case "leftclick": case "leftclick":
if (checklocation.funcLeftClick != null) { if (checklocation.funcLeftClick == null) { }
else {
checklocation.funcLeftClick(actionPoint, checklocation); checklocation.funcLeftClick(actionPoint, checklocation);
//console.log("Successfully did a UI action"); //console.log("Successfully did a left-click UI action");
return true; return true;
} }
break; break;
case "mouseover": case "mouseover":
if (checklocation.funcMouseover != null) { if (checklocation.funcMouseover == null) { }
else {
checklocation.funcMouseover(actionPoint, checklocation); checklocation.funcMouseover(actionPoint, checklocation);
//console.log("Successfully did a UI action"); //console.log("Successfully did a UI action");
return true; return true;
@ -269,14 +311,14 @@ function distance(x1, y1, x2, y2) {
function handleMouseUp(evt) function handleMouseUp(evt)
{ {
//evt.preventDefault(); //evt.preventDefault();
mouseIsDown=false; mouseIsDown = false;
//See if we have a mouse click //See if we have a mouse click
let deltaX = Math.abs(evt.pageX - mouseDownLocation.pageX); let deltaX = Math.abs(evt.pageX - mouseDownLocation.pageX);
let deltaY = Math.abs(evt.pageY - mouseDownLocation.pageY); let deltaY = Math.abs(evt.pageY - mouseDownLocation.pageY);
//console.log("delta " + deltaX + "," + deltaY); //console.log("delta " + deltaX + "," + deltaY);
if(deltaY < 3 && deltaX <3) if(deltaY < 3 && deltaX <3)
{ {
//We did not move much. Assume click //We did not move much. Assume click
if(evt.pageX <= menuItemSize && !mouseDidMovement) if(evt.pageX <= menuItemSize && !mouseDidMovement)
{ {
@ -287,14 +329,21 @@ function handleMouseUp(evt)
if(!mouseDidMovement) if(!mouseDidMovement)
{ //If we are not dragging, it is a click { //If we are not dragging, it is a click
var myevt = copyLocation(evt); var myevt = copyLocation(evt);
var needsrefresh = true;;
if (ui_selectRect == null) needsrefresh = false;
ui_selectRect = null; //remove any previous selected marker
//console.log("evt:" + JSON.stringify(myevt)); //console.log("evt:" + JSON.stringify(myevt));
if (CheckForActions(myevt, "leftclick")) return; //If we did this, do not do anything else. if (CheckForActions(myevt, "leftclick")) return; //If we did this, do not do anything else.
if(uiMode==1) TextWindow_handleMouseUp(evt); if(uiMode==1) TextWindow_handleMouseUp(evt);
else if(uiMode==2) TextWindow_handleMouseUp(evt); else if (uiMode == 2) TextWindow_handleMouseUp(evt);
if (needsrefresh) {
if (ui_selectRect == null) setStatus(""); //we clicked on nothing
PrintScreen();
}
} }
} }
mouseDidMovement=false; //reset it after we raise the button mouseDidMovement=false; //reset it after we raise the button
} }
function ui_PuzzleChoiceMenuLeftClick(evt) { function ui_PuzzleChoiceMenuLeftClick(evt) {
@ -312,6 +361,19 @@ function ui_eyeLeftClick(evt) {
PrintScreen(); PrintScreen();
} }
function ui_queryuserLeftClick(evt) {
console.log("Selected 'queryuser' button in action");
//It is the eye button
ui_helplevel++;
if (ui_helplevel > 3) ui_helplevel = 0;
if (ui_helplevel == 0) setStatus("There is a disturbance in the force. Guessing...");
if (ui_helplevel == 1) setStatus("Service check detected a problem.");
if (ui_helplevel == 2) setStatus("Someone submitted a trouble ticket.");
if (ui_helplevel == 3) setStatus("Interviewed users for detailed info.");
PrintScreen();
}
function ui_InfoLeftClick(evt) { function ui_InfoLeftClick(evt) {
console.log("Selected info button in action"); console.log("Selected info button in action");
//It is the info button //It is the info button
@ -321,9 +383,9 @@ function ui_InfoLeftClick(evt) {
function handleMouseMove(evt) function handleMouseMove(evt)
{ {
//evt.preventDefault(); //evt.preventDefault();
if(mouseIsDown) if(mouseIsDown)
{ {
let deltaX = evt.pageX - mouseDownLocation.pageX; let deltaX = evt.pageX - mouseDownLocation.pageX;
let deltaY = evt.pageY - mouseDownLocation.pageY; let deltaY = evt.pageY - mouseDownLocation.pageY;
if(isNaN(deltaY)) deltaY=0; if(isNaN(deltaY)) deltaY=0;
@ -340,22 +402,22 @@ function handleMouseMove(evt)
else //Mouse is not down. Not dragging else //Mouse is not down. Not dragging
{ {
var needrefresh = false; var needrefresh = false;
var oldRect = structuredClone(ui_highlightRect); var oldRect = structuredClone(findHighlightsNamed("mouseover"));
removeHighlightsNamed("mouseover");
if (!CheckForActions(evt, "mouseover")) { if (!CheckForActions(evt, "mouseover")) {
//We did not find anything //We did not find anything
if (JSON.stringify(ui_highlightRect) === JSON.stringify(oldRect)) { if (oldRect == null) {
} }
else { else {
//console.log("Rects are not equal:" + JSON.stringify(ui_highlightRect) + " - " + JSON.stringify(oldRect) ) //We used to have a highlight, but it was removed
needrefresh = true; needrefresh = true;
} }
ui_highlightRect = null; //nothing to highlight
if (ui_HadHighlight) { needrefresh = true; } if (ui_HadHighlight) { needrefresh = true; }
if (needrefresh) { if (needrefresh) {
PrintScreen(); PrintScreen();
} }
} }
if(uiMode==2) if(uiMode==2)
{ {
textMenu_HandleMouseMove(evt); textMenu_HandleMouseMove(evt);
@ -371,9 +433,9 @@ function copyLocation({ pageX, pageY }) {
function PrintNetworkLink(linkToPrint) function PrintNetworkLink(linkToPrint)
{ {
//We should have passed in a working link, make sure it exists //We should have passed in a working link, make sure it exists
if(linkToPrint !== null) if(linkToPrint !== null)
{ {
if(linkToPrint.SrcNic !== null && linkToPrint.DestNic !== null) if(linkToPrint.SrcNic !== null && linkToPrint.DestNic !== null)
{ {
//console.log("printing link from " + linkToPrint.SrcNic.hostname); //console.log("printing link from " + linkToPrint.SrcNic.hostname);
@ -403,9 +465,9 @@ function PrintNetworkLink(linkToPrint)
function PrintAllNetworkLinks() function PrintAllNetworkLinks()
{ {
if (puzzle == null) return; //If the puzzle has not been set, exit if (puzzle == null) return; //If the puzzle has not been set, exit
let index=0; let index=0;
if(puzzle.link !== null && typeof(puzzle.link) === "object") if(puzzle.link !== null && typeof(puzzle.link) === "object")
{ {
while (index < puzzle.link.length) { while (index < puzzle.link.length) {
@ -417,9 +479,9 @@ function PrintAllNetworkLinks()
function PrintNetworkDevice(ToPrint) function PrintNetworkDevice(ToPrint)
{ {
//We should have passed in a working device, make sure it exists //We should have passed in a working device, make sure it exists
if(ToPrint !== null) if(ToPrint !== null)
{ {
var rect = deviceRectangle(ToPrint); var rect = deviceRectangle(ToPrint);
var actionrect = makeRectangle(rect.spoint.x, rect.spoint.y, rect.width, rect.height); var actionrect = makeRectangle(rect.spoint.x, rect.spoint.y, rect.width, rect.height);
@ -427,8 +489,14 @@ function PrintNetworkDevice(ToPrint)
if(dname=="net_switch") dname="switch"; if(dname=="net_switch") dname="switch";
if(dname=="net_hub") dname="hub"; if(dname=="net_hub") dname="hub";
//console.log("printing device " + dname); //console.log("printing device " + dname);
if (deviceHasProblem(ToPrint)) {
var thshape = returnHighlightShape("square", actionrect, "red", "problem", 0.2);
drawhighlight(thshape);
}
MainCanvas_ctx.drawImage(imageFromName(dname), rect.spoint.x, rect.spoint.y, rect.width, rect.height); MainCanvas_ctx.drawImage(imageFromName(dname), rect.spoint.x, rect.spoint.y, rect.width, rect.height);
registerActionStruct("square", actionrect, ToPrint, null, null, generic_mouseoverHighlight); registerActionStruct("square", actionrect, ToPrint, device_clickOn, null, generic_mouseoverHighlight);
//Now, we see if we need to print the name, or a list of IPs.. //Now, we see if we need to print the name, or a list of IPs..
var xpoint = rect.center.x; var xpoint = rect.center.x;
@ -465,22 +533,45 @@ function PrintNetworkDevice(ToPrint)
delta = printCenteredText(MainCanvas_ctx, mystring, xpoint, ystart); delta = printCenteredText(MainCanvas_ctx, mystring, xpoint, ystart);
ystart += (delta / 2); ystart += (delta / 2);
break; break;
} }
} }
break; break;
} }
} }
}
function checkDevicesForIssues()
{
return; //Doing it a different way
if (puzzle == null) return; //If the puzzle has not been set, exit
removeHighlightsNamed("problem");
//console.log("Looking for problems in devices." + puzzle.device.length);
let index = 0;
while (index < puzzle.device.length) {
if (deviceHasProblem(puzzle.device[index])) {
console.log("Found a problem. Registering it...");
var actionrect = deviceRectangle(puzzle.device[index]);
//If the help level is bigger than 0 (guessing), show which devices have problems
if (ui_helplevel > 0) {
var answer = registerHighlightShape("square", actionrect, "red", "problem", 0.2);
console.log("registered it." + JSON.stringify(answer));
}
}
index++;
}
} }
function PrintAllNetworkDevices() function PrintAllNetworkDevices()
{ {
if (puzzle == null) return; //If the puzzle has not been set, exit if (puzzle == null) return; //If the puzzle has not been set, exit
let index=0; let index = 0;
while (index < puzzle.device.length) { while (index < puzzle.device.length) {
PrintNetworkDevice(puzzle.device[index]); PrintNetworkDevice(puzzle.device[index]);
index++; index++;
} }
} }
//print centered text. We use y as the top-most y position. But we center around the x position //print centered text. We use y as the top-most y position. But we center around the x position
@ -505,52 +596,74 @@ function printCenteredText(canvas_context, text, centerx, top_y, font = "15px se
return yHeight; //report back how much space we used. Just in case they want it. return yHeight; //report back how much space we used. Just in case they want it.
} }
//print text. We use y as the top-most y position.
function printLeftJustifiedText(canvas_context, text, LeftX, top_y, font = "15px serif", textcolor = "black") {
var metrics = canvas_context.measureText(text);
var yHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent + tmTextYGap;
var xWidth = metrics.width;
var oldfill = canvas_context.fillStyle;
var oldstroke = canvas_context.strokeStyle;
canvas_context.font = font;
canvas_context.fillStyle = textcolor;
canvas_context.strokeStyle = textcolor;
canvas_context.fillText(text, LeftX, top_y + (yHeight / 3));
//reset stuff when done
canvas_context.fillStyle = oldfill;
canvas_context.strokeStyle = oldstroke;
return yHeight; //report back how much space we used. Just in case they want it.
}
function convertXYPointToActual(point) function convertXYPointToActual(point)
{ {
//We have an x and y coordinate which needs to be converted to the canvas size //We have an x and y coordinate which needs to be converted to the canvas size
var deltax = (MainCanvas.width - menuItemSize) / puzzle.width; var deltax = (MainCanvas.width - menuItemSize) / puzzle.width;
var deltay = MainCanvas.height / puzzle.height; var deltay = MainCanvas.height / puzzle.height;
return newPointFromPair((point.x * deltax) + menuItemSize, point.y * deltay); return newPointFromPair((point.x * deltax) + menuItemSize, point.y * deltay);
} }
function convertXYpairToActual(x,y) function convertXYpairToActual(x,y)
{ {
return convertXYPointToActual(newPointFromPair(x,y)); return convertXYPointToActual(newPointFromPair(x,y));
} }
function newPointFromPair(x,y) function newPointFromPair(x,y)
{ {
var point = { var point = {
'x' : Math.floor(x), 'x' : Math.floor(x),
'y' : Math.floor(y) 'y' : Math.floor(y)
} }
return point; return point;
} }
function newPointFromString(pointasstring) function newPointFromString(pointasstring)
{ {
if(typeof(pointasstring) == "string") if(typeof(pointasstring) == "string")
{ {
var tarray=pointasstring.split(","); var tarray=pointasstring.split(",");
return newPointFromPair(Number(tarray[0]),Number(tarray[1])); return newPointFromPair(Number(tarray[0]),Number(tarray[1]));
} }
} }
//return a rectangle for the device //return a rectangle for the device
function deviceRectangle(theDevice) function deviceRectangle(theDevice)
{ {
var centerpoint = convertXYPointToActual(newPointFromString(theDevice.location)); var centerpoint = convertXYPointToActual(newPointFromString(theDevice.location));
var delta = imageSize / 2; var delta = imageSize / 2;
var rect = { var rect = {
spoint : newPointFromPair(centerpoint.x-delta, centerpoint.y-delta), spoint : newPointFromPair(centerpoint.x-delta, centerpoint.y-delta),
height : imageSize, height : imageSize,
width : imageSize, width : imageSize,
epoint : newPointFromPair(centerpoint.x + delta, centerpoint.y + delta), epoint : newPointFromPair(centerpoint.x + delta, centerpoint.y + delta),
center: centerpoint, center: centerpoint,
} }
return rect; return rect;
} }
function makeRectangle(x1, y1, deltax, deltay, offsetx = 0, offsety = 0) { function makeRectangle(x1, y1, deltax, deltay, offsetx = 0, offsety = 0) {
@ -575,22 +688,22 @@ function makeLine(x1, y1, x2, y2, offsetx = 0, offsety = 0) {
} }
//Make a structure to hold all our data //Make a structure to hold all our data
function actionStruct(shapeText, shapePoints, theObject=null, funcLeftClick=null, funcRightClick=null, funcMouseover=null) { class actionStruct {
var struct = { constructor(shapeText, shapePoints, theObject=null, funcLeftClick=null, funcRightClick=null, funcMouseover=null) {
shapeText: shapeText,
shapePoints: structuredClone(shapePoints), this.shapeText= shapeText
theObject: theObject, this.shapePoints= structuredClone(shapePoints)
funcLeftClick: funcLeftClick, this.shapePoints.shapeText = shapeText;
funcRightClick: funcRightClick, this.theObject= theObject
funcMouseover: funcMouseover, this.funcLeftClick= funcLeftClick
this.funcRightClick= funcRightClick
this.funcMouseover= funcMouseover
} }
shapePoints.shapeText = shapeText;
return struct;
} }
function registerActionStruct(shapeText, shapePoints, theObject=null, funcLeftClick=null, funcRightClick=null, funcMouseover=null) { function registerActionStruct(shapeText, shapePoints, theObject=null, funcLeftClick=null, funcRightClick=null, funcMouseover=null) {
//Make an object with all the data //Make an object with all the data
var what = actionStruct(shapeText, shapePoints, theObject, funcLeftClick, funcRightClick, funcMouseover); var what = new actionStruct(shapeText, shapePoints, theObject, funcLeftClick, funcRightClick, funcMouseover);
//console.log("Pushing an action: " + shapeText); //console.log("Pushing an action: " + shapeText);
//Push it onto the uiActions list //Push it onto the uiActions list
uiActions.unshift(what); //Put it at the beginning of the list uiActions.unshift(what); //Put it at the beginning of the list
@ -601,24 +714,215 @@ function clearActionStructs() {
uiActions = []; uiActions = [];
} }
function setStatus(text) {
ui_StatusText = text; //set the text.
}
//go through all highlights and print all of them
function printHighlights(countof="mouseover") {
var count = 0;
//console.log("Printing highlights. " + ui_HighlightArray.length)
for (var index = 0; index < ui_HighlightArray.length; index++) {
var highlight = ui_HighlightArray[index];
//console.log("trying to highlight something: " + JSON.stringify(highlight));
if (highlight.shapeName == countof) count++;
drawhighlight(highlight);
}
return countof; //the count of the item we were supposed to count
}
function drawhighlight(highlight, canvas = null) {
if (canvas == null)
canvas = MainCanvas_ctx;
canvas.fillStyle = highlight.shapeColor;
canvas.globalAlpha = highlight.opaciticy; //mostly transparent
var oldWidth;
if (highlight.shapeText == "square")
canvas.fillRect(highlight.shapePoints.sx, highlight.shapePoints.sy, highlight.shapePoints.deltax, highlight.shapePoints.deltay);
else if (highlight.shapeText == "line") {
oldWidth = canvas.lineWidth;
canvas.lineWidth += 6;
canvas.strokeStyle = highlight.shapeColor;
canvas.beginPath();
canvas.moveTo(highlight.shapePoints.sx, highlight.shapePoints.sy);
canvas.lineTo(highlight.shapePoints.dx, highlight.shapePoints.dy);
canvas.stroke();
canvas.lineWidth = oldWidth;
canvas.strokeStyle = "black";
}
else if (highlight.shapeText == "selectbox") {
//console.log("Printing a selectbox");
canvas.fillStyle = "green";
oldWidth = canvas.lineWidth;
canvas.lineWidth += 2;
canvas.strokeStyle = "green";
canvas.beginPath();
canvas.moveTo(highlight.shapePoints.sx, highlight.shapePoints.sy);
canvas.lineTo(highlight.shapePoints.dx, highlight.shapePoints.sy);
canvas.lineTo(highlight.shapePoints.dx, highlight.shapePoints.dy);
canvas.lineTo(highlight.shapePoints.sx, highlight.shapePoints.dy);
canvas.lineTo(highlight.shapePoints.sx, highlight.shapePoints.sy);
canvas.stroke();
canvas.lineWidth = oldWidth;
canvas.strokeStyle = "black";
}
canvas.globalAlpha = 1.0; //reset
canvas.fillStyle = "black"; //reset
}
//We use drawhighlight to draw one-off shapes
function drawshape( shape, rect, color, opaciticy = 0.4, canvas = null) {
if (canvas == null)
canvas = MainCanvas_ctx;
var tmp_queryhighlight = returnHighlightShape(shape, rect, color, "none", opaciticy);
drawhighlight(tmp_queryhighlight, canvas);
}
function countHighlightsNamed(countof = "mouseover") {
var count = 0;
for (var index = 0; index < ui_HighlightArray.length; index++) {
if (ui_HighlightArray[index].shapeName == countof)
count++;
}
return countof; //the count of the item we were supposed to count
}
function returnHighlightShape(shapeText, shapePoints, shapeColor, shapeName, opaciticy = 0.4) {
//Create a highlight record with the needed info
var newhighlight = {
shapeText: shapeText,
shapePoints: structuredClone(shapePoints),
shapeColor: shapeColor,
shapeName: shapeName, //Used when we remove them later
opaciticy, opaciticy,
}
return newhighlight;
}
//There may be multiple things
function registerHighlightShape(shapeText, shapePoints, shapeColor, shapeName, opaciticy=0.4) {
//Create a highlight record with the needed info
var newhighlight = returnHighlightShape(shapeText, structuredClone(shapePoints), shapeColor, shapeName, opaciticy)
//console.log("registering a highlight: " + JSON.stringify(newhighlight));
//Add it to the list of highlights.
ui_HighlightArray.unshift(newhighlight);
return newhighlight;
}
function removeHighlightsNamed(shapeName) {
//console.log("Trying to remove " + shapeName + " in array of " + ui_HighlightArray.length);
for (var index = ui_HighlightArray.length; index >= 0; index--) {
if (ui_HighlightArray[index] == null) { }
else {
//console.log("Comparing " + shapeName + " in " + JSON.stringify(ui_HighlightArray[index]));
if (ui_HighlightArray[index].shapeName == shapeName) {
//console.log("removing " + shapeName + " at index:" + index + " " + ui_HighlightArray.length);
ui_HighlightArray.splice(index, 1); //remove it if found
}
}
}
}
function findHighlightsNamed(shapeName) {
for (var index = ui_HighlightArray.length; index >= 0; index--) {
if (ui_HighlightArray[index] == null) { }
else {
if (ui_HighlightArray[index].shapeName == shapeName)
return ui_HighlightArray[index];
}
}
return null; //null if not there
}
//This takes generic information for us to highlight the background //This takes generic information for us to highlight the background
function generic_mouseoverHighlight(point, actionrec) { function generic_mouseoverHighlight(point, actionrec) {
//console.log("Found highlight " + JSON.stringify(actionrec)); //console.log("Found highlight " + JSON.stringify(actionrec));
//The point is the place where the mouse is, but the actionrec.shapePoints is the rectangle (or shape) we want to highlight //The point is the place where the mouse is, but the actionrec.shapePoints is the rectangle (or shape) we want to highlight
var oldrec = structuredClone(ui_highlightRect); //var oldrec = structuredClone(ui_highlightRect);
var oldrec = findHighlightsNamed("mouseover");
var newrec = null;
//console.log("setting highlights to:" + JSON.stringify(actionrec));
removeHighlightsNamed("mouseover");
if (actionrec.shapeText == "square") { if (actionrec.shapeText == "square") {
ui_highlightRect = structuredClone(actionrec.shapePoints); //ui_highlightRect = structuredClone(actionrec.shapePoints);
ui_highlightRect.shapeText = "square"; //ui_highlightRect.shapeText = "square";
newrec = registerHighlightShape("square", actionrec.shapePoints, "white", "mouseover"); //opacity is default
//console.log("setting highlights to:" + JSON.stringify(ui_highlightRect)); //console.log("setting highlights to:" + JSON.stringify(ui_highlightRect));
} }
if (actionrec.shapeText == "line") { if (actionrec.shapeText == "line") {
ui_highlightRect = structuredClone(actionrec.shapePoints); //ui_highlightRect = structuredClone(actionrec.shapePoints);
ui_highlightRect.shapeText = "line"; //ui_highlightRect.shapeText = "line";
newrec = registerHighlightShape("line", actionrec.shapePoints, "white", "mouseover"); //opacity is default
//console.log("setting highlights to:" + JSON.stringify(ui_highlightRect)); //console.log("setting highlights to:" + JSON.stringify(ui_highlightRect));
} }
if (JSON.stringify(ui_highlightRect) === JSON.stringify(oldrec)) { if (JSON.stringify(newrec) === JSON.stringify(oldrec)) {
//they are the same. Nothing to do //they are the same. Nothing to do
} }
else else
PrintScreen(); //two different areas. Need to print the screen PrintScreen(); //two different areas. Need to print the screen
} }
function device_clickOn(point, actionrec) {
if (actionrec.theObject !== null && actionrec.theObject.name !== null) {
ui_selectRect = structuredClone(actionrec.shapePoints);
//console.log("Setting select rect:" + JSON.stringify(ui_selectRect));
var ipaddresses = ipsFromDevice(actionrec.theObject);
var additional = "";
for (var x = 0; x < ipaddresses.length; x++) {
//Print the IP address if the type is correct.
//console.log(JSON.stringify(ipaddresses[x]));
switch (ipaddresses[x].nictype) {
case "eth":
case "management_interface":
//console.log("Found a " + ipaddresses[x].nictype)
additional += " " + ipaddresses[x].cidrip;
break;
}
}
if (deviceHasProblem(actionrec.theObject)) {
//If we know nothing, we change nothing
if (ui_helplevel > 0) {
if (ui_helplevel == 1) additional = " " + translator.getStr("NT_TstDscriptProblem");
else {
//here we get all the problem statements and combine them
errors = returnProblemStrings(actionrec.theObject);
additional = " " + errors.join(' - ');
}
}
}
setStatus(actionrec.theObject.hostname + additional);
//We probably do not want to do printecreen here, but we are doing it here now...
PrintScreen();
}
}
function Language(lang = null) {
var __construct = function () {
if (lang == null) {
lang = "en";
}
//console.log("Defining language:" + lang);
ui_language = lang;
return;
}()
this.getStr = function (str, defaultStr) {
var toget = 'language.' + ui_language + "." + str + ".value";
//console.log("Translating: " + toget);
var retStr = eval(toget);
if (typeof retStr != 'undefined') {
return retStr;
} else {
if (typeof defaultStr != 'undefined') {
return defaultStr;
} else {
toget = "language.en." + str;
//console.log("First translation failed, falling back to en: " + toget);
return eval(toget);
}
}
}
}