Compare commits

..

3 Commits

Author SHA1 Message Date
Will Webberley
4eeb573e3e updated logger URL and tidied up scripts 2016-03-30 20:50:48 +00:00
Will Webberley
e272016176 ensure app copes with undefined elements 2016-03-30 20:11:27 +00:00
Will Webberley
3983b781a4 changes re. Dave for Sherlock-SAM exp 2016-03-30 21:02:24 +01:00
11 changed files with 357 additions and 485 deletions

1
.gitignore vendored
View File

@ -1,2 +1 @@
*.sw* *.sw*
node_modules/

View File

@ -1,14 +0,0 @@
from nginx:latest
RUN rm /etc/nginx/conf.d/*
ADD ./nginx_sherlock.conf /etc/nginx/conf.d
ADD js /var/www/sherlock/js
ADD css /var/www/sherlock/css
ADD media /var/www/sherlock/media
ADD node_modules /var/www/sherlock/node_modules
ADD index.html /var/www/sherlock
ADD models /models
EXPOSE 80

View File

@ -1,71 +1,14 @@
# SHERLOCK # SHERLOCK
## Introduction This repository contains the source code for the ITA project's SHERLOCK game for CE experiments.
This repository contains the source code for the ITA project's SHERLOCK game for Controlled English experiments.
The game uses the CENode library to maintain a knowledge base, which is described purely in ITA Controlled English. The game uses the CENode library to maintain a knowledge base, which is described purely in ITA Controlled English.
For more information on the ITA project and CENode, take a look at the following webpages: For more information, take a look at the following webpages:
* [dais-ita.org/pub](https://dais-ita.org/pub) * [usukita.org](https://www.usukita.org)
* [cenode.io](http://cenode.io) * [cenode.io](http://cenode.io)
## Running the game
### Getting started
The easiest way to run the game is to use Docker:
```
docker run -p 80:80 flyingsparx/sherlock
```
Then navigate to [localhost](http://localhost) to start the game using the default Sherlock 'world' in an isolated environment.
### Extending the game's world
To enable users to start the game with more context, extra models can be passed, where each model is described by a JavaScript array of pure CE sentences inside a global variable named `CUSTOM_MODEL`.
For example, the following model can be used to tell CENode that there is such a thing called a 'movie', and that there is a movie called Harry Potter:
```javascript
var CUSTOM_MODEL = [
"conceptualise a ~ movie ~ M",
"there is a movie named 'Harry Potter'"
];
```
To start a new Sherlock game such that its world contains this information, we can pass it into the Docker container (given the model is saved in a file called `harry_potter.js`):
```
docker run -p 80:80 -v ${PWD}/harry_potter.js:/models/custom.js flyingsparx/sherlock
```
### Use case: multiplayer
CENode supports inter-node communication out-of-the-box, through use of [policies](https://github.com/willwebberley/CENode/wiki/Policies). Since policies are again described by pure CE, a multiplayer game can be set-up through a relay CENode instance using the same `CUSTOM_MODEL` setup.
For example, given a relay CENode instance is configured at `http://mycenode.com`, the relevant policies can be described in a file called `multiplayer.js`:
```javascript
var CUSTOM_MODEL = [
"there is an agent named 'RemoteAgent' that has 'mycenode.com' as address",
"there is a tell policy named 'p2' that has 'true' as enabled and has the agent 'RemoteAgent' as target",
"there is a listen policy named 'p4' that has 'true' as enabled and has the agent 'RemoteAgent' as target"
];
```
And this can be passed into the Docker container as before to enable players of the game to exist in the same 'world':
```
docker run -p 80:80 -v ${PWD}/multiplayer.js:/models/custom.js flyingsparx/sherlock
```
The policies on the node mean that the game allows players to continue even when they have no network connectivity. The games will sync up as individual players leave and join the network.
To set-up a simple CENode relay, take a look at the [CENode Explorer project](https://github.com/willwebberley/CENode-explorer).
## Licensing ## Licensing
The contents of this repository are licensed under the Apache License v2. See LICENSE for further information. The contents of this repository are licensed under the Apache License v2. See LICENSE for further information.

View File

@ -20,11 +20,11 @@
<input class="username clear" id="login_username" placeholder="User ID" type="text" autofocus> <input class="username clear" id="login_username" placeholder="User ID" type="text" autofocus>
<div class="clear"></div> <div class="clear"></div>
<p style="display:none;color:rgb(220,220,220);font-weight:300;font-size:15px;" id="login_error">Please enter a User ID to continue.</p> <p style="display:none;color:rgb(220,220,220);font-weight:300;font-size:15px;" id="login_error">Please enter a User ID to continue.</p>
<!--<input id="multiplayer" type="checkbox" checked="checked" style="width:20px;"/><span style="margin-left:5px;color:white;">Multiplayer</span>--> <input id="multiplayer" type="checkbox" checked="checked" style="width:20px;"/><span style="margin-left:5px;color:white;">Multiplayer</span>
<div class="clear"></div> <div class="clear"></div>
<button id="login">Login</button> <button id="login">Login</button>
</div> </div>
<img src="media/logo.jpg" class="attribution"> <img src="/media/logo.jpg" class="attribution">
</div> </div>
<div class="overlay" id="moira_overlay"> <div class="overlay" id="moira_overlay">
<header> <header>
@ -35,6 +35,7 @@
<div id="unanswered"></div> <div id="unanswered"></div>
</div> </div>
<button class="change_view dashboard" data-view="dashboard" id="score">Dashboard</button> <button class="change_view dashboard" data-view="dashboard" id="score">Dashboard</button>
<!--<button class="logout" id="logout">Logout</button>-->
<div id="online_status" class="status"></div> <div id="online_status" class="status"></div>
<div class="clear"></div> <div class="clear"></div>
@ -45,6 +46,7 @@
<input id="autofill" type="checkbox" checked="checked"/><span style="margin-left:5px;">Input suggestions</span> <input id="autofill" type="checkbox" checked="checked"/><span style="margin-left:5px;">Input suggestions</span>
</div> </div>
<div style="text-align:left;margin-left:1%;display:inline-block;float:left;"> <div style="text-align:left;margin-left:1%;display:inline-block;float:left;">
<!-- <div id="online_status" class="status"></div>-->
</div> </div>
</div> </div>
<div id="text_input_area"> <div id="text_input_area">
@ -61,10 +63,7 @@
</div> </div>
</div> </div>
<script src="node_modules/cenode/dist/cenode.min.js"></script> <script src="http://cenode.io/cenode.js"></script>
<script src="node_modules/cenode/dist/models.js"></script>
<script src="js/sherlock-models.js"></script>
<script src="models/custom.js"></script>
<script src="js/main.js"></script> <script src="js/main.js"></script>
</body> </body>
</html> </html>

View File

@ -1,22 +1,151 @@
var node; var node;
var shownCards = []; var shown_cards = [];
var askedQuestions = []; var asked_questions = [];
var submittedStatements = []; var submitted_statements = [];
var scoredCards = []; var scored_cards = [];
var spacePressed = 0; var space_pressed = 0;
var lastSpacePressed = 0; var last_space_pressed = 0;
var forbidInput = false; var last_successful_request = 0;
//var multiplayer; var latest_latitude = null;
var latestLatitude = null; var latest_longitude = null;
var latestLongitude = null; var latest_card = null;
var loggingConfigs = [ var logging_configs = [
//{url: 'http://logger.cenode.io/cards/sherlock', loggedCards: []}, {url: 'http://logger.cenode.io/cards/sherlockSam', logged_cards: []},
//{url: 'http://logger2.cenode.io/cards/sherlock', loggedCards: []} {url: 'http://logger2.cenode.io/cards/sherlockSam', logged_cards: []}
];
var SHERLOCK_CORE = [
"conceptualise a ~ sherlock thing ~ S that is an entity and is an imageable thing",
"conceptualise an ~ organisation ~ O that is a sherlock thing",
"conceptualise a ~ fruit ~ F that is a sherlock thing and is a locatable thing",
"conceptualise a ~ room ~ R that is a location and is a sherlock thing",
"conceptualise a ~ shirt colour ~ C",
"conceptualise a ~ sport ~ S",
"conceptualise a ~ character ~ C that is a sherlock thing and is a locatable thing and has the shirt colour C as ~ shirt colour ~",
"conceptualise the character C ~ works for ~ the organisation O and ~ eats ~ the fruit F and ~ plays ~ the sport S",
"conceptualise the shirt colour C ~ is worn by ~ the character C",
"conceptualise an ~ object ~ O that is an entity",
"conceptualise the object O ~ resides in ~ the room R",
"conceptualise the room R ~ contains ~ the fruit F and has the character C as ~ contents ~ and has the object O as ~ additional contents ~",
"conceptualise the fruit F ~ is eaten by ~ the character C",
"conceptualise the sport S ~ is played by ~ the character C and ~ is in ~ the room R",
"conceptualise a ~ question ~ Q that has the value V as ~ text ~ and has the value W as ~ value ~ and has the value X as ~ relationship ~",
"conceptualise the question Q ~ concerns ~ the sherlock thing C",
"there is a rule named r1 that has 'if the character C ~ eats ~ the fruit F then the fruit F ~ is eaten by ~ the character C' as instruction",
"there is a rule named r2 that has 'if the character C ~ plays ~ the sport S then the sport S ~ is played by ~ the character C' as instruction",
"there is a rule named r3 that has 'if the character C has the shirt colour S as ~ shirt colour ~ then the shirt colour S ~ is worn by ~ the character C' as instruction",
"there is a rule named r4 that has 'if the character C ~ is in ~ the room R then the room R has the character C as ~ contents ~' as instruction",
"there is a rule named r5 that has 'if the fruit F ~ is in ~ the room R then the room R ~ contains ~ the fruit F' as instruction",
// Inverse rules:
"there is a rule named r6 that has 'if the fruit F ~ is eaten by ~ the character C then the character C ~ eats ~ the fruit F' as instruction",
"there is a rule named r7 that has 'if the sport S ~ is played by ~ the character C then the character C ~ plays ~ the sport S' as instruction",
"there is a rule named r8 that has 'if the shirt colour S ~ is worn by ~ the character C then the character C has the shirt colour S as ~ shirt colour ~' as instruction",
"there is a rule named r9 that has 'if the room R has the character C as ~ contents ~ then the character C ~ is in ~ the room R' as instruction",
"there is a rule named r10 that has 'if the room R ~ contains ~ the fruit F then the fruit F ~ is in ~ the room R' as instruction",
"there is an organisation named 'police'",
"there is a character named 'Prof Crane' that has 'http://sherlock.cenode.io/media/crane.png' as image",
"there is a character named 'Dr Finch' that has 'http://sherlock.cenode.io/media/finch.png' as image",
"there is a character named 'Col Robin' that has 'http://sherlock.cenode.io/media/robin.png' as image",
"there is a character named 'Sgt Stork' that has 'http://sherlock.cenode.io/media/stork.png' as image",
"there is a character named 'Rev Hawk' that has 'http://sherlock.cenode.io/media/hawk.png' as image",
"there is a character named 'Capt Falcon' that has 'http://sherlock.cenode.io/media/falcon.png' as image",
"there is a character named 'Elephant' that has 'http://sherlock.cenode.io/media/Elephant.png' as image",
"there is a character named 'Giraffe' that has 'http://sherlock.cenode.io/media/Giraffe.png' as image",
"there is a character named 'Hippopotamus' that has 'http://sherlock.cenode.io/media/Hippopotamus.png' as image",
"there is a character named 'Leopard' that has 'http://sherlock.cenode.io/media/Leopard.png' as image",
"there is a character named 'Lion' that has 'http://sherlock.cenode.io/media/Lion.png' as image",
"there is a character named 'Zebra' that has 'http://sherlock.cenode.io/media/Zebra.png' as image",
"there is a room named 'Ruby Room'",
"there is a room named 'Sapphire Room'",
"there is a room named 'Gold Room'",
"there is a room named 'Amber Room'",
"there is a room named 'Emerald Room'",
"there is a room named 'Silver Room'",
"there is a fruit named 'pineapple'",
"there is a fruit named 'apple'",
"there is a fruit named 'banana'",
"there is a fruit named 'orange'",
"there is a fruit named 'lemon'",
"there is a fruit named 'pear'",
"there is a fruit named 'grape'",
"there is a fruit named 'kiwi'",
"there is a fruit named 'tomato'",
"there is a shirt colour named 'green'",
"there is a shirt colour named 'red'",
"there is a shirt colour named 'yellow'",
"there is a shirt colour named 'black'",
"there is a shirt colour named 'white'",
"there is a shirt colour named 'purple'",
"there is a shirt colour named 'pink'",
"there is a shirt colour named 'blue'",
"there is a shirt colour named 'brown'",
"there is a shirt colour named 'grey'",
"there is a sport named 'tennis'",
"there is a sport named 'badminton'",
"there is a sport named 'rugby'",
"there is a sport named 'football'",
"there is a sport named 'soccer'",
"there is a sport named 'running'",
"there is a sport named 'swimming'",
"there is a sport named 'athletic'",
"there is a sport named 'baseball'",
"there is a sport named 'rounders'",
"there is a sport named 'softball'",
"there is a sport named 'cricket'",
"there is a sport named 'golf'",
"there is a sport named 'basketball'",
"there is a rule named objectrule1 that has 'if the object O ~ resides in ~ the room R then the room R has the object O as ~ additional contents ~' as instruction",
"there is an object named 'gorilla'",
"there is an object named 'dinosaur'",
"there is an object named 'robot'",
"there is an object named 'ghost'",
"there is an object named 'balloon'",
"there is a question named 'q1' that has 'What character eats pineapples?' as text and has 'is eaten by' as relationship and concerns the sherlock thing 'pineapple'",
"there is a question named 'q2' that has 'What sport does Zebra play?' as text and has 'plays' as relationship and concerns the sherlock thing 'Zebra'",
"there is a question named 'q3' that has 'What character eats apples?' as text and has 'is eaten by' as relationship and concerns the sherlock thing 'apple'",
"there is a question named 'q4' that has 'What colour hat is Elephant wearing?' as text and has 'hat colour' as value and concerns the sherlock thing 'Elephant'",
"there is a question named 'q6' that has 'Where is Giraffe?' as text and has 'is in' as relationship and concerns the sherlock thing 'Giraffe'",
"there is a question named 'q7' that has 'What colour hat is Lion wearing?' as text and has 'hat colour' as value and concerns the sherlock thing 'Lion'",
"there is a question named 'q8' that has 'Where is Lion?' as text and has 'is in' as relationship and concerns the sherlock thing 'Lion'",
"there is a question named 'q9' that has 'Which character is in the emerald room?' as text and has 'contents' as value and concerns the sherlock thing 'Emerald Room'",
"there is a question named 'q12' that has 'What character eats bananas?' as text and has 'is eaten by' as relationship and concerns the sherlock thing 'banana'",
"there is a question named 'q13' that has 'What character is in the sapphire room?' as text and has 'contents' as value and concerns the sherlock thing 'Sapphire Room'",
"there is a question named 'q17' that has 'What sport does Elephant play?' as text and has 'plays' as relationship and concerns the sherlock thing 'Elephant'",
"there is a question named 'q18' that has 'What character is wearing a red hat?' as text and has 'is worn by' as relationship and concerns the sherlock thing 'red'",
"there is a question named 'q19' that has 'What character plays rugby?' as text and has 'is played by' as relationship and concerns the sherlock thing 'rugby'",
"there is a question named 'q20' that has 'What fruit does Leopard eat?' as text and has 'eats' as relationship and concerns the sherlock thing 'Leopard'",
"there is a question named 'q23' that has 'What fruit does Giraffe eat?' as text and has 'eats' as relationship and concerns the sherlock thing 'Giraffe'",
"there is a question named 'q24' that has 'What colour hat is Zebra wearing?' as text and has 'hat colour' as value and concerns the sherlock thing 'Zebra'",
"there is a question named 'q25' that has 'Where is the apple?' as text and has 'is in' as relationship and concerns the sherlock thing 'apple'",
"there is a question named 'q26' that has 'What character is wearing a yellow hat?' as text and has 'is worn by' as relationship and concerns the sherlock thing 'yellow'",
"there is a question named 'q28' that has 'What fruit is in the silver room?' as text and has 'contains' as relationship and concerns the sherlock thing 'Silver Room'",
"there is a question named 'q30' that has 'What character is wearing a blue hat?' as text and has 'is worn by' as relationship and concerns the sherlock thing 'blue'",
"there is a question named 'q31' that has 'What character eats lemons?' as text and has 'is eaten by' as relationship and concerns the sherlock thing 'lemon'",
"there is a question named 'q33' that has 'What fruit does Elephant eat?' as text and has 'eats' as relationship and concerns the sherlock thing 'Elephant'",
"there is a question named 'q34' that has 'What character plays basketball?' as text and has 'is played by' as relationship and concerns the sherlock thing 'basketball'",
"there is a question named 'q35' that has 'What character plays soccer?' as text and has 'is played by' as relationship and concerns the sherlock thing 'soccer'",
"there is a question named 'q36' that has 'What sport does Lion play?' as text and has 'plays' as relationship and concerns the sherlock thing 'Lion'",
"there is a question named 'q37' that has 'What character is in the ruby room?' as text and has 'contents' as value and concerns the sherlock thing 'Ruby Room'",
"there is a question named 'q39' that has 'What character plays golf?' as text and has 'is played by' as relationship and concerns the sherlock thing 'golf'",
"there is a question named 'q40' that has 'What character eats oranges?' as text and has 'is eaten by' as relationship and concerns the sherlock thing 'orange'",
"there is a question named 'q41' that has 'What colour hat is Hippopotamus wearing?' as text and has 'hat colour' as value and concerns the sherlock thing 'Hippopotamus'",
"there is a question named 'q45' that has 'What character is in the amber room?' as text and has 'contents' as value and concerns the sherlock thing 'Amber Room'",
"there is a question named 'q47' that has 'Where is Elephant?' as text and has 'is in' as relationship and concerns the sherlock thing 'Elephant'",
"there is a question named 'q48' that has 'Where is the pear?' as text and has 'is in' as relationship and concerns the sherlock thing 'pear'",
"there is a question named 'q50' that has 'What fruit does Lion eat?' as text and has 'eats' as relationship and concerns the sherlock thing 'Lion'",
"there is a question named 'q52' that has 'What sport does Giraffe play?' as text and has 'plays' as relationship and concerns the sherlock thing 'Giraffe'",
"there is a question named 'q53' that has 'Where is Hippopotamus?' as text and has 'is in' as relationship and concerns the sherlock thing 'Hippopotamus'",
"there is a question named 'q54' that has 'What sport does Hippopotamus play?' as text and has 'plays' as relationship and concerns the sherlock thing 'Hippopotamus'"
]; ];
var settings = { var settings = {
loggedIn : false, logged_in : false,
}; };
var user = { var user = {
@ -25,16 +154,16 @@ var user = {
questions : [], questions : [],
answers : [], answers : [],
inputs: [], inputs: [],
inputCounter : 0, input_counter : 0,
score : 0, score : 0,
currentScreen : "login" current_screen : "login"
}; };
var log = { var log = {
recordingPresses : false, recording_presses : false,
keypresses : 0, keypresses : 0,
startTime : 0, start_time : 0,
endTime : 0 end_time : 0
}; };
var ui = { var ui = {
@ -43,60 +172,55 @@ var ui = {
logout : null, logout : null,
}, },
inputs : { inputs : {
loginUserId : null, login_user_id : null,
mainUserId : null, main_user_id : null,
text : null, text : null,
guess : null, guess : null,
autofill : null, autofill : null
//multiplayer: null
}, },
overlays : { overlays : {
login : null, login : null,
moira : null, moira : null,
dashboard: null dashboard: null
}, },
viewChangers : [], view_changers : [],
info : { info : {
cards : null, cards : null,
questions : null, questions : null,
loginError : null, login_error : null,
score : null, score : null,
onlineStatus : null online_status : null
} }
}; };
function initializeUi(){ function initialize_ui(){
ui.buttons.login = document.getElementById("login"); ui.buttons.login = document.getElementById("login");
ui.inputs.loginUserId = document.getElementById("login_username"); ui.inputs.login_user_id = document.getElementById("login_username");
ui.inputs.mainUserId = document.getElementById("username"); ui.inputs.main_user_id = document.getElementById("username");
ui.inputs.text = document.getElementById("text"); ui.inputs.text = document.getElementById("text");
ui.inputs.guess = document.getElementById("guess"); ui.inputs.guess = document.getElementById("guess");
ui.inputs.autofill = document.getElementById("autofill"); ui.inputs.autofill = document.getElementById("autofill");
//ui.inputs.multiplayer = document.getElementById("multiplayer");
ui.overlays.login = document.getElementById("login_overlay"); ui.overlays.login = document.getElementById("login_overlay");
ui.overlays.moira = document.getElementById("moira_overlay"); ui.overlays.moira = document.getElementById("moira_overlay");
ui.overlays.dashboard = document.getElementById("dashboard_overlay");
ui.info.cards = document.getElementById("cards"); ui.info.cards = document.getElementById("cards");
ui.info.questions = document.getElementById("questions"); ui.info.login_error = document.getElementById("login_error");
ui.info.loginError = document.getElementById("login_error"); ui.info.online_status = document.getElementById("online_status");
ui.info.score = document.getElementById("score"); ui.view_changers = document.getElementsByClassName("change_view");
ui.info.onlineStatus = document.getElementById("online_status");
ui.viewChangers = document.getElementsByClassName("change_view");
} }
function bindListeners(){ function bind_listeners(){
ui.buttons.login.onclick = login; ui.buttons.login.onclick = login;
ui.inputs.loginUserId.onkeyup = login; ui.inputs.login_user_id.onkeyup = login;
ui.inputs.text.onkeyup = keyUp; ui.inputs.text.onkeyup = key_up;
ui.inputs.text.onkeydown = keyDown; ui.inputs.text.onkeydown = key_down;
for(var i = 0; i < ui.viewChangers.length; i++){ for(var i = 0; i < ui.view_changers.length; i++){
ui.viewChangers[i].onclick = function(e){changeView(e.target.getAttribute("data-view"));}; ui.view_changers[i].onclick = function(e){change_view(e.target.getAttribute("data-view"));};
} }
} }
function changeView(view){ function change_view(view){
user.selectedScreen = view; user.selected_screen = view;
updateUi(); update_ui();
} }
function login(e){ function login(e){
@ -105,107 +229,96 @@ function login(e){
return; return;
} }
} }
user.id = ui.inputs.loginUserId.value.charAt(0).toUpperCase() + ui.inputs.loginUserId.value.slice(1); user.id = ui.inputs.login_user_id.value.charAt(0).toUpperCase() + ui.inputs.login_user_id.value.slice(1);
user.id = user.id.trim(); user.id = user.id.trim();
//multiplayer = ui.inputs.multiplayer.checked == true;
if(user.id == null || user.id == ""){ if(user.id == null || user.id == ""){
ui.info.loginError.style.display = "block"; ui.info.login_error.style.display = "block";
return; return;
} }
//if(MULTIPLAYER_MODEL){ node = new CENode(MODELS.CORE, SHERLOCK_CORE);
node = new CENode(CEModels.core, SHERLOCK_CORE_MODEL, CUSTOM_MODEL); ui.info.online_status.style.display = "none";
ui.info.onlineStatus.style.display = "block";
checkOnline(); node.agent.set_name(user.id+" agent");
/*}
else{
node = new CENode(CEModels.core, SHERLOCK_CORE_MODEL, CUSTOM_MODEL);
ui.info.onlineStatus.style.display = "none";
}*/
node.attachAgent();
node.agent.setName(user.id+" agent");
window.setTimeout(function(){ window.setTimeout(function(){
node.addSentence("there is a tell card named 'msg_{uid}' that is from the agent '"+node.agent.name.replace(/'/g, "\\'")+"' and is to the agent '"+node.agent.name.replace(/'/g, "\\'")+"' and has the timestamp '{now}' as timestamp and has 'there is an agent named \\'"+node.agent.name.replace(/'/g, "\\\'")+"\\'' as content"); node.add_sentence("there is a tell card named 'msg_{uid}' that is from the agent '"+node.agent.get_name().replace(/'/g, "\\'")+"' and is to the agent '"+node.agent.get_name().replace(/'/g, "\\'")+"' and has the timestamp '{now}' as timestamp and has 'there is an agent named \\'"+node.agent.get_name().replace(/'/g, "\\\'")+"\\'' as content");
node.addSentence("there is a feedback policy named 'p3' that has the individual '"+user.id+"' as target and has 'true' as enabled and has 'full' as acknowledgement"); node.add_sentence("there is a feedback policy named 'p3' that has the individual '"+user.id+"' as target and has 'true' as enabled and has 'full' as acknowledgement");
}, 100); }, 100);
settings.loggedIn = true; settings.logged_in = true;
user.selectedScreen = "moira"; user.selected_screen = "moira";
user.cards = []; user.cards = [];
ui.info.loginError.style.display = "none"; ui.info.login_error.style.display = "none";
updateUi(); update_ui();
loadQuestions(); load_questions();//fetch_questions();
pollForInstances(); poll_for_instances();
for(var i = 0; i < loggingConfigs.length; i++){ for(var i = 0; i < logging_configs.length; i++){
logCards(loggingConfigs[i]); log_cards(logging_configs[i]);
} }
} }
function keyDown(e){
if(forbidInput){ function add_sentence(t){
e.preventDefault(); node.add_sentence(t);
return false; }
}
function key_down(e){
if(e.keyCode == 9){ if(e.keyCode == 9){
e.preventDefault(); e.preventDefault();
return false; return false;
} }
if(e.keyCode == 32){ if(e.keyCode == 32){
spacePressed = new Date().getTime(); space_pressed = new Date().getTime();
if((spacePressed - lastSpacePressed) < 400 && ui.inputs.text.value.slice(-1) == ' '){ if((space_pressed - last_space_pressed) < 400 && ui.inputs.text.value.slice(-1) == ' '){
if(ui.inputs.text.value.length < ui.inputs.guess.value.length && ui.inputs.autofill.checked == true){ if(ui.inputs.text.value.length < ui.inputs.guess.value.length && ui.inputs.autofill.checked == true){
e.preventDefault(); e.preventDefault();
ui.inputs.text.value = node.nlParser.guessNext(ui.inputs.text.value.substring(0, ui.inputs.text.value.length-1)) + " "; ui.inputs.text.value = node.guess_next(ui.inputs.text.value.substring(0, ui.inputs.text.value.length-1)) + " ";
return false; return false;
} }
} }
lastSpacePressed = new Date().getTime(); last_space_pressed = new Date().getTime();
} }
} }
function keyUp(e){ function key_up(e){
if(forbidInput){
e.preventDefault();
return false;
}
if(e.keyCode == 13){ if(e.keyCode == 13){
log.recordingPresses = false; log.recording_presses = false;
log.endTime = parseInt(new Date().getTime()); log.end_time = parseInt(new Date().getTime());
send(); send();
} }
else if(e.keyCode == 38){ else if(e.keyCode == 38){
if(user.inputCounter > 0){ if(user.input_counter > 0){
user.inputCounter--; user.input_counter--;
ui.inputs.text.value = user.inputs[user.inputCounter]; ui.inputs.text.value = user.inputs[user.input_counter];
} }
e.preventDefault(); e.preventDefault();
} }
else if(e.keyCode == 40){ else if(e.keyCode == 40){
if(user.inputCounter < user.inputs.length-1){ if(user.input_counter < user.inputs.length-1){
user.inputCounter++; user.input_counter++;
ui.inputs.text.value = user.inputs[user.inputCounter]; ui.inputs.text.value = user.inputs[user.input_counter];
} }
else{ else{
ui.inputs.text.value = ""; ui.inputs.text.value = "";
} }
} }
else if(e.keyCode == 9){ else if(e.keyCode == 9){
ui.inputs.text.value = node.nlParser.guessNext(ui.inputs.text.value); ui.inputs.text.value = node.guess_next(ui.inputs.text.value);
e.preventDefault(); e.preventDefault();
return false; return false;
} }
else{ else{
if(log.recordingPresses == false){ if(log.recording_presses == false){
log.recordingPresses = true; log.recording_presses = true;
log.startTime = parseInt(new Date().getTime()); log.start_time = parseInt(new Date().getTime());
log.keypresses = 0; log.keypresses = 0;
} }
log.keypresses++; log.keypresses++;
} }
if(ui.inputs.autofill.checked == true){ if(ui.inputs.autofill.checked == true){
ui.inputs.guess.value = node.nlParser.guessNext(ui.inputs.text.value); ui.inputs.guess.value = node.guess_next(ui.inputs.text.value);
} }
else{ else{
ui.inputs.guess.value = ""; ui.inputs.guess.value = "";
@ -217,108 +330,106 @@ function send(){
ui.inputs.text.value = ""; ui.inputs.text.value = "";
user.inputs.push(input); user.inputs.push(input);
user.inputCounter = user.inputs.length; user.input_counter = user.inputs.length;
var sentence = input.replace(/'/g, "\\'"); var sentence = input.replace(/'/g, "\\'");
var card; var card;
if(sentence.toLowerCase().trim() == 'show anomalies'){ if(latest_card && sentence.toLowerCase().trim() == 'y' || sentence.toLowerCase().trim() == 'yes'){
addCardSimple(sentence, 'user'); confirm_card(latest_card.name, latest_card.content);
}
else if(latest_card && sentence.toLowerCase().trim() == 'n' || sentence.toLowerCase().trim() == 'no'){
unconfirm_card(latest_card.name);
}
else if(sentence.toLowerCase().trim() == 'show anomalies'){
add_card_simple(sentence, 'user');
var objects = node.concepts.object.instances; var objects = node.concepts.object.instances;
for(var i = 0; i < objects.length; i++){ for(var i = 0; i < objects.length; i++){
addCardSimple(objects[i].gist, 'friend'); add_card_simple(objects[i].gist, 'friend');
} }
return; return;
} }
else if(sentence.toLowerCase().indexOf("who ") == 0 || sentence.toLowerCase().indexOf("what ") == 0 || sentence.toLowerCase().indexOf("where ") == 0 || sentence.toLowerCase().indexOf("list ") == 0){ else if(sentence.toLowerCase().indexOf("who ") == 0 || sentence.toLowerCase().indexOf("what ") == 0 || sentence.toLowerCase().indexOf("where ") == 0 || sentence.toLowerCase().indexOf("list ") == 0){
card = "there is an ask card named 'msg_{uid}' that has '"+sentence+"' as content and is to the agent '"+node.agent.name.replace(/'/g, "\\'")+"' and is from the individual '"+user.id+"' and has the timestamp '{now}' as timestamp"; card = "there is an ask card named 'msg_{uid}' that has '"+sentence+"' as content and is to the agent '"+node.agent.get_name().replace(/'/g, "\\'")+"' and is from the individual '"+user.id+"' and has the timestamp '{now}' as timestamp";
addCardSimple(input, 'user'); add_card_simple(input, 'user');
} }
else{ else{
if(submittedStatements.indexOf(input.toLowerCase()) > -1 ){ submitted_statements.push(input.toLowerCase());
addCardSimple("I cannot accept duplicate information from the same user.", 'friend');
return window.alert("The input is invalid or you've already entered this information!");
}
submittedStatements.push(input.toLowerCase());
card = "there is an nl card named 'msg_{uid}' that has '"+sentence+"' as content and is to the agent '"+node.agent.name.replace(/'/g, "\\'")+"' and is from the individual '"+user.id+"' and has the timestamp '{now}' as timestamp"; card = "there is an nl card named 'msg_{uid}' that has '"+sentence+"' as content and is to the agent '"+node.agent.get_name().replace(/'/g, "\\'")+"' and is from the individual '"+user.id+"' and has the timestamp '{now}' as timestamp";
addCardSimple(input, 'user'); add_card_simple(input, 'user');
} }
node.addSentence(card); node.add_sentence(card);
} }
function confirmCard(id, content){ function confirm_card(id, content){
document.getElementById("confirm_"+id).style.display = "none"; try{
document.getElementById("unconfirm_"+id).style.display = "none"; document.getElementById("confirm_"+id).style.display = "none";
forbidInput = false; document.getElementById("unconfirm_"+id).style.display = "none";
ui.inputs.text.focus(); }
catch(err){
if(submittedStatements.indexOf(content.toLowerCase()) > -1){ console.log(err);
addCardSimple("I cannot accept duplicate information from the same user.", 'friend');
return window.alert("You have already entered or conifirmed this statement.");
} }
submittedStatements.push(content.toLowerCase());
addCardSimple("Yes.", 'user'); submitted_statements.push(content.toLowerCase());
var card = "there is a tell card named 'msg_{uid}' that has '"+content.replace(/'/g, "\\'")+"' as content and is to the agent '"+node.agent.name.replace(/'/g, "\\'")+"' and is from the individual '"+user.id+"' and has the timestamp '{now}' as timestamp and is in reply to the card '"+id+"'";
add_card_simple("Yes.", 'user');
var card = "there is a tell card named 'msg_{uid}' that has '"+content.replace(/'/g, "\\'")+"' as content and is to the agent '"+node.agent.get_name().replace(/'/g, "\\'")+"' and is from the individual '"+user.id+"' and has the timestamp '{now}' as timestamp and is in reply to the card '"+id+"'";
card+=" and has '"+log.keypresses+"' as number of keystrokes"; card+=" and has '"+log.keypresses+"' as number of keystrokes";
card+=" and has '"+log.endTime+"' as submit time"; card+=" and has '"+log.end_time+"' as submit time";
card+=" and has '"+log.startTime+"' as start time"; card+=" and has '"+log.start_time+"' as start time";
if(latestLatitude && latestLongitude){ if(latest_latitude && latest_longitude){
card+=" and has '"+latestLatitude+"' as latitude"; card+=" and has '"+latest_latitude+"' as latitude";
card+=" and has '"+latestLongitude+"' as longitude"; card+=" and has '"+latest_longitude+"' as longitude";
} }
node.add_sentence(card);
node.addSentence(card);
}
function unconfirmCard(id){
document.getElementById("confirm_"+id).style.display = "none";
document.getElementById("unconfirm_"+id).style.display = "none";
addCardSimple("No.", 'user');
addCardSimple("OK.", 'friend');
forbidInput = false;
ui.inputs.text.focus(); ui.inputs.text.focus();
} }
function updateUi(){ function unconfirm_card(id){
if(settings.loggedIn == true){ document.getElementById("confirm_"+id).style.display = "none";
document.getElementById("unconfirm_"+id).style.display = "none";
add_card_simple("No.", 'user');
add_card_simple("OK.", 'friend');
ui.inputs.text.focus();
}
function update_ui(){
if(settings.logged_in == true){
ui.overlays.login.style.display = "none"; ui.overlays.login.style.display = "none";
ui.info.score.innerHTML = user.score+' points'; if(user.selected_screen == "moira"){
if(user.selectedScreen == "moira"){ ui.overlays.moira.style.display = "block";
ui.overlays.moira.style.display = "block";
ui.overlays.dashboard.style.display = "none";
} }
else if(user.selectedScreen == "dashboard"){ else if(user.selected_screen == "dashboard"){
ui.overlays.dashboard.style.display = "block";
ui.overlays.moira.style.display = "none"; ui.overlays.moira.style.display = "none";
} }
} }
else{ else{
ui.overlays.login.style.display = "block"; ui.overlays.login.style.display = "block";
ui.overlays.moira.style.display = "none"; ui.overlays.moira.style.display = "none";
ui.inputs.loginUserId.value = ""; ui.inputs.login_user_id.value = "";
ui.info.cards.innerHTML = ""; ui.info.cards.innerHTML = "";
} }
} }
function addCardSimple(text, user){ function add_card_simple(text, user){
ui.info.cards.innerHTML += '<li class="card '+user+'"><p>'+text+'</p></li>'; ui.info.cards.innerHTML += '<li class="card '+user+'"><p>'+text+'</p></li>';
ui.info.cards.scrollTop = ui.info.cards.scrollHeight; ui.info.cards.scrollTop = ui.info.cards.scrollHeight;
} }
function addCard(card){ function add_card(card){
latest_card = card;
var content = card.content; var content = card.content;
var id = card.name; var id = card.name;
var tos = card.is_tos.map(function(to){ var tos = card.is_tos.map(function(to){
return to.name.toLowerCase(); return to.name.toLowerCase();
}); });
var from = card.is_from.name; var from = card.is_from.name;
var cardType = card.type; var card_type = card.type;
var linkedContent = card.linked_content; var linked_content = card.linked_content;
if(!content){return;} if(!content){return;}
if(id == null || (id != null && shownCards.indexOf(id) == -1)){ if(id == null || (id != null && shown_cards.indexOf(id) == -1)){
shownCards.push(id); shown_cards.push(id);
navigator.vibrate = navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate; navigator.vibrate = navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate;
var c = '<li class="card'; var c = '<li class="card';
if(tos && tos.indexOf(user.id) > -1){c+=' user';} if(tos && tos.indexOf(user.id) > -1){c+=' user';}
@ -330,17 +441,16 @@ function addCard(card){
} }
c+='">'; c+='">';
c+='<p>'; c+='<p>';
if(cardType != null && cardType.name == "confirm card"){ if(card_type != null && card_type.name == "confirm card"){
c+='OK. Is this what you meant?<br /><br />'; c+='OK. Is this what you meant?<br /><br />';
} }
c+=content.replace(/(?:\r\n|\r|\n)/g, ' <br /> ').replace(/ /g, '&nbsp;&nbsp;')+'</p>'; c+=content.replace(/(?:\r\n|\r|\n)/g, ' <br /> ').replace(/ /g, '&nbsp;&nbsp;')+'</p>';
if(cardType != null && cardType.name == "confirm card"){ if(card_type != null && card_type.name == "confirm card"){
c+='<button id="confirm_'+id+'" class="confirm" onclick="confirmCard(\''+id+'\', \''+content.replace(/'/g, "\\'")+'\')">Yes</button>'; c+='<button id="confirm_'+id+'" class="confirm" onclick="confirm_card(\''+id+'\', \''+content.replace(/'/g, "\\'")+'\')">Yes</button>';
c+='<button id="unconfirm_'+id+'" class="unconfirm" onclick="unconfirmCard(\''+id+'\')">No</button>'; c+='<button id="unconfirm_'+id+'" class="unconfirm" onclick="unconfirm_card(\''+id+'\')">No</button>';
forbidInput = true;
} }
if(linkedContent != null){ if(linked_content != null){
c+='<img src="'+linkedContent+'" alt="Attachment" />'; c+='<img src="'+linked_content+'" alt="Attachment" />';
} }
c+='</li>'; c+='</li>';
ui.info.cards.innerHTML+=c; ui.info.cards.innerHTML+=c;
@ -348,32 +458,32 @@ function addCard(card){
} }
} }
function getQuestionState(q){ function get_question_state(q){
if(q.responses.length == 0){return "unanswered";} if(q.responses.length == 0){return "unanswered";}
else if(q.responses.length < 3){return "unconfident";} else if(q.responses.length < 3){return "unconfident";}
else{ else{
var responses = {}; var responses = {};
var responseVols = []; var response_vols = [];
for(var j = 0; j < q.responses.length; j++){ for(var j = 0; j < q.responses.length; j++){
if(!(q.responses[j] in responses)){responses[q.responses[j]] = 0;} if(!(q.responses[j] in responses)){responses[q.responses[j]] = 0;}
responses[q.responses[j]]++; responses[q.responses[j]]++;
} }
for(key in responses){responseVols.push(responses[key]);} for(key in responses){response_vols.push(responses[key]);}
responseVols.sort().reverse(); response_vols.sort().reverse();
if(responseVols.length == 1){return "answered";} if(response_vols.length == 1){return "answered";}
else if(responseVols.length > 1 && (responseVols[0]-responseVols[1]) >= 3){return "answered";} else if(response_vols.length > 1 && (response_vols[0]-response_vols[1]) >= 3){return "answered";}
else{return "contested";} else{return "contested";}
} }
} }
function loadQuestions(){ function load_questions(){
var qs = node.getInstances("question"); var qs = node.get_instances("question");
for(var i = 0; i < qs.length; i++){ for(var i = 0; i < qs.length; i++){
var q = {}; var q = {};
q.responses = []; q.responses = [];
for(var j = 0; j < qs[i].values.length; j++){ for(var j = 0; j < qs[i].values.length; j++){
var insName = typeof qs[i].values[j].instance == 'string' ? qs[i].values[j].instance : qs[i].values[j].instance.name; var ins_name = typeof qs[i].values[j].instance == 'string' ? qs[i].values[j].instance : qs[i].values[j].instance.name;
q[qs[i].values[j].label] = insName; q[qs[i].values[j].label] = ins_name;
} }
for(var j = 0; j < qs[i].relationships.length; j++){ for(var j = 0; j < qs[i].relationships.length; j++){
q[qs[i].relationships[j].label] = qs[i].relationships[j].instance.name; q[qs[i].relationships[j].label] = qs[i].relationships[j].instance.name;
@ -382,12 +492,12 @@ function loadQuestions(){
} }
} }
function pollForInstances(){ function poll_for_instances(){
if(node == null){ if(node == null){
return; return;
} }
setTimeout(function(){ setTimeout(function(){
var ins = node.getInstances(); var ins = node.get_instances();
for(var i = 0; i < user.questions.length; i++){user.questions[i].responses = [];} for(var i = 0; i < user.questions.length; i++){user.questions[i].responses = [];}
for(var i = 0; i < ins.length; i++){ for(var i = 0; i < ins.length; i++){
// Detect if type of card. If so, filter and add to UI if necessary // Detect if type of card. If so, filter and add to UI if necessary
@ -395,7 +505,7 @@ function pollForInstances(){
var tos = ins[i].is_tos; var tos = ins[i].is_tos;
if(tos){for(var j = 0; j < tos.length; j++){ if(tos){for(var j = 0; j < tos.length; j++){
if(tos[j].name.toLowerCase() == user.id.toLowerCase()){ if(tos[j].name.toLowerCase() == user.id.toLowerCase()){
addCard(ins[i]); add_card(ins[i]);
} }
}} }}
} }
@ -427,12 +537,12 @@ function pollForInstances(){
} }
} }
} }
ui.info.questions.innerHTML = ""; // ui.info.questions.innerHTML = "";
user.score = 0; user.score = 0;
var ratios = {}; var ratios = {};
for(var i = 0; i < user.questions.length ; i++){ for(var i = 0; i < user.questions.length ; i++){
var state = getQuestionState(user.questions[i]); var state = get_question_state(user.questions[i]);
ui.info.questions.innerHTML += '<li onclick="alert(\''+user.questions[i].text+'\');" class="response question '+state+'">'+(i+1)+'</li>'; // ui.info.questions.innerHTML += '<li onclick="alert(\''+user.questions[i].text+'\');" class="response question '+state+'">'+(i+1)+'</li>';
if(state == 'answered'){ if(state == 'answered'){
user.score++; user.score++;
} }
@ -441,112 +551,122 @@ function pollForInstances(){
} }
ratios[state]++; ratios[state]++;
} }
var bars = document.getElementById('dashboard_indicator').getElementsByTagName('div'); // var bars = document.getElementById('dashboard_indicator').getElementsByTagName('div');
for(var i = 0; i < bars.length; i++){ // for(var i = 0; i < bars.length; i++){
bars[i].style.width = "0%"; // bars[i].style.width = "0%";
} // }
for(var type in ratios){ for(var type in ratios){
document.getElementById(type).style.width = Math.floor(ratios[type] * 100 / parseFloat(user.questions.length))+'%'; var typeElem = document.getElementById(type);
if (typeElem) {
typeElem.style.width = Math.floor(ratios[type] * 100 / parseFloat(user.questions.length))+'%';
}
} }
updateUi(); update_ui();
pollForInstances(); poll_for_instances();
},1000); },1000);
} }
function logCards(config){ function log_cards(config){
try{ try{
var cards = node.getInstances("card", true); var cards = node.get_instances("card", true);
var properties = ['timestamp', 'content', 'is in reply to', 'is from', 'number of keystrokes', 'submit time', 'start time', 'latitude', 'longitude']; var properties = ['timestamp', 'content', 'is in reply to', 'is from', 'number of keystrokes', 'submit time', 'start time', 'latitude', 'longitude'];
var unloggedCards = []; var unlogged_cards = [];
for(var i = 0; i < cards.length; i++){ for(var i = 0; i < cards.length; i++){
if(config.loggedCards.indexOf(cards[i].name) == -1){ if(config.logged_cards.indexOf(cards[i].name) == -1){
var cardToLog = {}; var card_to_log = {};
cardToLog.name = cards[i].name; card_to_log.name = cards[i].name;
cardToLog.type = cards[i].type.name; card_to_log.type = cards[i].type.name;
for(var j = 0; j < properties.length; j++){ for(var j = 0; j < properties.length; j++){
var prop = properties[j]; var prop = properties[j];
if(cards[i].property(prop)){ if(cards[i].property(prop)){
cardToLog[prop] = cards[i].property(prop).name || cards[i].property(prop); card_to_log[prop] = cards[i].property(prop).name || cards[i].property(prop);
} }
} }
unloggedCards.push(cardToLog); unlogged_cards.push(card_to_log);
} }
} }
if(unloggedCards.length == 0){ if(unlogged_cards.length == 0){
setTimeout(function(){ setTimeout(function(){
logCards(config); log_cards(config);
}, 3000); }, 3000);
return; return;
} }
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open("POST", config.url); xhr.open("POST", config.url);
xhr.onreadystatechange = function(){ xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){ if(xhr.readyState == 4 && xhr.status == 200){
setTimeout(function(){ setTimeout(function(){
for(var i = 0; i < unloggedCards.length; i++){ for(var i = 0; i < unlogged_cards.length; i++){
config.loggedCards.push(unloggedCards[i].name); config.logged_cards.push(unlogged_cards[i].name);
} }
logCards(config); log_cards(config);
}, 10000); }, 10000);
} }
else if(xhr.readyState == 4 && xhr.status != 200){ else if(xhr.readyState == 4 && xhr.status != 200){
setTimeout(function(){ setTimeout(function(){
logCards(config); log_cards(config);
}, 5000); }, 5000);
} }
} }
xhr.send(JSON.stringify(unloggedCards)); xhr.send(JSON.stringify(unlogged_cards));
} }
catch(err){ catch(err){
console.log(err); console.log(err);
setTimeout(function(){ setTimeout(function(){
logCards(config); log_cards(config);
}, 5000); }, 5000);
} }
} }
function checkOnline(){ function check_online(){
var now = new Date().getTime(); var now = new Date().getTime();
if (node.agent){ var last = node.agent.get_last_successful_request();
var last = node.agent.policyHandler.lastSuccessfulRequest; var diff = now - last;
var diff = now - last; if(diff < 5000){
if(diff < 5000){ ui.info.online_status.style.backgroundColor = "green";
ui.info.onlineStatus.style.backgroundColor = "green"; }
} else{
else{ ui.info.online_status.style.backgroundColor = "rgb(200,200,200)";
ui.info.onlineStatus.style.backgroundColor = "rgb(200,200,200)";
}
} }
setTimeout(function(){ setTimeout(function(){
checkOnline(); check_online();
}, 1000); }, 1000);
} }
var recordPosition = function(position){ var record_position = function(position){
latestLongitude = position.coords.longitude; latest_longitude = position.coords.longitude;
latestLatitude = position.coords.latitude; latest_latitude = position.coords.latitude;
} }
window.onresize = function(event) { window.onresize = function(event) {
ui.info.cards.style.height = (window.innerHeight - 200)+'px'; ui.info.cards.style.height = (window.innerHeight - 350)+'px';
ui.info.cards.scrollTop = ui.info.cards.scrollHeight; ui.info.cards.scrollTop = ui.info.cards.scrollHeight;
document.getElementById('wrapper').style.height = window.innerHeight+'px';
var content = document.getElementById("main-content");
content.style.height = (window.innerHeight - 50) + "px";
} }
window.onbeforeunload = function() { window.onbeforeunload = function() {
return "Quitting Sherlock may mean you can't resume from where you left off."; return "Quitting Sherlock may mean you can't resume from where you left off.";
}; };
window.onload = function(){ var loadChat = function() {
initializeUi(); initialize_ui();
bindListeners(); bind_listeners();
ui.overlays.moira.style.display = "none"; ui.overlays.moira.style.display = "none";
ui.overlays.dashboard.style.display = "none";
if (navigator.geolocation) { if (navigator.geolocation) {
navigator.geolocation.watchPosition(recordPosition); navigator.geolocation.watchPosition(record_position);
} }
ui.inputs.text.focus(); ui.inputs.text.focus();
ui.info.cards.style.height = (window.innerHeight - 200)+'px'; ui.info.cards.style.height = (window.innerHeight - 350)+'px';
document.getElementById('wrapper').style.height = window.innerHeight+'px';
var content = document.getElementById("main-content");
if(content){
content.style.height = (window.innerHeight - 50) + "px";
}
}
window.onload = function(){
loadChat();
}; };

View File

@ -1,127 +0,0 @@
var SHERLOCK_CORE_MODEL = [
"conceptualise a ~ sherlock thing ~ S that is an entity and is an imageable thing",
"conceptualise an ~ organisation ~ O that is a sherlock thing",
"conceptualise a ~ fruit ~ F that is a sherlock thing and is a locatable thing",
"conceptualise a ~ room ~ R that is a location and is a sherlock thing",
"conceptualise a ~ hat colour ~ C",
"conceptualise a ~ sport ~ S",
"conceptualise a ~ character ~ C that is a sherlock thing and is a locatable thing and has the hat colour C as ~ hat colour ~",
"conceptualise the character C ~ works for ~ the organisation O and ~ eats ~ the fruit F and ~ plays ~ the sport S",
"conceptualise the hat colour C ~ is worn by ~ the character C",
"conceptualise an ~ object ~ O that is an entity",
"conceptualise the object O ~ resides in ~ the room R",
"conceptualise the room R ~ contains ~ the fruit F and has the character C as ~ contents ~ and has the object O as ~ additional contents ~",
"conceptualise the fruit F ~ is eaten by ~ the character C",
"conceptualise the sport S ~ is played by ~ the character C and ~ is in ~ the room R",
"conceptualise a ~ question ~ Q that has the value V as ~ text ~ and has the value W as ~ value ~ and has the value X as ~ relationship ~",
"conceptualise the question Q ~ concerns ~ the sherlock thing C",
"there is a rule named r1 that has 'if the character C ~ eats ~ the fruit F then the fruit F ~ is eaten by ~ the character C' as instruction",
"there is a rule named r2 that has 'if the character C ~ plays ~ the sport S then the sport S ~ is played by ~ the character C' as instruction",
"there is a rule named r3 that has 'if the character C has the hat colour S as ~ hat colour ~ then the hat colour S ~ is worn by ~ the character C' as instruction",
"there is a rule named r4 that has 'if the character C ~ is in ~ the room R then the room R has the character C as ~ contents ~' as instruction",
"there is a rule named r5 that has 'if the fruit F ~ is in ~ the room R then the room R ~ contains ~ the fruit F' as instruction",
// Inverse rules:
"there is a rule named r6 that has 'if the fruit F ~ is eaten by ~ the character C then the character C ~ eats ~ the fruit F' as instruction",
"there is a rule named r7 that has 'if the sport S ~ is played by ~ the character C then the character C ~ plays ~ the sport S' as instruction",
"there is a rule named r8 that has 'if the hat colour S ~ is worn by ~ the character C then the character C has the hat colour S as ~ hat colour ~' as instruction",
"there is a rule named r9 that has 'if the room R has the character C as ~ contents ~ then the character C ~ is in ~ the room R' as instruction",
"there is a rule named r10 that has 'if the room R ~ contains ~ the fruit F then the fruit F ~ is in ~ the room R' as instruction",
"there is a character named 'Prof Crane' that has 'http://sherlock.cenode.io/media/crane.png' as image",
"there is a character named 'Dr Finch' that has 'http://sherlock.cenode.io/media/finch.png' as image",
"there is a character named 'Col Robin' that has 'http://sherlock.cenode.io/media/robin.png' as image",
"there is a character named 'Sgt Stork' that has 'http://sherlock.cenode.io/media/stork.png' as image",
"there is a character named 'Rev Hawk' that has 'http://sherlock.cenode.io/media/hawk.png' as image",
"there is a character named 'Capt Falcon' that has 'http://sherlock.cenode.io/media/falcon.png' as image",
"there is a character named 'Elephant' that has 'http://sherlock.cenode.io/media/Elephant.png' as image",
"there is a character named 'Giraffe' that has 'http://sherlock.cenode.io/media/Giraffe.png' as image",
"there is a character named 'Hippopotamus' that has 'http://sherlock.cenode.io/media/Hippopotamus.png' as image",
"there is a character named 'Leopard' that has 'http://sherlock.cenode.io/media/Leopard.png' as image",
"there is a character named 'Lion' that has 'http://sherlock.cenode.io/media/Lion.png' as image",
"there is a character named 'Zebra' that has 'http://sherlock.cenode.io/media/Zebra.png' as image",
"there is a room named 'Ruby Room'",
"there is a room named 'Sapphire Room'",
"there is a room named 'Gold Room'",
"there is a room named 'Amber Room'",
"there is a room named 'Emerald Room'",
"there is a room named 'Silver Room'",
"there is a fruit named 'pineapple'",
"there is a fruit named 'apple'",
"there is a fruit named 'banana'",
"there is a fruit named 'orange'",
"there is a fruit named 'lemon'",
"there is a fruit named 'pear'",
"there is a fruit named 'grape'",
"there is a fruit named 'kiwi'",
"there is a fruit named 'tomato'",
"there is a hat colour named 'green'",
"there is a hat colour named 'red'",
"there is a hat colour named 'yellow'",
"there is a hat colour named 'black'",
"there is a hat colour named 'white'",
"there is a hat colour named 'purple'",
"there is a hat colour named 'pink'",
"there is a hat colour named 'blue'",
"there is a hat colour named 'brown'",
"there is a hat colour named 'grey'",
"there is a sport named 'tennis'",
"there is a sport named 'badminton'",
"there is a sport named 'rugby'",
"there is a sport named 'football'",
"there is a sport named 'soccer'",
"there is a sport named 'running'",
"there is a sport named 'swimming'",
"there is a sport named 'athletics'",
"there is a sport named 'baseball'",
"there is a sport named 'rounders'",
"there is a sport named 'softball'",
"there is a sport named 'cricket'",
"there is a sport named 'golf'",
"there is a sport named 'basketball'",
"there is a rule named objectrule1 that has 'if the object O ~ resides in ~ the room R then the room R has the object O as ~ additional contents ~' as instruction",
"there is an object named 'gorilla'",
"there is an object named 'dinosaur'",
"there is an object named 'robot'",
"there is an object named 'ghost'",
"there is an object named 'balloon'",
"there is a question named 'q1' that has 'What character eats pineapples?' as text and has 'is eaten by' as relationship and concerns the sherlock thing 'pineapple'",
"there is a question named 'q2' that has 'What sport does Zebra play?' as text and has 'plays' as relationship and concerns the sherlock thing 'Zebra'",
"there is a question named 'q3' that has 'What character eats apples?' as text and has 'is eaten by' as relationship and concerns the sherlock thing 'apple'",
"there is a question named 'q4' that has 'What colour hat is Elephant wearing?' as text and has 'hat colour' as value and concerns the sherlock thing 'Elephant'",
"there is a question named 'q6' that has 'Where is Giraffe?' as text and has 'is in' as relationship and concerns the sherlock thing 'Giraffe'",
"there is a question named 'q7' that has 'What colour hat is Lion wearing?' as text and has 'hat colour' as value and concerns the sherlock thing 'Lion'",
"there is a question named 'q8' that has 'Where is Lion?' as text and has 'is in' as relationship and concerns the sherlock thing 'Lion'",
"there is a question named 'q9' that has 'Which character is in the emerald room?' as text and has 'contents' as value and concerns the sherlock thing 'Emerald Room'",
"there is a question named 'q12' that has 'What character eats bananas?' as text and has 'is eaten by' as relationship and concerns the sherlock thing 'banana'",
"there is a question named 'q13' that has 'What character is in the sapphire room?' as text and has 'contents' as value and concerns the sherlock thing 'Sapphire Room'",
"there is a question named 'q17' that has 'What sport does Elephant play?' as text and has 'plays' as relationship and concerns the sherlock thing 'Elephant'",
"there is a question named 'q18' that has 'What character is wearing a red hat?' as text and has 'is worn by' as relationship and concerns the sherlock thing 'red'",
"there is a question named 'q19' that has 'What character plays rugby?' as text and has 'is played by' as relationship and concerns the sherlock thing 'rugby'",
"there is a question named 'q20' that has 'What fruit does Leopard eat?' as text and has 'eats' as relationship and concerns the sherlock thing 'Leopard'",
"there is a question named 'q23' that has 'What fruit does Giraffe eat?' as text and has 'eats' as relationship and concerns the sherlock thing 'Giraffe'",
"there is a question named 'q24' that has 'What colour hat is Zebra wearing?' as text and has 'hat colour' as value and concerns the sherlock thing 'Zebra'",
"there is a question named 'q25' that has 'Where is the apple?' as text and has 'is in' as relationship and concerns the sherlock thing 'apple'",
"there is a question named 'q26' that has 'What character is wearing a yellow hat?' as text and has 'is worn by' as relationship and concerns the sherlock thing 'yellow'",
"there is a question named 'q28' that has 'What fruit is in the silver room?' as text and has 'contains' as relationship and concerns the sherlock thing 'Silver Room'",
"there is a question named 'q30' that has 'What character is wearing a blue hat?' as text and has 'is worn by' as relationship and concerns the sherlock thing 'blue'",
"there is a question named 'q31' that has 'What character eats lemons?' as text and has 'is eaten by' as relationship and concerns the sherlock thing 'lemon'",
"there is a question named 'q33' that has 'What fruit does Elephant eat?' as text and has 'eats' as relationship and concerns the sherlock thing 'Elephant'",
"there is a question named 'q34' that has 'What character plays basketball?' as text and has 'is played by' as relationship and concerns the sherlock thing 'basketball'",
"there is a question named 'q35' that has 'What character plays soccer?' as text and has 'is played by' as relationship and concerns the sherlock thing 'soccer'",
"there is a question named 'q36' that has 'What sport does Lion play?' as text and has 'plays' as relationship and concerns the sherlock thing 'Lion'",
"there is a question named 'q37' that has 'What character is in the ruby room?' as text and has 'contents' as value and concerns the sherlock thing 'Ruby Room'",
"there is a question named 'q39' that has 'What character plays golf?' as text and has 'is played by' as relationship and concerns the sherlock thing 'golf'",
"there is a question named 'q40' that has 'What character eats oranges?' as text and has 'is eaten by' as relationship and concerns the sherlock thing 'orange'",
"there is a question named 'q41' that has 'What colour hat is Hippopotamus wearing?' as text and has 'hat colour' as value and concerns the sherlock thing 'Hippopotamus'",
"there is a question named 'q45' that has 'What character is in the amber room?' as text and has 'contents' as value and concerns the sherlock thing 'Amber Room'",
"there is a question named 'q47' that has 'Where is Elephant?' as text and has 'is in' as relationship and concerns the sherlock thing 'Elephant'",
"there is a question named 'q48' that has 'Where is the pear?' as text and has 'is in' as relationship and concerns the sherlock thing 'pear'",
"there is a question named 'q50' that has 'What fruit does Lion eat?' as text and has 'eats' as relationship and concerns the sherlock thing 'Lion'",
"there is a question named 'q52' that has 'What sport does Giraffe play?' as text and has 'plays' as relationship and concerns the sherlock thing 'Giraffe'",
"there is a question named 'q53' that has 'Where is Hippopotamus?' as text and has 'is in' as relationship and concerns the sherlock thing 'Hippopotamus'",
"there is a question named 'q54' that has 'What sport does Hippopotamus play?' as text and has 'plays' as relationship and concerns the sherlock thing 'Hippopotamus'"
];

View File

@ -1,3 +0,0 @@
var CUSTOM_MODEL= [
];

View File

@ -1,5 +0,0 @@
var CUSTOM_MODEL= [
"there is an agent named 'RemoteAgent' that has 'explorer.cenode.io' as address",
"there is a tell policy named 'p2' that has 'true' as enabled and has the agent 'RemoteAgent' as target",
"there is a listen policy named 'p4' that has 'true' as enabled and has the agent 'RemoteAgent' as target"
];

View File

@ -1,14 +0,0 @@
server_tokens off; # for security-by-obscurity: stop displaying nginx version
server {
listen 80 default_server;
server_name _;
root /var/www/sherlock/;
location / {
root /var/www/sherlock/;
}
location /models {
root /;
}
}

13
package-lock.json generated
View File

@ -1,13 +0,0 @@
{
"name": "sherlock",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"cenode": {
"version": "3.0.12",
"resolved": "https://registry.npmjs.org/cenode/-/cenode-3.0.12.tgz",
"integrity": "sha1-AU+CypoLDpOgr9oigEddDoVkpj4="
}
}
}

View File

@ -1,13 +0,0 @@
{
"name": "sherlock",
"version": "1.0.0",
"repository": {
"type": "git",
"url": "git+https://github.com/flyingsparx/sherlock.git"
},
"author": "Will Webberley & Alun Preece",
"license": "Apache-2.0",
"dependencies": {
"cenode": "^3.0.11"
}
}