From 8e27d9b9c07457e8f6c7c2ca4645ebcab62f818f Mon Sep 17 00:00:00 2001 From: karu Date: Sun, 9 Mar 2025 20:07:57 -0400 Subject: [PATCH 01/68] First commit test script --- .gitignore | 0 js/MPL.js | 4 ++++ tests/test.js | 3 +++ 3 files changed, 7 insertions(+) create mode 100644 .gitignore create mode 100644 tests/test.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/js/MPL.js b/js/MPL.js index ae84542..d5ae897 100644 --- a/js/MPL.js +++ b/js/MPL.js @@ -7,6 +7,7 @@ * Copyright (c) 2013-2015 Ross Kirsling * Released under the MIT License. */ +const FormulaParser = require('../lib/formula-parser.min.js'); var MPL = (function (FormulaParser) { 'use strict'; @@ -515,3 +516,6 @@ var MPL = (function (FormulaParser) { }; })(FormulaParser); + + +module.exports = MPL; // [TEST] diff --git a/tests/test.js b/tests/test.js new file mode 100644 index 0000000..8786fdb --- /dev/null +++ b/tests/test.js @@ -0,0 +1,3 @@ +// Importar todo desde MLP.js +const MPL = require('../js/MPL.js'); +console.log(MPL) From 6c6d620759094889bf95ed8499f4a1a98849d466 Mon Sep 17 00:00:00 2001 From: karu Date: Sun, 9 Mar 2025 20:29:53 -0400 Subject: [PATCH 02/68] Adding syntax for common knowledge. --- js/MPL.js | 52 +++++++++++++++++++++++++++++------------------- tests/scripts.js | 5 +++++ tests/test.js | 21 +++++++++++++++++-- 3 files changed, 55 insertions(+), 23 deletions(-) create mode 100644 tests/scripts.js diff --git a/js/MPL.js b/js/MPL.js index d5ae897..6e95808 100644 --- a/js/MPL.js +++ b/js/MPL.js @@ -17,20 +17,21 @@ var MPL = (function (FormulaParser) { var variableKey = 'prop'; var unaries = [ - { symbol: '~', key: 'neg', precedence: 6 }, - { symbol: '\u25a1', key: 'nec', precedence: 6 }, - { symbol: '<>', key: 'poss', precedence: 6 }, - { symbol: '[', key: 'annce_start', precedence: 5 }, - { symbol: 'K{', key: 'kno_start', precedence: 4 } + { symbol: '~', key: 'neg', precedence: 6 }, + { symbol: '\u25a1', key: 'nec', precedence: 6 }, + { symbol: '<>', key: 'poss', precedence: 6 }, + { symbol: '[', key: 'annce_start', precedence: 5 }, + { symbol: 'K{', key: 'kno_start', precedence: 4 }, + { symbol: 'C{', key: 'common_start', precedence: 4 } // [CA] Common knowledge operator ]; var binaries = [ - { symbol: ']', key: 'annce_end', precedence: 5, associativity: 'right' }, // the left operand to annce_end must be annce_start - { symbol: '}', key: 'kno_end', precedence: 4, associativity: 'right' }, // the left operand to kno_end must be kno_start - { symbol: '&', key: 'conj', precedence: 3, associativity: 'right' }, - { symbol: '|', key: 'disj', precedence: 2, associativity: 'right' }, - { symbol: '->', key: 'impl', precedence: 1, associativity: 'right' }, - { symbol: '<->', key: 'equi', precedence: 0, associativity: 'right' } + { symbol: ']', key: 'annce_end', precedence: 5, associativity: 'right' }, // the left operand to annce_end must be annce_start + { symbol: '}', key: 'kno_end', precedence: 4, associativity: 'right' }, // the left operand to kno_end must be kno_start + { symbol: '&', key: 'conj', precedence: 3, associativity: 'right' }, + { symbol: '|', key: 'disj', precedence: 2, associativity: 'right' }, + { symbol: '->', key: 'impl', precedence: 1, associativity: 'right' }, + { symbol: '<->', key: 'equi', precedence: 0, associativity: 'right' } ]; var MPLParser = new FormulaParser(variableKey, unaries, binaries); @@ -64,7 +65,15 @@ var MPL = (function (FormulaParser) { ) { const agents = json.kno_start.kno_end[0].prop.split(''); return 'K{' + agents.join(',') + '}' + _jsonToASCII(json.kno_start.kno_end[1]); - } + } + else if (json.common_start && // [CA] common knowledge + json.common_start.kno_end && //[CA] NOTE THAT common end is equal to kno_end. + json.common_start.kno_end[0].prop && //TODO: change name kno_end to general one. + json.common_start.kno_end.length === 2 + ) { + const agents = json.common_start.kno_end[0].prop.split(''); + return 'C{' + agents.join(',') + '}' + _jsonToASCII(json.common_start.kno_end[1]); + } else if (json.annce_start && json.annce_start.annce_end && json.annce_start.annce_end.length === 2 @@ -88,15 +97,16 @@ var MPL = (function (FormulaParser) { * @private */ function _asciiToLaTeX(ascii) { - return ascii.replace(/~/g, '\\lnot{}') - .replace(/\u25a1/g, '\\Box{}') - .replace(/<>/g, '\\Diamond{}') - .replace(/K\{/g, 'K_{') - .replace(/\}/g, '}') - .replace(/ & /g, '\\land{}') - .replace(/ \| /g, '\\lor{}') - .replace(/ <-> /g, '\\leftrightarrow{}') - .replace(/ -> /g, '\\rightarrow{}'); + return ascii.replace(/~/g, '\\lnot{}') + .replace(/\u25a1/g, '\\Box{}') + .replace(/<>/g, '\\Diamond{}') + .replace(/K\{/g, 'K_{') + .replace(/\}/g, '}') + .replace(/ & /g, '\\land{}') + .replace(/ \| /g, '\\lor{}') + .replace(/ <-> /g, '\\leftrightarrow{}') + .replace(/ -> /g, '\\rightarrow{}') + .replace(/C\{/g, 'C_{'); // [CA] Common knowledge. } /** diff --git a/tests/scripts.js b/tests/scripts.js new file mode 100644 index 0000000..e800b6b --- /dev/null +++ b/tests/scripts.js @@ -0,0 +1,5 @@ +// ESTE ARCHIVO SIRVE COMO SCRATCH PARA ALGUNAS FUNCIONES +const MPL = require('../js/MPL.js'); + +const formula = new MPL.Wff('C{abc}(p -> q)'); +console.log(formula.latex()) diff --git a/tests/test.js b/tests/test.js index 8786fdb..5a4cb1e 100644 --- a/tests/test.js +++ b/tests/test.js @@ -1,3 +1,20 @@ -// Importar todo desde MLP.js +// TEST FILE const MPL = require('../js/MPL.js'); -console.log(MPL) +console.log("EMPEZANDO TESTS") + +function testCommonKnowledge() { + // Verificar conversión a ASCII + const formula6 = new MPL.Wff('C{a,b}p'); + runTest('Convertir C{a,b}p a ASCII', formula6.ascii() === 'C{a,b}p'); + + // Verificar conversión a LaTeX + const formula7 = new MPL.Wff('C{a,b}p'); + runTest('Convertir C{a,b}p a LaTeX', formula7.latex() === 'C_{a,b}p'); + + // Verificar conversión a Unicode + const formula8 = new MPL.Wff('C{a,b}p'); + runTest('Convertir C{a,b}p a Unicode', formula8.unicode() === 'C{a,b}p'); +} + +// Ejecutar los tests +testCommonKnowledge(); From dd920a7bcd6ebfbc6955370e9ff9de1e2b98621f Mon Sep 17 00:00:00 2001 From: karu Date: Sun, 9 Mar 2025 21:04:49 -0400 Subject: [PATCH 03/68] Json reader: [add states] --- js/MPL.js | 44 +++++++++++++++++++++++++++++-------------- package-lock.json | 6 ++++++ tests/model.json | 39 ++++++++++++++++++++++++++++++++++++++ tests/scripts.js | 48 +++++++++++++++++++++++++++++++++++++++++++++-- tests/test.js | 16 ---------------- 5 files changed, 121 insertions(+), 32 deletions(-) create mode 100644 package-lock.json create mode 100644 tests/model.json diff --git a/js/MPL.js b/js/MPL.js index 6e95808..5f561fd 100644 --- a/js/MPL.js +++ b/js/MPL.js @@ -27,7 +27,7 @@ var MPL = (function (FormulaParser) { var binaries = [ { symbol: ']', key: 'annce_end', precedence: 5, associativity: 'right' }, // the left operand to annce_end must be annce_start - { symbol: '}', key: 'kno_end', precedence: 4, associativity: 'right' }, // the left operand to kno_end must be kno_start + { symbol: '}', key: 'group_end', precedence: 4, associativity: 'right' }, // the left operand to kno_end must be kno_start { symbol: '&', key: 'conj', precedence: 3, associativity: 'right' }, { symbol: '|', key: 'disj', precedence: 2, associativity: 'right' }, { symbol: '->', key: 'impl', precedence: 1, associativity: 'right' }, @@ -59,20 +59,20 @@ var MPL = (function (FormulaParser) { else if (json.poss) return '<>' + _jsonToASCII(json.poss); else if (json.kno_start && - json.kno_start.kno_end && - json.kno_start.kno_end[0].prop && - json.kno_start.kno_end.length === 2 + json.kno_start.group_end && + json.kno_start.group_end[0].prop && + json.kno_start.group_end.length === 2 ) { - const agents = json.kno_start.kno_end[0].prop.split(''); - return 'K{' + agents.join(',') + '}' + _jsonToASCII(json.kno_start.kno_end[1]); + const agents = json.kno_start.group_end[0].prop.split(''); + return 'K{' + agents.join(',') + '}' + _jsonToASCII(json.kno_start.group_end[1]); } else if (json.common_start && // [CA] common knowledge - json.common_start.kno_end && //[CA] NOTE THAT common end is equal to kno_end. - json.common_start.kno_end[0].prop && //TODO: change name kno_end to general one. - json.common_start.kno_end.length === 2 + json.common_start.group_end && //[CA] NOTE THAT common end is equal to kno_end. + json.common_start.group_end[0].prop && //TODO: change name kno_end to general one. + json.common_start.group_end.length === 2 ) { - const agents = json.common_start.kno_end[0].prop.split(''); - return 'C{' + agents.join(',') + '}' + _jsonToASCII(json.common_start.kno_end[1]); + const agents = json.common_start.group_end[0].prop.split(''); + return 'C{' + agents.join(',') + '}' + _jsonToASCII(json.common_start.group_end[1]); } else if (json.annce_start && json.annce_start.annce_end && @@ -180,6 +180,22 @@ var MPL = (function (FormulaParser) { // {assignment: {'p': true}, successors: [] }] var _states = []; + /** + * [CA] Create a model from json. + * TODO: AUTOMATICAMENTE RENOMBRA LOS MUNDOS A PARTIR DE 0,1,2,3,4 + */ + this.fromJSON = function (jsonString) { + let jsonData = JSON.parse(jsonString) + jsonData.states.forEach(state => { + this.addState(state.assignment) + state.successors.forEach(succ => { + console.log(`Adding transition (${state.id},${succ.target},${succ.agent})`) + this.addTransition(state.id, succ.target, succ.agent) + }) + }) + } + + /** * Adds a transition to the model, given source and target state indices. */ @@ -474,10 +490,10 @@ var MPL = (function (FormulaParser) { return model.valuation(json.prop, state); else if (json.neg) return !_truth(model, state, json.neg); - else if (json.kno_start && json.kno_start.kno_end && json.kno_start.kno_end[0].prop) { - const agents = json.kno_start.kno_end[0].prop.split(''); + else if (json.kno_start && json.kno_start.group_end && json.kno_start.group_end[0].prop) { + const agents = json.kno_start.group_end[0].prop.split(''); return agents.every(agent => model.getSuccessorsOf(state).every( - (succ) => succ.agent !== agent || _truth(model, succ.target, json.kno_start.kno_end[1]) + (succ) => succ.agent !== agent || _truth(model, succ.target, json.kno_start.group_end[1]) )); } else if (json.annce_start && json.annce_start.annce_end) { if (_truth(model, state, json.annce_start.annce_end[0])) { diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1db444d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "epistemicmodallogic", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/tests/model.json b/tests/model.json new file mode 100644 index 0000000..8445dbe --- /dev/null +++ b/tests/model.json @@ -0,0 +1,39 @@ +{ + "states": [ + { + "id": 0, + "assignment": { + "p": true, + "q": false + }, + "successors": [ + { + "agent": "a", + "target": 1 + }, + { + "agent": "b", + "target": 0 + } + ] + }, + { + "id": 1, + "assignment": { + "p": false, + "q": true + }, + "successors": [ + { + "agent": "a", + "target": 0 + }, + { + "agent": "b", + "target": 1 + } + ] + } + ], + "agents": ["a", "b"] +} diff --git a/tests/scripts.js b/tests/scripts.js index e800b6b..c807f11 100644 --- a/tests/scripts.js +++ b/tests/scripts.js @@ -1,5 +1,49 @@ // ESTE ARCHIVO SIRVE COMO SCRATCH PARA ALGUNAS FUNCIONES +var fs = require("fs"); const MPL = require('../js/MPL.js'); -const formula = new MPL.Wff('C{abc}(p -> q)'); -console.log(formula.latex()) +var jsonString =`{ + "states": [ + { + "id": 0, + "assignment": { + "p": true, + "q": true + }, + "successors": [ + { + "agent": "a", + "target": 1 + }, + { + "agent": "b", + "target": 0 + } + ] + }, + { + "id": 1, + "assignment": { + "p": false, + "q": true + }, + "successors": [ + { + "agent": "a", + "target": 0 + }, + { + "agent": "b", + "target": 1 + } + ] + } + ], + "agents": ["a", "b"] +}` + +const model = new MPL.Model +model.fromJSON(jsonString) + +console.log(model.getStates()) +console.log(model.getModelString()) diff --git a/tests/test.js b/tests/test.js index 5a4cb1e..4c13be3 100644 --- a/tests/test.js +++ b/tests/test.js @@ -2,19 +2,3 @@ const MPL = require('../js/MPL.js'); console.log("EMPEZANDO TESTS") -function testCommonKnowledge() { - // Verificar conversión a ASCII - const formula6 = new MPL.Wff('C{a,b}p'); - runTest('Convertir C{a,b}p a ASCII', formula6.ascii() === 'C{a,b}p'); - - // Verificar conversión a LaTeX - const formula7 = new MPL.Wff('C{a,b}p'); - runTest('Convertir C{a,b}p a LaTeX', formula7.latex() === 'C_{a,b}p'); - - // Verificar conversión a Unicode - const formula8 = new MPL.Wff('C{a,b}p'); - runTest('Convertir C{a,b}p a Unicode', formula8.unicode() === 'C{a,b}p'); -} - -// Ejecutar los tests -testCommonKnowledge(); From 66cc2a11b1a0945d927ff60599918454b4dffdfd Mon Sep 17 00:00:00 2001 From: karu Date: Mon, 10 Mar 2025 07:39:17 -0400 Subject: [PATCH 04/68] Complete model from JSON --- js/MPL.js | 5 +++-- tests/scripts.js | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/js/MPL.js b/js/MPL.js index 5f561fd..733c725 100644 --- a/js/MPL.js +++ b/js/MPL.js @@ -186,8 +186,10 @@ var MPL = (function (FormulaParser) { */ this.fromJSON = function (jsonString) { let jsonData = JSON.parse(jsonString) - jsonData.states.forEach(state => { + jsonData.states.forEach(state => { //Adding worlds this.addState(state.assignment) + }) + jsonData.states.forEach(state => {//Addings relations state.successors.forEach(succ => { console.log(`Adding transition (${state.id},${succ.target},${succ.agent})`) this.addTransition(state.id, succ.target, succ.agent) @@ -195,7 +197,6 @@ var MPL = (function (FormulaParser) { }) } - /** * Adds a transition to the model, given source and target state indices. */ diff --git a/tests/scripts.js b/tests/scripts.js index c807f11..8f62724 100644 --- a/tests/scripts.js +++ b/tests/scripts.js @@ -45,5 +45,6 @@ var jsonString =`{ const model = new MPL.Model model.fromJSON(jsonString) + console.log(model.getStates()) console.log(model.getModelString()) From df1a63bd2f26d3243f41eacdd1025faf60178470 Mon Sep 17 00:00:00 2001 From: karu Date: Mon, 10 Mar 2025 09:02:42 -0400 Subject: [PATCH 05/68] =?UTF-8?q?A=C3=B1adir=20meter=20el=20modelo=20como?= =?UTF-8?q?=20un=20json.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + index.html | 7 + js/MPL.js | 6 +- js/app.js | 34 +++- package-lock.json | 428 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 5 + 6 files changed, 469 insertions(+), 12 deletions(-) create mode 100644 package.json diff --git a/.gitignore b/.gitignore index e69de29..8d87b1d 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/* diff --git a/index.html b/index.html index ce58854..e18313d 100644 --- a/index.html +++ b/index.html @@ -19,6 +19,9 @@

Dynamic Epistemic Logic Playground

+
@@ -97,6 +100,10 @@

Dynamic Epistemic Logic Playground

+
+ + +
loading...
diff --git a/js/MPL.js b/js/MPL.js index 733c725..bcdcb7d 100644 --- a/js/MPL.js +++ b/js/MPL.js @@ -7,7 +7,7 @@ * Copyright (c) 2013-2015 Ross Kirsling * Released under the MIT License. */ -const FormulaParser = require('../lib/formula-parser.min.js'); +// const FormulaParser = require('../lib/formula-parser.min.js'); var MPL = (function (FormulaParser) { 'use strict'; @@ -185,13 +185,13 @@ var MPL = (function (FormulaParser) { * TODO: AUTOMATICAMENTE RENOMBRA LOS MUNDOS A PARTIR DE 0,1,2,3,4 */ this.fromJSON = function (jsonString) { + this.removeAllStatesAndTransitions(); let jsonData = JSON.parse(jsonString) jsonData.states.forEach(state => { //Adding worlds this.addState(state.assignment) }) jsonData.states.forEach(state => {//Addings relations state.successors.forEach(succ => { - console.log(`Adding transition (${state.id},${succ.target},${succ.agent})`) this.addTransition(state.id, succ.target, succ.agent) }) }) @@ -545,4 +545,4 @@ var MPL = (function (FormulaParser) { })(FormulaParser); -module.exports = MPL; // [TEST] +// module.exports = MPL; // [TEST] diff --git a/js/app.js b/js/app.js index ed84770..c344070 100644 --- a/js/app.js +++ b/js/app.js @@ -9,8 +9,9 @@ // app mode constants var MODE = { - EDIT: 0, - EVAL: 1 + EDIT: 0, + EVAL: 1, + TEXT: 2 }, appMode = MODE.EDIT; @@ -196,7 +197,6 @@ function announceFormula() { try { wff = new MPL.Wff(formula); } catch(e) { - console.log(e); evalOutput .html('
Invalid formula!
') .classed('inactive', false); @@ -283,7 +283,6 @@ function evaluateFormula() { try { wff = new MPL.Wff(formula); } catch(e) { - console.log(e); evalOutput .html('
Invalid formula!
') .classed('inactive', false); @@ -990,6 +989,26 @@ function keyup() { var modeButtons = d3.selectAll('#mode-select button'), panes = d3.selectAll('#app-body .panel .tab-pane'); +// Función que actualza el modelo en base a un json. Para ello crea una url nueva. IMP> No mantiene la información de la fórmula. +function updateModel(){ + let json = document.getElementById("jsonModel").value + let new_model = new MPL.Model() + new_model.fromJSON(json); + let modelString = new_model.getModelString(); + let currentUrl = window.location.href; + const modelRegex = /([&?]model=)[^&]*/; + let newUrl; + if (modelRegex.test(currentUrl)) { + newUrl = currentUrl.replace(modelRegex, `$1${modelString}?`); + } else { + const separator = currentUrl.includes('?') ? '&' : '?'; + newUrl = `${currentUrl}${separator}model=${modelString}?`; + } + window.history.replaceState({}, '', newUrl); +} + + + function setAppMode(newMode) { // mode-specific settings if(newMode === MODE.EDIT) { @@ -1008,7 +1027,7 @@ function setAppMode(newMode) { .classed('true', false) .classed('false', false); currentFormula.classed('inactive', true); - } else if(newMode === MODE.EVAL) { + } else if(newMode === MODE.EVAL || newMode === MODE.TEXT) { // disable listeners (except for I-bar prevention) svg.classed('edit', false) .on('mousedown', function() { d3.event.preventDefault(); }) @@ -1047,8 +1066,8 @@ function setAppMode(newMode) { else d3.select(this).classed('active', true); }); panes.each(function(d,i) { - if(i !== newMode) d3.select(this).classed('active', false); - else d3.select(this).classed('active', true); + if(i !== newMode) d3.select(this).classed('active', false); + else d3.select(this).classed('active', true); }); appMode = newMode; @@ -1068,7 +1087,6 @@ evalInput.select('input') // app starts here setAppMode(MODE.EDIT); - setVarCount(varCount); if (formulaParam && formulaParam[1].length > 0) { diff --git a/package-lock.json b/package-lock.json index 1db444d..03d94b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,5 +2,431 @@ "name": "epistemicmodallogic", "lockfileVersion": 3, "requires": true, - "packages": {} + "packages": { + "": { + "dependencies": { + "d3": "^7.9.0" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + } + } } diff --git a/package.json b/package.json new file mode 100644 index 0000000..037e638 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "d3": "^7.9.0" + } +} From 6a0d9971efeeb7713760959715305f790306924c Mon Sep 17 00:00:00 2001 From: karu Date: Mon, 10 Mar 2025 10:20:56 -0400 Subject: [PATCH 06/68] Implemented transitivity closure. --- js/MPL.js | 63 ++++++++++++++++++++++++++++++++++++++++++++++-- tests/scripts.js | 21 ++++++++++++---- 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/js/MPL.js b/js/MPL.js index bcdcb7d..f58ecd6 100644 --- a/js/MPL.js +++ b/js/MPL.js @@ -7,7 +7,7 @@ * Copyright (c) 2013-2015 Ross Kirsling * Released under the MIT License. */ -// const FormulaParser = require('../lib/formula-parser.min.js'); +const FormulaParser = require('../lib/formula-parser.min.js'); var MPL = (function (FormulaParser) { 'use strict'; @@ -467,6 +467,65 @@ var MPL = (function (FormulaParser) { } } + this.getSuccessorOfAgent = function(agent){ + let allAccRel = [] + _states.forEach((state, index) => { + state.successors.forEach(successor => { + if (agent == successor.agent){ + let relation = { + source: index, + target: successor.target, + agent: successor.agent + + } + allAccRel.push(relation) + } + }); + }); + return allAccRel; + } + + // Devuelve el conjunto de relaciones para un array de agentes. + this.getGroupSuccessor = function (agents){ + let groupSucc = []; + agents.forEach ((agent) => { + let succ = this.getSuccessorOfAgent(agent); + groupSucc.push(...succ); + }); + return groupSucc; + } + + this.transivityClosure = function (relations){ //Esto genera extras. pero no debería haber ningun problema + let n = this.getStates().length; + let matrix = Array.from({ length: n }, () => Array(n).fill(0)); + relations.forEach(rel => { + matrix[rel.source][rel.target] = 1; + }); + + for (let k = 0; k < n; k++) { + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + matrix[i][j] = matrix[i][j] || (matrix[i][k] && matrix[k][j]); + } + } + } + return matrix; + } + + //TODO: Utils method + this.matrixToRelation = function (matrix) { + let relations = [] + let agent = 'c' + for (let i = 0; i < matrix.length; i++) { + for (let j = 0; j < matrix[i].length; j++) { + if (matrix[i][j] === 1) { + relations.push({ source: i, target: j, agent: agent }); + } + } + } + return relations + } + /** * Returns an identical, but seperate, copy of this MPL model. */ @@ -545,4 +604,4 @@ var MPL = (function (FormulaParser) { })(FormulaParser); -// module.exports = MPL; // [TEST] +module.exports = MPL; // [TEST] diff --git a/tests/scripts.js b/tests/scripts.js index 8f62724..93f3df4 100644 --- a/tests/scripts.js +++ b/tests/scripts.js @@ -34,9 +34,18 @@ var jsonString =`{ }, { "agent": "b", - "target": 1 + "target": 2 } ] + }, + { + "id": 2, + "assignment": { + "p": false, + "q": true + }, + "successors": [ + ] } ], "agents": ["a", "b"] @@ -44,7 +53,9 @@ var jsonString =`{ const model = new MPL.Model model.fromJSON(jsonString) - - -console.log(model.getStates()) -console.log(model.getModelString()) +let relations = model.getGroupSuccessor(['b','a']) +console.log(relations) +console.log("---") +let matrix = model.transivityClosure(relations) +let rel = model.matrixToRelation(matrix) +console.log(rel) From 5e1a6e94734d814794b923a48d34677a32bf1ddd Mon Sep 17 00:00:00 2001 From: karu Date: Mon, 10 Mar 2025 10:36:21 -0400 Subject: [PATCH 07/68] Group closure --- js/MPL.js | 40 +++++++++++++++++++++++++++------------- tests/scripts.js | 8 +++----- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/js/MPL.js b/js/MPL.js index f58ecd6..4c0ce3f 100644 --- a/js/MPL.js +++ b/js/MPL.js @@ -495,22 +495,25 @@ var MPL = (function (FormulaParser) { return groupSucc; } - this.transivityClosure = function (relations){ //Esto genera extras. pero no debería haber ningun problema - let n = this.getStates().length; - let matrix = Array.from({ length: n }, () => Array(n).fill(0)); - relations.forEach(rel => { - matrix[rel.source][rel.target] = 1; - }); - - for (let k = 0; k < n; k++) { - for (let i = 0; i < n; i++) { - for (let j = 0; j < n; j++) { - matrix[i][j] = matrix[i][j] || (matrix[i][k] && matrix[k][j]); + + // group matrix = cierre transitivo + reflexivo + this.groupMatrix = function (relations){ + let n = this.getStates().length; + let matrix = Array.from({ length: n }, () => Array(n).fill(0)); + relations.forEach(rel => { + matrix[rel.source][rel.target] = 1; + }); + + for (let k = 0; k < n; k++) { + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + matrix[i][j] = matrix[i][j] || (matrix[i][k] && matrix[k][j]); + matrix[i][i] = 1; + } } } + return matrix; } - return matrix; - } //TODO: Utils method this.matrixToRelation = function (matrix) { @@ -526,6 +529,17 @@ var MPL = (function (FormulaParser) { return relations } + this.groupClosure = function (agents) { + // obtenemos todos las relaciones del grupo. + let allRelations = this.getGroupSuccessor(agents) + + // Aplicamos cierre transitivo+reflexio + let matrix = this.groupMatrix(allRelations) + let transRelation = this.matrixToRelation(matrix) + + transRelation.forEach( relation => {this.addTransition(relation.source, relation.target, relation.agent)}); + + } /** * Returns an identical, but seperate, copy of this MPL model. */ diff --git a/tests/scripts.js b/tests/scripts.js index 93f3df4..bb0dba8 100644 --- a/tests/scripts.js +++ b/tests/scripts.js @@ -53,9 +53,7 @@ var jsonString =`{ const model = new MPL.Model model.fromJSON(jsonString) -let relations = model.getGroupSuccessor(['b','a']) -console.log(relations) +console.log(model.getModelString()) console.log("---") -let matrix = model.transivityClosure(relations) -let rel = model.matrixToRelation(matrix) -console.log(rel) +model.groupClosure(['a','b']) +console.log(model.getModelString()) From 87f8f27094e3b1dc6c6da8e2c69a37040271d5e8 Mon Sep 17 00:00:00 2001 From: karu Date: Mon, 10 Mar 2025 11:40:04 -0400 Subject: [PATCH 08/68] 1st try common knowledge. --- js/MPL.js | 21 +++++++++++++++++---- js/app.js | 18 +++++++++++++----- tests/scripts.js | 3 +-- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/js/MPL.js b/js/MPL.js index 4c0ce3f..8ed66cc 100644 --- a/js/MPL.js +++ b/js/MPL.js @@ -7,7 +7,7 @@ * Copyright (c) 2013-2015 Ross Kirsling * Released under the MIT License. */ -const FormulaParser = require('../lib/formula-parser.min.js'); +// const FormulaParser = require('../lib/formula-parser.min.js'); //[TEST] var MPL = (function (FormulaParser) { 'use strict'; @@ -537,9 +537,16 @@ var MPL = (function (FormulaParser) { let matrix = this.groupMatrix(allRelations) let transRelation = this.matrixToRelation(matrix) - transRelation.forEach( relation => {this.addTransition(relation.source, relation.target, relation.agent)}); - + let modelprima = new Model(); + _states.forEach(state => modelprima.addState()) + transRelation.forEach( relation => {modelprima.addTransition(relation.source, relation.target, null)}); + return modelprima } + + this.getGroupSuccessorOf = function(state, agents) { + let groupModel = this.groupClosure(agents) + return groupModel.getSuccessorsOf(state) + } /** * Returns an identical, but seperate, copy of this MPL model. */ @@ -564,6 +571,12 @@ var MPL = (function (FormulaParser) { return model.valuation(json.prop, state); else if (json.neg) return !_truth(model, state, json.neg); + else if (json.common_start && json.common_start.group_end && json.common_start.group_end[0].prop) { + const agents = json.common_start.group_end[0].prop.split(''); + let modelprima = model.groupClosure(agents) + let succs = modelprima.getGroupSuccessorOf(state,agents) //Computa cada vez lo transitivo optimizar TODO + return succs.every( succ => _truth(model, succ.target, json.common_start.group_end[1])); + } else if (json.kno_start && json.kno_start.group_end && json.kno_start.group_end[0].prop) { const agents = json.kno_start.group_end[0].prop.split(''); return agents.every(agent => model.getSuccessorsOf(state).every( @@ -618,4 +631,4 @@ var MPL = (function (FormulaParser) { })(FormulaParser); -module.exports = MPL; // [TEST] +// module.exports = MPL; // [TEST] diff --git a/js/app.js b/js/app.js index c344070..c7ac146 100644 --- a/js/app.js +++ b/js/app.js @@ -361,13 +361,21 @@ function getWffAgentsAndProps(json) { return getWffAgentsAndProps(json.nec); else if (json.poss) return getWffAgentsAndProps(json.poss); + else if (json.common_start && + json.common_start.group_end && + json.common_start.group_end[0].prop && + json.common_start.group_end.length === 2 + ) { + const agent = json.common_start.group_end[0].prop; + return [{ agent }].concat(getWffAgentsAndProps(json.common_start.group_end[1])); + } else if (json.kno_start && - json.kno_start.kno_end && - json.kno_start.kno_end[0].prop && - json.kno_start.kno_end.length === 2 + json.kno_start.group_end && + json.kno_start.group_end[0].prop && + json.kno_start.group_end.length === 2 ) { - const agent = json.kno_start.kno_end[0].prop; - return [{ agent }].concat(getWffAgentsAndProps(json.kno_start.kno_end[1])); + const agent = json.kno_start.group_end[0].prop; + return [{ agent }].concat(getWffAgentsAndProps(json.kno_start.group_end[1])); } else if (json.annce_start && json.annce_start.annce_end && diff --git a/tests/scripts.js b/tests/scripts.js index bb0dba8..ba973cf 100644 --- a/tests/scripts.js +++ b/tests/scripts.js @@ -55,5 +55,4 @@ const model = new MPL.Model model.fromJSON(jsonString) console.log(model.getModelString()) console.log("---") -model.groupClosure(['a','b']) -console.log(model.getModelString()) +console.log(model.getGroupSuccessorOf(0,['a','b'])) From 49fe8f9f273ee5e3228a9c5693f5f0e59f254ebd Mon Sep 17 00:00:00 2001 From: Carlos AGUILERA VENTURA Date: Tue, 11 Mar 2025 10:43:53 +0100 Subject: [PATCH 09/68] fork --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a062a29..731853b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Epistemic Logic Playground +Epistemic Logic Playground(FORK for T4TL) ====================== This project is based on the open-source Modal Logic Playground by Ross Kirsling. The Epistemic Logic Playground was made by Elliot Evans. From 616a3085cb3832d6eb90086312468246f5e2ebbf Mon Sep 17 00:00:00 2001 From: Carlos AGUILERA VENTURA Date: Tue, 11 Mar 2025 11:00:47 +0100 Subject: [PATCH 10/68] checkout --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a062a29..e7a9730 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,11 @@ Epistemic Logic Playground ====================== -This project is based on the open-source Modal Logic Playground by Ross Kirsling. - The Epistemic Logic Playground was made by Elliot Evans. - Special thanks to my non-classical logic instructors Richard Zach and Audrey Yap, as well - as my classmates who provided feedback on this project. - +This project is based on the open-source Epistemic Logic Playground by Elliot vezwork + and Modal Logic Playground by Ross Kirsling. The Epistemic Logic Playground is a graphical semantic calculator for Dynamic Epistemic logic, built using [D3](http://d3js.org/), [MathJax](http://www.mathjax.org/), and [Bootstrap](http://getbootstrap.com/). -See it in action at [vezwork.github.io/modallogic](https://vezwork.github.io/modallogic)! +See it in action at (NOT YET) ### Reusable code * The core part of the code is MPL.js, a library for parsing and evaluating well-formed formulas of modal propositional logic. See the API Reference [here](API-Reference.md). From c5e08e6344261f4a7b209257d21f746ef7a79faa Mon Sep 17 00:00:00 2001 From: Carlos AGUILERA VENTURA Date: Wed, 12 Mar 2025 17:43:15 +0100 Subject: [PATCH 11/68] mer. 12 mars 2025 17:43:15 CET --- index.html | 51 +++++++++++++++++++++++++++++++++++++++++++++--- js/app.js | 34 ++++++++++++++------------------ tests/model.json | 3 +-- 3 files changed, 64 insertions(+), 24 deletions(-) diff --git a/index.html b/index.html index e18313d..7e53e05 100644 --- a/index.html +++ b/index.html @@ -9,8 +9,8 @@
- -

Dynamic Epistemic Logic Playground

+ +

Dynamic Epistemic Logic Playground(FORK)

- +
@@ -118,6 +157,12 @@

Dynamic Epistemic Logic Playground

+
+

New things

+
    +
  • Insert model using JSON
  • +
+

Editing Instructions

    diff --git a/js/app.js b/js/app.js index c7ac146..97505c1 100644 --- a/js/app.js +++ b/js/app.js @@ -33,6 +33,7 @@ const formulaParam = window.location.search.match(/\?formula=(.*)/); model.loadFromModelString(modelString); + // set up initial nodes and links (edges) of graph, based on MPL model var lastNodeId = -1, nodes = [], @@ -736,8 +737,8 @@ function restart() { // Set the reflexive, symmetric, and transitive checkboxes to the correct state whenever the model // changes. Also update the URL with the shareable model and formula state. -function onStateModified() { - const modelString = '?model=' + model.getModelString(); +function onStateModified(new_model=model) { + const modelString = '?model=' + new_model.getModelString(); let formulaString = '?formula=' + evalInput.select('input').node().value; formulaString = formulaString.split(' ').join(''); //remove spaces formulaString = formulaString.split('>').join(''); //remove > (> doesn't work in URLs) @@ -747,7 +748,7 @@ function onStateModified() { const symmetricCheckEl = document.getElementById('symmetric-check'); const transitiveCheckEl = document.getElementById('transitive-check'); - const activeAgents = model.getActiveAgents(); + const activeAgents = new_model.getActiveAgents(); if (activeAgents.length === 0) { reflexiveCheckEl.checked = false; symmetricCheckEl.checked = false; @@ -759,9 +760,9 @@ function onStateModified() { let symmetricForActiveAgents = true; let transitiveForActiveAgents = true; for (const agent of activeAgents) { - reflexiveForActiveAgents = reflexiveForActiveAgents && model.isReflexive(agent); - symmetricForActiveAgents = symmetricForActiveAgents && model.isSymmetric(agent); - transitiveForActiveAgents = transitiveForActiveAgents && model.isTransitive(agent); + reflexiveForActiveAgents = reflexiveForActiveAgents && new_model.isReflexive(agent); + symmetricForActiveAgents = symmetricForActiveAgents && new_model.isSymmetric(agent); + transitiveForActiveAgents = transitiveForActiveAgents && new_model.isTransitive(agent); } reflexiveCheckEl.checked = reflexiveForActiveAgents; symmetricCheckEl.checked = symmetricForActiveAgents; @@ -1002,24 +1003,19 @@ function updateModel(){ let json = document.getElementById("jsonModel").value let new_model = new MPL.Model() new_model.fromJSON(json); - let modelString = new_model.getModelString(); - let currentUrl = window.location.href; - const modelRegex = /([&?]model=)[^&]*/; - let newUrl; - if (modelRegex.test(currentUrl)) { - newUrl = currentUrl.replace(modelRegex, `$1${modelString}?`); - } else { - const separator = currentUrl.includes('?') ? '&' : '?'; - newUrl = `${currentUrl}${separator}model=${modelString}?`; - } - window.history.replaceState({}, '', newUrl); + // const modelString = '?model=' + new_model.getModelString(); + // let formulaString = '?formula=' + evalInput.select('input').node().value; + // formulaString = formulaString.split(' ').join(''); //remove spaces + // formulaString = formulaString.split('>').join(''); //remove > (> doesn't work in URLs) + // history.pushState({}, '', location.pathname + modelString + formulaString); + onStateModified(new_model); } function setAppMode(newMode) { // mode-specific settings - if(newMode === MODE.EDIT) { + if(newMode === MODE.EDIT || newMode === MODE.TEXT) { // enable listeners svg.classed('edit', true) .on('mousedown', mousedown) @@ -1035,7 +1031,7 @@ function setAppMode(newMode) { .classed('true', false) .classed('false', false); currentFormula.classed('inactive', true); - } else if(newMode === MODE.EVAL || newMode === MODE.TEXT) { + } else if(newMode === MODE.EVAL ) { // disable listeners (except for I-bar prevention) svg.classed('edit', false) .on('mousedown', function() { d3.event.preventDefault(); }) diff --git a/tests/model.json b/tests/model.json index 8445dbe..98f17c3 100644 --- a/tests/model.json +++ b/tests/model.json @@ -34,6 +34,5 @@ } ] } - ], - "agents": ["a", "b"] + ] } From ef77b6936bdb87ed672825b4d53f43911eb00843 Mon Sep 17 00:00:00 2001 From: Carlos AGUILERA VENTURA Date: Thu, 13 Mar 2025 13:28:18 +0100 Subject: [PATCH 12/68] updateModel function --- js/app.js | 532 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 292 insertions(+), 240 deletions(-) diff --git a/js/app.js b/js/app.js index 97505c1..da80b1c 100644 --- a/js/app.js +++ b/js/app.js @@ -33,61 +33,60 @@ const formulaParam = window.location.search.match(/\?formula=(.*)/); model.loadFromModelString(modelString); - // set up initial nodes and links (edges) of graph, based on MPL model var lastNodeId = -1, - nodes = [], - links = []; + nodes = [], + links = []; // --> nodes setup var states = model.getStates(); const propVarsInUse = new Set(); states.forEach(function(state) { - if(!state) { lastNodeId++; return; } + if(!state) { lastNodeId++; return; } - var defaultVals = propvars.map(function() { return false; }), - node = {id: ++lastNodeId, vals: defaultVals}; + var defaultVals = propvars.map(function() { return false; }), + node = {id: ++lastNodeId, vals: defaultVals}; - for(var propvar in state) { - propVarsInUse.add(propvar); - var index = propvars.indexOf(propvar); - if(index !== -1) { - node.vals[index] = true; - varCount = Math.max(varCount, index+1); // set correct var count from state - } - } + for(var propvar in state) { + propVarsInUse.add(propvar); + var index = propvars.indexOf(propvar); + if(index !== -1) { + node.vals[index] = true; + varCount = Math.max(varCount, index+1); // set correct var count from state + } + } - nodes.push(node); + nodes.push(node); }); // --> links setup for (const source of nodes) { - const sourceId = source.id; - for (const succ of model.getSuccessorsOf(sourceId)) { - const targetId = succ.target; - if(sourceId === targetId) { - links.push({source: source, target: source, left: true, right: true, agent: succ.agent }); - continue; - } - - const target = nodes.filter(function(node) { return node.id === targetId; })[0]; - const link = links.filter(l => l.source === target && l.target === source && l.agent === succ.agent)[0]; - - if (link) { - if(sourceId < targetId) { - link.right = true; - } else { - link.left = true; - } - } else { - if(sourceId < targetId) { - links.push({source: source, target: target, left: false, right: true, agent: succ.agent }); - } else { - links.push({source: target, target: source, left: true, right: false, agent: succ.agent }); - } - } - } + const sourceId = source.id; + for (const succ of model.getSuccessorsOf(sourceId)) { + const targetId = succ.target; + if(sourceId === targetId) { + links.push({source: source, target: source, left: true, right: true, agent: succ.agent }); + continue; + } + + const target = nodes.filter(function(node) { return node.id === targetId; })[0]; + const link = links.filter(l => l.source === target && l.target === source && l.agent === succ.agent)[0]; + + if (link) { + if(sourceId < targetId) { + link.right = true; + } else { + link.left = true; + } + } else { + if(sourceId < targetId) { + links.push({source: source, target: target, left: false, right: true, agent: succ.agent }); + } else { + links.push({source: target, target: source, left: true, right: false, agent: succ.agent }); + } + } + } } // set up SVG for D3 @@ -521,6 +520,71 @@ function tick() { }); } +function updateModel() { + let json = document.getElementById("jsonModel").value + model.fromJSON(json); + onStateModified() + + lastNodeId = -1; + nodes = []; + links = []; + + var states = model.getStates(); + const propVarsInUse = new Set(); + states.forEach(function(state) { + if (!state) { lastNodeId++; return; } + + var defaultVals = propvars.map(function() { return false; }), + node = { id: ++lastNodeId, vals: defaultVals }; + + for (var propvar in state) { + propVarsInUse.add(propvar); + var index = propvars.indexOf(propvar); + if (index !== -1) { + node.vals[index] = true; + varCount = Math.max(varCount, index + 1); + } + } + + nodes.push(node); + }); + + for (const source of nodes) { + const sourceId = source.id; + for (const succ of model.getSuccessorsOf(sourceId)) { + const targetId = succ.target; + if (sourceId === targetId) { + links.push({ source: source, target: source, left: true, right: true, agent: succ.agent }); + continue; + } + + const target = nodes.filter(function(node) { return node.id === targetId; })[0]; + const link = links.filter(l => l.source === target && l.target === source && l.agent === succ.agent)[0]; + + if (link) { + if (sourceId < targetId) { + link.right = true; + } else { + link.left = true; + } + } else { + if (sourceId < targetId) { + links.push({ source: source, target: target, left: false, right: true, agent: succ.agent }); + } else { + links.push({ source: target, target: source, left: true, right: false, agent: succ.agent }); + } + } + } + } + + force.nodes(nodes); + force.links(links); + force.start(); + restart(); +} + + + function getDoubleCurvedSVGPath([x1, y1], [x2, y2], curviness) { const facing = [ x2 - x1, @@ -551,194 +615,193 @@ function getSingleCurvedSVGPath([x1, y1], [x2, y2], curviness) { // update graph (called when needed) function restart() { - // path (link) group - path = path.data(links); - - function mid(d) { - return `url(#mid-arrow-${d.agent})`; - } - function start(d) { - return d.left ? `url(#start-arrow-${d.agent})` : ''; - } - function end(d) { - return d.right ? `url(#end-arrow-${d.agent})` : ''; - } - - // update existing links - path.classed('selected', function(d) { return d === selected_link; }) - .classed('agent-a', function(d) { return d.agent === 'a'; }) - .classed('agent-b', function(d) { return d.agent === 'b'; }) - .classed('agent-c', function(d) { return d.agent === 'c'; }) - .classed('agent-d', function(d) { return d.agent === 'd'; }) - .classed('agent-e', function(d) { return d.agent === 'e'; }) - .style('marker-start', start) - .style('marker-end', end) - .style('marker-mid', mid); - - // add new links - path.enter().append('svg:path') - .attr('class', 'link') - .classed('selected', function(d) { return d === selected_link; }) - .classed('agent-a', function(d) { return d.agent === 'a'; }) - .classed('agent-b', function(d) { return d.agent === 'b'; }) - .classed('agent-c', function(d) { return d.agent === 'c'; }) - .classed('agent-d', function(d) { return d.agent === 'd'; }) - .classed('agent-e', function(d) { return d.agent === 'e'; }) - .style('marker-start', start) - .style('marker-end', end) - .style('marker-mid', mid) - .on('mousedown', function(d) { - if(appMode !== MODE.EDIT || d3.event.ctrlKey) return; - - // select link - mousedown_link = d; - if(mousedown_link === selected_link) selected_link = null; - else selected_link = mousedown_link; - setSelectedNode(null); - restart(); - }); - - // remove old links - path.exit().remove(); - - // circle (node) group - // NB: the function arg is crucial here! nodes are known by id, not by index! - circle = circle.data(nodes, function(d) { return d.id; }); - - // update existing nodes (reflexive & selected visual states) - circle.selectAll('circle') - .style('fill', d => (d === selected_node) ? d3.rgb(colors(d.id)).brighter() : colors(d.id)) - .style('stroke-width', '3px') - .style('stroke', d => (d === selected_node) ? 'black': 'transparent'); - - // add new nodes - var g = circle.enter().append('svg:g'); - - g.append('svg:circle') - .attr('class', 'node') - .attr('r', 15) - .style('fill', d => (d === selected_node) ? d3.rgb(colors(d.id)).brighter() : colors(d.id)) - .style('stroke-width', '3px') - .style('stroke', d => (d === selected_node) ? 'black': 'transparent') - .on('mouseover', function(d) { - if(appMode !== MODE.EDIT || !mousedown_node || d === mousedown_node) return; - // enlarge target node - d3.select(this).attr('transform', 'scale(1.1)'); - }) - .on('mouseout', function(d) { - if(appMode !== MODE.EDIT || !mousedown_node || d === mousedown_node) return; - // unenlarge target node - d3.select(this).attr('transform', ''); - }) - .on('mousedown', function(d) { - if(appMode !== MODE.EDIT || d3.event.ctrlKey) return; - - // select node - mousedown_node = d; - if(mousedown_node === selected_node) setSelectedNode(null); - else setSelectedNode(mousedown_node); - selected_link = null; - - // start dragging with drag line - drag_line - .style('marker-end', `url(#end-arrow-${currentEpistemicAgent})`) - .classed('hidden', false) - .classed('agent-a', function() { return currentEpistemicAgent === 'a'; }) - .classed('agent-b', function() { return currentEpistemicAgent === 'b'; }) - .classed('agent-c', function() { return currentEpistemicAgent === 'c'; }) - .classed('agent-d', function() { return currentEpistemicAgent === 'd'; }) - .classed('agent-e', function() { return currentEpistemicAgent === 'e'; }) - .attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'Q' + mousedown_node.x + ' ' + mousedown_node.y + ',' + mousedown_node.x + ' ' + mousedown_node.y) - .style('marker-mid', mid); - - function mid() { - return `url(#mid-arrow-${currentEpistemicAgent})`; - } - - restart(); - }) - .on('mouseup', function(d) { - if(appMode !== MODE.EDIT || !mousedown_node) return; - - // drag line dropped ontop of a node - drag_line - .classed('hidden', true) - .style('marker-end', ''); - - // check for drag-to-self - mouseup_node = d; - if(mouseup_node === mousedown_node) { resetMouseVars(); return; } - - // unenlarge target node - d3.select(this).attr('transform', ''); - - // add transition to model - model.addTransition(mousedown_node.id, mouseup_node.id, currentEpistemicAgent); - onStateModified(); - - // add link to graph (update if exists) - // note: links are strictly source < target; arrows separately specified by booleans - var source, target, direction; - if(mousedown_node.id < mouseup_node.id) { - source = mousedown_node; - target = mouseup_node; - direction = 'right'; - } else { - source = mouseup_node; - target = mousedown_node; - direction = 'left'; - } - - var link = links.filter(function(l) { - return (l.source === source && l.target === target && l.agent === currentEpistemicAgent); - })[0]; - - if(link) { - link[direction] = true; - } else { - link = {source: source, target: target, left: false, right: false, agent: currentEpistemicAgent}; - link[direction] = true; - links.push(link); - } - - // select new link - selected_link = link; - setSelectedNode(null); - restart(); - }); - - // show node IDs - g.append('svg:text') - .attr('x', 0) - .attr('y', 4) - .attr('class', 'id') - .attr('fill', 'white') - .text(function(d) { return d.id; }); - - // text shadow - g.append('svg:text') - .attr('x', 18) - .attr('y', 4) - .attr('class', 'shadow') - .text(makeAssignmentString); - - // text foreground - g.append('svg:text') - .attr('x', 18) - .attr('y', 4) - .text(makeAssignmentString); - - // remove old nodes - circle.exit().remove(); - - // set the graph in motion - force.start(); + // path (link) group + path = path.data(links); + + function mid(d) { + return `url(#mid-arrow-${d.agent})`; + } + function start(d) { + return d.left ? `url(#start-arrow-${d.agent})` : ''; + } + function end(d) { + return d.right ? `url(#end-arrow-${d.agent})` : ''; + } + + // update existing links + path.classed('selected', function(d) { return d === selected_link; }) + .classed('agent-a', function(d) { return d.agent === 'a'; }) + .classed('agent-b', function(d) { return d.agent === 'b'; }) + .classed('agent-c', function(d) { return d.agent === 'c'; }) + .classed('agent-d', function(d) { return d.agent === 'd'; }) + .classed('agent-e', function(d) { return d.agent === 'e'; }) + .style('marker-start', start) + .style('marker-end', end) + .style('marker-mid', mid); + + // add new links + path.enter().append('svg:path') + .attr('class', 'link') + .classed('selected', function(d) { return d === selected_link; }) + .classed('agent-a', function(d) { return d.agent === 'a'; }) + .classed('agent-b', function(d) { return d.agent === 'b'; }) + .classed('agent-c', function(d) { return d.agent === 'c'; }) + .classed('agent-d', function(d) { return d.agent === 'd'; }) + .classed('agent-e', function(d) { return d.agent === 'e'; }) + .style('marker-start', start) + .style('marker-end', end) + .style('marker-mid', mid) + .on('mousedown', function(d) { + if(appMode !== MODE.EDIT || d3.event.ctrlKey) return; + // select link + mousedown_link = d; + if(mousedown_link === selected_link) selected_link = null; + else selected_link = mousedown_link; + setSelectedNode(null); + restart(); + }); + + // remove old links + path.exit().remove(); + + // circle (node) group + // NB: the function arg is crucial here! nodes are known by id, not by index! + circle = circle.data(nodes, function(d) { return d.id; }); + + // update existing nodes (reflexive & selected visual states) + circle.selectAll('circle') + .style('fill', d => (d === selected_node) ? d3.rgb(colors(d.id)).brighter() : colors(d.id)) + .style('stroke-width', '3px') + .style('stroke', d => (d === selected_node) ? 'black': 'transparent'); + + // add new nodes + var g = circle.enter().append('svg:g'); + + g.append('svg:circle') + .attr('class', 'node') + .attr('r', 15) + .style('fill', d => (d === selected_node) ? d3.rgb(colors(d.id)).brighter() : colors(d.id)) + .style('stroke-width', '3px') + .style('stroke', d => (d === selected_node) ? 'black': 'transparent') + .on('mouseover', function(d) { + if(appMode !== MODE.EDIT || !mousedown_node || d === mousedown_node) return; + // enlarge target node + d3.select(this).attr('transform', 'scale(1.1)'); + }) + .on('mouseout', function(d) { + if(appMode !== MODE.EDIT || !mousedown_node || d === mousedown_node) return; + // unenlarge target node + d3.select(this).attr('transform', ''); + }) + .on('mousedown', function(d) { + if(appMode !== MODE.EDIT || d3.event.ctrlKey) return; + + // select node + mousedown_node = d; + if(mousedown_node === selected_node) setSelectedNode(null); + else setSelectedNode(mousedown_node); + selected_link = null; + + // start dragging with drag line + drag_line + .style('marker-end', `url(#end-arrow-${currentEpistemicAgent})`) + .classed('hidden', false) + .classed('agent-a', function() { return currentEpistemicAgent === 'a'; }) + .classed('agent-b', function() { return currentEpistemicAgent === 'b'; }) + .classed('agent-c', function() { return currentEpistemicAgent === 'c'; }) + .classed('agent-d', function() { return currentEpistemicAgent === 'd'; }) + .classed('agent-e', function() { return currentEpistemicAgent === 'e'; }) + .attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'Q' + mousedown_node.x + ' ' + mousedown_node.y + ',' + mousedown_node.x + ' ' + mousedown_node.y) + .style('marker-mid', mid); + + function mid() { + return `url(#mid-arrow-${currentEpistemicAgent})`; + } + + restart(); + }) + .on('mouseup', function(d) { + if(appMode !== MODE.EDIT || !mousedown_node) return; + + // drag line dropped ontop of a node + drag_line + .classed('hidden', true) + .style('marker-end', ''); + + // check for drag-to-self + mouseup_node = d; + if(mouseup_node === mousedown_node) { resetMouseVars(); return; } + + // unenlarge target node + d3.select(this).attr('transform', ''); + + // add transition to model + model.addTransition(mousedown_node.id, mouseup_node.id, currentEpistemicAgent); + onStateModified(); + + // add link to graph (update if exists) + // note: links are strictly source < target; arrows separately specified by booleans + var source, target, direction; + if(mousedown_node.id < mouseup_node.id) { + source = mousedown_node; + target = mouseup_node; + direction = 'right'; + } else { + source = mouseup_node; + target = mousedown_node; + direction = 'left'; + } + + var link = links.filter(function(l) { + return (l.source === source && l.target === target && l.agent === currentEpistemicAgent); + })[0]; + + if(link) { + link[direction] = true; + } else { + link = {source: source, target: target, left: false, right: false, agent: currentEpistemicAgent}; + link[direction] = true; + links.push(link); + } + + // select new link + selected_link = link; + setSelectedNode(null); + restart(); + }); + + // show node IDs + g.append('svg:text') + .attr('x', 0) + .attr('y', 4) + .attr('class', 'id') + .attr('fill', 'white') + .text(function(d) { return d.id; }); + + // text shadow + g.append('svg:text') + .attr('x', 18) + .attr('y', 4) + .attr('class', 'shadow') + .text(makeAssignmentString); + + // text foreground + g.append('svg:text') + .attr('x', 18) + .attr('y', 4) + .text(makeAssignmentString); + + // remove old nodes + circle.exit().remove(); + + // set the graph in motion + force.start(); } // Set the reflexive, symmetric, and transitive checkboxes to the correct state whenever the model // changes. Also update the URL with the shareable model and formula state. -function onStateModified(new_model=model) { - const modelString = '?model=' + new_model.getModelString(); +function onStateModified() { + const modelString = '?model=' + model.getModelString(); let formulaString = '?formula=' + evalInput.select('input').node().value; formulaString = formulaString.split(' ').join(''); //remove spaces formulaString = formulaString.split('>').join(''); //remove > (> doesn't work in URLs) @@ -748,7 +811,7 @@ function onStateModified(new_model=model) { const symmetricCheckEl = document.getElementById('symmetric-check'); const transitiveCheckEl = document.getElementById('transitive-check'); - const activeAgents = new_model.getActiveAgents(); + const activeAgents = model.getActiveAgents(); if (activeAgents.length === 0) { reflexiveCheckEl.checked = false; symmetricCheckEl.checked = false; @@ -760,9 +823,9 @@ function onStateModified(new_model=model) { let symmetricForActiveAgents = true; let transitiveForActiveAgents = true; for (const agent of activeAgents) { - reflexiveForActiveAgents = reflexiveForActiveAgents && new_model.isReflexive(agent); - symmetricForActiveAgents = symmetricForActiveAgents && new_model.isSymmetric(agent); - transitiveForActiveAgents = transitiveForActiveAgents && new_model.isTransitive(agent); + reflexiveForActiveAgents = reflexiveForActiveAgents && model.isReflexive(agent); + symmetricForActiveAgents = symmetricForActiveAgents && model.isSymmetric(agent); + transitiveForActiveAgents = transitiveForActiveAgents && model.isTransitive(agent); } reflexiveCheckEl.checked = reflexiveForActiveAgents; symmetricCheckEl.checked = symmetricForActiveAgents; @@ -998,18 +1061,7 @@ function keyup() { var modeButtons = d3.selectAll('#mode-select button'), panes = d3.selectAll('#app-body .panel .tab-pane'); -// Función que actualza el modelo en base a un json. Para ello crea una url nueva. IMP> No mantiene la información de la fórmula. -function updateModel(){ - let json = document.getElementById("jsonModel").value - let new_model = new MPL.Model() - new_model.fromJSON(json); - // const modelString = '?model=' + new_model.getModelString(); - // let formulaString = '?formula=' + evalInput.select('input').node().value; - // formulaString = formulaString.split(' ').join(''); //remove spaces - // formulaString = formulaString.split('>').join(''); //remove > (> doesn't work in URLs) - // history.pushState({}, '', location.pathname + modelString + formulaString); - onStateModified(new_model); -} + From 0de47cd9aff6afe3f001beffed303f64a1e4e5b9 Mon Sep 17 00:00:00 2001 From: Carlos AGUILERA VENTURA Date: Thu, 13 Mar 2025 16:57:31 +0100 Subject: [PATCH 13/68] jeu. 13 mars 2025 16:57:31 CET --- index.html | 2 +- js/app.js | 67 ++++-------------------------------------------------- 2 files changed, 5 insertions(+), 64 deletions(-) diff --git a/index.html b/index.html index 7e53e05..43d5028 100644 --- a/index.html +++ b/index.html @@ -101,7 +101,7 @@

    Dynamic Epistemic Logic Playground(FORK)

    - - -
    - -
    - loading...
    - -
    - -
    - - -
    -
    -
    - - -
-
-

New things

-
    -
  • Insert model using JSON
  • -
-
-
-

Editing Instructions

-
    -
  • Click in the open space to add a world
  • -
  • Drag between worlds to add a transition for the current agent
  • -
  • Ctrl-drag a world to move graph layout
  • -
  • Click a world or a transition to select it
  • -
  • - When a world is selected: -
      -
    • R toggles reflexivity for the current agent
    • -
    • Delete removes the world
    • -
    -
  • -
  • - When a transition is selected: -
      -
    • L(eft), R(ight), B(oth) change direction
    • -
    • Delete removes the transition
    • -
    -
  • -
  • Copy the URL from your browser's URL bar to share your model!
  • -
-
-
-

Examples

- -
-
-

What is (Epistemic) Logic?

- Epistemic Logic is way of formally reasoning about knowledge. - In order to understand how Epistemic logic works, let's start with classical logic and build - up from there. -

Classical Logic and Formulas

-

- In classical logic we start with propositional variables, our propositional - variables are $p$, $q$, $r$, $s$, and $t$. Each propositional variable can either be - true or false. For example we can say $p$ is false, written as $\lnot p$, and let's say - $q$ is true, written just as $q$. -

- - 0¬p, q¬p, q - -

- Alongside propositional variables, we have the classical logical connectives: -

    -
  • $\lnot A$ (not) which is true when $A$ is false,
  • -
  • $A \land B$ (and) which is true when both $A$ and $B$ are true,
  • -
  • $A \lor B$ (or) which is true when $A$ is true, or $B$ is true, or both are true,
  • -
  • and $A \rightarrow B$ (conditional) which is true if $B$ is true whenever $A$ is true.
  • -
- We can apply the logical connectives, along with parantheses, - to propositional variables to build up complex formulas. For example - $(p \rightarrow q) \land (q \rightarrow p)$ is a formula which is true when $p = q$, - or $p \lor \lnot p$ is a formula which is always true! -
- pro tip: $(p \rightarrow q) \land (q \rightarrow p)$ can - be written shorthand as (p <-> q) in the playground. -
-

-

Worlds, Agents, and Epistemic Logic

-

- Epistemic Logic is designed for reasoning about the knowledge of someone (we call that someone an agent). - We might imagine that an agent does not know whether they are in a situation where - $p$ is true, or a situation where $p$ is not true, i.e. $\lnot p$. - We express situations as worlds. - We express an agent's knowledge by drawing relations (arrows) between worlds. These worlds - and agent relations together are called a model. -

-

- Here's an example model for when an agent $a$ doesn't know if they are in - a situation where $p$, or a situation where $\lnot p$: - - a - - - - 0pp1¬p¬p - -

-

- When you enter a classical formula into the playground, the formula is evaluated at each world as if that - world was just a classical logic by itself. Epistemic logic introduces a new logical connective which takes advantage of agents' relations - between worlds: -

    -
  • $K_b A$ (knowledge of an agent $b$) which is true at a world when $A$ is true at all worlds connected to that - world by $b$ arrows.
  • -
  • along with $K_{a,b,c} A$ which is shorthand for $K_a A\land K_b A\land K_c A$.
  • -
- Now, I understand if this definition isn't intuitive, it's not obvious what $K_b A$ has - to do with knowledge. In order to start intuitively understanding, let's consider our previous - example. - We can write a formula to check whether an agent $a$ knows that they are in - a situation where $p$ or that they know they are in a situation where $\lnot p$: - - This formula is false, by definition of $K_a$, at both worlds because they are each connected to both a world - where $p$ is false and a world where $p$ is true. - - a - - - - 0pp1¬p¬p - - In an intuitive sense, agent $a$ does not know what $p$ is because they cannot distinguish between - the world where $p$ is true and the world where $p$ is false. -

-

- If you add more than one agent you can reason about one agent's knowledge of - another agent's knowledge e.g. $K_a K_b p$, $a$ knows that $b$ knows that $p$ is true. -

-

- Finally, for the sake of representing knowledge, in Epistemic logic it is expected that all agent's relations between worlds are - equivalence relations, i.e. each agent's relation is: -

    -
  • reflexive, so each world is related to itself;
  • -
  • symmetric, if a world $0$ is related to a world $1$, then world $1$ is also related to world $0$;
  • -
  • and transitive, if a world $0$ is related to a world $1$, and world $1$ is related to world $2$ then - world $0$ has to be related to world $2$ as well. -
  • -
-

-

Dynamic Epistemic Logic - Public Announcement

-

- Dynamic Epistemic Logic introduces announcement, a mechanism for publicly announcing facts that - become the knowledge of all agents. Given a formula $A$, a public announcement removes all - worlds where $A$ is not true. -

-

- Dynamic Epistemic Logic also introduces a logical connective: -

    -
  • $[A]B$ (public announcement of $A$) which is true at a world if $B$ is true after $A$ is announced, or if the world - is removed by the announcement.
  • -
- Try out the announcement button and the announcement connective in the playground. -

-
-
-

Project Information

-

- This project is based on the open-source Modal Logic Playground by Ross Kirsling. - The Epistemic Logic Playground was made by Elliot Evans. - Special thanks to my non-classical logic instructors Richard Zach and Audrey Yap, as well - as my classmates Jaxson, Parker, Koray, Alejandro, and Tina who provided feedback on this project. -

-

- More resources on Epistemic Logic and this project: -

-

-
- - - - - - - - - - - - +
+
+
+
+ + +
+								
+
+
+ Current agent: +
+
+ + + + + +
+
+
+ Number of propositional variables: +
+
+ + + + + +
+
+
+
+ No world selected +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ p: + +
+ + +
+
+ q: + +
+ + +
+
+ r: + +
+ + +
+
+ s: + +
+ + +
+
+ t: + +
+ + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + +
+
+ Enter a formula: + + + or + +
+
+
+
+
    +
  • + When entering a formula: +
      +
    • + use + + ~A + + for $\lnot{}A$ +
    • +
    • + use + + (A & B) + + for $(A\land{}B)$ +
    • +
    • + use + + (A | B) + + for $(A\lor{}B)$ +
    • +
    • + use + + (A -> B) + + for $(A\rightarrow{}B)$ +
    • +
    • + use + + K{a,b,c}A + + for $K_{a,b,c}A$ +
    • +
    • + use + + [A]B + + for $[A]B$ +
    • +
    +
  • +
+
+
+
+ +
+
+
+ + loading... + +
+ + +
+ + +
+ + +
+
+
+
+
+ +
+ +
+

+ New things +

+
    +
  • + Insert model using JSON +
  • +
+
+
+

+ Editing Instructions +

+
    +
  • + Click in the open space to + + add a world + +
  • +
  • + Drag between worlds to + + add a transition for the current agent + +
  • +
  • + Ctrl-drag a world to + + move + + graph layout +
  • +
  • + Click a world or a transition to + + select + + it +
  • +
  • + When a world is selected: +
      +
    • + + R + + toggles reflexivity for the current agent +
    • +
    • + + Delete + + removes the world +
    • +
    +
  • +
  • + When a transition is selected: +
      +
    • + + L + + (eft), + + R + + (ight), + + B + + (oth) change direction +
    • +
    • + + Delete + + removes the transition +
    • +
    +
  • +
  • + Copy the URL from your browser's URL bar to share your model! +
  • +
+
+
+

+ Examples +

+ +
+
+

+ What is (Epistemic) Logic? +

+ Epistemic Logic is way of formally reasoning about knowledge. + In order to understand how Epistemic logic works, let's start with classical logic and build + up from there. +

+ Classical Logic and Formulas +

+

+ In classical logic we start with propositional variables, our propositional + variables are $p$, $q$, $r$, $s$, and $t$. Each propositional variable can either be + true or false. For example we can say $p$ is false, written as $\lnot p$, and let's say + $q$ is true, written just as $q$. +

+ + + + + + 0 + + + ¬p, q + + + ¬p, q + + + +

+ Alongside propositional variables, we have the classical logical connectives: +

    +
  • + $\lnot A$ (not) which is true when $A$ is false, +
  • +
  • + $A \land B$ (and) which is true when both $A$ and $B$ are true, +
  • +
  • + $A \lor B$ (or) which is true when $A$ is true, or $B$ is true, or both are true, +
  • +
  • + and $A \rightarrow B$ (conditional) which is true if $B$ is true whenever $A$ is true. +
  • +
+ We can apply the logical connectives, along with parantheses, + to propositional variables to build up complex formulas. For example + + $(p \rightarrow q) \land (q \rightarrow p)$ is a formula which is true when $p = q$ + + , + or + + $p \lor \lnot p$ is a formula which is always true! + +
+ pro tip: $(p \rightarrow q) \land (q \rightarrow p)$ can + be written shorthand as + + (p <-> q) + + in the playground. +
+

+

+ Worlds, Agents, and Epistemic Logic +

+

+ Epistemic Logic is designed for reasoning about the knowledge of someone (we call that someone an agent). + We might imagine that an agent does not know whether they are in a situation where + $p$ is true, or a situation where $p$ is not true, i.e. $\lnot p$. + We express situations as worlds. + We express an agent's knowledge by drawing relations (arrows) between worlds. These worlds + and agent relations together are called a model. +

+

+ Here's + + an example model + + for when an agent $a$ doesn't know if they are in + a situation where $p$, or a situation where $\lnot p$: + + + + + a + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + p + + + p + + + + + + + 1 + + + ¬p + + + ¬p + + + + +

+

+ When you enter a classical formula into the playground, the formula is evaluated at each world as if that + world was just a classical logic by itself. Epistemic logic introduces a new logical connective which takes advantage of agents' relations + between worlds: +

    +
  • + $K_b A$ (knowledge of an agent $b$) which is true at a world when $A$ is true at all worlds connected to that + world by $b$ arrows. +
  • +
  • + along with $K_{a,b,c} A$ which is shorthand for $K_a A\land K_b A\land K_c A$. +
  • +
+ Now, I understand if this definition isn't intuitive, it's not obvious what $K_b A$ has + to do with knowledge. In order to start intuitively understanding, let's consider our previous + example. + We can write a formula to check whether an agent $a$ knows that they are in + a situation where $p$ or that they know they are in a situation where $\lnot p$: + + This formula is false, by definition of $K_a$, at both worlds because they are each connected to both a world + where $p$ is false and a world where $p$ is true. + + + + + a + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + p + + + p + + + + + + + 1 + + + ¬p + + + ¬p + + + + + In an intuitive sense, agent $a$ does not know what $p$ is because they cannot distinguish between + the world where $p$ is true and the world where $p$ is false. +

+

+ If you add more than one agent you can reason about one agent's knowledge of + another agent's knowledge e.g. + + $K_a K_b p$, $a$ knows that $b$ knows that $p$ is true. + +

+

+ Finally, for the sake of representing knowledge, in Epistemic logic it is expected that all agent's relations between worlds are + equivalence relations, i.e. each agent's relation is: +

    +
  • + + reflexive + + , so each world is related to itself; +
  • +
  • + + symmetric + + , if a world $0$ is related to a world $1$, then world $1$ is also related to world $0$; +
  • +
  • + and + + transitive + + , if a world $0$ is related to a world $1$, and world $1$ is related to world $2$ then + world $0$ has to be related to world $2$ as well. +
  • +
+

+

+ Dynamic Epistemic Logic - Public Announcement +

+

+ Dynamic Epistemic Logic introduces announcement, a mechanism for publicly announcing facts that + become the knowledge of all agents. Given a formula $A$, a public announcement removes all + worlds where $A$ is not true. +

+

+ Dynamic Epistemic Logic also introduces a logical connective: +

    +
  • + $[A]B$ (public announcement of $A$) which is true at a world if $B$ is true after $A$ is announced, or if the world + is removed by the announcement. +
  • +
+ Try out the announcement button and the announcement connective in the playground. +

+
+
+

+ Project Information +

+

+ This project is based on the open-source + + Modal Logic Playground + + by + + Ross Kirsling + + . + The Epistemic Logic Playground was made by + + Elliot Evans + + . + Special thanks to my non-classical logic instructors Richard Zach and Audrey Yap, as well + as my classmates Jaxson, Parker, Koray, Alejandro, and Tina who provided feedback on this project. +

+

+ More resources on Epistemic Logic and this project: +

+

+
+ + + + + + + + + + diff --git a/js/utils.js b/js/utils.js index 2d79e58..e45d5f5 100644 --- a/js/utils.js +++ b/js/utils.js @@ -25,3 +25,70 @@ document.getElementById('fileInput').addEventListener('change', function(event) } }); + +function addText(conector, element=null) { + var text = document.getElementById('formulaInput'); + + text.focus(); + if (conector === "delete"){ + text.value = ''; + return; + }else{ + text.value += conector; + } + if (element===null){ + return + } + const className = element.className; + + let styleScript = document.getElementById('button-style'); + if (!styleScript) { + styleScript = document.createElement('style'); + styleScript.id = 'button-style'; // Asigna el id + document.head.appendChild(styleScript); + } + + switch(className){ + case "atom-button": + hide = ["atom-button", "monadic-button", "modal-button", "agent-button"] + show = ["diadic-button"] + break; + case "monadic-button": + hide = ["diadic-button","agent-button"] + show = ["monadic-button", "atom-button", "modal-button"] + break; + case "modal-button": + hide = ["diadic-button"] + show = ["monadic-button", "atom-button", "modal-button"] + break; + case "group-button": + hide = ["monadic-button", "atom-button", "modal-button", "diadic-button"] + show = ["agent-button"] + break; + case "agent-button": + hide = ["diadic-button"] + show = ["agent-button", "monadic-button", "atom-button", "modal-button"] + break; + case "diadic-button": + hide = ["diadic-button"] + show = ["monadic-button", "atom-button", "modal-button"] + break; + } + + styleScript.innerHTML = ''; // Elimina todas las reglas CSS previas + applyStyles(show, hide); +} + + + + +// Función para aplicar los estilos (mostrar/ocultar los botones) +function applyStyles(show, hide) { + let styleScript = document.getElementById('button-style'); + hide.forEach(clase => { + styleScript.innerHTML += `.${clase} { display:none; }`; + }); + show.forEach(clase => { + styleScript.innerHTML += `.${clase} { display:inline; }`; + }); +} From de0d7d6fd1338e463ce2122a5734d78f66776af2 Mon Sep 17 00:00:00 2001 From: karu Date: Wed, 2 Apr 2025 20:10:44 +0200 Subject: [PATCH 36/68] remove file \ --- "\\" | 94 ------------------------------------------------------------ 1 file changed, 94 deletions(-) delete mode 100644 "\\" diff --git "a/\\" "b/\\" deleted file mode 100644 index e45d5f5..0000000 --- "a/\\" +++ /dev/null @@ -1,94 +0,0 @@ - -// When the button is clicked. -document.getElementById('readFileButton').addEventListener('click', function() { - document.getElementById('fileInput').click(); -}); - -// -document.getElementById('fileInput').addEventListener('change', function(event) { - const file = event.target.files[0]; // Obtiene el archivo seleccionado - - if (file) { - const reader = new FileReader(); - - reader.onload = function(e) { - updateModel(e.target.result); //TODO parser - }; - - reader.onerror = function(e) { - console.error("Error al leer el archivo:", e.target.error); - }; - - reader.readAsText(file); - } else { - console.log("No se seleccionó ningún archivo."); - } -}); - - -function addText(conector, element=null) { - var text = document.getElementById('formulaInput'); - - text.focus(); - if (conector === "delete"){ - text.value = ''; - return; - }else{ - text.value += conector; - } - if (element===null){ - return - } - const className = element.className; - - let styleScript = document.getElementById('button-style'); - if (!styleScript) { - styleScript = document.createElement('style'); - styleScript.id = 'button-style'; // Asigna el id - document.head.appendChild(styleScript); - } - - switch(className){ - case "atom-button": - hide = ["atom-button", "monadic-button", "modal-button", "agent-button"] - show = ["diadic-button"] - break; - case "monadic-button": - hide = ["diadic-button","agent-button"] - show = ["monadic-button", "atom-button", "modal-button"] - break; - case "modal-button": - hide = ["diadic-button"] - show = ["monadic-button", "atom-button", "modal-button"] - break; - case "group-button": - hide = ["monadic-button", "atom-button", "modal-button", "diadic-button"] - show = ["agent-button"] - break; - case "agent-button": - hide = ["diadic-button"] - show = ["agent-button", "monadic-button", "atom-button", "modal-button"] - break; - case "diadic-button": - hide = ["diadic-button"] - show = ["monadic-button", "atom-button", "modal-button"] - break; - } - - styleScript.innerHTML = ''; // Elimina todas las reglas CSS previas - applyStyles(show, hide); -} - - - - -// Función para aplicar los estilos (mostrar/ocultar los botones) -function applyStyles(show, hide) { - let styleScript = document.getElementById('button-style'); - hide.forEach(clase => { - styleScript.innerHTML += `.${clase} { display:none; }`; - }); - show.forEach(clase => { - styleScript.innerHTML += `.${clase} { display:inline; }`; - }); -} From e22bf4a1b55024f6f9ab5b49b8d850714efcedfe Mon Sep 17 00:00:00 2001 From: Carlos AGUILERA VENTURA Date: Thu, 5 Jun 2025 14:33:10 +0200 Subject: [PATCH 37/68] README --- API-Reference.md | 213 ----------------------------------------------- LICENSE | 20 ----- README.md | 2 +- 3 files changed, 1 insertion(+), 234 deletions(-) delete mode 100644 API-Reference.md delete mode 100644 LICENSE diff --git a/API-Reference.md b/API-Reference.md deleted file mode 100644 index 6d3fd69..0000000 --- a/API-Reference.md +++ /dev/null @@ -1,213 +0,0 @@ -# MPL.js: API Reference - -MPL is a library for parsing and evaluating well-formed formulas (wffs) of modal propositional logic. - -MPL has a single dependency, [formula-parser](https://www.npmjs.com/package/formula-parser). - -## Parsing and displaying wffs - -MPL wffs can be represented in four ways: -* ASCII, for typing -* JSON, for processing -* LaTeX, for displaying nicely -* Unicode, for displaying accessibly - -All four are stored in a `Wff` object, created by providing either the ASCII or JSON representation as input. - -In each case: -* Parentheses and whitespace don't matter. -* Binary connectives are strictly binary. -* Propositional variables may be any alphanumeric string. - -In the table below, `p` is a propositional variable, while `A` and `B` are arbitrary subwffs. - - - - - - - - - - - - - - - -
ASCIIJSONLaTeXUnicode
Propositionp{prop: 'p'}pp
Negation~A{neg: A}\lnot{}A\u00acA
Necessity[]A{nec: A}\Box{}A\u25a1A
Possibility<>A{poss: A}\Diamond{}A\u25caA
Conjunction(A & B){conj: [A, B]}(A\land{}B)(A \u2227 B)
Disjunction(A | B){disj: [A, B]}(A\lor{}B)(A \u2228 B)
Implication(A -> B){impl: [A, B]}(A\rightarrow{}B)(A \u2192 B)
Equivalence(A <-> B){equi: [A, B]}(A\leftrightarrow{}B)(A \u2194 B)
- -### MPL.Wff( asciiOrJSON ) - -Constructor for MPL wff. Takes either ASCII or JSON representation as input. - -```javascript -// the following are equivalent: -var wff = new MPL.Wff('(p -> []p)'); -var wff = new MPL.Wff({impl: [{prop: 'p'}, {nec: {prop: 'p'}}]}); -``` - -### wff.ascii() - -Returns the ASCII representation of an MPL wff. - -```javascript -wff.ascii(); -// => '(p -> []p)' -``` - -### wff.json() - -Returns the JSON representation of an MPL wff. - -```javascript -wff.json(); -// => {impl: [{prop: 'p'}, {nec: {prop: 'p'}}]} -``` - -### wff.latex() - -Returns the LaTeX representation of an MPL wff. - -```javascript -wff.latex(); -// => '(p\\rightarrow{}\\Box{}p)' -``` - -### wff.unicode() - -Returns the Unicode representation of an MPL wff. - -```javascript -wff.unicode(); -// => '(p \u2192 \u25a1p)' -``` - - -## Kripke models - -Mathematically, a Kripke model consists of: -* a set of *states* (or *worlds*) -* an *accessibility relation* (i.e., a set of *transitions*) -* a *valuation* (a complete assignment of truth values to each variable at each state) - -Specifically, in an MPL `Model`: -* Each state has a zero-based index and an assignment. -* An assignment is an object in which the keys are propositional variable names and the values are booleans. -* Only **true** propositional variables are actually stored! All others are automatically interpreted as false. - -Models can also be exported to, and imported from, a compact 'model string' notation. - -### MPL.Model() - -Constructor for Kripke model. Takes no initial input. - -```javascript -var model = new MPL.Model(); -``` - -### model.addTransition( source, target ) - -Adds a transition to the model, given source and target state indices. - -```javascript -// example: a model where states 0 and 1 have been added and not removed -model.addTransition(0, 1); -``` - -### model.removeTransition( source, target ) - -Removes a transition from the model, given source and target state indices. - -```javascript -// example: a model where states 0 and 1 have been added and not removed -model.removeTransition(0, 1); -``` - -### model.getSuccessorsOf( source ) - -Returns an array of successor states for a given state index. - -```javascript -// example: a model with transitions (0,0) and (0,1) -model.getSuccessorsOf(0); -// => [0, 1] -``` - -### model.addState( assignment ) - -Adds a state with a given assignment to the model. - -```javascript -model.addState({'p': true}); -``` - -### model.editState( state, assignment ) - -Edits the assignment of a state in the model, given a state index and a new partial assignment. - -```javascript -model.editState(0, {'p': false, 'q': true}); -``` - -### model.removeState( state ) - -Removes a state and all related transitions from the model, given a state index. - -```javascript -model.removeState(0); -``` - -### model.getStates() - -Returns an array containing the assignment (or null) of each state in the model. -(Only true propositional variables are returned in each assignment.) - -```javascript -// example: a model with states 0 and 2 (where state 1 has been removed); 'q' is true at 0, nothing true at 2 -model.getStates(); -// => [{'q': true}, null, {}] -``` - -### model.valuation( propvar, state ) - -Returns the truth value of a given propositional variable at a given state index. - -```javascript -// example: a model where only 'q' is true at state 0 -model.valuation('r', 0); -// => false -``` - -### model.getModelString() - -Returns current model as a compact string suitable for use as a URL parameter. - -```javascript -// example: a model with states 0 and 2 (where state 1 has been removed) and transitions (0,0) and (0,2); -// 'q' is true at 0, nothing true at 2 -model.getModelString(); -// => 'AqS0,2;;AS;' -``` - -### model.loadFromModelString( modelString ) - -Restores a model from a given model string. - -```javascript -model.loadFromModelString('AqS0,2;;AS;'); -``` - - -## Evaluating wffs - -### MPL.truth( model, state, wff ) - -Evaluate the truth of an MPL wff at a given state within a given model. - -```javascript -// example: model is an MPL Model with only state 0 and no transitions; 'p' is true at state 0 -// wff is the MPL Wff '(p -> []p)' -MPL.truth(model, 0, wff); -// => true -``` diff --git a/LICENSE b/LICENSE deleted file mode 100644 index b5bf9ec..0000000 --- a/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2013 Ross Kirsling - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index a972c6c..51cea0d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Epistemic Logic Playground(FORK for T4TL) +(FORK) Epistemic Logic Playground ====================== This project is based on the open-source Epistemic Logic Playground by Elliot vezwork and Modal Logic Playground by Ross Kirsling. From ca951cbab31c2c82c1ed2dbe33dda9935c7730d4 Mon Sep 17 00:00:00 2001 From: cagve <68747055+cagve@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:04:52 +0100 Subject: [PATCH 38/68] Add TODO section in README Added a TODO section to outline future work. --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 51cea0d..ad4372e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ (FORK) Epistemic Logic Playground ====================== +## TODO +- [ ] (Subformulas) get back to the original model. + + This project is based on the open-source Epistemic Logic Playground by Elliot vezwork - and Modal Logic Playground by Ross Kirsling. + and Modal Logic Playground by Ross Kirsling. The Epistemic Logic Playground is a graphical semantic calculator for Dynamic Epistemic logic, built using [D3](http://d3js.org/), [MathJax](http://www.mathjax.org/), and [Bootstrap](http://getbootstrap.com/). From 2b348d77f64472badd23f78e8b80ee31cd9d7be4 Mon Sep 17 00:00:00 2001 From: cagve <68747055+cagve@users.noreply.github.com> Date: Tue, 3 Feb 2026 13:06:07 +0100 Subject: [PATCH 39/68] Add FORK section and format TODO heading Updated the README to include a FORK section and improved formatting. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ad4372e..d509c33 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,12 @@ (FORK) Epistemic Logic Playground ====================== -## TODO +### TODO - [ ] (Subformulas) get back to the original model. +- [ ] Text about Common and Distributed Knowledge. +- [ ] +### FORK This project is based on the open-source Epistemic Logic Playground by Elliot vezwork and Modal Logic Playground by Ross Kirsling. From acc911bc395563efb1caa3dab4f101630c464a2c Mon Sep 17 00:00:00 2001 From: karu Date: Wed, 4 Feb 2026 10:23:39 +0100 Subject: [PATCH 40/68] prerefactor --- css/app.css | 4 ++++ index.html | 35 ++-------------------------- js/app.js | 67 +++++++++++++++++++++++++++++++++-------------------- 3 files changed, 48 insertions(+), 58 deletions(-) diff --git a/css/app.css b/css/app.css index 32b1e79..62ec41c 100644 --- a/css/app.css +++ b/css/app.css @@ -2,6 +2,10 @@ body { font-family: 'Open Sans', sans-serif; } +#formula-container { + cursor: pointer; +} + #page-container { width: 962px; position: relative; diff --git a/index.html b/index.html index 1b4fc6c..ca9d585 100644 --- a/index.html +++ b/index.html @@ -27,19 +27,10 @@

-
-
- - -
-								
-
Current agent:
@@ -128,28 +119,6 @@

-
- - - - - - - - - - - - - - - - - - - - -
Enter a formula:
-
+
- diff --git a/js/app.js b/js/app.js index c07cec4..e6eb611 100644 --- a/js/app.js +++ b/js/app.js @@ -6,10 +6,6 @@ * Copyright (c) 2013 Ross Kirsling * Released under the MIT License. */ - -// const { index } = require("d3"); - -// app mode constants var MODE = { EDIT: 0, EVAL: 1, @@ -187,8 +183,8 @@ var varCountButtons = d3.selectAll('#edit-pane .var-count button'), selectedNodeLabel = d3.select('#edit-pane .selected-node-id'), evalInput = d3.select('#eval-pane .eval-input'), evalOutput = d3.select('#eval-pane .eval-output'), - currentFormula = d3.select('#app-body .current-formula'); - currentSubFormula = d3.select('#app-body .current-subformula'); + currentFormula = d3.select('#app-body .current-formula'), + currentSubformula = d3.select('#app-body .current-subformula'), btnSubformulae = d3.select('#btn-formulae'); function announceFormula() { @@ -347,30 +343,38 @@ function evaluateFormula() { .classed('false', !truthVal); }); + currentFormula + .append("div") + // .attr("class", "dropdown-content") + // display evaluated formula currentFormula .html('Current formula:
$' + wff.latex() + '$') - .classed('inactive', false); + .classed('inactive', false) + .on('click', function(event) { + console.log('hola') + }); - currentSubFormula.selectAll("*").remove(); + currentSubformula.selectAll("*").remove(); - //display subformulas - currentSubFormula + currentSubformula .classed('inactive', false); - currentSubFormula + currentSubformula .append("button") .attr("class", "btn btn-primary") .attr("id", "btn-subformulae") .html("Subformulas") - currentSubFormula + // currentSubformula + + currentSubformula .append("div") .attr("class", "dropdown-content") - let dropdownmenu = d3.select('.dropdown-content'); + let dropdownmenu = d3.select('.dropdown-content'); subFormulas.forEach((subf, index) =>{ - dropdownmenu.append("a") + dropdownmenu.append("a") .attr("id", `subFormulaRadio_${index}`) .html("$"+subf.latex()+"$") .on("click", ()=> { @@ -379,9 +383,10 @@ function evaluateFormula() { }) - // display truth evaluation + // display true evaluation var latexTrue = trueStates.length ? '$w_{' + trueStates.join('},$ $w_{') + '}$' : '$\\varnothing$', - latexFalse = falseStates.length ? '$w_{' + falseStates.join('},$ $w_{') + '}$' : '$\\varnothing$'; + latexFalse = falseStates.length ? '$w_{' + falseStates.join('},$ $w_{') + '}$' : '$\\varnothing$'; + evalOutput .html('
True:
' + latexTrue + '
' + '
False:
' + latexFalse + '
') @@ -389,7 +394,7 @@ function evaluateFormula() { // re-render LaTeX MathJax.Hub.Queue(['Typeset', MathJax.Hub, currentFormula.node()]); - MathJax.Hub.Queue(['Typeset', MathJax.Hub, currentSubFormula.node()]); + MathJax.Hub.Queue(['Typeset', MathJax.Hub, currentSubformula.node()]); MathJax.Hub.Queue(['Typeset', MathJax.Hub, evalOutput.node()]); } @@ -620,7 +625,18 @@ function getSingleCurvedSVGPath([x1, y1], [x2, y2], curviness) { ',' + x2 + ' ' + y2; } -function printGraph(relations){ +function printGraphAtoms(){ + circle.selectAll('text.atoms') + .text(function(d) { + return propvars + .filter(function(_, i) { return d.vals[i]; }) + .join(', '); + }) + .attr('y', 5); +} + + +function printGraphRelations(relations){ //remove groups links links = links.filter(d => d.agent !== ('g') && d.agent !== ('h')); relations.forEach(rel => { @@ -657,7 +673,7 @@ function printGraph(relations){ function resetGraph(){ let rel = model.getAllRelationsOfList(epistemicAgents) - printGraph(rel); + printGraphRelations(rel); } function subformulaeGraph(wff){ @@ -683,7 +699,7 @@ function subformulaeGraph(wff){ // For showing other arrows. //links = links.filter(d => !agents.includes(d.agent)); links = [] - printGraph(commonRelations) + printGraphRelations(commonRelations) }else if (json.dist_start && json.dist_start.group_end && json.dist_start.group_end[0].prop) { links = [] const agents = json.dist_start.group_end[0].prop.split(''); @@ -692,11 +708,11 @@ function subformulaeGraph(wff){ return { ...rel, agent: 'h' }; }); distRelations=removeDuplicates(distRelations); - printGraph(distRelations) + printGraphRelations(distRelations) } else { const relations = model.getAllRelationsOfList(epistemicAgents); - printGraph(relations) + printGraphRelations(relations) } MathJax.Hub.Queue(['Typeset', MathJax.Hub, dropbtn]); } @@ -1183,9 +1199,10 @@ function setAppMode(newMode) { .classed('true', false) .classed('false', false); - currentFormula.classed('inactive', true); - currentSubFormula.classed('inactive', true); - currentSubFormula.selectAll("*").remove(); + currentFormula.classed('inactive', true); + currentSubformula.classed('inactive', true); + currentSubformula.selectAll("*").remove(); + } else if(newMode === MODE.EVAL|| newMode === MODE.TEXT ) { // disable listeners (except for I-bar prevention) svg.classed('edit', false) From 1953edac67a1ce0c997a75e96fe4f1e71f7c59c8 Mon Sep 17 00:00:00 2001 From: karu Date: Wed, 4 Feb 2026 12:23:40 +0100 Subject: [PATCH 41/68] Tree file --- index.html | 26 +++++++++++++++++++++++--- js/app.js | 16 ++++++++++------ js/tree.js | 3 +++ js/utils.js | 28 ---------------------------- 4 files changed, 36 insertions(+), 37 deletions(-) create mode 100644 js/tree.js diff --git a/index.html b/index.html index ca9d585..b033d4a 100644 --- a/index.html +++ b/index.html @@ -27,6 +27,9 @@

+

@@ -181,11 +184,26 @@

-
- +
+
+
+ + Formula: + + + +
+
-
+
loading... @@ -676,4 +694,6 @@

+ diff --git a/js/app.js b/js/app.js index e6eb611..c61757e 100644 --- a/js/app.js +++ b/js/app.js @@ -6,11 +6,7 @@ * Copyright (c) 2013 Ross Kirsling * Released under the MIT License. */ -var MODE = { - EDIT: 0, - EVAL: 1, - TEXT: 2 - }, +var MODE = { EDIT: 0, EVAL: 1, TREE: 2 }, appMode = MODE.EDIT; // set up initial MPL model (loads saved model if available, default otherwise) @@ -1184,6 +1180,7 @@ function setAppMode(newMode) { // mode-specific settings if(newMode === MODE.EDIT ) { resetGraph(); + d3.select('#info-box').style('display', 'block'); // enable listeners svg.classed('edit', true) .on('mousedown', mousedown) @@ -1203,8 +1200,9 @@ function setAppMode(newMode) { currentSubformula.classed('inactive', true); currentSubformula.selectAll("*").remove(); - } else if(newMode === MODE.EVAL|| newMode === MODE.TEXT ) { + } else if(newMode === MODE.EVAL|| newMode === MODE.TREE ) { // disable listeners (except for I-bar prevention) + d3.select('#info-box').style('display', 'block'); svg.classed('edit', false) .on('mousedown', function() { d3.event.preventDefault(); }) .on('mousemove', null) @@ -1234,6 +1232,12 @@ function setAppMode(newMode) { // reset eval state circle.classed('waiting', true); evalOutput.classed('inactive', true); + if (newMode === MODE.TREE){ + d3.select('#app-body .graph').style('display', 'none'); + d3.select('#info-box').style('display', 'none'); + currentFormula.classed('inactive', true); + currentSubformula.classed('inactive', true); + } } else return; // switch button and panel states and set new mode diff --git a/js/tree.js b/js/tree.js new file mode 100644 index 0000000..eaf9cfb --- /dev/null +++ b/js/tree.js @@ -0,0 +1,3 @@ +function runTableau(){ + console.log("HOLA") +} diff --git a/js/utils.js b/js/utils.js index e45d5f5..f50f55c 100644 --- a/js/utils.js +++ b/js/utils.js @@ -1,31 +1,3 @@ - -// When the button is clicked. -document.getElementById('readFileButton').addEventListener('click', function() { - document.getElementById('fileInput').click(); -}); - -// -document.getElementById('fileInput').addEventListener('change', function(event) { - const file = event.target.files[0]; // Obtiene el archivo seleccionado - - if (file) { - const reader = new FileReader(); - - reader.onload = function(e) { - updateModel(e.target.result); //TODO parser - }; - - reader.onerror = function(e) { - console.error("Error al leer el archivo:", e.target.error); - }; - - reader.readAsText(file); - } else { - console.log("No se seleccionó ningún archivo."); - } -}); - - function addText(conector, element=null) { var text = document.getElementById('formulaInput'); From 3851ca3caedd14f90cf43acb32d7fe5ea631e3e6 Mon Sep 17 00:00:00 2001 From: karu Date: Wed, 4 Feb 2026 12:25:35 +0100 Subject: [PATCH 42/68] create tree folder --- tree/d3.js | 281 +++++++ tree/index.html | 41 + tree/interactived3.js | 60 ++ tree/js/MPL.js | 760 +++++++++++++++++++ tree/js/app.js | 1274 ++++++++++++++++++++++++++++++++ tree/js/lib.js | 20 + tree/js/tree.js | 155 ++++ tree/js/utils.js | 92 +++ tree/lib/bootstrap.min.css | 9 + tree/lib/d3.min.js | 5 + tree/lib/formula-parser.min.js | 2 + tree/script.js | 705 ++++++++++++++++++ tree/style.css | 131 ++++ 13 files changed, 3535 insertions(+) create mode 100644 tree/d3.js create mode 100644 tree/index.html create mode 100644 tree/interactived3.js create mode 100644 tree/js/MPL.js create mode 100644 tree/js/app.js create mode 100644 tree/js/lib.js create mode 100644 tree/js/tree.js create mode 100644 tree/js/utils.js create mode 100644 tree/lib/bootstrap.min.css create mode 100644 tree/lib/d3.min.js create mode 100644 tree/lib/formula-parser.min.js create mode 100644 tree/script.js create mode 100644 tree/style.css diff --git a/tree/d3.js b/tree/d3.js new file mode 100644 index 0000000..1853606 --- /dev/null +++ b/tree/d3.js @@ -0,0 +1,281 @@ +import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm"; + + +document.addEventListener('DOMContentLoaded', () => { + document.getElementById('ez-button').addEventListener('click', () => run(true)); + document.getElementById('clear-button').addEventListener('click', () => clear()); + document.getElementById('run-button').addEventListener('click', () => run()); + document.getElementById('formulaInput').addEventListener('keydown', event => { + if (event.key === 'Enter') { + event.preventDefault(); + run(); + } + }); + + // Listen for window resize to update dimensions + window.addEventListener('resize', run); +}); + +let maxLabel = 150; +let duration = 500; +let radius = 5; +let i = 0; +let root; +let columnAttribute = []; +let svg, tree, diagonal; +let currentTableau = null; +const logger = new Logger(); +let container = document.getElementById('tree-container'); +let width = container.clientWidth - 40; +let height = container.clientHeight - 100; + +function run(ezmode=false) { + logger.clearLogs(); + const formula = document.getElementById('formulaInput').value; + const f = new MPL.Wff(formula) + const tableau = new Tableau(formula); + logger.addLog("Creating tableau in EZMODE for formula: " + f.unicode()) + if (ezmode){ + tableau.runTableau(logger); + } + const treeData = tableau.toD3(); + currentTableau = tableau; + + columnAttribute = []; + i = 0; + + d3.select("#tree-container").selectAll("*").remove(); + + // Set up SVG with dynamic width and height based on the container size + svg = d3.select("#tree-container").append("svg") + .attr("width", width) + .attr("height", height) + .append("g") + .attr("transform", `translate(0, ${maxLabel})`); + + // Set up tree layout + tree = d3.tree().size([width, height - maxLabel * 2]); + diagonal = d3.linkVertical() + .x(d => d.x) + .y(d => d.y); + + root = d3.hierarchy(treeData, (d) => d.children); + root.each(function(d) { + d.id = d.data.id || d.id; // Ensure IDs are not overwritten + }); + root.x0 = width / 2; + root.y0 = 0; + + displayLogsInHTML(logger); + update(root); + +} + +function update(source) { + displayLogsInHTML(logger); + + // Get the container element again in case it was resized + container = document.getElementById('tree-container'); + width = container.clientWidth - 40; // Adjust for padding/margin + height = container.clientHeight - 100; // Adjust for padding/margin + + // Set the size of the tree layout based on the container size + const treeData = tree(root); + const nodes = treeData.descendants(); + const links = treeData.links(); + + let visibleDepth = getVisibleDepth(root); + height = (visibleDepth + 2) * maxLabel; // Adjust height based on visible depth + tree.size([width, height - maxLabel * 2]); + + // Update SVG height dynamically based on the new tree size + d3.select("svg").transition().duration(duration).attr("height", height); + + nodes.forEach(d => d.y = d.depth * maxLabel); + + const node = svg.selectAll("g.node") + .data(nodes, d => d.id || (d.id = ++i)); + + const nodeEnter = node.enter().append("g") + .attr("class", "node") + .attr("transform", d => `translate(${source.x0},${source.y0})`) + .on("click", click) + .on("contextmenu", rclick) + .on("dblclick", dblClick); + + nodeEnter.append("circle") + .attr("r", 0) + .attr("class", d => currentTableau.isAvailable(d.id) ? "clickable" : "non-cickable"); + + nodeEnter.append("text") + .attr("x", d => { + const spacing = computeRadius(d.data) + 5; + return d.children || d._children ? -spacing : spacing; + }) + .attr("dy", "3") + .attr("text-anchor", d => d.children || d._children ? "end" : "start") + .text(d => `(${d.id}) ${d.data.label}: ${d.data.value.unicode()}`) + .style("fill-opacity", 0); + + const nodeUpdate = node.merge(nodeEnter).transition() + .duration(duration) + .attr("transform", d => `translate(${d.x},${d.y})`); + + nodeUpdate.select("circle") + .attr("r", d => computeRadius(d.data)) + .attr("class", d => currentTableau.isAvailable(d.id) ? "clickable" : "non-cickable"); + + nodeUpdate.select("text").style("fill-opacity", 1); + + const nodeExit = node.exit().transition() + .duration(duration) + .attr("transform", d => `translate(${source.x},${source.y})`) + .remove(); + + nodeExit.select("circle").attr("r", 0); + nodeExit.select("text").style("fill-opacity", 0); + + const link = svg.selectAll("path.link") + .data(links, d => d.target.id); + + link.enter().insert("path", "g") + .attr("class", "link") + .attr("d", d => { + const o = { x: source.x0, y: source.y0 }; + return diagonal({ source: o, target: o }); + }) + .merge(link) + .transition().duration(duration) + .attr("d", diagonal); + + link.exit().transition().duration(duration) + .attr("d", d => { + const o = { x: source.x, y: source.y }; + return diagonal({ source: o, target: o }); + }) + .remove(); + + nodes.forEach(d => { + d.x0 = d.x; + d.y0 = d.y; + }); + + // Verificar si el tableau está cerrado + // [FiX] Mejorar + // const isClosed = currentTableau.isClosed(); + // if (isClosed){ + // setTimeout(() => { + // console.log(svg.selectAll("circle")); + // svg.selectAll("circle") + // .transition().duration(duration) + // .style("fill", 'red'); + // + // svg.selectAll("path.link") + // .transition().duration(duration) + // .style("stroke", 'red'); + // + // }, 600); + // } +} + +function computeRadius(d) { + return (d.children || d._children) ? radius + (radius * nbEndNodes(d) / 10) : radius; +} + +function nbEndNodes(d) { + if (d.children) return d.children.reduce((acc, c) => acc + nbEndNodes(c), 0); + if (d._children) return d._children.reduce((acc, c) => acc + nbEndNodes(c), 0); + return 1; +} + +function click(event, d) { + if (d.children) { + d._children = d.children; + d.children = null; + } else { + d.children = d._children; + d._children = null; + } + update(d); + // highlightLink(d) + +} + +function dblClick(event, d) { + columnAttribute.push(d.data.name); +} + +function rclick(event, d) { + event.preventDefault(); + if (currentTableau) { + let closedLeafs = currentTableau.applyRule(d.id, logger); + const newTreeData = currentTableau.toD3(); + root = d3.hierarchy(newTreeData, (d) => d.children); + root.each(function(d) { + d.id = d.data.id || d.id; // Ensure IDs are not overwritten + }); + root.x0 = container.clientWidth / 2; + root.y0 = 0; + // TODO: UNIFY IN THE BRAIN + if (closedLeafs == null){ + logger.addLog(`[Error] Can not apply rule to ID: ${d.id})}`); + } + if(currentTableau.isEnded()){ + logger.addLog("Tableau finished"); + } + update(d); + } +} + +function getVisibleDepth(node, depth = 0) { + if (!node.children) return depth; + return Math.max(...node.children.map(child => getVisibleDepth(child, depth + 1))); +} + +function displayLogsInHTML(logger) { + const logContainer = document.getElementById('log-container'); + logContainer.innerHTML = ''; + const logs = logger.getLogs(); + + logs.forEach(log => { + const logElement = document.createElement('div'); + logElement.className = `log-entry log-${log.type}`; + logElement.innerHTML = `${log.message}`; + logContainer.appendChild(logElement); + }); +} + + +function highlightLink(node) { + if (node.children && node.children.length > 0){ + update(node); + return; + }; + const path = getPathToRoot(node); + svg.selectAll("path.link") + .transition().duration(400) + .style("stroke", d => { + return path.includes(d.source) && path.includes(d.target) ? 'red' : '#ccc'; + }); + + svg.selectAll(".node") + .transition().duration(400) + .style("fill", d => path.includes(d) ? 'red' : '#000'); +} + +function getPathToRoot(node) { + const path = []; + let current = node; + while (current) { + path.push(current); + current = current.parent; + } + return path; +} + +function clear(){ + logger.clearLogs(); + document.getElementById('formulaInput').value = ''; + document.getElementById('tree-container').innerHTML = ""; + displayLogsInHTML(logger) +} diff --git a/tree/index.html b/tree/index.html new file mode 100644 index 0000000..ce98a0c --- /dev/null +++ b/tree/index.html @@ -0,0 +1,41 @@ + + + + + BINARY TREE + + + + + + + + + + + + +

Tableau

+
+
+
+ Enter a formula: + + + + + +
+
+
+
+
+
+
+ + diff --git a/tree/interactived3.js b/tree/interactived3.js new file mode 100644 index 0000000..515c028 --- /dev/null +++ b/tree/interactived3.js @@ -0,0 +1,60 @@ +var data = { + "id": 1, + "name": "Animals", + "type": "Root", + "description": "A living organism that feeds on organic matter", + "children": [ + { + "id": 2, + "name": "Carnivores", + "type": "Type", + "description": "Diet consists solely of animal materials", + "children": [ + { + "id": 3, + "name": "Javanese Cat", + "type": "Organism", + "description": "Domestic breed of cats, of oriental origin", + "children": [] + }, + { + "id": 4, + "name": "Polar Bear", + "type": "Organism", + "description": "White bear native to the Arctic Circle", + "children": [] + }, + { + "id": 5, + "name": "Panda Bear", + "type": "Organism", + "description": "Spotted bear native to South Central China", + "children": [] + } + ] + }, + { + "id": 6, + "name": "Herbivores", + "type": "Type", + "description": "Diet consists solely of plant matter", + "children": [ + { + "id": 7, + "name": "Angus Cattle", + "type": "Organism", + "description": "Scottish breed of black cattle", + "children": [] + }, + { + "id": 8, + "name": "Barb Horse", + "type": "Organism", + "description": "A breed of Northern African horses with high stamina and hardiness. Their generally hot temperament makes it harder to tame.", + "children": [] + } + ] + } + ] +}; + diff --git a/tree/js/MPL.js b/tree/js/MPL.js new file mode 100644 index 0000000..13e95d3 --- /dev/null +++ b/tree/js/MPL.js @@ -0,0 +1,760 @@ +/** + * MPL v1.3.2 + * (http://github.com/rkirsling/modallogic) + * + * A library for parsing and evaluating well-formed formulas (wffs) of modal propositional logic. + * + * Copyright (c) 2013-2015 Ross Kirsling + * Released under the MIT License. + */ +// const FormulaParser = require('../lib/formula-parser.min.js'); //[TEST] +var MPL = (function (FormulaParser) { + 'use strict'; + + // begin formula-parser setup + if (typeof FormulaParser === 'undefined') throw new Error('MPL could not find dependency: formula-parser'); + + var variableKey = 'prop'; + + var unaries = [ + { symbol: '~', key: 'neg', precedence: 6 }, + { symbol: '\u25a1', key: 'nec', precedence: 6 }, + { symbol: '<>', key: 'poss', precedence: 6 }, + { symbol: '[', key: 'annce_start', precedence: 5 }, + { symbol: 'K{', key: 'kno_start', precedence: 4 }, + { symbol: 'C{', key: 'common_start', precedence: 4 }, + { symbol: 'D{', key: 'dist_start', precedence: 4 } + ]; + + var binaries = [ + { symbol: ']', key: 'annce_end', precedence: 5, associativity: 'right' }, // the left operand to annce_end must be annce_start + { symbol: '}', key: 'group_end', precedence: 4, associativity: 'right' }, // the left operand to kno_end must be kno_start + { symbol: '&', key: 'conj', precedence: 3, associativity: 'right' }, + { symbol: '|', key: 'disj', precedence: 2, associativity: 'right' }, + { symbol: '->', key: 'impl', precedence: 1, associativity: 'right' }, + { symbol: '<->', key: 'equi', precedence: 0, associativity: 'right' } + ]; + + var MPLParser = new FormulaParser(variableKey, unaries, binaries); + // end formula-parser setup + + /** + * Converts an MPL wff from ASCII to JSON. + * @private + */ + function _asciiToJSON(ascii) { + return MPLParser.parse(ascii); + } + + + /** + * Converts an MPL wff from JSON to ASCII. + * @private + */ + function _jsonToASCII(json) { + if (json.prop) + return json.prop; + else if (json.neg) + return '~' + _jsonToASCII(json.neg); + else if (json.nec) + return '\u25a1' + _jsonToASCII(json.nec); + else if (json.poss) + return '<>' + _jsonToASCII(json.poss); + else if (json.kno_start && + json.kno_start.group_end && + json.kno_start.group_end[0].prop && + json.kno_start.group_end.length === 2 + ) { + const agents = json.kno_start.group_end[0].prop.split(''); + return 'K{' + agents.join(',') + '}' + _jsonToASCII(json.kno_start.group_end[1]); + } + else if (json.common_start && // [CA] common knowledge + json.common_start.group_end && //[CA] NOTE THAT common end is equal to kno_end. + json.common_start.group_end[0].prop && //TODO: change name kno_end to general one. + json.common_start.group_end.length === 2 + ) { + const agents = json.common_start.group_end[0].prop.split(''); + return 'C{' + agents.join(',') + '}' + _jsonToASCII(json.common_start.group_end[1]); + } + else if (json.dist_start && // [CA] dist knowledge + json.dist_start.group_end && //[CA] NOTE THAT dist end is equal to kno_end. + json.dist_start.group_end[0].prop && //TODO: change name kno_end to general one. + json.dist_start.group_end.length === 2 + ) { + const agents = json.dist_start.group_end[0].prop.split(''); + return 'D{' + agents.join(',') + '}' + _jsonToASCII(json.dist_start.group_end[1]); + } + else if (json.annce_start && + json.annce_start.annce_end && + json.annce_start.annce_end.length === 2 + ) { + const announcement = _jsonToASCII(json.annce_start.annce_end[0]); + return '[' + announcement + ']' + _jsonToASCII(json.annce_start.annce_end[1]); + } else if (json.conj && json.conj.length === 2) + return '(' + _jsonToASCII(json.conj[0]) + ' & ' + _jsonToASCII(json.conj[1]) + ')'; + else if (json.disj && json.disj.length === 2) + return '(' + _jsonToASCII(json.disj[0]) + ' | ' + _jsonToASCII(json.disj[1]) + ')'; + else if (json.impl && json.impl.length === 2) + return '(' + _jsonToASCII(json.impl[0]) + ' -> ' + _jsonToASCII(json.impl[1]) + ')'; + else if (json.equi && json.equi.length === 2) + return '(' + _jsonToASCII(json.equi[0]) + ' <-> ' + _jsonToASCII(json.equi[1]) + ')'; + else + throw new Error('Invalid JSON for formula!'); + } + + /** + * Converts an MPL wff from ASCII to LaTeX. + * @private + */ + function _asciiToLaTeX(ascii) { + return ascii.replace(/~/g, '\\lnot{}') + .replace(/\u25a1/g, '\\Box{}') + .replace(/<>/g, '\\Diamond{}') + .replace(/K\{/g, 'K_{') + .replace(/\}/g, '}') + .replace(/ & /g, '\\land{}') + .replace(/ \| /g, '\\lor{}') + .replace(/ <-> /g, '\\leftrightarrow{}') + .replace(/ -> /g, '\\rightarrow{}') + .replace(/C\{/g, 'C_{') // [CA] Common knowledge. + .replace(/D\{/g, 'D_{'); // [CA] Common knowledge. + } + + function negateWff(json){ + var simply = simplifyWff(json) + var ascii = _jsonToASCII(simply) + var f = '~('+ascii+')' + var result = _jsonToASCII(simplifyWff(new Wff(f).json())) + return new Wff(result) + } + + function simplifyWff(json){ + if (json.neg){ + if(json.neg.neg){ + return json.neg.neg + } + } + return json + } + + /** + * Converts an MPL wff from ASCII to Unicode. + * @private + */ + function _asciiToUnicode(ascii) { + return ascii.replace(/~/g, '\u00ac') + .replace(/\u25a1/g, '\u25a1') + .replace(/<>/g, '\u25ca') + // .replace(/K\[/g, 'K[') don't change from ascii for knowledge operator + // .replace(/\]/g, ']') don't change from ascii for knowledge operator + .replace(/&/g, '\u2227') + .replace(/\|/g, '\u2228') + .replace(/<->/g, '\u2194') + .replace(/->/g, '\u2192'); + } + + /** + * Constructor for MPL wff. Takes either ASCII or JSON representation as input. + * @constructor + */ + function Wff(asciiOrJSON) { + // Strings for the four representations: ASCII, JSON, LaTeX, and Unicode. + var _ascii = '', _json = '', _latex = '', _unicode = ''; + + /** + * Returns the ASCII representation of an MPL wff. + */ + this.ascii = function () { + return _ascii; + }; + + /** + * Returns the JSON representation of an MPL wff. + */ + this.json = function () { + return _json; + }; + + /** + * Returns the LaTeX representation of an MPL wff. + */ + this.latex = function () { + return _latex; + }; + + /** + * Returns the Unicode representation of an MPL wff. + */ + this.unicode = function () { + return _unicode; + }; + + + _json = (typeof asciiOrJSON === 'object') ? asciiOrJSON : _asciiToJSON(asciiOrJSON); + _ascii = _jsonToASCII(_json); + _latex = _asciiToLaTeX(_ascii); + _unicode = _asciiToUnicode(_ascii); + } + + + /** + * Constructor for Kripke model. Takes no initial input. + * @constructor + */ + function Model() { + // Array of states (worlds) in model. + // Each state is an object with two properties: + // - assignment: a truth assignment (in which only true values are actually stored) + // - successors: an array of successors, each successor is an accessible target state and an agent + // ex: [{assignment: {}, successors: [{target: 0, agent: 'a'}, {target: 1, agent: 'a'}]}, + // {assignment: {'p': true}, successors: [] }] + var _states = []; + + /** + * [CA] Create a model from json. + * TODO: AUTOMATICAMENTE RENOMBRA LOS MUNDOS A PARTIR DE 0,1,2,3,4 + */ + this.fromJSON = function (jsonString) { + this.removeAllStatesAndTransitions(); + let jsonData = JSON.parse(jsonString) + jsonData.states.forEach(state => { //Adding worlds + this.addState(state.assignment) + }) + jsonData.states.forEach(state => {//Addings relations + state.successors.forEach(succ => { + this.addTransition(state.id, succ.target, succ.agent) + }) + }) + } + + /** + * Adds a transition to the model, given source and target state indices. + */ + this.addTransition = function (source, target, agent) { + if (!_states[source] || !_states[target]) return; + + const successors = _states[source].successors; + const isTransitionNew = successors.every((el) => el.target !== target || el.agent !== agent); + + if (isTransitionNew) { + successors.push({ target, agent }); + } + }; + + /** + * Removes a transition from the model, given source and target state indices. + */ + this.removeTransition = function (source, target, agent) { + if (!_states[source]) return; + + const successors = _states[source].successors; + let index; + if (agent) { + index = successors.findIndex((el) => el.target === target && el.agent === agent); + } else { + index = successors.findIndex((el) => el.target === target); + } + const isTransitionFound = index !== -1; + + if (isTransitionFound) { + successors.splice(index, 1); + } + }; + + /** + * Returns an array of successor states for a given state index and optional agent. + */ + this.getSuccessorsOf = function (source, agent) { + if (!_states[source]) return []; + + if (agent) { + return _states[source].successors.filter(successor => successor.agent === agent); + } else { + return _states[source].successors; + } + }; + + /** + * Adds a state with a given assignment to the model. + */ + this.addState = function (assignment) { + var processedAssignment = {}; + for (var propvar in assignment) + if (assignment[propvar] === true) + processedAssignment[propvar] = assignment[propvar]; + + _states.push({assignment: processedAssignment, successors: []}); + const stateIndex = _states.length - 1; + return stateIndex; + }; + this.addState = function (assignment) { + var processedAssignment = {}; + for (var propvar in assignment) + if (assignment[propvar] === true) + processedAssignment[propvar] = assignment[propvar]; + + _states.push({assignment: processedAssignment, successors: []}); + const stateIndex = _states.length - 1; + return stateIndex; + }; + + /** + * Edits the assignment of a state in the model, given a state index and a new partial assignment. + */ + this.editState = function (state, assignment) { + if (!_states[state]) return; + + var stateAssignment = _states[state].assignment; + for (var propvar in assignment) { + if (assignment[propvar] === true) stateAssignment[propvar] = true; + else if (assignment[propvar] === false) delete stateAssignment[propvar]; + } + }; + + /** + * Removes a state and all related transitions from the model, given a state index. + */ + this.removeState = function (state) { + if (!_states[state]) return; + var self = this; + + _states[state] = null; + _states.forEach(function (source, index) { + if (source) self.removeTransition(index, state); + }); + }; + + /** + * Returns an array containing the assignment (or null) of each state in the model. + * (Only true propositional variables are returned in each assignment.) + */ + this.getStates = function () { + var stateList = []; + _states.forEach(function (state) { + if (state) stateList.push(state.assignment); + else stateList.push(null); + }); + + return stateList; + }; + + /** + * Returns the truth value of a given propositional variable at a given state index. + */ + this.valuation = function (propvar, state) { + if (!_states[state]) throw new Error('State ' + state + ' not found!'); + + return !!_states[state].assignment[propvar]; + }; + + /** + * Returns current model as a compact string suitable for use as a URL parameter. + * ex: [{ + * assignment: {'q': true}, + * successors: [{target: 0, agent: 'a'}, {target: 2, agent: 'a'}] + * }, + * null, + * {assignment: {}, successors: []} + * ] + * compresses to 'AqS0a,2a;;AS;' + */ + this.getModelString = function () { + let modelString = ''; + + for (const state of _states) { + modelString += this.getStateString(state); + } + + return modelString.slice(0, modelString.length-1); // remove trailing ';' + }; + + /** + * Returns the given state represented as a compact string, used as part of a + * compact model string. + */ + this.getStateString = function (state) { + if (!state) { + return ';'; + } else { + let successorString = ''; + for (const successor of state.successors) { + successorString += successor.target + successor.agent + ','; + } + + return 'A' + Object.keys(state.assignment).join('') + 'S' + successorString + ';'; + } + } + + /** + * Restores a model from a given model string. + */ + this.loadFromModelString = function (modelString) { + this.removeAllStatesAndTransitions(); + + const transitionsToAdd = []; + const statesToRemove = []; + for (const stateString of modelString.split(';')) { + if (stateString === '') { + const stateIndex = this.addState(); + statesToRemove.push(stateIndex); + } else { + const indexOfA = stateString.lastIndexOf('A'); + const indexOfS = stateString.lastIndexOf('S'); + if (indexOfA === -1 || indexOfS === -1) { + break; + } + + const propvarsSubstring = stateString.slice(indexOfA+1, indexOfS); + let assignment = {}; + for (const propvar of propvarsSubstring) { + assignment[propvar] = true; + } + const stateIndex = this.addState(assignment); + + const transitionsSubstring = stateString.slice(indexOfS+1); + const transitionStrings = transitionsSubstring.split(','); + for (const transitionString of transitionStrings) { + if (transitionString === '') { + break; + } + const targetString = transitionString.slice(0, transitionString.length - 1); + const targetIndex = Number.parseInt(targetString); + const agent = transitionString[transitionString.length - 1]; + transitionsToAdd.push([stateIndex, targetIndex, agent]); + } + } + } + // transitions must be added after all states are added becase the states being referenced by + // the transitions must be present when the transition is added + for (const [stateIndex, targetIndex, agent] of transitionsToAdd) { + this.addTransition(stateIndex, targetIndex, agent); + } + for (const stateIndex of statesToRemove) { + this.removeState(stateIndex); + } + }; + + /** + * Resets the model to its initial state with no states or transitions + */ + this.removeAllStatesAndTransitions = function () { + _states = []; + } + + /** + * An agent's relation is reflexive iff ∀w Rww + * i.e. for all states w: w is a successor of itself. + */ + this.isReflexive = function(agent) { + return _states.every((stateW, w) => stateW === null || this.isSuccessor(w, w, agent)); + } + + /** + * An agent's relation is transitive iff ∀u∀v∀w (Ruv∧Rvw)→Ruw + * i.e. for all states u, v, and w: If v is a successor of u and w is a successor of v, then + * w is a successor of u. + */ + this.isTransitive = function(agent) { + return _states.every((stateU, u) => + stateU === null || + this.getSuccessorsOf(u, agent).every(successorV => + this.getSuccessorsOf(successorV.target, agent).every(successorW => + this.isSuccessor(u, successorW.target, agent) + ) + ) + ); + } + + /** + * An agent's relation is symmetric iff ∀w∀v Rwv -> Rvw + * i.e. for all states w and v: If v is a successor of w, then w must be a successor of v. + */ + this.isSymmetric = function(agent) { + return _states.every((stateW, w) => + stateW === null || + this.getSuccessorsOf(w, agent).every(successorV => + this.isSuccessor(successorV.target, w, agent) + ) + ); + } + + /** + * Get's all the agents currently present in all state's successors. + */ + this.getActiveAgents = function() { + const activeAgents = new Set(); + for (const state of _states) { + if (state !== null) { + for (const successor of state.successors) { + activeAgents.add(successor.agent); + } + } + } + return [...activeAgents].sort(); + } + + /** + * Gives a boolean answer for whether state2 is a successor of state1. + */ + this.isSuccessor = function(stateIndex1, stateIndex2, agent) { + const state1 = _states[stateIndex1]; + if (!state1) return false; + if (agent) { + return state1.successors + .some(successor => successor.agent === agent && successor.target === stateIndex2); + } else { + return state1.successors.some(successor => successor.target === stateIndex2); + } + } + + this.getAllRelationsOfAgent = function(agent){ + let allAccRel = [] + _states.forEach((state, index) => { + if (state){ + state.successors.forEach(successor => { + if (agent == successor.agent){ + let relation = { + source: index, + target: successor.target, + agent: successor.agent + + } + allAccRel.push(relation) + } + }); + } + }) + return allAccRel; + } + + this.getAllRelationsOfList = function (agents){ + let groupSucc = []; + agents.forEach ((agent) => { + if (agent){ + let succ = this.getAllRelationsOfAgent(agent); + groupSucc.push(...succ); + } + }); + return groupSucc; + } + + this.getDistributedRelations = function(agents){ + let allRel = this.getAllRelationsOfList(agents) + const agentKeyMap = agents.reduce((acc, agent) => { + acc[agent] = new Set(allRel.filter(item => item.agent === agent).map(item => `${item.source}-${item.target}`)); + return acc; + }, {}); + + const commonKeys = agents.reduce((acc, agent) => { + if (acc.size === 0) return new Set(agentKeyMap[agent]); + return new Set([...acc].filter(key => agentKeyMap[agent].has(key))); + }, new Set()); + + let intersection = allRel.filter(item => commonKeys.has(`${item.source}-${item.target}`)); + return intersection + } + + this.getCommonRelations = function (agents) { + let allRels = this.getAllRelationsOfList(agents) + let n = this.getStates().length; + let matrix = Array.from({ length: n }, () => Array(n).fill(0)); + allRels.forEach(rel => { + matrix[rel.source][rel.target] = 1; + }); + + // Cierre transitivo+reflexivo + for (let k = 0; k < n; k++) { + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + matrix[i][j] = matrix[i][j] || (matrix[i][k] && matrix[k][j]); + if (matrix[i].some(Boolean)) { //Aplicamos cierre reflexivo solo si existe alguna relacion y no es un mundo final + matrix[i][i] = 1; + } + } + } + } + + let relations = [] + for (let i = 0; i < matrix.length; i++) { + for (let j = 0; j < matrix[i].length; j++) { + if (matrix[i][j] === 1) { + agents.forEach( agent => { relations.push({ source: i, target: j, agent: agent })}); + } + } + } + return relations + } + + + + this.getDistributedPrimaModel = function(agents){ + let allRelations = this.getDistributedRelations(agents); + let modelprima = new Model(); + _states.forEach( state =>{ + if (state){ //if state + modelprima.addState(state.assignment) + }else { // if null + let idx = modelprima.addState() + modelprima.removeState(idx) + } + }); + allRelations.forEach( relation => {modelprima.addTransition(relation.source, relation.target, relation.agent)}); + return modelprima + } + + this.getCommonPrimaModel = function (agents) { + let allRelations = this.getCommonRelations(agents); + let modelprima = new MPL.Model(); + _states.forEach(state => { + if (state){ //if state + modelprima.addState(state.assignment) + }else { // if null + let idx = modelprima.addState() + modelprima.removeState(idx) + } + }) + allRelations.forEach( relation => {modelprima.addTransition(relation.source, relation.target, relation.agent)}); + return modelprima + } + + /** + * Returns an identical, but seperate, copy of this MPL model. + */ + this.deepCopy = function() { + const copy = new MPL.Model(); + copy.copied = true; + copy.loadFromModelString(this.getModelString()); + return copy; + } + + this.getRawStates = function() { + return _states; + } + } + + /** + * Evaluate the truth of an MPL wff (in JSON representation) at a given state within a given model. + * @private + */ + function _truth(model, state, json) { + if (json.prop) + return model.valuation(json.prop, state); + else if (json.neg) + return !_truth(model, state, json.neg); + else if (json.common_start && json.common_start.group_end && json.common_start.group_end[0].prop) { + const agents = json.common_start.group_end[0].prop.split(''); + let modelprima = model.getCommonPrimaModel(agents) + console.log("[debug] url: "+modelprima.getModelString()) + return agents.every(agent => modelprima.getSuccessorsOf(state).every( + (succ) =>succ.agent !== agent || _truth(model, succ.target, json.common_start.group_end[1]) + )); + } + else if (json.dist_start && json.dist_start.group_end && json.dist_start.group_end[0].prop) { + const agents = json.dist_start.group_end[0].prop.split(''); + let modelprima = model.getDistributedPrimaModel(agents) + console.log("[debug] url: "+modelprima.getModelString()) + return agents.every(agent => modelprima.getSuccessorsOf(state).every( + (succ) =>succ.agent !== agent || _truth(model, succ.target, json.dist_start.group_end[1]) + )); + } + else if (json.kno_start && json.kno_start.group_end && json.kno_start.group_end[0].prop) { + const agents = json.kno_start.group_end[0].prop.split(''); + return agents.every(agent => model.getSuccessorsOf(state).every( + (succ) => succ.agent !== agent || _truth(model, succ.target, json.kno_start.group_end[1]) + )); + } else if (json.annce_start && json.annce_start.annce_end) { + if (_truth(model, state, json.annce_start.annce_end[0])) { + const postAnnouncementModel = model.deepCopy(); + postAnnouncementModel.getRawStates().forEach((stateW, w) => { + if (stateW && !_truth(model, w, json.annce_start.annce_end[0])) { + postAnnouncementModel.removeState(w); + } + }); + return _truth(postAnnouncementModel, state, json.annce_start.annce_end[1]) + } else { + return true; + } + } else if (json.conj) + return (_truth(model, state, json.conj[0]) && _truth(model, state, json.conj[1])); + else if (json.disj) + return (_truth(model, state, json.disj[0]) || _truth(model, state, json.disj[1])); + else if (json.impl) + return (!_truth(model, state, json.impl[0]) || _truth(model, state, json.impl[1])); + else if (json.equi) + return (_truth(model, state, json.equi[0]) === _truth(model, state, json.equi[1])); + else if (json.nec) + return model.getSuccessorsOf(state).every((succ) => _truth(model, succ.target, json.nec)); + else if (json.poss) + return model.getSuccessorsOf(state).some((succ) => _truth(model, succ.target, json.poss)); + else + throw new Error('Invalid formula!'); + } + + /** + * Evaluate the truth of an MPL wff at a given state within a given model. + */ + function truth(model, state, wff) { + if (!(model instanceof MPL.Model)) throw new Error('Invalid model!'); + if (!model.getStates()[state]) throw new Error('State ' + state + ' not found!'); + if (!(wff instanceof MPL.Wff)) throw new Error('Invalid wff!'); + + return _truth(model, state, wff.json()); + } + + function subformulas(json, subs = []) { + subs.push(json); + if (json.prop) { + // subs.push(json); + } else if (json.neg){ + subs.push(json.neg); + subformulas(json.neg, subs); + } else if (json.common_start && json.common_start.group_end && json.common_start.group_end[0].prop) { + subs.push(json.common_start.group_end[1]); + subformulas(json.common_start.group_end[1], subs); + } else if (json.kno_start && json.kno_start.group_end && json.kno_start.group_end[0].prop) { + subs.push(json.kno_start.group_end[1]); + subformulas(json.kno_start.group_end[1], subs); + } else if (json.dist_start && json.dist_start.group_end && json.dist_start.group_end[0].prop) { + subs.push(json.dist_start.group_end[1]); + subformulas(json.dist_start.group_end[1], subs); + } else if (json.conj) { + subs.push(json.conj[0]); + subs.push(json.conj[1]); + subformulas(json.conj[0], subs); + subformulas(json.conj[1], subs); + } else if (json.disj) { + subs.push(json.disj[0]); + subs.push(json.disj[1]); + subformulas(json.disj[0], subs); + subformulas(json.disj[1], subs); + } else if (json.impl) { + subs.push(json.impl[0]); + subs.push(json.impl[1]); + subformulas(json.impl[0], subs); + subformulas(json.impl[1], subs); + } else if (json.equi) { + subs.push(json.equi[0]); + subs.push(json.equi[1]); + subformulas(json.equi[0], subs); + subformulas(json.equi[1], subs); + } + // TODO: filtrar antes de añadir + return removeDuplicates(subs); + } + + + // export public methods + return { + Wff: Wff, + Model: Model, + truth: truth, + negateWff: negateWff, + _jsonToASCII: _jsonToASCII, + subformulas: subformulas + }; + +})(FormulaParser); + + + +// module.exports = MPL; // [TEST] diff --git a/tree/js/app.js b/tree/js/app.js new file mode 100644 index 0000000..6d952de --- /dev/null +++ b/tree/js/app.js @@ -0,0 +1,1274 @@ +/* + * Modal Logic Playground -- application code + * + * Dependencies: D3, MathJax, MPL + * + * Copyright (c) 2013 Ross Kirsling + * Released under the MIT License. + */ + +// const { index } = require("d3"); + +// app mode constants +var MODE = { + EDIT: 0, + EVAL: 1, + TEXT: 2 + }, + appMode = MODE.EDIT; + +// set up initial MPL model (loads saved model if available, default otherwise) +var propvars = ['p','q','r','s','t'], + varCount = 2; + +let epistemicAgents = ['a', 'b', 'c', 'd', 'e', 'g', 'h']; +let currentEpistemicAgent = 'a'; + +const agentButtons = d3.selectAll('#edit-pane .agent-btns button'); + +const model = new MPL.Model(); +let modelString = ';AS0a,'; + +const modelParam = window.location.search.match(/\?model=(.*)/); +if (modelParam) modelString = modelParam[1]; +const formulaParam = window.location.search.match(/\?formula=(.*)/); + +model.loadFromModelString(modelString); + +// set up initial nodes and links (edges) of graph, based on MPL model +var lastNodeId = -1, + nodes = [], + links = []; + + +// --> nodes setup +var states = model.getStates(); +const propVarsInUse = new Set(); +states.forEach(function(state) { + if(!state) { lastNodeId++; return; } + + var defaultVals = propvars.map(function() { return false; }), + node = {id: ++lastNodeId, vals: defaultVals}; + + for(var propvar in state) { + propVarsInUse.add(propvar); + var index = propvars.indexOf(propvar); + if(index !== -1) { + node.vals[index] = true; + varCount = Math.max(varCount, index+1); // set correct var count from state + } + } + + nodes.push(node); +}); + + +// --> links setup +for (const source of nodes) { + const sourceId = source.id; + for (const succ of model.getSuccessorsOf(sourceId)) { + const targetId = succ.target; + if(sourceId === targetId) { + links.push({source: source, target: source, left: true, right: true, agent: succ.agent }); + continue; + } + + const target = nodes.filter(function(node) { return node.id === targetId; })[0]; + const link = links.filter(l => l.source === target && l.target === source && l.agent === succ.agent)[0]; + + if (link) { + if(sourceId < targetId) { + link.right = true; + } else { + link.left = true; + } + } else { + if(sourceId < targetId) { + links.push({source: source, target: target, left: false, right: true, agent: succ.agent }); + } else { + links.push({source: target, target: source, left: true, right: false, agent: succ.agent }); + } + } + } +} + + + +// set up SVG for D3 +var width = 640, + height = 540, + colors = d3.scale.category10(); + +var svg = d3.select('#app-body .graph') + .append('svg') + .on('contextmenu', function() { d3.event.preventDefault(); }) + .attr('width', width) + .attr('height', height); + +// init D3 force layout +var force = d3.layout.force() + .nodes(nodes) + .links(links) + .size([width, height]) + .linkDistance(180) + .charge(-800) + .on('tick', tick); + +// Función para poner diferente texto para difernetes agentes en los links. +function setLinkAgent(agent){ + return agent; +} + +for (const agent of epistemicAgents) { + // define agent markers for graph links + svg.append('svg:defs').append('svg:marker') + .attr('id', 'mid-arrow-'+agent) + .attr('viewBox', '-2 -5 10 10') + .attr('refX', 0) + .attr('markerWidth', 10) + .attr('markerHeight', 10) + .attr('orient', 0) + .append('svg:text') + .text(setLinkAgent(agent)) + .classed('agent-text', true) + .classed('agent-'+agent, true); + + // define arrow markers for graph links + svg.append('svg:defs').append('svg:marker') + .attr('id', 'end-arrow-'+agent) + .attr('viewBox', '0 -5 10 10') + .attr('refX', 6) + .attr('markerWidth', 4) + .attr('markerHeight', 4) + .attr('orient', 'auto') + .append('svg:path') + .attr('d', 'M0,-5L10,0L0,5') + .classed('agent-'+agent, true); + + svg.append('svg:defs').append('svg:marker') + .attr('id', 'start-arrow-'+agent) + .attr('viewBox', '0 -5 10 10') + .attr('refX', 4) + .attr('markerWidth', 4) + .attr('markerHeight', 4) + .attr('orient', 'auto') + .append('svg:path') + .attr('d', 'M10,-5L0,0L10,5') + .attr('fill', '#000') + .classed('agent-'+agent, true); +} + +// line displayed when dragging new nodes +var drag_line = svg.append('svg:path') + .attr('class', 'link dragline hidden') + .attr('d', 'M0,0Q0 0, 0 0'); + +// handles to link and node element groups +var path = svg.append('svg:g').selectAll('path'), + circle = svg.append('svg:g').selectAll('g'); + +// mouse event vars +var selected_node = null, + selected_link = null, + mousedown_link = null, + mousedown_node = null, + mouseup_node = null; + +function resetMouseVars() { + mousedown_node = null; + mouseup_node = null; + mousedown_link = null; +} + +// handles for dynamic content in panel +var varCountButtons = d3.selectAll('#edit-pane .var-count button'), + varTable = d3.select('#edit-pane table.propvars'), + varTableRows = varTable.selectAll('tr'), + selectedNodeLabel = d3.select('#edit-pane .selected-node-id'), + evalInput = d3.select('#eval-pane .eval-input'), + evalOutput = d3.select('#eval-pane .eval-output'), + currentFormula = d3.select('#app-body .current-formula'); + currentSubFormula = d3.select('#app-body .current-subformula'); + btnSubformulae = d3.select('#btn-formulae'); + +function announceFormula() { + // make sure a formula has been input + var formula = evalInput.select('input').node().value; + formula = formula.split(',').join(''); // remove commas for parsing + formula = formula.split('[').join('[('); + formula = formula.split(']').join(')]'); + if(!formula) { + evalOutput + .html('
No formula!
') + .classed('inactive', false); + return; + } + + // parse formula and catch bad input + var wff = null; + try { + wff = new MPL.Wff(formula); + } catch(e) { + evalOutput + .html('
Invalid formula!
') + .classed('inactive', false); + return; + } + + // check formula for bad vars or agents + const propsAndAgentsInWff = getWffAgentsAndProps(wff.json()); + for (const propOrAgent of propsAndAgentsInWff) { + if (propOrAgent.prop) { + if (!propvars.includes(propOrAgent.prop)) { + evalOutput + .html(`
Formula contains invalid propositional variable: ${propOrAgent.prop}
`) + .classed('inactive', false); + return; + }; + } + if (propOrAgent.agent) { + const agents = propOrAgent.agent.split(''); + for (const agent of agents) { + if (!epistemicAgents.includes(agent)) { + evalOutput + .html(`
Formula contains invalid agent: ${agent}
`) + .classed('inactive', false); + return; + } + } + } + } + + // evaluate formula at each state in model + var trueStates = [], + falseStates = []; + nodes.forEach(function(node, index) { + var id = node.id, + truthVal = MPL.truth(model, id, wff); + + if(truthVal) { + trueStates.push(id); + } else { + falseStates.push(id); + } + }); + for (const falseStateId of falseStates) { + model.removeState(falseStateId); + const falseNode = nodes.find(node => node.id === falseStateId); + nodes.splice(nodes.indexOf(falseNode), 1); + spliceLinksForNode(falseNode); + } + onStateModified(); + restart(); + + // display evaluated formula + currentFormula + .html('Announced formula:
$' + wff.latex() + '$') + .classed('inactive', false); + + // display truth evaluation + const latexFalse = falseStates.length ? '$w_{' + falseStates.join('},$ $w_{') + '}$' : '$\\varnothing$'; + evalOutput + .html('
Worlds removed by announcement:
' + latexFalse + '
') + .classed('inactive', false); + + // re-render LaTeX + MathJax.Hub.Queue(['Typeset', MathJax.Hub, currentFormula.node()]); + MathJax.Hub.Queue(['Typeset', MathJax.Hub, evalOutput.node()]); +} + +function evaluateFormula() { + resetGraph(); + // make sure a formula has been input + var formula = evalInput.select('input').node().value; + formula = formula.split(',').join(''); // remove commas for parsing + formula = formula.split('[').join('[('); + formula = formula.split(']').join(')]'); + if(!formula) { + evalOutput + .html('
No formula!
') + .classed('inactive', false); + return; + } + + // parse formula and catch bad input + var wff = null; + try { + wff = new MPL.Wff(formula); + } catch(e) { + evalOutput + .html('
Invalid formula!
') + .classed('inactive', false); + return; + } + + + let subsjson = MPL.subformulas(wff.json()) + let subFormulas = subsjson.map(ff => new MPL.Wff(ff)); + + // check formula for bad vars or agents + const propsAndAgentsInWff = getWffAgentsAndProps(wff.json()); + for (const propOrAgent of propsAndAgentsInWff) { + if (propOrAgent.prop) { + if (!propvars.includes(propOrAgent.prop)) { + evalOutput + .html(`
Formula contains invalid propositional variable: ${propOrAgent.prop}
`) + .classed('inactive', false); + return; + }; + } + if (propOrAgent.agent) { + const agents = propOrAgent.agent.split(''); + for (const agent of agents) { + if (!epistemicAgents.includes(agent)) { + evalOutput + .html(`
Formula contains invalid agent: ${agent}
`) + .classed('inactive', false); + return; + } + } + } + } + onStateModified(); + + // evaluate formula at each state in model + var trueStates = [], + falseStates = []; + nodes.forEach(function(node, index) { + var id = node.id, + truthVal = MPL.truth(model, id, wff); + + if(truthVal) trueStates.push(id); + else falseStates.push(id); + + d3.select(circle[0][index]) + .classed('waiting', false) + .classed('true', truthVal) + .classed('false', !truthVal); + }); + + // display evaluated formula + currentFormula + .html('Current formula:
$' + wff.latex() + '$') + .classed('inactive', false); + + currentSubFormula.selectAll("*").remove(); + + //display subformulas + currentSubFormula + .classed('inactive', false); + + currentSubFormula + .append("button") + .attr("class", "btn btn-primary") + .attr("id", "btn-subformulae") + .html("Subformulas") + + currentSubFormula + .append("div") + .attr("class", "dropdown-content") + + let dropdownmenu = d3.select('.dropdown-content'); + subFormulas.forEach((subf, index) =>{ + dropdownmenu.append("a") + .attr("id", `subFormulaRadio_${index}`) + .html("$"+subf.latex()+"$") + .on("click", ()=> { + subformulaeGraph(subf) + }); + + }) + + // display truth evaluation + var latexTrue = trueStates.length ? '$w_{' + trueStates.join('},$ $w_{') + '}$' : '$\\varnothing$', + latexFalse = falseStates.length ? '$w_{' + falseStates.join('},$ $w_{') + '}$' : '$\\varnothing$'; + evalOutput + .html('
True:
' + latexTrue + '
' + + '
False:
' + latexFalse + '
') + .classed('inactive', false); + + // re-render LaTeX + MathJax.Hub.Queue(['Typeset', MathJax.Hub, currentFormula.node()]); + MathJax.Hub.Queue(['Typeset', MathJax.Hub, currentSubFormula.node()]); + MathJax.Hub.Queue(['Typeset', MathJax.Hub, evalOutput.node()]); +} + +/** + * Returns an array of all propositional variables and agents used in the given Wff json. + * i.e. [{ prop: 'p' }, { prop: 'q' }, { agent: 'b' }] + */ +function getWffAgentsAndProps(json) { + if (json.prop) + return [{ prop: json.prop }]; + else if (json.neg) + return getWffAgentsAndProps(json.neg); + else if (json.nec) + return getWffAgentsAndProps(json.nec); + else if (json.poss) + return getWffAgentsAndProps(json.poss); + else if (json.dist_start && + json.dist_start.group_end && + json.dist_start.group_end[0].prop && + json.dist_start.group_end.length === 2 + ) { + const agent = json.dist_start.group_end[0].prop; + return [{ agent }].concat(getWffAgentsAndProps(json.dist_start.group_end[1])); + } + else if (json.common_start && + json.common_start.group_end && + json.common_start.group_end[0].prop && + json.common_start.group_end.length === 2 + ) { + const agent = json.common_start.group_end[0].prop; + return [{ agent }].concat(getWffAgentsAndProps(json.common_start.group_end[1])); + } + else if (json.kno_start && + json.kno_start.group_end && + json.kno_start.group_end[0].prop && + json.kno_start.group_end.length === 2 + ) { + const agent = json.kno_start.group_end[0].prop; + return [{ agent }].concat(getWffAgentsAndProps(json.kno_start.group_end[1])); + } + else if (json.annce_start && + json.annce_start.annce_end && + json.annce_start.annce_end.length === 2 + ) { + const announcement = getWffAgentsAndProps(json.annce_start.annce_end[0]); + return announcement.concat(getWffAgentsAndProps(json.annce_start.annce_end[1])); + } + else if (json.conj && json.conj.length === 2) + return getWffAgentsAndProps(json.conj[0]).concat(getWffAgentsAndProps(json.conj[1])); + else if (json.disj && json.disj.length === 2) + return getWffAgentsAndProps(json.disj[0]).concat(getWffAgentsAndProps(json.disj[1])); + else if (json.impl && json.impl.length === 2) + return getWffAgentsAndProps(json.impl[0]).concat(getWffAgentsAndProps(json.impl[1])); + else if (json.equi && json.equi.length === 2) + return getWffAgentsAndProps(json.equi[0]).concat(getWffAgentsAndProps(json.equi[1])); + else + throw new Error('Invalid JSON for formula!'); +} + +// set selected node and notify panel of changes +function setSelectedNode(node) { + selected_node = node; + + // update selected node label + selectedNodeLabel.html(selected_node ? 'World '+selected_node.id+'' : 'No world selected'); + + // update variable table + if(selected_node) { + var vals = selected_node.vals; + varTableRows.each(function(d,i) { + d3.select(this).select('.var-value .btn-success').classed('active', vals[i]); + d3.select(this).select('.var-value .btn-danger').classed('active', !vals[i]); + }); + } + varTable.classed('inactive', !selected_node); +} + +// get truth assignment for node as a displayable string +function makeAssignmentString(node) { + var vals = node.vals, + outputVars = []; + + for(var i = 0; i < varCount; i++) { + // attach 'not' symbol to false values + outputVars.push((vals[i] ? '' : '\u00ac') + propvars[i]); + } + + return outputVars.join(', '); +} + +function setCurrentAgent(agentNumber) { + currentEpistemicAgent = epistemicAgents[agentNumber]; + + // update variable count button states + agentButtons.each(function(d,i) { + if(currentEpistemicAgent !== epistemicAgents[i]) d3.select(this).classed('active', false); + else d3.select(this).classed('active', true); + }); +} + +// set # of vars currently in use and notify panel of changes +function setVarCount(count) { + varCount = count; + + // update variable count button states + varCountButtons.each(function(d,i) { + if(i !== varCount-1) d3.select(this).classed('active', false); + else d3.select(this).classed('active', true); + }); + + //update graph text + circle.selectAll('text:not(.id)').text(makeAssignmentString); + + //update variable table rows + varTableRows.each(function(d,i) { + if(i < varCount) d3.select(this).classed('inactive', false); + else d3.select(this).classed('inactive', true); + }); +} + +function setVarForSelectedNode(varnum, value) { + //update node in graph and state in model + selected_node.vals[varnum] = value; + var update = {}; + update[propvars[varnum]] = value; + model.editState(selected_node.id, update); + onStateModified(); + + //update buttons + var row = d3.select(varTableRows[0][varnum]); + row.select('.var-value .btn-success').classed('active', value); + row.select('.var-value .btn-danger').classed('active', !value); + + //update graph text + circle.selectAll('text:not(.id)').text(makeAssignmentString); +} + +// update force layout (called automatically each iteration) +function tick() { + // draw directed edges with proper padding from node centers + //TODO: change the ending position of arrows depending on the agent + path.attr('d', function(d) { + let angle = 0; + if (d.agent === 'a') angle = 0; + if (d.agent === 'b') angle = -0.5; + if (d.agent === 'c') angle = 0.5; + if (d.agent === 'd') angle = -1; + if (d.agent === 'e') angle = 1; + if (d.agent === 'g') angle = 0; // No necesita un angulo diferente porque elimina el resto de relaciones + if (d.agent === 'h') angle = 0; // No necesita un angulo diferente porque elimina el resto de relaciones + + if (d.source === d.target) { + let selfLoopOffset = [1, 0]; + selfLoopOffset = rotateByAngle(selfLoopOffset, -angle); + return getDoubleCurvedSVGPath([d.source.x, d.source.y], [d.source.x+selfLoopOffset[0], d.source.y+selfLoopOffset[1]], 30); + } + + const facing = normalize([ + d.target.x - d.source.x, + d.target.y - d.source.y + ]); + const sourceNorm = rotateByAngle(facing, -angle); + const targetNorm = rotateByAngle(facing, angle + Math.PI); + const sourcePadding = d.left ? 21 : 16; + const targetPadding = d.right ? 21 : 16; + const sourceX = d.source.x + (sourcePadding * sourceNorm[0]), + sourceY = d.source.y + (sourcePadding * sourceNorm[1]), + targetX = d.target.x + (targetPadding * targetNorm[0]), + targetY = d.target.y + (targetPadding * targetNorm[1]); + + let mul = 0; + if (d.agent === 'a') mul = 0; + if (d.agent === 'b') mul = -20; + if (d.agent === 'c') mul = 20; + if (d.agent === 'd') mul = -40; + if (d.agent === 'e') mul = 40; + if (d.agent === 'g') mul = 0; // No necesita un angulo diferente porque elimina el resto de relaciones + if (d.agent === 'h') mul = 0; // No necesita un angulo diferente porque elimina el resto de relaciones + + return getDoubleCurvedSVGPath([sourceX, sourceY], [targetX, targetY], mul); + }); + + circle.attr('transform', function(d) { + return 'translate(' + d.x + ',' + d.y + ')'; + }); +} + +function updateModel(json) { // TODO recarga a la pagina inicial. Funciona con redireccion de url. + if (!json){ + json = document.getElementById("jsonModel").value + } + model.fromJSON(json); + const modelString = '?model=' + model.getModelString(); + let formulaString = '?formula=' + evalInput.select('input').node().value; + formulaString = formulaString.split(' ').join(''); //remove spaces + formulaString = formulaString.split('>').join(''); //remove > (> doesn't work in URLs) + history.pushState({}, '', location.pathname + modelString + formulaString); + window.location.reload(); +} + + + +function getDoubleCurvedSVGPath([x1, y1], [x2, y2], curviness) { + const facing = [ + x2 - x1, + y2 - y1, + ]; + const orthogonalUnit = rotate90deg(normalize(facing)); + + const curveCtrlPoint = [ + x1 + facing[0]/2 + orthogonalUnit[0]*curviness, + y1 + facing[1]/2 + orthogonalUnit[1]*curviness + ] + + return 'M' + x1 + ',' + y1 + + getSingleCurvedSVGPath([x1, y1], curveCtrlPoint, curviness/2) + + getSingleCurvedSVGPath(curveCtrlPoint, [x2, y2], curviness/2); +} + +function getSingleCurvedSVGPath([x1, y1], [x2, y2], curviness) { + const facing = [ + x2 - x1, + y2 - y1, + ]; + const orthogonalUnit = rotate90deg(normalize(facing)); + + return 'Q' + (x1 + facing[0]/2 + orthogonalUnit[0]*curviness) + ' ' + (y1 + facing[1]/2 + orthogonalUnit[1]*curviness) + + ',' + x2 + ' ' + y2; +} + +function printGraph(relations){ + //remove groups links + links = links.filter(d => d.agent !== ('g') && d.agent !== ('h')); + relations.forEach(rel => { + const sourceId = rel.source + const targetId = rel.target + + const source = nodes.filter(function(node) { return node.id === sourceId; })[0]; + const target = nodes.filter(function(node) { return node.id === targetId; })[0]; + + if(sourceId === targetId) { + links.push({source: source, target: source, left: true, right: true, agent: rel.agent }); + return; + } + + const link = links.filter(l => l.source === target && l.target === source && l.agent === rel.agent)[0]; + + if (link) { + if(sourceId < targetId) { + link.right = true; + } else { + link.left = true; + } + } else { + if(sourceId < targetId) { + links.push({source: source, target: target, left: false, right: true, agent: rel.agent }); + } else { + links.push({source: target, target: source, left: true, right: false, agent: rel.agent }); + } + } + + }) + restart(); +} + +function resetGraph(){ + let rel = model.getAllRelationsOfList(epistemicAgents) + printGraph(rel); +} + +function subformulaeGraph(wff){ + const dropbtn = document.querySelector('#btn-subformulae'); + dropbtn.textContent = "$"+wff.latex()+"$"; + circle.selectAll('text:not(.id)').each(function(d, i) { + var id = d.id + truthVal = MPL.truth(model, id, wff); + if ( truthVal ){ + d3.select(this).text(wff.unicode()); + }else{ + d3.select(this).text(""); + } + }); + const json = wff.json(); + if (json.common_start && json.common_start.group_end && json.common_start.group_end[0].prop) { + const agents = json.common_start.group_end[0].prop.split(''); + let commonRelations = model.getCommonRelations(agents) + commonRelations = commonRelations.map((rel) => { + return { ...rel, agent: 'g' }; + }); + commonRelations=removeDuplicates(commonRelations); + // For showing other arrows. + //links = links.filter(d => !agents.includes(d.agent)); + links = [] + printGraph(commonRelations) + }else if (json.dist_start && json.dist_start.group_end && json.dist_start.group_end[0].prop) { + links = [] + const agents = json.dist_start.group_end[0].prop.split(''); + let distRelations = model.getDistributedRelations(agents) + distRelations = distRelations.map((rel) => { + return { ...rel, agent: 'h' }; + }); + distRelations=removeDuplicates(distRelations); + printGraph(distRelations) + + } else { + const relations = model.getAllRelationsOfList(epistemicAgents); + printGraph(relations) + } + MathJax.Hub.Queue(['Typeset', MathJax.Hub, dropbtn]); +} + +function hard_restart(){ + restart() +} + +// update graph (called when needed) +function restart() { + // path (link) group + path = path.data(links); + + function mid(d) { + return `url(#mid-arrow-${d.agent})`; + } + function start(d) { + return d.left ? `url(#start-arrow-${d.agent})` : ''; + } + function end(d) { + return d.right ? `url(#end-arrow-${d.agent})` : ''; + } + + // update existing links + path.classed('selected', function(d) { return d === selected_link; }) + .classed('agent-a', function(d) { return d.agent === 'a'; }) + .classed('agent-b', function(d) { return d.agent === 'b'; }) + .classed('agent-c', function(d) { return d.agent === 'c'; }) + .classed('agent-d', function(d) { return d.agent === 'd'; }) + .classed('agent-e', function(d) { return d.agent === 'e'; }) + .classed('agent-g', function(d) { return d.agent === 'g'; }) + .classed('agent-h', function(d) { return d.agent === 'h'; }) + .style('marker-start', start) + .style('marker-end', end) + .style('marker-mid', mid); + + // add new links + path.enter().append('svg:path') + .attr('class', 'link') + .classed('selected', function(d) { return d === selected_link; }) + .classed('agent-a', function(d) { return d.agent === 'a'; }) + .classed('agent-b', function(d) { return d.agent === 'b'; }) + .classed('agent-c', function(d) { return d.agent === 'c'; }) + .classed('agent-d', function(d) { return d.agent === 'd'; }) + .classed('agent-e', function(d) { return d.agent === 'e'; }) + .classed('agent-g', function(d) { return d.agent === 'g'; }) + .classed('agent-h', function(d) { return d.agent === 'h'; }) + .style('marker-start', start) + .style('marker-end', end) + .style('marker-mid', mid) + .on('mousedown', function(d) { + if(appMode !== MODE.EDIT || d3.event.ctrlKey) return; + // select link + mousedown_link = d; + if(mousedown_link === selected_link) selected_link = null; + else selected_link = mousedown_link; + setSelectedNode(null); + restart(); + }); + + // remove old links + path.exit().remove(); + + // circle (node) group + // NB: the function arg is crucial here! nodes are known by id, not by index! + circle = circle.data(nodes, function(d) { return d.id+1; }); + + // update existing nodes (reflexive & selected visual states) + circle.selectAll('circle') + .style('fill', d => (d === selected_node) ? d3.rgb(colors(d.id)).brighter() : colors(d.id)) + .style('stroke-width', '3px') + .style('stroke', d => (d === selected_node) ? 'black': 'transparent'); + + // add new nodes + var g = circle.enter().append('svg:g'); + + g.append('svg:circle') + .attr('class', 'node') + .attr('r', 15) + .style('fill', d => (d === selected_node) ? d3.rgb(colors(d.id)).brighter() : colors(d.id)) + .style('stroke-width', '3px') + .style('stroke', d => (d === selected_node) ? 'black': 'transparent') + .on('mouseover', function(d) { + if(appMode !== MODE.EDIT || !mousedown_node || d === mousedown_node) return; + // enlarge target node + d3.select(this).attr('transform', 'scale(1.1)'); + }) + .on('mouseout', function(d) { + if(appMode !== MODE.EDIT || !mousedown_node || d === mousedown_node) return; + // unenlarge target node + d3.select(this).attr('transform', ''); + }) + .on('mousedown', function(d) { + if(appMode !== MODE.EDIT || d3.event.ctrlKey) return; + + // select node + mousedown_node = d; + if(mousedown_node === selected_node) setSelectedNode(null); + else setSelectedNode(mousedown_node); + selected_link = null; + + // start dragging with drag line + drag_line + .style('marker-end', `url(#end-arrow-${currentEpistemicAgent})`) + .classed('hidden', false) + .classed('agent-a', function() { return currentEpistemicAgent === 'a'; }) + .classed('agent-b', function() { return currentEpistemicAgent === 'b'; }) + .classed('agent-c', function() { return currentEpistemicAgent === 'c'; }) + .classed('agent-d', function() { return currentEpistemicAgent === 'd'; }) + .classed('agent-e', function() { return currentEpistemicAgent === 'e'; }) + .classed('agent-g', function() { return currentEpistemicAgent === 'g'; }) + .classed('agent-h', function() { return currentEpistemicAgent === 'h'; }) + .attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'Q' + mousedown_node.x + ' ' + mousedown_node.y + ',' + mousedown_node.x + ' ' + mousedown_node.y) + .style('marker-mid', mid); + + function mid() { + return `url(#mid-arrow-${currentEpistemicAgent})`; + } + + restart(); + }) + .on('mouseup', function(d) { + if(appMode !== MODE.EDIT || !mousedown_node) return; + + // drag line dropped ontop of a node + drag_line + .classed('hidden', true) + .style('marker-end', ''); + + // check for drag-to-self + mouseup_node = d; + if(mouseup_node === mousedown_node) { resetMouseVars(); return; } + + // unenlarge target node + d3.select(this).attr('transform', ''); + + // add transition to model + model.addTransition(mousedown_node.id, mouseup_node.id, currentEpistemicAgent); + onStateModified(); + + // add link to graph (update if exists) + // note: links are strictly source < target; arrows separately specified by booleans + var source, target, direction; + if(mousedown_node.id < mouseup_node.id) { + source = mousedown_node; + target = mouseup_node; + direction = 'right'; + } else { + source = mouseup_node; + target = mousedown_node; + direction = 'left'; + } + + var link = links.filter(function(l) { + return (l.source === source && l.target === target && l.agent === currentEpistemicAgent); + })[0]; + + if(link) { + link[direction] = true; + } else { + link = {source: source, target: target, left: false, right: false, agent: currentEpistemicAgent}; + link[direction] = true; + links.push(link); + } + + // select new link + selected_link = link; + setSelectedNode(null); + restart(); + }); + + // show node IDs + g.append('svg:text') + .attr('x', 0) + .attr('y', 4) + .attr('class', 'id') + .attr('fill', 'white') + .text(function(d) { return d.id; }); + + // text shadow + g.append('svg:text') + .attr('x', 18) + .attr('y', 4) + .attr('class', 'shadow') + .text(makeAssignmentString); + + // text foreground + g.append('svg:text') + .attr('x', 18) + .attr('y', 4) + .text(makeAssignmentString); + + // remove old nodes + circle.exit().remove(); + + // set the graph in motion + force.start(); +} + +// Set the reflexive, symmetric, and transitive checkboxes to the correct state whenever the model +// changes. Also update the URL with the shareable model and formula state. +function onStateModified() { + const modelString = '?model=' + model.getModelString(); + let formulaString = '?formula=' + evalInput.select('input').node().value; + formulaString = formulaString.split(' ').join(''); //remove spaces + formulaString = formulaString.split('>').join(''); //remove > (> doesn't work in URLs) + history.pushState({}, '', location.pathname + modelString + formulaString); + + const reflexiveCheckEl = document.getElementById('reflexive-check'); + const symmetricCheckEl = document.getElementById('symmetric-check'); + const transitiveCheckEl = document.getElementById('transitive-check'); + + const activeAgents = model.getActiveAgents(); + if (activeAgents.length === 0) { + reflexiveCheckEl.checked = false; + symmetricCheckEl.checked = false; + transitiveCheckEl.checked = false; + document.getElementById('checks-title').innerHTML = + `No agents in use!`; + } else { + let reflexiveForActiveAgents = true; + let symmetricForActiveAgents = true; + let transitiveForActiveAgents = true; + for (const agent of activeAgents) { + reflexiveForActiveAgents = reflexiveForActiveAgents && model.isReflexive(agent); + symmetricForActiveAgents = symmetricForActiveAgents && model.isSymmetric(agent); + transitiveForActiveAgents = transitiveForActiveAgents && model.isTransitive(agent); + } + reflexiveCheckEl.checked = reflexiveForActiveAgents; + symmetricCheckEl.checked = symmetricForActiveAgents; + transitiveCheckEl.checked = transitiveForActiveAgents; + document.getElementById('checks-title').innerHTML = + `For agent${activeAgents.length === 1 ? '' : 's'} ${activeAgents.join()} :`; + } +} + +onStateModified(); + +function mousedown() { + // prevent I-bar on drag + d3.event.preventDefault(); + + // because :active only works in WebKit? + svg.classed('active', true); + + if(d3.event.ctrlKey || mousedown_node || mousedown_link) return; + + // insert new node at point + var point = d3.mouse(this), + defaultVals = propvars.map(function() { return false; }), + node = {id: ++lastNodeId, vals: defaultVals}; + node.x = point[0]; + node.y = point[1]; + nodes.push(node); + setSelectedNode(node); + + // add state to model + model.addState(); + onStateModified(); + + restart(); +} + + +function mousemove() { + if(!mousedown_node) return; + + // update drag line on move + const facing = [ + d3.mouse(this)[0] - mousedown_node.x, + d3.mouse(this)[1] - mousedown_node.y, + ]; + const orthogonalUnit = rotate90deg(normalize(facing)); + + drag_line + .attr('d', getDoubleCurvedSVGPath([mousedown_node.x, mousedown_node.y], d3.mouse(this), 0)) + .classed('agent-a', function() { return currentEpistemicAgent === 'a'; }) + .classed('agent-b', function() { return currentEpistemicAgent === 'b'; }) + .classed('agent-c', function() { return currentEpistemicAgent === 'c'; }) + .classed('agent-d', function() { return currentEpistemicAgent === 'd'; }) + .classed('agent-e', function() { return currentEpistemicAgent === 'e'; }) + .classed('agent-g', function() { return currentEpistemicAgent === 'g'; }) + .classed('agent-h', function() { return currentEpistemicAgent === 'h'; }) + .style('marker-end', `url(#end-arrow-${currentEpistemicAgent})`) + .style('marker-mid', mid); + + function mid() { + return `url(#mid-arrow-${currentEpistemicAgent})`; + } + + restart(); +} + +function normalize([x, y]) { + const normalizationFactor = 1/length([x, y]); + return [x*normalizationFactor, y*normalizationFactor]; +} + +function length([x, y]) { + return Math.sqrt(x**2 + y**2); +} + +function rotate90deg([x, y]) { + return [y, -x]; +} + +function rotateByAngle([x, y], angle) { + return [Math.cos(angle)*x - Math.sin(angle)*y, Math.sin(angle)*x + Math.cos(angle)*y] +} + +function mouseup() { + if(mousedown_node) { + // release and hide drag line + drag_line + .classed('hidden', true) + .style('marker-end', ''); + } + + // because :active only works in WebKit? + svg.classed('active', false); + + // clear mouse event vars + resetMouseVars(); +} + +function removeLinkFromModel(link) { + const sourceId = link.source.id; + const targetId = link.target.id; + const agent = link.agent; + + // remove leftward transition + if(link.left) model.removeTransition(targetId, sourceId, agent); + + // remove rightward transition + if(link.right) model.removeTransition(sourceId, targetId, agent); + onStateModified(); +} + +function spliceLinksForNode(node) { + var toSplice = links.filter(function(l) { + return (l.source === node || l.target === node); + }); + toSplice.map(function(l) { + links.splice(links.indexOf(l), 1); + }); +} + +// only respond once per keydown +var lastKeyDown = -1; + +function keydown() { + d3.event.preventDefault(); + + if(lastKeyDown !== -1) return; + lastKeyDown = d3.event.keyCode; + + // ctrl + if(d3.event.keyCode === 17) { + circle.call(force.drag); + svg.classed('ctrl', true); + return; + } + + if(!selected_node && !selected_link) return; + switch(d3.event.keyCode) { + case 8: // backspace + case 46: // delete + if(selected_node) { + model.removeState(selected_node.id); + nodes.splice(nodes.indexOf(selected_node), 1); + spliceLinksForNode(selected_node); + } else if(selected_link) { + removeLinkFromModel(selected_link); + links.splice(links.indexOf(selected_link), 1); + } + onStateModified(); + selected_link = null; + setSelectedNode(null); + restart(); + break; + case 66: // B + if(selected_link) { + var sourceId = selected_link.source.id, + targetId = selected_link.target.id; + const agent = selected_link.agent; + // set link direction to both left and right + if(!selected_link.left) { + selected_link.left = true; + model.addTransition(targetId, sourceId, agent); + } + if(!selected_link.right) { + selected_link.right = true; + model.addTransition(sourceId, targetId, agent); + } + } + onStateModified(); + restart(); + break; + case 76: // L + if(selected_link) { + var sourceId = selected_link.source.id, + targetId = selected_link.target.id; + const agent = selected_link.agent; + // set link direction to left only + if(!selected_link.left) { + selected_link.left = true; + model.addTransition(targetId, sourceId, agent); + } + if(selected_link.right) { + selected_link.right = false; + model.removeTransition(sourceId, targetId, agent); + } + } + onStateModified(); + restart(); + break; + case 82: // R + if(selected_node) { + // toggle node reflexivity + const reflexiveLink = links.filter(l => l.source === selected_node && l.target === selected_node && l.agent === currentEpistemicAgent)[0]; + if(reflexiveLink) { + model.removeTransition(selected_node.id, selected_node.id, currentEpistemicAgent); + removeLinkFromModel(reflexiveLink); + links.splice(links.indexOf(reflexiveLink), 1); + } else { + model.addTransition(selected_node.id, selected_node.id, currentEpistemicAgent); + links.push({source: selected_node, target: selected_node, left: true, right: true, agent: currentEpistemicAgent}); + } + } else if(selected_link) { + var sourceId = selected_link.source.id, + targetId = selected_link.target.id; + const agent = selected_link.agent; + // set link direction to right only + if(selected_link.left) { + selected_link.left = false; + model.removeTransition(targetId, sourceId, agent); + } + if(!selected_link.right) { + selected_link.right = true; + model.addTransition(sourceId, targetId, agent); + } + } + onStateModified(); + restart(); + break; + } +} + +function keyup() { + lastKeyDown = -1; + + // ctrl + if(d3.event.keyCode === 17) { + // "uncall" force.drag + // see: https://groups.google.com/forum/?fromgroups=#!topic/d3-js/-HcNN1deSow + circle + .on('mousedown.drag', null) + .on('touchstart.drag', null); + svg.classed('ctrl', false); + } +} + +// handles to mode select buttons and left-hand panel +var modeButtons = d3.selectAll('#mode-select button'), + panes = d3.selectAll('#app-body .panel .tab-pane'); + + +function setAppMode(newMode) { + // mode-specific settings + if(newMode === MODE.EDIT ) { + resetGraph(); + // enable listeners + svg.classed('edit', true) + .on('mousedown', mousedown) + .on('mousemove', mousemove) + .on('mouseup', mouseup); + d3.select(window) + .on('keydown', keydown) + .on('keyup', keyup); + + // remove eval classes + circle + .classed('waiting', false) + .classed('true', false) + .classed('false', false); + + currentFormula.classed('inactive', true); + currentSubFormula.classed('inactive', true); + currentSubFormula.selectAll("*").remove(); + } else if(newMode === MODE.EVAL|| newMode === MODE.TEXT ) { + // disable listeners (except for I-bar prevention) + svg.classed('edit', false) + .on('mousedown', function() { d3.event.preventDefault(); }) + .on('mousemove', null) + .on('mouseup', null); + d3.select(window) + .on('keydown', null) + .on('keyup', null); + + // in case ctrl still held + circle + .on('mousedown.drag', null) + .on('touchstart.drag', null); + svg.classed('ctrl', false); + lastKeyDown = -1; + + // stop showing drag line if the app switches to another mode e.g. from the 'Edit Modal' tab + // to the 'Evaluate Formula' tab. + drag_line + .classed('hidden', true) + .style('marker-end', ''); + + // clear mouse vars + selected_link = null; + setSelectedNode(null); + resetMouseVars(); + + // reset eval state + circle.classed('waiting', true); + evalOutput.classed('inactive', true); + + + // BUTTONS + // const invertPropvars = propvars.slice(0,varCount).reverse() + // var ezmode = document.getElementById('ezmode'); + // for (let i=0; i< varCount; i++){ + // const a = document.createElement('button') + // let txt = invertPropvars[i] + // a.innerHTML = txt; + // a.setAttribute('class', "btn btn-small atom-button") + // a.setAttribute('id', "prop"+i) + // a.onclick = function(){ + // addText(txt, this) + // }; + // ezmode.insertBefore(a, ezmode.firstChild) + // } + + } else return; + + // switch button and panel states and set new mode + modeButtons.each(function(d,i) { + if(i !== newMode) d3.select(this).classed('active', false); + else d3.select(this).classed('active', true); + }); + panes.each(function(d,i) { + if(i !== newMode) d3.select(this).classed('active', false); + else d3.select(this).classed('active', true); + }); + appMode = newMode; + + restart(); +} + +// allow enter key to evaluate formula +evalInput.select('input') + .on('keyup', function() { + // enter + if(d3.event.keyCode === 13) evaluateFormula(); + }) + .on('keydown', function() { + // enter -- needed on IE9 + if(d3.event.keyCode === 13) d3.event.preventDefault(); + }); + +// app starts here +setAppMode(MODE.EDIT); +setVarCount(varCount); + +if (formulaParam && formulaParam[1].length > 0) { + let formulaValue = formulaParam[1]; + formulaValue = formulaValue.split('-').join('->'); + evalInput.select('input').node().value = formulaValue; + setAppMode(MODE.EVAL); + evaluateFormula(); +} diff --git a/tree/js/lib.js b/tree/js/lib.js new file mode 100644 index 0000000..e6a4316 --- /dev/null +++ b/tree/js/lib.js @@ -0,0 +1,20 @@ +// lib.js +function removeDuplicates(arr) { + const uniqueItems = []; + const seen = new Set(); + + for (const item of arr) { + const key = JSON.stringify(item); + + if (!seen.has(key)) { + seen.add(key); + uniqueItems.push(item); + } + } + return uniqueItems; +} + +function removeAgentsRelations(agents, relations) { + relations = relations.filter(rel => !agents.includes(rel.agent)); + return relations; +} diff --git a/tree/js/tree.js b/tree/js/tree.js new file mode 100644 index 0000000..f67a112 --- /dev/null +++ b/tree/js/tree.js @@ -0,0 +1,155 @@ +const MPL = require('../js/MPL.js'); +class Tableaux { + constructor() { + this.branches = []; + this.contradictions = new Set(); + } + + // Apply tableaux rules to a formula + applyRules(formula, isNegated = false) { + const wff = formula.json() + + // Handle double negation + if (wff.neg !== undefined && wff.neg.neg !== '¬') { + return this.applyRules(wff.neg.neg, isNegated); + } + + const actualType = isNegated ? this.negateOperator(wff.type) : wff.type; + + switch (actualType) { + case 'prop': + return [[{ formula: wff, isNegated }]]; + case 'neg': + return this.applyRules(wff.children[0], !isNegated); + case 'conj': + const leftAnd = this.applyRules(wff.children[0], isNegated); + const rightAnd = this.applyRules(wff.children[1], isNegated); + return this.combineBranches(leftAnd, rightAnd, false); + case '¬∧': // Negated AND (NAND) - equivalent to ¬A ∨ ¬B (De Morgan) + const leftNand = this.applyRules(wff.children[0], !isNegated); + const rightNand = this.applyRules(wff.children[1], !isNegated); + return [...leftNand, ...rightNand]; + + case '¬∨': // Negated OR (NOR) - equivalent to ¬A ∧ ¬B (De Morgan) + const leftNor = this.applyRules(wff.children[0], !isNegated); + const rightNor = this.applyRules(wff.children[1], !isNegated); + return this.combineBranches(leftNor, rightNor, false); + + default: + throw new Error(`Unknown operator: ${wff.type}`); + } + } + + // Negate an operator + negateOperator(op) { + switch (op) { + case '∧': return '¬∧'; + case '∨': return '¬∨'; + case '→': return '∧'; // ¬(A → B) is A ∧ ¬B + case '↔': return '∨'; // ¬(A ↔ B) is (A ∧ ¬B) ∨ (¬A ∧ B) + default: return op; + } + } + + // Combine branches from two subformulas + combineBranches(left, right, isConjunctive) { + if (isConjunctive) { + const combined = []; + for (const lBranch of left) { + for (const rBranch of right) { + combined.push([...lBranch, ...rBranch]); + } + } + return combined; + } else { + return [...left, ...right]; + } + } + + // Check for contradictions in a branch + checkContradictions(branch) { + const atoms = new Map(); + + for (const { formula, isNegated } of branch) { + if (formula.type === 'atom') { + const key = formula.value; + if (atoms.has(key)) { + if (atoms.get(key) !== isNegated) { + return true; // Contradiction found + } + } else { + atoms.set(key, isNegated); + } + } + } + + return false; + } + + // Build the tableaux for a formula + build(formula) { + const initialBranches = this.applyRules(formula); + this.branches = initialBranches; + + // Check each branch for contradictions + this.contradictions = new Set(); + this.branches.forEach((branch, i) => { + if (this.checkContradictions(branch)) { + this.contradictions.add(i); + } + }); + + return this; + } + + // Check if the formula is valid (all branches close) + isValid() { + return this.branches.length > 0 && + this.branches.every((_, i) => this.contradictions.has(i)); + } + + // Check if the formula is satisfiable (at least one open branch) + isSatisfiable() { + return this.branches.some((_, i) => !this.contradictions.has(i)); + } + + display() { + console.log('Tableaux Method Results:'); + console.log('-----------------------'); + + this.branches.forEach((branch, i) => { + const status = this.contradictions.has(i) ? 'CLOSED' : 'OPEN'; + console.log(`Branch ${i + 1} (${status}):`); + + branch.forEach(({ formula, isNegated }) => { + const formulaStr = this.formatFormula(formula); + console.log(` ${isNegated ? '¬' : ''}${formulaStr}`); + }); + + console.log(''); + }); + + console.log(`Formula is ${this.isValid() ? 'valid' : 'not valid'}`); + console.log(`Formula is ${this.isSatisfiable() ? 'satisfiable' : 'not satisfiable'}`); + } + + // Format a formula AST back to string + formatFormula(node) { + if (node.type === 'atom') return node.value; + if (node.type === '¬') return `¬${this.formatFormula(node.children[0])}`; + + const left = this.formatFormula(node.children[0]); + const right = this.formatFormula(node.children[1]); + + return `(${left} ${node.type} ${right})`; + } +} + +// Example usage: +const tableaux = new Tableaux(); +const formula = "~~p" +const wff = new MPL.Wff(formula); +console.log(wff.json().neg.neg) +// tableaux.build('((P → Q) ∧ P) → Q)'); // Modus ponens - should be valid +// tableaux.display(); + diff --git a/tree/js/utils.js b/tree/js/utils.js new file mode 100644 index 0000000..fbd51ef --- /dev/null +++ b/tree/js/utils.js @@ -0,0 +1,92 @@ +var show = [] //para los botones en el ezmode +var hide = [] //para los botones. + +// When the button is clicked. +document.getElementById('readFileButton').addEventListener('click', function() { + document.getElementById('fileInput').click(); +}); + +document.getElementById('fileInput').addEventListener('change', function(event) { + const file = event.target.files[0]; // Obtiene el archivo seleccionado + + if (file) { + const reader = new FileReader(); + + reader.onload = function(e) { + updateModel(e.target.result); //TODO parser + }; + + reader.onerror = function(e) { + console.error("Error al leer el archivo:", e.target.error); + }; + + reader.readAsText(file); + } else { + console.log("No se seleccionó ningún archivo."); + } +}); + + +function addText(conector, element=null) { + var text = document.getElementById('formulaInput'); + + text.focus(); + if (conector === "delete"){ + text.value = ''; + return; + }else{ + text.value += conector; + } + if (element===null){ + return + } + const ezmode = false + if (ezmode){ + const className = element.className; + + let styleScript = document.getElementById('button-style'); + if (!styleScript) { + styleScript = document.createElement('style'); + styleScript.id = 'button-style'; + document.head.appendChild(styleScript); + } + styleScript.innerHTML = ''; + + if (className.includes("atom-button")){ + hide = ["atom-button", "monadic-button", "modal-button", "group-button", "agent-button"] + show = ["diadic-button"] + }else if (className.includes("monadic-button")){ + hide = ["diadic-button","agent-button"] + show = ["monadic-button", "atom-button", "modal-button"] + }else if (className.includes("modal-button")){ + hide = ["diadic-button"] + show = ["monadic-button", "atom-button", "modal-button"] + }else if (className.includes("group-button")){ + hide = ["monadic-button", "atom-button", "modal-button", "group-button", "diadic-button"] + show = ["agent-button"] + }else if (className.includes("agent-button")){ + hide = ["diadic-button"] + show = ["agent-button", "monadic-button", "atom-button", "modal-button", "group-button"] + }else if (className.includes("diadic-button")){ + hide = ["diadic-button"] + show = ["monadic-button", "atom-button", "modal-button"] + } + applyStyles(show, hide); + } +} + + + + +// Función para aplicar los estilos (mostrar/ocultar los botones) +function applyStyles(showClasses, hideClasses) { + console.log("HOLA") + let styleScript = document.getElementById('button-style'); + console.log(hideClasses) + hideClasses.forEach(clase => { + styleScript.innerHTML += `.${clase} { display:none; }`; + }); + showClasses.forEach(clase => { + styleScript.innerHTML += `.${clase} { display:inline; }`; + }); +} diff --git a/tree/lib/bootstrap.min.css b/tree/lib/bootstrap.min.css new file mode 100644 index 0000000..140f731 --- /dev/null +++ b/tree/lib/bootstrap.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v2.2.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover{color:#808080}.text-warning{color:#c09853}a.text-warning:hover{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover{color:#2d6987}.text-success{color:#468847}a.text-success:hover{color:#356635}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success td{background-color:#dff0d8}.table tbody tr.error td{background-color:#f2dede}.table tbody tr.warning td{background-color:#fcf8e3}.table tbody tr.info td{background-color:#d9edf7}.table-hover tbody tr.success:hover td{background-color:#d0e9c6}.table-hover tbody tr.error:hover td{background-color:#ebcccc}.table-hover tbody tr.warning:hover td{background-color:#faf2cc}.table-hover tbody tr.info:hover td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbb;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#c5c5c5;border-color:rgba(0,0,0,0.15) rgba(0,0,0,0.15) rgba(0,0,0,0.25)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret{border-top-color:#555;border-bottom-color:#555}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px}.tooltip.right{margin-left:3px}.tooltip.bottom{margin-top:3px}.tooltip.left{margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media .pull-left{margin-right:10px}.media .pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} diff --git a/tree/lib/d3.min.js b/tree/lib/d3.min.js new file mode 100644 index 0000000..34d5513 --- /dev/null +++ b/tree/lib/d3.min.js @@ -0,0 +1,5 @@ +!function(){function n(n){return n&&(n.ownerDocument||n.document||n).documentElement}function t(n){return n&&(n.ownerDocument&&n.ownerDocument.defaultView||n.document&&n||n.defaultView)}function e(n,t){return t>n?-1:n>t?1:n>=t?0:0/0}function r(n){return null===n?0/0:+n}function u(n){return!isNaN(n)}function i(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function o(n){return n.length}function a(n){for(var t=1;n*t%1;)t*=10;return t}function c(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function l(){this._=Object.create(null)}function s(n){return(n+="")===pa||n[0]===va?va+n:n}function f(n){return(n+="")[0]===va?n.slice(1):n}function h(n){return s(n)in this._}function g(n){return(n=s(n))in this._&&delete this._[n]}function p(){var n=[];for(var t in this._)n.push(f(t));return n}function v(){var n=0;for(var t in this._)++n;return n}function d(){for(var n in this._)return!1;return!0}function m(){this._=Object.create(null)}function y(n){return n}function M(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function x(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=da.length;r>e;++e){var u=da[e]+t;if(u in n)return u}}function b(){}function _(){}function w(n){function t(){for(var t,r=e,u=-1,i=r.length;++ue;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function Z(n){return ya(n,Sa),n}function V(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t0&&(n=n.slice(0,a));var l=ka.get(n);return l&&(n=l,c=B),a?t?u:r:t?b:i}function $(n,t){return function(e){var r=ta.event;ta.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ta.event=r}}}function B(n,t){var e=$(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function W(e){var r=".dragsuppress-"+ ++Aa,u="click"+r,i=ta.select(t(e)).on("touchmove"+r,S).on("dragstart"+r,S).on("selectstart"+r,S);if(null==Ea&&(Ea="onselectstart"in e?!1:x(e.style,"userSelect")),Ea){var o=n(e).style,a=o[Ea];o[Ea]="none"}return function(n){if(i.on(r,null),Ea&&(o[Ea]=a),n){var t=function(){i.on(u,null)};i.on(u,function(){S(),t()},!0),setTimeout(t,0)}}}function J(n,e){e.changedTouches&&(e=e.changedTouches[0]);var r=n.ownerSVGElement||n;if(r.createSVGPoint){var u=r.createSVGPoint();if(0>Na){var i=t(n);if(i.scrollX||i.scrollY){r=ta.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var o=r[0][0].getScreenCTM();Na=!(o.f||o.e),r.remove()}}return Na?(u.x=e.pageX,u.y=e.pageY):(u.x=e.clientX,u.y=e.clientY),u=u.matrixTransform(n.getScreenCTM().inverse()),[u.x,u.y]}var a=n.getBoundingClientRect();return[e.clientX-a.left-n.clientLeft,e.clientY-a.top-n.clientTop]}function G(){return ta.event.changedTouches[0].identifier}function K(n){return n>0?1:0>n?-1:0}function Q(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function nt(n){return n>1?0:-1>n?qa:Math.acos(n)}function tt(n){return n>1?Ra:-1>n?-Ra:Math.asin(n)}function et(n){return((n=Math.exp(n))-1/n)/2}function rt(n){return((n=Math.exp(n))+1/n)/2}function ut(n){return((n=Math.exp(2*n))-1)/(n+1)}function it(n){return(n=Math.sin(n/2))*n}function ot(){}function at(n,t,e){return this instanceof at?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof at?new at(n.h,n.s,n.l):bt(""+n,_t,at):new at(n,t,e)}function ct(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,new mt(u(n+120),u(n),u(n-120))}function lt(n,t,e){return this instanceof lt?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof lt?new lt(n.h,n.c,n.l):n instanceof ft?gt(n.l,n.a,n.b):gt((n=wt((n=ta.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new lt(n,t,e)}function st(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new ft(e,Math.cos(n*=Da)*t,Math.sin(n)*t)}function ft(n,t,e){return this instanceof ft?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof ft?new ft(n.l,n.a,n.b):n instanceof lt?st(n.h,n.c,n.l):wt((n=mt(n)).r,n.g,n.b):new ft(n,t,e)}function ht(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=pt(u)*Xa,r=pt(r)*$a,i=pt(i)*Ba,new mt(dt(3.2404542*u-1.5371385*r-.4985314*i),dt(-.969266*u+1.8760108*r+.041556*i),dt(.0556434*u-.2040259*r+1.0572252*i))}function gt(n,t,e){return n>0?new lt(Math.atan2(e,t)*Pa,Math.sqrt(t*t+e*e),n):new lt(0/0,0/0,n)}function pt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function vt(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function dt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function mt(n,t,e){return this instanceof mt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof mt?new mt(n.r,n.g,n.b):bt(""+n,mt,ct):new mt(n,t,e)}function yt(n){return new mt(n>>16,n>>8&255,255&n)}function Mt(n){return yt(n)+""}function xt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function bt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(kt(u[0]),kt(u[1]),kt(u[2]))}return(i=Ga.get(n.toLowerCase()))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function _t(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new at(r,u,c)}function wt(n,t,e){n=St(n),t=St(t),e=St(e);var r=vt((.4124564*n+.3575761*t+.1804375*e)/Xa),u=vt((.2126729*n+.7151522*t+.072175*e)/$a),i=vt((.0193339*n+.119192*t+.9503041*e)/Ba);return ft(116*u-16,500*(r-u),200*(u-i))}function St(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function kt(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function Et(n){return"function"==typeof n?n:function(){return n}}function At(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Nt(t,e,n,r)}}function Nt(n,t,e,r){function u(){var n,t=c.status;if(!t&&zt(c)||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return void o.error.call(i,r)}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=ta.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,l=null;return!this.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=ta.event;ta.event=n;try{o.progress.call(i,c)}finally{ta.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(l=n,i):l},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(ra(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var s in a)c.setRequestHeader(s,a[s]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},ta.rebind(i,o,"on"),null==r?i:i.get(Ct(r))}function Ct(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function zt(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function qt(){var n=Lt(),t=Tt()-n;t>24?(isFinite(t)&&(clearTimeout(tc),tc=setTimeout(qt,t)),nc=0):(nc=1,rc(qt))}function Lt(){var n=Date.now();for(ec=Ka;ec;)n>=ec.t&&(ec.f=ec.c(n-ec.t)),ec=ec.n;return n}function Tt(){for(var n,t=Ka,e=1/0;t;)t.f?t=n?n.n=t.n:Ka=t.n:(t.t8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Pt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r&&e?function(n,t){for(var u=n.length,i=[],o=0,a=r[0],c=0;u>0&&a>0&&(c+a+1>t&&(a=Math.max(1,t-c)),i.push(n.substring(u-=a,u+a)),!((c+=a+1)>t));)a=r[o=(o+1)%r.length];return i.reverse().join(e)}:y;return function(n){var e=ic.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",c=e[4]||"",l=e[5],s=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1,y=!0;switch(h&&(h=+h.substring(1)),(l||"0"===r&&"="===o)&&(l=r="0",o="="),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":y=!1;case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=oc.get(g)||Ut;var M=l&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>p){var c=ta.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var x,b,_=n.lastIndexOf(".");if(0>_){var w=y?n.lastIndexOf("e"):-1;0>w?(x=n,b=""):(x=n.substring(0,w),b=n.substring(w))}else x=n.substring(0,_),b=t+n.substring(_+1);!l&&f&&(x=i(x,1/0));var S=v.length+x.length+b.length+(M?0:u.length),k=s>S?new Array(S=s-S+1).join(r):"";return M&&(x=i(k+x,k.length?s-b.length:1/0)),u+=v,n=x+b,("<"===o?u+n+k:">"===o?k+u+n:"^"===o?k.substring(0,S>>=1)+u+n+k.substring(S):u+(M?n:k+n))+e}}}function Ut(n){return n+""}function jt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Ft(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new cc(e-1)),1),e}function i(n,e){return t(n=new cc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{cc=jt;var r=new jt;return r._=n,o(r,t,e)}finally{cc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Ht(n);return c.floor=c,c.round=Ht(r),c.ceil=Ht(u),c.offset=Ht(i),c.range=a,n}function Ht(n){return function(t,e){try{cc=jt;var r=new jt;return r._=t,n(r,e)._}finally{cc=Date}}}function Ot(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++aa;){if(r>=l)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=C[o in sc?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){_.lastIndex=0;var r=_.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){x.lastIndex=0;var r=x.exec(t.slice(e));return r?(n.w=b.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.slice(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,N.c.toString(),t,r)}function c(n,t,r){return e(n,N.x.toString(),t,r)}function l(n,t,r){return e(n,N.X.toString(),t,r)}function s(n,t,e){var r=M.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{cc=jt;var t=new cc;return t._=n,r(t)}finally{cc=Date}}var r=t(n);return e.parse=function(n){try{cc=jt;var t=r.parse(n);return t&&t._}finally{cc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ae;var M=ta.map(),x=Yt(v),b=Zt(v),_=Yt(d),w=Zt(d),S=Yt(m),k=Zt(m),E=Yt(y),A=Zt(y);p.forEach(function(n,t){M.set(n.toLowerCase(),t)});var N={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return It(n.getDate(),t,2)},e:function(n,t){return It(n.getDate(),t,2)},H:function(n,t){return It(n.getHours(),t,2)},I:function(n,t){return It(n.getHours()%12||12,t,2)},j:function(n,t){return It(1+ac.dayOfYear(n),t,3)},L:function(n,t){return It(n.getMilliseconds(),t,3)},m:function(n,t){return It(n.getMonth()+1,t,2)},M:function(n,t){return It(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return It(n.getSeconds(),t,2)},U:function(n,t){return It(ac.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return It(ac.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return It(n.getFullYear()%100,t,2)},Y:function(n,t){return It(n.getFullYear()%1e4,t,4)},Z:ie,"%":function(){return"%"}},C={a:r,A:u,b:i,B:o,c:a,d:Qt,e:Qt,H:te,I:te,j:ne,L:ue,m:Kt,M:ee,p:s,S:re,U:Xt,w:Vt,W:$t,x:c,X:l,y:Wt,Y:Bt,Z:Jt,"%":oe};return t}function It(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function Yt(n){return new RegExp("^(?:"+n.map(ta.requote).join("|")+")","i")}function Zt(n){for(var t=new l,e=-1,r=n.length;++e68?1900:2e3)}function Kt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Qt(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function ne(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function te(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ee(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function re(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ue(n,t,e){fc.lastIndex=0;var r=fc.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ie(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=ga(t)/60|0,u=ga(t)%60;return e+It(r,"0",2)+It(u,"0",2)}function oe(n,t,e){hc.lastIndex=0;var r=hc.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ae(n){for(var t=n.length,e=-1;++e=0?1:-1,a=o*e,c=Math.cos(t),l=Math.sin(t),s=i*l,f=u*c+s*Math.cos(a),h=s*o*Math.sin(a);yc.add(Math.atan2(h,f)),r=n,u=c,i=l}var t,e,r,u,i;Mc.point=function(o,a){Mc.point=n,r=(t=o)*Da,u=Math.cos(a=(e=a)*Da/2+qa/4),i=Math.sin(a)},Mc.lineEnd=function(){n(t,e)}}function pe(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function ve(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function de(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function me(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function ye(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function Me(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function xe(n){return[Math.atan2(n[1],n[0]),tt(n[2])]}function be(n,t){return ga(n[0]-t[0])a;++a)u.point((e=n[a])[0],e[1]);return void u.lineEnd()}var c=new qe(e,n,null,!0),l=new qe(e,null,c,!1);c.o=l,i.push(c),o.push(l),c=new qe(r,n,null,!1),l=new qe(r,null,c,!0),c.o=l,i.push(c),o.push(l)}}),o.sort(t),ze(i),ze(o),i.length){for(var a=0,c=e,l=o.length;l>a;++a)o[a].e=c=!c;for(var s,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;s=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,l=s.length;l>a;++a)u.point((f=s[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){s=g.p.z;for(var a=s.length-1;a>=0;--a)u.point((f=s[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,s=g.z,p=!p}while(!g.v);u.lineEnd()}}}function ze(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r0){for(b||(i.polygonStart(),b=!0),i.lineStart();++o1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Te))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:l,polygonStart:function(){y.point=s,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=l,g=ta.merge(g);var n=Fe(m,p);g.length?(b||(i.polygonStart(),b=!0),Ce(g,De,n,e,i)):n&&(b||(i.polygonStart(),b=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),b&&(i.polygonEnd(),b=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},M=Re(),x=t(M),b=!1;return y}}function Te(n){return n.length>1}function Re(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:b,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function De(n,t){return((n=n.x)[0]<0?n[1]-Ra-Ca:Ra-n[1])-((t=t.x)[0]<0?t[1]-Ra-Ca:Ra-t[1])}function Pe(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?qa:-qa,c=ga(i-e);ga(c-qa)0?Ra:-Ra),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=qa&&(ga(e-u)Ca?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function je(n,t,e,r){var u;if(null==n)u=e*Ra,r.point(-qa,u),r.point(0,u),r.point(qa,u),r.point(qa,0),r.point(qa,-u),r.point(0,-u),r.point(-qa,-u),r.point(-qa,0),r.point(-qa,u);else if(ga(n[0]-t[0])>Ca){var i=n[0]a;++a){var l=t[a],s=l.length;if(s)for(var f=l[0],h=f[0],g=f[1]/2+qa/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===s&&(d=0),n=l[d];var m=n[0],y=n[1]/2+qa/4,M=Math.sin(y),x=Math.cos(y),b=m-h,_=b>=0?1:-1,w=_*b,S=w>qa,k=p*M;if(yc.add(Math.atan2(k*_*Math.sin(w),v*x+k*Math.cos(w))),i+=S?b+_*La:b,S^h>=e^m>=e){var E=de(pe(f),pe(n));Me(E);var A=de(u,E);Me(A);var N=(S^b>=0?-1:1)*tt(A[2]);(r>N||r===N&&(E[0]||E[1]))&&(o+=S^b>=0?1:-1)}if(!d++)break;h=m,p=M,v=x,f=n}}return(-Ca>i||Ca>i&&0>yc)^1&o}function He(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,l,s;return{lineStart:function(){l=c=!1,s=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?qa:-qa),h):0;if(!e&&(l=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(be(e,g)||be(p,g))&&(p[0]+=Ca,p[1]+=Ca,v=t(p[0],p[1]))),v!==c)s=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(s=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&be(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return s|(l&&c)<<1}}}function r(n,t,e){var r=pe(n),u=pe(t),o=[1,0,0],a=de(r,u),c=ve(a,a),l=a[0],s=c-l*l;if(!s)return!e&&n;var f=i*c/s,h=-i*l/s,g=de(o,a),p=ye(o,f),v=ye(a,h);me(p,v);var d=g,m=ve(p,d),y=ve(d,d),M=m*m-y*(ve(p,p)-1);if(!(0>M)){var x=Math.sqrt(M),b=ye(d,(-m-x)/y);if(me(b,p),b=xe(b),!e)return b;var _,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(_=w,w=S,S=_);var A=S-w,N=ga(A-qa)A;if(!N&&k>E&&(_=k,k=E,E=_),C?N?k+E>0^b[1]<(ga(b[0]-w)qa^(w<=b[0]&&b[0]<=S)){var z=ye(d,(-m+x)/y);return me(z,p),[b,xe(z)]}}}function u(t,e){var r=o?n:qa-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ga(i)>Ca,c=gr(n,6*Da);return Le(t,e,c,o?[0,-n]:[-qa,n-qa])}function Oe(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,l=o.y,s=a.x,f=a.y,h=0,g=1,p=s-c,v=f-l;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-l,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-l,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:l+h*v}),1>g&&(u.b={x:c+g*p,y:l+g*v}),u}}}}}}function Ie(n,t,e,r){function u(r,u){return ga(r[0]-n)0?0:3:ga(r[0]-e)0?2:1:ga(r[1]-t)0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,l=a[0];c>o;++o)i=a[o],l[1]<=r?i[1]>r&&Q(l,i,n)>0&&++t:i[1]<=r&&Q(l,i,n)<0&&--t,l=i;return 0!==t}function l(i,a,c,l){var s=0,f=0;if(null==i||(s=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do l.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+c+4)%4)!==f)}else l.point(a[0],a[1])}function s(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){s(n,t)&&a.point(n,t)}function h(){C.point=p,d&&d.push(m=[]),S=!0,w=!1,b=_=0/0}function g(){v&&(p(y,M),x&&w&&A.rejoin(),v.push(A.buffer())),C.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-Tc,Math.min(Tc,n)),t=Math.max(-Tc,Math.min(Tc,t));var e=s(n,t);if(d&&m.push([n,t]),S)y=n,M=t,x=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:b,y:_},b:{x:n,y:t}};N(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}b=n,_=t,w=e}var v,d,m,y,M,x,b,_,w,S,k,E=a,A=Re(),N=Oe(n,t,e,r),C={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=ta.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),l(null,null,1,a),a.lineEnd()),u&&Ce(v,i,t,l,a),a.polygonEnd()),v=d=m=null}};return C}}function Ye(n){var t=0,e=qa/3,r=ir(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*qa/180,e=n[1]*qa/180):[t/qa*180,e/qa*180]},u}function Ze(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,tt((i-(n*n+e*e)*u*u)/(2*u))]},e}function Ve(){function n(n,t){Dc+=u*n-r*t,r=n,u=t}var t,e,r,u;Hc.point=function(i,o){Hc.point=n,t=r=i,e=u=o},Hc.lineEnd=function(){n(t,e)}}function Xe(n,t){Pc>n&&(Pc=n),n>jc&&(jc=n),Uc>t&&(Uc=t),t>Fc&&(Fc=t)}function $e(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Be(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Be(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Be(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function We(n,t){_c+=n,wc+=t,++Sc}function Je(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);kc+=o*(t+n)/2,Ec+=o*(e+r)/2,Ac+=o,We(t=n,e=r)}var t,e;Ic.point=function(r,u){Ic.point=n,We(t=r,e=u)}}function Ge(){Ic.point=We}function Ke(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);kc+=o*(r+n)/2,Ec+=o*(u+t)/2,Ac+=o,o=u*n-r*t,Nc+=o*(r+n),Cc+=o*(u+t),zc+=3*o,We(r=n,u=t)}var t,e,r,u;Ic.point=function(i,o){Ic.point=n,We(t=r=i,e=u=o)},Ic.lineEnd=function(){n(t,e)}}function Qe(n){function t(t,e){n.moveTo(t+o,e),n.arc(t,e,o,0,La)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:b};return a}function nr(n){function t(n){return(a?r:e)(n)}function e(t){return rr(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){M=0/0,S.point=i,t.lineStart()}function i(e,r){var i=pe([e,r]),o=n(e,r);u(M,x,y,b,_,w,M=o[0],x=o[1],y=e,b=i[0],_=i[1],w=i[2],a,t),t.point(M,x)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=l,S.lineEnd=s}function l(n,t){i(f=n,h=t),g=M,p=x,v=b,d=_,m=w,S.point=i}function s(){u(M,x,y,b,_,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,M,x,b,_,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c +},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,l,s,f,h,g,p,v,d,m){var y=s-t,M=f-e,x=y*y+M*M;if(x>4*i&&d--){var b=a+g,_=c+p,w=l+v,S=Math.sqrt(b*b+_*_+w*w),k=Math.asin(w/=S),E=ga(ga(w)-1)i||ga((y*z+M*q)/x-.5)>.3||o>a*g+c*p+l*v)&&(u(t,e,r,a,c,l,N,C,E,b/=S,_/=S,w,d,m),m.point(N,C),u(N,C,E,b,_,w,s,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Da),a=16;return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function tr(n){var t=nr(function(t,e){return n([t*Pa,e*Pa])});return function(n){return or(t(n))}}function er(n){this.stream=n}function rr(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function ur(n){return ir(function(){return n})()}function ir(n){function t(n){return n=a(n[0]*Da,n[1]*Da),[n[0]*h+c,l-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Pa,n[1]*Pa]}function r(){a=Ae(o=lr(m,M,x),i);var n=i(v,d);return c=g-n[0]*h,l=p+n[1]*h,u()}function u(){return s&&(s.valid=!1,s=null),t}var i,o,a,c,l,s,f=nr(function(n,t){return n=i(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,M=0,x=0,b=Lc,_=y,w=null,S=null;return t.stream=function(n){return s&&(s.valid=!1),s=or(b(o,f(_(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(b=null==n?(w=n,Lc):He((w=+n)*Da),u()):w},t.clipExtent=function(n){return arguments.length?(S=n,_=n?Ie(n[0][0],n[0][1],n[1][0],n[1][1]):y,u()):S},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Da,d=n[1]%360*Da,r()):[v*Pa,d*Pa]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Da,M=n[1]%360*Da,x=n.length>2?n[2]%360*Da:0,r()):[m*Pa,M*Pa,x*Pa]},ta.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function or(n){return rr(n,function(t,e){n.point(t*Da,e*Da)})}function ar(n,t){return[n,t]}function cr(n,t){return[n>qa?n-La:-qa>n?n+La:n,t]}function lr(n,t,e){return n?t||e?Ae(fr(n),hr(t,e)):fr(n):t||e?hr(t,e):cr}function sr(n){return function(t,e){return t+=n,[t>qa?t-La:-qa>t?t+La:t,e]}}function fr(n){var t=sr(n);return t.invert=sr(-n),t}function hr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*r+a*u;return[Math.atan2(c*i-s*o,a*r-l*u),tt(s*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*i-c*o;return[Math.atan2(c*i+l*o,a*r+s*u),tt(s*r-a*u)]},e}function gr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=pr(e,u),i=pr(e,i),(o>0?i>u:u>i)&&(u+=o*La)):(u=n+o*La,i=n-.5*c);for(var l,s=u;o>0?s>i:i>s;s-=c)a.point((l=xe([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],l[1])}}function pr(n,t){var e=pe(t);e[0]-=n,Me(e);var r=nt(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Ca)%(2*Math.PI)}function vr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function dr(n,t,e){var r=ta.range(n,t-Ca,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function mr(n){return n.source}function yr(n){return n.target}function Mr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),l=u*Math.sin(n),s=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(it(r-t)+u*o*it(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*s,u=e*l+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Pa,Math.atan2(o,Math.sqrt(r*r+u*u))*Pa]}:function(){return[n*Pa,t*Pa]};return p.distance=h,p}function xr(){function n(n,u){var i=Math.sin(u*=Da),o=Math.cos(u),a=ga((n*=Da)-t),c=Math.cos(a);Yc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Zc.point=function(u,i){t=u*Da,e=Math.sin(i*=Da),r=Math.cos(i),Zc.point=n},Zc.lineEnd=function(){Zc.point=Zc.lineEnd=b}}function br(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function _r(n,t){function e(n,t){o>0?-Ra+Ca>t&&(t=-Ra+Ca):t>Ra-Ca&&(t=Ra-Ca);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(qa/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=K(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Ra]},e):Sr}function wr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ga(u)u;u++){for(;r>1&&Q(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function zr(n,t){return n[0]-t[0]||n[1]-t[1]}function qr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Lr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],l=e[1],s=t[1]-c,f=r[1]-l,h=(a*(c-l)-f*(u-i))/(f*o-a*s);return[u+h*o,c+h*s]}function Tr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Rr(){tu(this),this.edge=this.site=this.circle=null}function Dr(n){var t=el.pop()||new Rr;return t.site=n,t}function Pr(n){Xr(n),Qc.remove(n),el.push(n),tu(n)}function Ur(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Pr(n);for(var c=i;c.circle&&ga(e-c.circle.x)s;++s)l=a[s],c=a[s-1],Kr(l.edge,c.site,l.site,u);c=a[0],l=a[f-1],l.edge=Jr(c.site,l.site,null,u),Vr(c),Vr(l)}function jr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Qc._;a;)if(r=Fr(a,o)-i,r>Ca)a=a.L;else{if(u=i-Hr(a,o),!(u>Ca)){r>-Ca?(t=a.P,e=a):u>-Ca?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Dr(n);if(Qc.insert(t,c),t||e){if(t===e)return Xr(t),e=Dr(t.site),Qc.insert(c,e),c.edge=e.edge=Jr(t.site,c.site),Vr(t),void Vr(e);if(!e)return void(c.edge=Jr(t.site,c.site));Xr(t),Xr(e);var l=t.site,s=l.x,f=l.y,h=n.x-s,g=n.y-f,p=e.site,v=p.x-s,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,M=v*v+d*d,x={x:(d*y-g*M)/m+s,y:(h*M-v*y)/m+f};Kr(e.edge,l,p,x),c.edge=Jr(l,n,null,x),e.edge=Jr(n,p,null,x),Vr(t),Vr(e)}}function Fr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,l=c-t;if(!l)return a;var s=a-r,f=1/i-1/l,h=s/l;return f?(-h+Math.sqrt(h*h-2*f*(s*s/(-2*l)-c+l/2+u-i/2)))/f+r:(r+a)/2}function Hr(n,t){var e=n.N;if(e)return Fr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Or(n){this.site=n,this.edges=[]}function Ir(n){for(var t,e,r,u,i,o,a,c,l,s,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Kc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)s=a[o].end(),r=s.x,u=s.y,l=a[++o%c].start(),t=l.x,e=l.y,(ga(r-t)>Ca||ga(u-e)>Ca)&&(a.splice(o,0,new Qr(Gr(i.site,s,ga(r-f)Ca?{x:f,y:ga(t-f)Ca?{x:ga(e-p)Ca?{x:h,y:ga(t-h)Ca?{x:ga(e-g)=-za)){var g=c*c+l*l,p=s*s+f*f,v=(f*g-l*p)/h,d=(c*p-s*g)/h,f=d+a,m=rl.pop()||new Zr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,M=tl._;M;)if(m.yd||d>=a)return;if(h>p){if(i){if(i.y>=l)return}else i={x:d,y:c};e={x:d,y:l}}else{if(i){if(i.yr||r>1)if(h>p){if(i){if(i.y>=l)return}else i={x:(c-u)/r,y:c};e={x:(l-u)/r,y:l}}else{if(i){if(i.yg){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.xi||f>o||r>h||u>g)){if(p=n.point){var p,v=t-n.x,d=e-n.y,m=v*v+d*d;if(c>m){var y=Math.sqrt(c=m);r=t-y,u=e-y,i=t+y,o=e+y,a=p}}for(var M=n.nodes,x=.5*(s+h),b=.5*(f+g),_=t>=x,w=e>=b,S=w<<1|_,k=S+4;k>S;++S)if(n=M[3&S])switch(3&S){case 0:l(n,s,f,x,b);break;case 1:l(n,x,f,h,b);break;case 2:l(n,s,b,x,g);break;case 3:l(n,x,b,h,g)}}}(n,r,u,i,o),a}function gu(n,t){n=ta.rgb(n),t=ta.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+xt(Math.round(e+i*n))+xt(Math.round(r+o*n))+xt(Math.round(u+a*n))}}function pu(n,t){var e,r={},u={};for(e in n)e in t?r[e]=mu(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function vu(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function du(n,t){var e,r,u,i=il.lastIndex=ol.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=il.exec(n))&&(r=ol.exec(t));)(u=r.index)>i&&(u=t.slice(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:vu(e,r)})),i=ol.lastIndex;return ir;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function mu(n,t){for(var e,r=ta.interpolators.length;--r>=0&&!(e=ta.interpolators[r](n,t)););return e}function yu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(mu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function Mu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function xu(n){return function(t){return 1-n(1-t)}}function bu(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function _u(n){return n*n}function wu(n){return n*n*n}function Su(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function ku(n){return function(t){return Math.pow(t,n)}}function Eu(n){return 1-Math.cos(n*Ra)}function Au(n){return Math.pow(2,10*(n-1))}function Nu(n){return 1-Math.sqrt(1-n*n)}function Cu(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/La*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*La/t)}}function zu(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function qu(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Lu(n,t){n=ta.hcl(n),t=ta.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return st(e+i*n,r+o*n,u+a*n)+""}}function Tu(n,t){n=ta.hsl(n),t=ta.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return ct(e+i*n,r+o*n,u+a*n)+""}}function Ru(n,t){n=ta.lab(n),t=ta.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ht(e+i*n,r+o*n,u+a*n)+""}}function Du(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Pu(n){var t=[n.a,n.b],e=[n.c,n.d],r=ju(t),u=Uu(t,e),i=ju(Fu(e,t,-u))||0;t[0]*e[1]180?s+=360:s-l>180&&(l+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:vu(l,s)})):s&&r.push(r.pop()+"rotate("+s+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:vu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:vu(g[0],p[0])},{i:e-2,x:vu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i=0;)e.push(u[r])}function Qu(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++oe;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function si(n){return n.reduce(fi,0)}function fi(n,t){return n+t[1]}function hi(n,t){return gi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function gi(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function pi(n){return[ta.min(n),ta.max(n)]}function vi(n,t){return n.value-t.value}function di(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function mi(n,t){n._pack_next=t,t._pack_prev=n}function yi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function Mi(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var e,r,u,i,o,a,c,l,s=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(xi),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(u=e[1],u.x=u.r,u.y=0,t(u),l>2))for(i=e[2],wi(r,u,i),t(i),di(r,i),r._pack_prev=i,di(i,u),u=r._pack_next,o=3;l>o;o++){wi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(yi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!yi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.ro;o++)i=e[o],i.x-=m,i.y-=y,M=Math.max(M,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=M,e.forEach(bi)}}function xi(n){n._pack_next=n._pack_prev=n}function bi(n){delete n._pack_next,delete n._pack_prev}function _i(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Ci(n,t,e){return n.a.parent===t.parent?n.a:e}function zi(n){return 1+ta.max(n,function(n){return n.y})}function qi(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Li(n){var t=n.children;return t&&t.length?Li(t[0]):n}function Ti(n){var t,e=n.children;return e&&(t=e.length)?Ti(e[t-1]):n}function Ri(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Di(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Pi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ui(n){return n.rangeExtent?n.rangeExtent():Pi(n.range())}function ji(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Fi(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Hi(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ml}function Oi(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]2?Oi:ji,c=r?Iu:Ou;return o=u(n,t,c,e),a=u(t,n,c,mu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(Du)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Xi(n,t)},i.tickFormat=function(t,e){return $i(n,t,e)},i.nice=function(t){return Zi(n,t),u()},i.copy=function(){return Ii(n,t,e,r)},u()}function Yi(n,t){return ta.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Zi(n,t){return Fi(n,Hi(Vi(n,t)[2]))}function Vi(n,t){null==t&&(t=10);var e=Pi(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Xi(n,t){return ta.range.apply(ta,Vi(n,t))}function $i(n,t,e){var r=Vi(n,t);if(e){var u=ic.exec(e);if(u.shift(),"s"===u[8]){var i=ta.formatPrefix(Math.max(ga(r[0]),ga(r[1])));return u[7]||(u[7]="."+Bi(i.scale(r[2]))),u[8]="f",e=ta.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Wi(u[8],r)),e=u.join("")}else e=",."+Bi(r[2])+"f";return ta.format(e)}function Bi(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Wi(n,t){var e=Bi(t[2]);return n in yl?Math.abs(e-Bi(Math.max(ga(t[0]),ga(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Ji(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Fi(r.map(u),e?Math:xl);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Pi(r),o=[],a=n[0],c=n[1],l=Math.floor(u(a)),s=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(s-l)){if(e){for(;s>l;l++)for(var h=1;f>h;h++)o.push(i(l)*h);o.push(i(l))}else for(o.push(i(l));l++0;h--)o.push(i(l)*h);for(l=0;o[l]c;s--);o=o.slice(l,s)}return o},o.tickFormat=function(n,t){if(!arguments.length)return Ml;arguments.length<2?t=Ml:"function"!=typeof t&&(t=ta.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Ji(n.copy(),t,e,r)},Yi(o,n)}function Gi(n,t,e){function r(t){return n(u(t))}var u=Ki(t),i=Ki(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Xi(e,n)},r.tickFormat=function(n,t){return $i(e,n,t)},r.nice=function(n){return r.domain(Zi(e,n))},r.exponent=function(o){return arguments.length?(u=Ki(t=o),i=Ki(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Gi(n.copy(),t,e)},Yi(r,n)}function Ki(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Qi(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return ta.range(n.length).map(function(n){return t+e*n})}var u,i,o;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new l;for(var i,o=-1,a=r.length;++oe?[0/0,0/0]:[e>0?a[e-1]:n[0],et?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return to(n,t,e)},u()}function eo(n,t){function e(e){return e>=e?t[ta.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return eo(n,t)},e}function ro(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Xi(n,t)},t.tickFormat=function(t,e){return $i(n,t,e)},t.copy=function(){return ro(n)},t}function uo(){return 0}function io(n){return n.innerRadius}function oo(n){return n.outerRadius}function ao(n){return n.startAngle}function co(n){return n.endAngle}function lo(n){return n&&n.padAngle}function so(n,t,e,r){return(n-e)*t-(t-r)*n>0?0:1}function fo(n,t,e,r,u){var i=n[0]-t[0],o=n[1]-t[1],a=(u?r:-r)/Math.sqrt(i*i+o*o),c=a*o,l=-a*i,s=n[0]+c,f=n[1]+l,h=t[0]+c,g=t[1]+l,p=(s+h)/2,v=(f+g)/2,d=h-s,m=g-f,y=d*d+m*m,M=e-r,x=s*g-h*f,b=(0>m?-1:1)*Math.sqrt(M*M*y-x*x),_=(x*m-d*b)/y,w=(-x*d-m*b)/y,S=(x*m+d*b)/y,k=(-x*d+m*b)/y,E=_-p,A=w-v,N=S-p,C=k-v;return E*E+A*A>N*N+C*C&&(_=S,w=k),[[_-c,w-l],[_*e/M,w*e/M]]}function ho(n){function t(t){function o(){l.push("M",i(n(s),a))}for(var c,l=[],s=[],f=-1,h=t.length,g=Et(e),p=Et(r);++f1&&u.push("H",r[0]),u.join("")}function mo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var l=2;l9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function To(n){return n.length<3?go(n):n[0]+_o(n,Lo(n))}function Ro(n){for(var t,e,r,u=-1,i=n.length;++ur)return s();var u=i[i.active];u&&(--i.count,delete i[i.active],u.event&&u.event.interrupt.call(n,n.__data__,u.index)),i.active=r,o.event&&o.event.start.call(n,n.__data__,t),o.tween.forEach(function(e,r){(r=r.call(n,n.__data__,t))&&v.push(r)}),h=o.ease,f=o.duration,ta.timer(function(){return p.c=l(e||1)?Ne:l,1},0,a)}function l(e){if(i.active!==r)return 1;for(var u=e/f,a=h(u),c=v.length;c>0;)v[--c].call(n,a);return u>=1?(o.event&&o.event.end.call(n,n.__data__,t),s()):void 0}function s(){return--i.count?delete i[r]:delete n[e],1}var f,h,g=o.delay,p=ec,v=[];return p.t=g+a,u>=g?c(u-g):void(p.c=c)},0,a)}}function Bo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function Wo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function Jo(n){return n.toISOString()}function Go(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=ta.bisect(Vl,u);return i==Vl.length?[t.year,Vi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Vl[i-1]1?{floor:function(t){for(;e(t=n.floor(t));)t=Ko(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Ko(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Pi(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Ko(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Go(n.copy(),t,e)},Yi(r,n)}function Ko(n){return new Date(n)}function Qo(n){return JSON.parse(n.responseText)}function na(n){var t=ua.createRange();return t.selectNode(ua.body),t.createContextualFragment(n.responseText)}var ta={version:"3.5.5"},ea=[].slice,ra=function(n){return ea.call(n)},ua=this.document;if(ua)try{ra(ua.documentElement.childNodes)[0].nodeType}catch(ia){ra=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}if(Date.now||(Date.now=function(){return+new Date}),ua)try{ua.createElement("DIV").style.setProperty("opacity",0,"")}catch(oa){var aa=this.Element.prototype,ca=aa.setAttribute,la=aa.setAttributeNS,sa=this.CSSStyleDeclaration.prototype,fa=sa.setProperty;aa.setAttribute=function(n,t){ca.call(this,n,t+"")},aa.setAttributeNS=function(n,t,e){la.call(this,n,t,e+"")},sa.setProperty=function(n,t,e){fa.call(this,n,t+"",e)}}ta.ascending=e,ta.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},ta.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u=r){e=r;break}for(;++ur&&(e=r)}else{for(;++u=r){e=r;break}for(;++ur&&(e=r)}return e},ta.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u=r){e=r;break}for(;++ue&&(e=r)}else{for(;++u=r){e=r;break}for(;++ue&&(e=r)}return e},ta.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i=r){e=u=r;break}for(;++ir&&(e=r),r>u&&(u=r))}else{for(;++i=r){e=u=r;break}for(;++ir&&(e=r),r>u&&(u=r))}return[e,u]},ta.sum=function(n,t){var e,r=0,i=n.length,o=-1;if(1===arguments.length)for(;++o1?c/(s-1):void 0},ta.deviation=function(){var n=ta.variance.apply(this,arguments);return n?Math.sqrt(n):n};var ha=i(e);ta.bisectLeft=ha.left,ta.bisect=ta.bisectRight=ha.right,ta.bisector=function(n){return i(1===n.length?function(t,r){return e(n(t),r)}:n)},ta.shuffle=function(n,t,e){(i=arguments.length)<3&&(e=n.length,2>i&&(t=0));for(var r,u,i=e-t;i;)u=Math.random()*i--|0,r=n[i+t],n[i+t]=n[u+t],n[u+t]=r;return n},ta.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},ta.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},ta.zip=function(){if(!(r=arguments.length))return[];for(var n=-1,t=ta.min(arguments,o),e=new Array(t);++n=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ga=Math.abs;ta.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),(t-n)/e===1/0)throw new Error("infinite range");var r,u=[],i=a(ga(e)),o=-1;if(n*=i,t*=i,e*=i,0>e)for(;(r=n+e*++o)>t;)u.push(r/i);else for(;(r=n+e*++o)=i.length)return r?r.call(u,o):e?o.sort(e):o;for(var c,s,f,h,g=-1,p=o.length,v=i[a++],d=new l;++g=i.length)return n;var r=[],u=o[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],o=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(ta.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return o[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},ta.set=function(n){var t=new m;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},c(m,{has:h,add:function(n){return this._[s(n+="")]=!0,n},remove:g,values:p,size:v,empty:d,forEach:function(n){for(var t in this._)n.call(this,f(t))}}),ta.behavior={},ta.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ta.event=null,ta.requote=function(n){return n.replace(ma,"\\$&")};var ma=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ya={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},Ma=function(n,t){return t.querySelector(n)},xa=function(n,t){return t.querySelectorAll(n)},ba=function(n,t){var e=n.matches||n[x(n,"matchesSelector")];return(ba=function(n,t){return e.call(n,t)})(n,t)};"function"==typeof Sizzle&&(Ma=function(n,t){return Sizzle(n,t)[0]||null},xa=Sizzle,ba=Sizzle.matchesSelector),ta.selection=function(){return ta.select(ua.documentElement)};var _a=ta.selection.prototype=[];_a.select=function(n){var t,e,r,u,i=[];n=N(n);for(var o=-1,a=this.length;++o=0&&(e=n.slice(0,t),n=n.slice(t+1)),wa.hasOwnProperty(e)?{space:wa[e],local:n}:n}},_a.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ta.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(z(t,n[t]));return this}return this.each(z(n,t))},_a.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=T(n)).length,u=-1;if(t=e.classList){for(;++uu){if("string"!=typeof n){2>u&&(e="");for(r in n)this.each(P(r,n[r],e));return this}if(2>u){var i=this.node();return t(i).getComputedStyle(i,null).getPropertyValue(n)}r=""}return this.each(P(n,e,r))},_a.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(U(t,n[t]));return this}return this.each(U(n,t))},_a.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},_a.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},_a.append=function(n){return n=j(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},_a.insert=function(n,t){return n=j(n),t=N(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},_a.remove=function(){return this.each(F)},_a.data=function(n,t){function e(n,e){var r,u,i,o=n.length,f=e.length,h=Math.min(o,f),g=new Array(f),p=new Array(f),v=new Array(o);if(t){var d,m=new l,y=new Array(o);for(r=-1;++rr;++r)p[r]=H(e[r]);for(;o>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,a.push(p),c.push(g),s.push(v)}var r,u,i=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++ii;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return A(u)},_a.order=function(){for(var n=-1,t=this.length;++n=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},_a.sort=function(n){n=I.apply(this,arguments);for(var t=-1,e=this.length;++tn;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},_a.size=function(){var n=0;return Y(this,function(){++n}),n};var Sa=[];ta.selection.enter=Z,ta.selection.enter.prototype=Sa,Sa.append=_a.append,Sa.empty=_a.empty,Sa.node=_a.node,Sa.call=_a.call,Sa.size=_a.size,Sa.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++ar){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(X(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(X(n,t,e))};var ka=ta.map({mouseenter:"mouseover",mouseleave:"mouseout"});ua&&ka.forEach(function(n){"on"+n in ua&&ka.remove(n)});var Ea,Aa=0;ta.mouse=function(n){return J(n,k())};var Na=this.navigator&&/WebKit/.test(this.navigator.userAgent)?-1:0;ta.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=k().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return J(n,r)},ta.behavior.drag=function(){function n(){this.on("mousedown.drag",i).on("touchstart.drag",o)}function e(n,t,e,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-M[0],e=r[1]-M[1],p|=n|e,M=r,g({type:"drag",x:r[0]+l[0],y:r[1]+l[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&ta.event.target===f),g({type:"dragend"}))}var l,s=this,f=ta.event.target,h=s.parentNode,g=r.of(s,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=ta.select(e(f)).on(i+d,a).on(o+d,c),y=W(f),M=t(h,v);u?(l=u.apply(s,arguments),l=[l.x-M[0],l.y-M[1]]):l=[0,0],g({type:"dragstart"})}}var r=E(n,"drag","dragstart","dragend"),u=null,i=e(b,ta.mouse,t,"mousemove","mouseup"),o=e(G,ta.touch,y,"touchmove","touchend");return n.origin=function(t){return arguments.length?(u=t,n):u},ta.rebind(n,r,"on")},ta.touches=function(n,t){return arguments.length<2&&(t=k().touches),t?ra(t).map(function(t){var e=J(n,t);return e.identifier=t.identifier,e}):[]};var Ca=1e-6,za=Ca*Ca,qa=Math.PI,La=2*qa,Ta=La-Ca,Ra=qa/2,Da=qa/180,Pa=180/qa,Ua=Math.SQRT2,ja=2,Fa=4;ta.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=rt(v),o=i/(ja*h)*(e*ut(Ua*t+v)-et(v));return[r+o*l,u+o*s,i*e/rt(Ua*t+v)]}return[r+n*l,u+n*s,i*Math.exp(Ua*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],l=o-r,s=a-u,f=l*l+s*s,h=Math.sqrt(f),g=(c*c-i*i+Fa*f)/(2*i*ja*h),p=(c*c-i*i-Fa*f)/(2*c*ja*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/Ua;return e.duration=1e3*y,e},ta.behavior.zoom=function(){function n(n){n.on(q,f).on(Oa+".zoom",g).on("dblclick.zoom",p).on(R,h)}function e(n){return[(n[0]-k.x)/k.k,(n[1]-k.y)/k.k]}function r(n){return[n[0]*k.k+k.x,n[1]*k.k+k.y]}function u(n){k.k=Math.max(N[0],Math.min(N[1],n))}function i(n,t){t=r(t),k.x+=n[0]-t[0],k.y+=n[1]-t[1]}function o(t,e,r,o){t.__chart__={x:k.x,y:k.y,k:k.k},u(Math.pow(2,o)),i(d=e,r),t=ta.select(t),C>0&&(t=t.transition().duration(C)),t.call(n.event)}function a(){b&&b.domain(x.range().map(function(n){return(n-k.x)/k.k}).map(x.invert)),w&&w.domain(_.range().map(function(n){return(n-k.y)/k.k}).map(_.invert))}function c(n){z++||n({type:"zoomstart"})}function l(n){a(),n({type:"zoom",scale:k.k,translate:[k.x,k.y]})}function s(n){--z||n({type:"zoomend"}),d=null}function f(){function n(){f=1,i(ta.mouse(u),g),l(a)}function r(){h.on(L,null).on(T,null),p(f&&ta.event.target===o),s(a)}var u=this,o=ta.event.target,a=D.of(u,arguments),f=0,h=ta.select(t(u)).on(L,n).on(T,r),g=e(ta.mouse(u)),p=W(u);Dl.call(u),c(a)}function h(){function n(){var n=ta.touches(p);return g=k.k,n.forEach(function(n){n.identifier in d&&(d[n.identifier]=e(n))}),n}function t(){var t=ta.event.target;ta.select(t).on(x,r).on(b,a),_.push(t);for(var e=ta.event.changedTouches,u=0,i=e.length;i>u;++u)d[e[u].identifier]=null;var c=n(),l=Date.now();if(1===c.length){if(500>l-M){var s=c[0];o(p,s,d[s.identifier],Math.floor(Math.log(k.k)/Math.LN2)+1),S()}M=l}else if(c.length>1){var s=c[0],f=c[1],h=s[0]-f[0],g=s[1]-f[1];m=h*h+g*g}}function r(){var n,t,e,r,o=ta.touches(p);Dl.call(p);for(var a=0,c=o.length;c>a;++a,r=null)if(e=o[a],r=d[e.identifier]){if(t)break;n=e,t=r}if(r){var s=(s=e[0]-n[0])*s+(s=e[1]-n[1])*s,f=m&&Math.sqrt(s/m);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+r[0])/2,(t[1]+r[1])/2],u(f*g)}M=null,i(n,t),l(v)}function a(){if(ta.event.touches.length){for(var t=ta.event.changedTouches,e=0,r=t.length;r>e;++e)delete d[t[e].identifier];for(var u in d)return void n()}ta.selectAll(_).on(y,null),w.on(q,f).on(R,h),E(),s(v)}var g,p=this,v=D.of(p,arguments),d={},m=0,y=".zoom-"+ta.event.changedTouches[0].identifier,x="touchmove"+y,b="touchend"+y,_=[],w=ta.select(p),E=W(p);t(),c(v),w.on(q,null).on(R,t)}function g(){var n=D.of(this,arguments);y?clearTimeout(y):(v=e(d=m||ta.mouse(this)),Dl.call(this),c(n)),y=setTimeout(function(){y=null,s(n)},50),S(),u(Math.pow(2,.002*Ha())*k.k),i(d,v),l(n)}function p(){var n=ta.mouse(this),t=Math.log(k.k)/Math.LN2;o(this,n,e(n),ta.event.shiftKey?Math.ceil(t)-1:Math.floor(t)+1)}var v,d,m,y,M,x,b,_,w,k={x:0,y:0,k:1},A=[960,500],N=Ia,C=250,z=0,q="mousedown.zoom",L="mousemove.zoom",T="mouseup.zoom",R="touchstart.zoom",D=E(n,"zoomstart","zoom","zoomend");return Oa||(Oa="onwheel"in ua?(Ha=function(){return-ta.event.deltaY*(ta.event.deltaMode?120:1)},"wheel"):"onmousewheel"in ua?(Ha=function(){return ta.event.wheelDelta},"mousewheel"):(Ha=function(){return-ta.event.detail},"MozMousePixelScroll")),n.event=function(n){n.each(function(){var n=D.of(this,arguments),t=k;Tl?ta.select(this).transition().each("start.zoom",function(){k=this.__chart__||{x:0,y:0,k:1},c(n)}).tween("zoom:zoom",function(){var e=A[0],r=A[1],u=d?d[0]:e/2,i=d?d[1]:r/2,o=ta.interpolateZoom([(u-k.x)/k.k,(i-k.y)/k.k,e/k.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),a=e/r[2];this.__chart__=k={x:u-r[0]*a,y:i-r[1]*a,k:a},l(n)}}).each("interrupt.zoom",function(){s(n)}).each("end.zoom",function(){s(n)}):(this.__chart__=k,c(n),l(n),s(n))})},n.translate=function(t){return arguments.length?(k={x:+t[0],y:+t[1],k:k.k},a(),n):[k.x,k.y]},n.scale=function(t){return arguments.length?(k={x:k.x,y:k.y,k:+t},a(),n):k.k},n.scaleExtent=function(t){return arguments.length?(N=null==t?Ia:[+t[0],+t[1]],n):N},n.center=function(t){return arguments.length?(m=t&&[+t[0],+t[1]],n):m},n.size=function(t){return arguments.length?(A=t&&[+t[0],+t[1]],n):A},n.duration=function(t){return arguments.length?(C=+t,n):C},n.x=function(t){return arguments.length?(b=t,x=t.copy(),k={x:0,y:0,k:1},n):b},n.y=function(t){return arguments.length?(w=t,_=t.copy(),k={x:0,y:0,k:1},n):w},ta.rebind(n,D,"on")};var Ha,Oa,Ia=[0,1/0];ta.color=ot,ot.prototype.toString=function(){return this.rgb()+""},ta.hsl=at;var Ya=at.prototype=new ot;Ya.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,this.l/n)},Ya.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new at(this.h,this.s,n*this.l)},Ya.rgb=function(){return ct(this.h,this.s,this.l)},ta.hcl=lt;var Za=lt.prototype=new ot;Za.brighter=function(n){return new lt(this.h,this.c,Math.min(100,this.l+Va*(arguments.length?n:1)))},Za.darker=function(n){return new lt(this.h,this.c,Math.max(0,this.l-Va*(arguments.length?n:1)))},Za.rgb=function(){return st(this.h,this.c,this.l).rgb()},ta.lab=ft;var Va=18,Xa=.95047,$a=1,Ba=1.08883,Wa=ft.prototype=new ot;Wa.brighter=function(n){return new ft(Math.min(100,this.l+Va*(arguments.length?n:1)),this.a,this.b)},Wa.darker=function(n){return new ft(Math.max(0,this.l-Va*(arguments.length?n:1)),this.a,this.b)},Wa.rgb=function(){return ht(this.l,this.a,this.b)},ta.rgb=mt;var Ja=mt.prototype=new ot;Ja.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new mt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new mt(u,u,u)},Ja.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new mt(n*this.r,n*this.g,n*this.b)},Ja.hsl=function(){return _t(this.r,this.g,this.b)},Ja.toString=function(){return"#"+xt(this.r)+xt(this.g)+xt(this.b)};var Ga=ta.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});Ga.forEach(function(n,t){Ga.set(n,yt(t))}),ta.functor=Et,ta.xhr=At(y),ta.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=Nt(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(s>=l)return o;if(u)return u=!1,i;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++s;){var r=n.charCodeAt(s++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(s)&&(++s,++a);else if(r!==c)continue;return n.slice(t,s-a)}return n.slice(t)}for(var r,u,i={},o={},a=[],l=n.length,s=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,f++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new m,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},ta.csv=ta.dsv(",","text/csv"),ta.tsv=ta.dsv(" ","text/tab-separated-values");var Ka,Qa,nc,tc,ec,rc=this[x(this,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ta.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Qa?Qa.n=i:Ka=i,Qa=i,nc||(tc=clearTimeout(tc),nc=1,rc(qt))},ta.timer.flush=function(){Lt(),Tt()},ta.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var uc=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Dt);ta.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=ta.round(n,Rt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),uc[8+e/3]};var ic=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,oc=ta.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ta.round(n,Rt(n,t))).toFixed(Math.max(0,Math.min(20,Rt(n*(1+1e-15),t))))}}),ac=ta.time={},cc=Date;jt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){lc.setUTCDate.apply(this._,arguments)},setDay:function(){lc.setUTCDay.apply(this._,arguments)},setFullYear:function(){lc.setUTCFullYear.apply(this._,arguments)},setHours:function(){lc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){lc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){lc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){lc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){lc.setUTCSeconds.apply(this._,arguments)},setTime:function(){lc.setTime.apply(this._,arguments)}};var lc=Date.prototype;ac.year=Ft(function(n){return n=ac.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ac.years=ac.year.range,ac.years.utc=ac.year.utc.range,ac.day=Ft(function(n){var t=new cc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ac.days=ac.day.range,ac.days.utc=ac.day.utc.range,ac.dayOfYear=function(n){var t=ac.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=ac[n]=Ft(function(n){return(n=ac.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ac[n+"s"]=e.range,ac[n+"s"].utc=e.utc.range,ac[n+"OfYear"]=function(n){var e=ac.year(n).getDay();return Math.floor((ac.dayOfYear(n)+(e+t)%7)/7)}}),ac.week=ac.sunday,ac.weeks=ac.sunday.range,ac.weeks.utc=ac.sunday.utc.range,ac.weekOfYear=ac.sundayOfYear;var sc={"-":"",_:" ",0:"0"},fc=/^\s*\d+/,hc=/^%/;ta.locale=function(n){return{numberFormat:Pt(n),timeFormat:Ot(n)}};var gc=ta.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});ta.format=gc.numberFormat,ta.geo={},ce.prototype={s:0,t:0,add:function(n){le(n,this.t,pc),le(pc.s,this.s,this),this.s?this.t+=pc.t:this.s=pc.t +},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var pc=new ce;ta.geo.stream=function(n,t){n&&vc.hasOwnProperty(n.type)?vc[n.type](n,t):se(n,t)};var vc={Feature:function(n,t){se(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++rn?4*qa+n:n,Mc.lineStart=Mc.lineEnd=Mc.point=b}};ta.geo.bounds=function(){function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=pe([t*Da,e*Da]);if(m){var u=de(m,r),i=[u[1],-u[0],0],o=de(i,u);Me(o),o=xe(o);var c=t-p,l=c>0?1:-1,v=o[0]*Pa*l,d=ga(c)>180;if(d^(v>l*p&&l*t>v)){var y=o[1]*Pa;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>l*p&&l*t>v)){var y=-o[1]*Pa;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t)}else n(t,e);m=r,p=t}function e(){b.point=t}function r(){x[0]=s,x[1]=h,b.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ga(r)>180?r+(r>0?360:-360):r}else v=n,d=e;Mc.point(n,e),t(n,e)}function i(){Mc.lineStart()}function o(){u(v,d),Mc.lineEnd(),ga(y)>Ca&&(s=-(h=180)),x[0]=s,x[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:nyc?(s=-(h=180),f=-(g=90)):y>Ca?g=90:-Ca>y&&(f=-90),x[0]=s,x[1]=h}};return function(n){g=h=-(s=f=1/0),M=[],ta.geo.stream(n,b);var t=M.length;if(t){M.sort(c);for(var e,r=1,u=M[0],i=[u];t>r;++r)e=M[r],l(e[0],u)||l(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,s=e[0],h=u[1])}return M=x=null,1/0===s||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[s,f],[h,g]]}}(),ta.geo.centroid=function(n){xc=bc=_c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,qc);var t=Nc,e=Cc,r=zc,u=t*t+e*e+r*r;return za>u&&(t=kc,e=Ec,r=Ac,Ca>bc&&(t=_c,e=wc,r=Sc),u=t*t+e*e+r*r,za>u)?[0/0,0/0]:[Math.atan2(e,t)*Pa,tt(r/Math.sqrt(u))*Pa]};var xc,bc,_c,wc,Sc,kc,Ec,Ac,Nc,Cc,zc,qc={sphere:b,point:_e,lineStart:Se,lineEnd:ke,polygonStart:function(){qc.lineStart=Ee},polygonEnd:function(){qc.lineStart=Se}},Lc=Le(Ne,Pe,je,[-qa,-qa/2]),Tc=1e9;ta.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Ie(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(ta.geo.conicEqualArea=function(){return Ye(Ze)}).raw=Ze,ta.geo.albers=function(){return ta.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ta.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=ta.geo.albers(),o=ta.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=ta.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var l=i.scale(),s=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[s-.455*l,f-.238*l],[s+.455*l,f+.238*l]]).stream(c).point,r=o.translate([s-.307*l,f+.201*l]).clipExtent([[s-.425*l+Ca,f+.12*l+Ca],[s-.214*l-Ca,f+.234*l-Ca]]).stream(c).point,u=a.translate([s-.205*l,f+.212*l]).clipExtent([[s-.214*l+Ca,f+.166*l+Ca],[s-.115*l-Ca,f+.234*l-Ca]]).stream(c).point,n},n.scale(1070)};var Rc,Dc,Pc,Uc,jc,Fc,Hc={point:b,lineStart:b,lineEnd:b,polygonStart:function(){Dc=0,Hc.lineStart=Ve},polygonEnd:function(){Hc.lineStart=Hc.lineEnd=Hc.point=b,Rc+=ga(Dc/2)}},Oc={point:Xe,lineStart:b,lineEnd:b,polygonStart:b,polygonEnd:b},Ic={point:We,lineStart:Je,lineEnd:Ge,polygonStart:function(){Ic.lineStart=Ke},polygonEnd:function(){Ic.point=We,Ic.lineStart=Je,Ic.lineEnd=Ge}};ta.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),ta.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Rc=0,ta.geo.stream(n,u(Hc)),Rc},n.centroid=function(n){return _c=wc=Sc=kc=Ec=Ac=Nc=Cc=zc=0,ta.geo.stream(n,u(Ic)),zc?[Nc/zc,Cc/zc]:Ac?[kc/Ac,Ec/Ac]:Sc?[_c/Sc,wc/Sc]:[0/0,0/0]},n.bounds=function(n){return jc=Fc=-(Pc=Uc=1/0),ta.geo.stream(n,u(Oc)),[[Pc,Uc],[jc,Fc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||tr(n):y,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new $e:new Qe(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(ta.geo.albersUsa()).context(null)},ta.geo.transform=function(n){return{stream:function(t){var e=new er(t);for(var r in n)e[r]=n[r];return e}}},er.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},ta.geo.projection=ur,ta.geo.projectionMutator=ir,(ta.geo.equirectangular=function(){return ur(ar)}).raw=ar.invert=ar,ta.geo.rotation=function(n){function t(t){return t=n(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t}return n=lr(n[0]%360*Da,n[1]*Da,n.length>2?n[2]*Da:0),t.invert=function(t){return t=n.invert(t[0]*Da,t[1]*Da),t[0]*=Pa,t[1]*=Pa,t},t},cr.invert=ar,ta.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=lr(-n[0]*Da,-n[1]*Da,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Pa,n[1]*=Pa}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=gr((t=+r)*Da,u*Da),n):t},n.precision=function(r){return arguments.length?(e=gr(t*Da,(u=+r)*Da),n):u},n.angle(90)},ta.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Da,u=n[1]*Da,i=t[1]*Da,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),l=Math.cos(u),s=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=l*s-c*f*a)*e),c*s+l*f*a)},ta.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ta.range(Math.ceil(i/d)*d,u,d).map(h).concat(ta.range(Math.ceil(l/m)*m,c,m).map(g)).concat(ta.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ga(n%d)>Ca}).map(s)).concat(ta.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ga(n%m)>Ca}).map(f))}var e,r,u,i,o,a,c,l,s,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],l=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[i,l],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,s=vr(a,o,90),f=dr(r,e,y),h=vr(l,c,90),g=dr(i,u,y),n):y},n.majorExtent([[-180,-90+Ca],[180,90-Ca]]).minorExtent([[-180,-80-Ca],[180,80+Ca]])},ta.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=mr,u=yr;return n.distance=function(){return ta.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},ta.geo.interpolate=function(n,t){return Mr(n[0]*Da,n[1]*Da,t[0]*Da,t[1]*Da)},ta.geo.length=function(n){return Yc=0,ta.geo.stream(n,Zc),Yc};var Yc,Zc={sphere:b,point:b,lineStart:xr,lineEnd:b,polygonStart:b,polygonEnd:b},Vc=br(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ta.geo.azimuthalEqualArea=function(){return ur(Vc)}).raw=Vc;var Xc=br(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},y);(ta.geo.azimuthalEquidistant=function(){return ur(Xc)}).raw=Xc,(ta.geo.conicConformal=function(){return Ye(_r)}).raw=_r,(ta.geo.conicEquidistant=function(){return Ye(wr)}).raw=wr;var $c=br(function(n){return 1/n},Math.atan);(ta.geo.gnomonic=function(){return ur($c)}).raw=$c,Sr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ra]},(ta.geo.mercator=function(){return kr(Sr)}).raw=Sr;var Bc=br(function(){return 1},Math.asin);(ta.geo.orthographic=function(){return ur(Bc)}).raw=Bc;var Wc=br(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ta.geo.stereographic=function(){return ur(Wc)}).raw=Wc,Er.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Ra]},(ta.geo.transverseMercator=function(){var n=kr(Er),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Er,ta.geom={},ta.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=Et(e),i=Et(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(zr),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var l=Cr(a),s=Cr(c),f=s[0]===l[0],h=s[s.length-1]===l[l.length-1],g=[];for(t=l.length-1;t>=0;--t)g.push(n[a[l[t]][2]]);for(t=+f;t=r&&l.x<=i&&l.y>=u&&l.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];s.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/Ca)*Ca,y:Math.round(o(n,t)/Ca)*Ca,i:t}})}var r=Ar,u=Nr,i=r,o=u,a=ul;return n?t(n):(t.links=function(n){return iu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return iu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Yr),c=-1,l=a.length,s=a[l-1].edge,f=s.l===o?s.r:s.l;++c=l,h=r>=s,g=h<<1|f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=su()),f?u=l:a=l,h?o=s:c=s,i(n,t,e,r,u,o,a,c)}var s,f,h,g,p,v,d,m,y,M=Et(a),x=Et(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)s=n[g],s.xm&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);v>b&&(v=b),d>_&&(d=_),b>m&&(m=b),_>y&&(y=_),f.push(b),h.push(_)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=su();if(k.add=function(n){i(k,n,+M(n,++g),+x(n,g),v,d,m,y)},k.visit=function(n){fu(n,k,v,d,m,y)},k.find=function(n){return hu(k,n[0],n[1],v,d,m,y)},g=-1,null==t){for(;++g=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=cl.get(e)||al,r=ll.get(r)||y,Mu(r(e.apply(null,ea.call(arguments,1))))},ta.interpolateHcl=Lu,ta.interpolateHsl=Tu,ta.interpolateLab=Ru,ta.interpolateRound=Du,ta.transform=function(n){var t=ua.createElementNS(ta.ns.prefix.svg,"g");return(ta.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Pu(e?e.matrix:sl)})(n)},Pu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var sl={a:1,b:0,c:0,d:1,e:0,f:0};ta.interpolateTransform=Hu,ta.layout={},ta.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++ea*a/d){if(p>c){var l=t.charge/c;n.px-=i*l,n.py-=o*l}return!0}if(t.point&&c&&p>c){var l=t.pointCharge/c;n.px-=i*l,n.py-=o*l}}return!t.charge}}function t(n){n.px=ta.event.x,n.py=ta.event.y,a.resume()}var e,r,u,i,o,a={},c=ta.dispatch("start","tick","end"),l=[1,1],s=.9,f=fl,h=hl,g=-30,p=gl,v=.1,d=.64,m=[],M=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,y,x,b=m.length,_=M.length;for(e=0;_>e;++e)a=M[e],f=a.source,h=a.target,y=h.x-f.x,x=h.y-f.y,(p=y*y+x*x)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,y*=p,x*=p,h.x-=y*(d=f.weight/(h.weight+f.weight)),h.y-=x*d,f.x+=y*(d=1-d),f.y+=x*d);if((d=r*v)&&(y=l[0]/2,x=l[1]/2,e=-1,d))for(;++e0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),ta.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=M[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,l=o.length;++at;++t)(r=m[t]).index=t,r.weight=0;for(t=0;s>t;++t)r=M[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;s>t;++t)u[t]=+f.call(this,M[t],t);else for(t=0;s>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;s>t;++t)i[t]=+h.call(this,M[t],t);else for(t=0;s>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=ta.behavior.drag().origin(y).on("dragstart.force",Xu).on("drag.force",t).on("dragend.force",$u)),arguments.length?void this.on("mouseover.force",Bu).on("mouseout.force",Wu).call(e):e},ta.rebind(a,c,"on")};var fl=20,hl=1,gl=1/0;ta.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(l=e.call(n,i,i.depth))&&(c=l.length)){for(var c,l,s;--c>=0;)o.push(s=l[c]),s.parent=i,s.depth=i.depth+1;r&&(i.value=0),i.children=l}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Qu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=ei,e=ni,r=ti;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(Ku(t,function(n){n.children&&(n.value=0)}),Qu(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},ta.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,l=-1;for(r=t.value?r/t.value:0;++lf?-1:1),p=(f-c*g)/ta.sum(l),v=ta.range(c),d=[];return null!=e&&v.sort(e===pl?function(n,t){return l[t]-l[n]}:function(n,t){return e(o[n],o[t])}),v.forEach(function(n){d[n]={data:o[n],value:a=l[n],startAngle:s,endAngle:s+=a*p+g,padAngle:h}}),d}var t=Number,e=pl,r=0,u=La,i=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n.padAngle=function(t){return arguments.length?(i=t,n):i},n};var pl={};ta.layout.stack=function(){function n(a,c){if(!(h=a.length))return a;var l=a.map(function(e,r){return t.call(n,e,r)}),s=l.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,s,c);l=ta.permute(l,f),s=ta.permute(s,f);var h,g,p,v,d=r.call(n,s,c),m=l[0].length;for(p=0;m>p;++p)for(u.call(n,l[0][p],v=d[p],s[0][p][1]),g=1;h>g;++g)u.call(n,l[g][p],v+=s[g-1][p][1],s[g][p][1]);return a}var t=y,e=ai,r=ci,u=oi,i=ui,o=ii;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:vl.get(t)||ai,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:dl.get(t)||ci,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var vl=ta.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(li),i=n.map(si),o=ta.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],l.push(e)):(c+=i[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return ta.range(n.length).reverse()},"default":ai}),dl=ta.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];s>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ci});ta.layout.histogram=function(){function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u.call(this,s,l,i),i=-1,h=l.length,g=f.length-1,p=t?1:1/h;++i0)for(i=-1;++i=s[0]&&a<=s[1]&&(o=c[ta.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=pi,u=hi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=Et(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return gi(n,t)}:Et(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ta.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Qu(a,function(n){n.r=+s(n.value)}),Qu(a,Mi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;Qu(a,function(n){n.r+=f}),Qu(a,Mi),Qu(a,function(n){n.r-=f})}return _i(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,e=ta.layout.hierarchy().sort(vi),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Gu(n,e)},ta.layout.tree=function(){function n(n,u){var s=o.call(this,n,u),f=s[0],h=t(f);if(Qu(h,e),h.parent.m=-h.z,Ku(h,r),l)Ku(f,i);else{var g=f,p=f,v=f;Ku(f,function(n){n.xp.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);Ku(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return s}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Ni(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],l=u.m,s=i.m,f=o.m,h=c.m;o=Ei(o),u=ki(u),o&&u;)c=ki(c),i=Ei(i),i.a=n,r=o.z+f-u.z-l+a(o._,u._),r>0&&(Ai(Ci(o,n,e),n,r),l+=r,s+=r),f+=o.m,l+=u.m,h+=c.m,s+=i.m;o&&!Ei(i)&&(i.t=o,i.m+=f-s),u&&!ki(c)&&(c.t=u,c.m+=l-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=ta.layout.hierarchy().sort(null).value(null),a=Si,c=[1,1],l=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(l=null==(c=t)?i:null,n):l?null:c},n.nodeSize=function(t){return arguments.length?(l=null==(c=t)?null:i,n):l?c:null},Gu(n,o)},ta.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Qu(c,function(n){var t=n.children;t&&t.length?(n.x=qi(t),n.y=zi(t)):(n.x=o?l+=e(n,o):0,n.y=0,o=n)});var s=Li(c),f=Ti(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Qu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=ta.layout.hierarchy().sort(null).value(null),e=Si,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Gu(n,t)},ta.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++ut?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i.slice(),p=1/0,v="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(o=h[c-1]),s.area+=o.area,"squarify"!==g||(a=r(s,v))<=p?(h.pop(),p=a):(s.area-=s.pop().area,u(s,v,l,!1),v=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,v,l,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++oe&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++ie.dx)&&(s=e.dx);++ie&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=ta.random.normal.apply(ta,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ta.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ta.scale={};var ml={floor:y,ceil:y};ta.scale.linear=function(){return Ii([0,1],[0,1],mu,!1)};var yl={s:1,g:1,p:1,r:1,e:1};ta.scale.log=function(){return Ji(ta.scale.linear().domain([0,1]),10,!0,[1,10])};var Ml=ta.format(".0e"),xl={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ta.scale.pow=function(){return Gi(ta.scale.linear(),1,[0,1])},ta.scale.sqrt=function(){return ta.scale.pow().exponent(.5)},ta.scale.ordinal=function(){return Qi([],{t:"range",a:[[]]})},ta.scale.category10=function(){return ta.scale.ordinal().range(bl)},ta.scale.category20=function(){return ta.scale.ordinal().range(_l)},ta.scale.category20b=function(){return ta.scale.ordinal().range(wl)},ta.scale.category20c=function(){return ta.scale.ordinal().range(Sl)};var bl=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(Mt),_l=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(Mt),wl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(Mt),Sl=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(Mt);ta.scale.quantile=function(){return no([],[])},ta.scale.quantize=function(){return to(0,1,[0,1])},ta.scale.threshold=function(){return eo([.5],[0,1])},ta.scale.identity=function(){return ro([0,1])},ta.svg={},ta.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),l=Math.max(0,+r.apply(this,arguments)),s=o.apply(this,arguments)-Ra,f=a.apply(this,arguments)-Ra,h=Math.abs(f-s),g=s>f?0:1;if(n>l&&(p=l,l=n,n=p),h>=Ta)return t(l,g)+(n?t(n,1-g):"")+"Z";var p,v,d,m,y,M,x,b,_,w,S,k,E=0,A=0,N=[];if((m=(+c.apply(this,arguments)||0)/2)&&(d=i===kl?Math.sqrt(n*n+l*l):+i.apply(this,arguments),g||(A*=-1),l&&(A=tt(d/l*Math.sin(m))),n&&(E=tt(d/n*Math.sin(m)))),l){y=l*Math.cos(s+A),M=l*Math.sin(s+A),x=l*Math.cos(f-A),b=l*Math.sin(f-A);var C=Math.abs(f-s-2*A)<=qa?0:1;if(A&&so(y,M,x,b)===g^C){var z=(s+f)/2;y=l*Math.cos(z),M=l*Math.sin(z),x=b=null}}else y=M=0;if(n){_=n*Math.cos(f-E),w=n*Math.sin(f-E),S=n*Math.cos(s+E),k=n*Math.sin(s+E);var q=Math.abs(s-f+2*E)<=qa?0:1;if(E&&so(_,w,S,k)===1-g^q){var L=(s+f)/2;_=n*Math.cos(L),w=n*Math.sin(L),S=k=null}}else _=w=0;if((p=Math.min(Math.abs(l-n)/2,+u.apply(this,arguments)))>.001){v=l>n^g?0:1;var T=null==S?[_,w]:null==x?[y,M]:Lr([y,M],[S,k],[x,b],[_,w]),R=y-T[0],D=M-T[1],P=x-T[0],U=b-T[1],j=1/Math.sin(Math.acos((R*P+D*U)/(Math.sqrt(R*R+D*D)*Math.sqrt(P*P+U*U)))/2),F=Math.sqrt(T[0]*T[0]+T[1]*T[1]);if(null!=x){var H=Math.min(p,(l-F)/(j+1)),O=fo(null==S?[_,w]:[S,k],[y,M],l,H,g),I=fo([x,b],[_,w],l,H,g);p===H?N.push("M",O[0],"A",H,",",H," 0 0,",v," ",O[1],"A",l,",",l," 0 ",1-g^so(O[1][0],O[1][1],I[1][0],I[1][1]),",",g," ",I[1],"A",H,",",H," 0 0,",v," ",I[0]):N.push("M",O[0],"A",H,",",H," 0 1,",v," ",I[0])}else N.push("M",y,",",M);if(null!=S){var Y=Math.min(p,(n-F)/(j-1)),Z=fo([y,M],[S,k],n,-Y,g),V=fo([_,w],null==x?[y,M]:[x,b],n,-Y,g);p===Y?N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",V[1],"A",n,",",n," 0 ",g^so(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-g," ",Z[1],"A",Y,",",Y," 0 0,",v," ",Z[0]):N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",Z[0])}else N.push("L",_,",",w)}else N.push("M",y,",",M),null!=x&&N.push("A",l,",",l," 0 ",C,",",g," ",x,",",b),N.push("L",_,",",w),null!=S&&N.push("A",n,",",n," 0 ",q,",",1-g," ",S,",",k);return N.push("Z"),N.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=io,r=oo,u=uo,i=kl,o=ao,a=co,c=lo;return n.innerRadius=function(t){return arguments.length?(e=Et(t),n):e},n.outerRadius=function(t){return arguments.length?(r=Et(t),n):r},n.cornerRadius=function(t){return arguments.length?(u=Et(t),n):u},n.padRadius=function(t){return arguments.length?(i=t==kl?kl:Et(t),n):i},n.startAngle=function(t){return arguments.length?(o=Et(t),n):o},n.endAngle=function(t){return arguments.length?(a=Et(t),n):a},n.padAngle=function(t){return arguments.length?(c=Et(t),n):c},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Ra;return[Math.cos(t)*n,Math.sin(t)*n]},n};var kl="auto";ta.svg.line=function(){return ho(y)};var El=ta.map({linear:go,"linear-closed":po,step:vo,"step-before":mo,"step-after":yo,basis:So,"basis-open":ko,"basis-closed":Eo,bundle:Ao,cardinal:bo,"cardinal-open":Mo,"cardinal-closed":xo,monotone:To});El.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Al=[0,2/3,1/3,0],Nl=[0,1/3,2/3,0],Cl=[0,1/6,2/3,1/6];ta.svg.line.radial=function(){var n=ho(Ro);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},mo.reverse=yo,yo.reverse=mo,ta.svg.area=function(){return Do(y)},ta.svg.area.radial=function(){var n=Do(Ro);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ta.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)-Ra,s=l.call(n,u,r)-Ra;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>qa)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=mr,o=yr,a=Po,c=ao,l=co;return n.radius=function(t){return arguments.length?(a=Et(t),n):a},n.source=function(t){return arguments.length?(i=Et(t),n):i},n.target=function(t){return arguments.length?(o=Et(t),n):o},n.startAngle=function(t){return arguments.length?(c=Et(t),n):c},n.endAngle=function(t){return arguments.length?(l=Et(t),n):l},n},ta.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=mr,e=yr,r=Uo;return n.source=function(e){return arguments.length?(t=Et(e),n):t},n.target=function(t){return arguments.length?(e=Et(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ta.svg.diagonal.radial=function(){var n=ta.svg.diagonal(),t=Uo,e=n.projection;return n.projection=function(n){return arguments.length?e(jo(t=n)):t},n},ta.svg.symbol=function(){function n(n,r){return(zl.get(t.call(this,n,r))||Oo)(e.call(this,n,r))}var t=Ho,e=Fo;return n.type=function(e){return arguments.length?(t=Et(e),n):t},n.size=function(t){return arguments.length?(e=Et(t),n):e},n};var zl=ta.map({circle:Oo,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Ll)),e=t*Ll;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ta.svg.symbolTypes=zl.keys();var ql=Math.sqrt(3),Ll=Math.tan(30*Da);_a.transition=function(n){for(var t,e,r=Tl||++Ul,u=Xo(n),i=[],o=Rl||{time:Date.now(),ease:Su,delay:0,duration:250},a=-1,c=this.length;++ai;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return Yo(u,this.namespace,this.id)},Pl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(u){u[r][e].tween.set(n,t)})},Pl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Hu:mu,a=ta.ns.qualify(n);return Zo(this,"attr."+n,t,a.local?i:u)},Pl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=ta.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Pl.style=function(n,e,r){function u(){this.style.removeProperty(n)}function i(e){return null==e?u:(e+="",function(){var u,i=t(this).getComputedStyle(this,null).getPropertyValue(n);return i!==e&&(u=mu(i,e),function(t){this.style.setProperty(n,u(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Zo(this,"style."+n,e,i)},Pl.styleTween=function(n,e,r){function u(u,i){var o=e.call(this,u,i,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,u)},Pl.text=function(n){return Zo(this,"text",n,Vo)},Pl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Pl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ta.ease.apply(ta,arguments)),Y(this,function(r){r[e][t].ease=n}))},Pl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,u,i){r[e][t].delay=+n.call(r,r.__data__,u,i)}:(n=+n,function(r){r[e][t].delay=n}))},Pl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,u,i){r[e][t].duration=Math.max(1,n.call(r,r.__data__,u,i))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Pl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var u=Rl,i=Tl;try{Tl=e,Y(this,function(t,u,i){Rl=t[r][e],n.call(t,t.__data__,u,i)})}finally{Rl=u,Tl=i}}else Y(this,function(u){var i=u[r][e];(i.event||(i.event=ta.dispatch("start","end","interrupt"))).on(n,t)});return this},Pl.transition=function(){for(var n,t,e,r,u=this.id,i=++Ul,o=this.namespace,a=[],c=0,l=this.length;l>c;c++){a.push(n=[]);for(var t=this[c],s=0,f=t.length;f>s;s++)(e=t[s])&&(r=e[o][u],$o(e,s,o,i,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Yo(a,o,i)},ta.svg.axis=function(){function n(n){n.each(function(){var n,l=ta.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):y:t,p=l.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Ca),d=ta.transition(p.exit()).style("opacity",Ca).remove(),m=ta.transition(p.order()).style("opacity",1),M=Math.max(u,0)+o,x=Ui(f),b=l.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ta.transition(b));v.append("line"),v.append("text");var w,S,k,E,A=v.select("line"),N=m.select("line"),C=p.select("text").text(g),z=v.select("text"),q=m.select("text"),L="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=Bo,w="x",k="y",S="x2",E="y2",C.attr("dy",0>L?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+L*i+"V0H"+x[1]+"V"+L*i)):(n=Wo,w="y",k="x",S="y2",E="x2",C.attr("dy",".32em").style("text-anchor",0>L?"end":"start"),_.attr("d","M"+L*i+","+x[0]+"H0V"+x[1]+"H"+L*i)),A.attr(E,L*u),z.attr(k,L*M),N.attr(S,0).attr(E,L*u),q.attr(w,0).attr(k,L*M),f.rangeBand){var T=f,R=T.rangeBand()/2;s=f=function(n){return T(n)+R}}else s.rangeBand?s=f:d.call(n,f,s);v.call(n,s,f),m.call(n,f,f)})}var t,e=ta.scale.linear(),r=jl,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Fl?t+"":jl,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var jl="bottom",Fl={top:1,right:1,bottom:1,left:1};ta.svg.brush=function(){function n(t){t.each(function(){var t=ta.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",i).on("touchstart.brush",i),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,y);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Hl[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var c,f=ta.transition(t),h=ta.transition(o);l&&(c=Ui(l),h.attr("x",c[0]).attr("width",c[1]-c[0]),r(f)),s&&(c=Ui(s),h.attr("y",c[0]).attr("height",c[1]-c[0]),u(f)),e(f)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+f[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",f[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function u(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function i(){function i(){32==ta.event.keyCode&&(C||(M=null,q[0]-=f[1],q[1]-=h[1],C=2),S())}function v(){32==ta.event.keyCode&&2==C&&(q[0]+=f[1],q[1]+=h[1],C=0,S())}function d(){var n=ta.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ta.event.altKey?(M||(M=[(f[0]+f[1])/2,(h[0]+h[1])/2]),q[0]=f[+(n[0]s?(u=r,r=s):u=s),v[0]!=r||v[1]!=u?(e?a=null:o=null,v[0]=r,v[1]=u,!0):void 0}function y(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ta.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ta.select(ta.event.target),w=c.of(b,arguments),k=ta.select(b),E=_.datum(),A=!/^(n|s)$/.test(E)&&l,N=!/^(e|w)$/.test(E)&&s,C=_.classed("extent"),z=W(b),q=ta.mouse(b),L=ta.select(t(b)).on("keydown.brush",i).on("keyup.brush",v);if(ta.event.changedTouches?L.on("touchmove.brush",d).on("touchend.brush",y):L.on("mousemove.brush",d).on("mouseup.brush",y),k.interrupt().selectAll("*").interrupt(),C)q[0]=f[0]-q[0],q[1]=h[0]-q[1];else if(E){var T=+/w$/.test(E),R=+/^n/.test(E);x=[f[1-T]-q[0],h[1-R]-q[1]],q[0]=f[T],q[1]=h[R]}else ta.event.altKey&&(M=q.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ta.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,c=E(n,"brushstart","brush","brushend"),l=null,s=null,f=[0,0],h=[0,0],g=!0,p=!0,v=Ol[0];return n.event=function(n){n.each(function(){var n=c.of(this,arguments),t={x:f,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Tl?ta.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,f=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=yu(f,t.x),r=yu(h,t.y);return o=a=null,function(u){f=t.x=e(u),h=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(l=t,v=Ol[!l<<1|!s],n):l},n.y=function(t){return arguments.length?(s=t,v=Ol[!l<<1|!s],n):s},n.clamp=function(t){return arguments.length?(l&&s?(g=!!t[0],p=!!t[1]):l?g=!!t:s&&(p=!!t),n):l&&s?[g,p]:l?g:s?p:null},n.extent=function(t){var e,r,u,i,c;return arguments.length?(l&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),o=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(c=e,e=r,r=c),(e!=f[0]||r!=f[1])&&(f=[e,r])),s&&(u=t[0],i=t[1],l&&(u=u[1],i=i[1]),a=[u,i],s.invert&&(u=s(u),i=s(i)),u>i&&(c=u,u=i,i=c),(u!=h[0]||i!=h[1])&&(h=[u,i])),n):(l&&(o?(e=o[0],r=o[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(c=e,e=r,r=c))),s&&(a?(u=a[0],i=a[1]):(u=h[0],i=h[1],s.invert&&(u=s.invert(u),i=s.invert(i)),u>i&&(c=u,u=i,i=c))),l&&s?[[e,u],[r,i]]:l?[e,r]:s&&[u,i])},n.clear=function(){return n.empty()||(f=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!l&&f[0]==f[1]||!!s&&h[0]==h[1]},ta.rebind(n,c,"on")};var Hl={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ol=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Il=ac.format=gc.timeFormat,Yl=Il.utc,Zl=Yl("%Y-%m-%dT%H:%M:%S.%LZ");Il.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Jo:Zl,Jo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Jo.toString=Zl.toString,ac.second=Ft(function(n){return new cc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ac.seconds=ac.second.range,ac.seconds.utc=ac.second.utc.range,ac.minute=Ft(function(n){return new cc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ac.minutes=ac.minute.range,ac.minutes.utc=ac.minute.utc.range,ac.hour=Ft(function(n){var t=n.getTimezoneOffset()/60;return new cc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ac.hours=ac.hour.range,ac.hours.utc=ac.hour.utc.range,ac.month=Ft(function(n){return n=ac.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ac.months=ac.month.range,ac.months.utc=ac.month.utc.range;var Vl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Xl=[[ac.second,1],[ac.second,5],[ac.second,15],[ac.second,30],[ac.minute,1],[ac.minute,5],[ac.minute,15],[ac.minute,30],[ac.hour,1],[ac.hour,3],[ac.hour,6],[ac.hour,12],[ac.day,1],[ac.day,2],[ac.week,1],[ac.month,1],[ac.month,3],[ac.year,1]],$l=Il.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",Ne]]),Bl={range:function(n,t,e){return ta.range(Math.ceil(n/e)*e,+t,e).map(Ko)},floor:y,ceil:y};Xl.year=ac.year,ac.scale=function(){return Go(ta.scale.linear(),Xl,$l)};var Wl=Xl.map(function(n){return[n[0].utc,n[1]]}),Jl=Yl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",Ne]]);Wl.year=ac.year.utc,ac.scale.utc=function(){return Go(ta.scale.linear(),Wl,Jl)},ta.text=At(function(n){return n.responseText}),ta.json=function(n,t){return Nt(n,"application/json",Qo,t)},ta.html=function(n,t){return Nt(n,"text/html",na,t)},ta.xml=At(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(ta):"object"==typeof module&&module.exports&&(module.exports=ta),this.d3=ta}(); \ No newline at end of file diff --git a/tree/lib/formula-parser.min.js b/tree/lib/formula-parser.min.js new file mode 100644 index 0000000..81a6766 --- /dev/null +++ b/tree/lib/formula-parser.min.js @@ -0,0 +1,2 @@ +/*! formula-parser v1.0.2 by Ross Kirsling (MIT license) */ +!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.FormulaParser=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g 0) { + if (data.children.length === 1) { + const child = this.fromD3(data.children[0], node); + node.left = child; + } else if (data.children.length === 2) { + const leftChild = this.fromD3(data.children[0], node); + const rightChild = this.fromD3(data.children[1], node); + node.left = leftChild; + node.right = rightChild; + } + } + return node; + } + + + + addLog(message, type = 'info') { + const timestamp = new Date().toISOString(); + this.logs.push({ timestamp, type, message }); + } + + getLeafs(node = this.root, leafs=null){ + if (leafs === null){ + leafs = [] + } + + if (node === null){ + return; + } + if (node.left === null && node.right === null){ + if (!leafs.some(leaf => leaf.id === node.id)) { + leafs.push(node); + } + }else{ + this.getLeafs(node.left, leafs) + if(node.right !== null){ + this.getLeafs(node.right, leafs) + } + } + return leafs; + } + + applyRule(data, logger = null){ + var node = data; + if (typeof data === "string"){ + node = this.getNodeFromId(data) + if (!this.isAvailable(node)){ + return null + } + } + logger.addLog(`Applying rule on node ID: ${node.id}, formula: ${node.value.unicode()}`); + this.removeAvailableNode(node) + const formula = node.value.json(); + if (formula.prop){ + console.log("No more rules applied here") + }else if(formula.conj){ + const formula1 = new MPL.Wff(MPL._jsonToASCII(formula.conj[0])) + const formula2 = new MPL.Wff(MPL._jsonToASCII(formula.conj[1])) + this.addSingleExtension(formula1, node) + this.addSingleExtension(formula2, node) + }else if(formula.impl){ + const formula1 = MPL.negateWff(formula.impl[0]) + const formula2 = new MPL.Wff(MPL._jsonToASCII(formula.impl[1])) + this.addDoubleExtension(formula1,formula2, node); + }else if(formula.disj){ + const formula1 = new MPL.Wff(MPL._jsonToASCII(formula.disj[0])) + const formula2 = new MPL.Wff(MPL._jsonToASCII(formula.disj[1])) + this.addDoubleExtension(formula1,formula2, node); + }else if(formula.kno_start){ + const formula1 = new MPL.Wff(MPL._jsonToASCII(formula)) + var term = new MPL.Wff(MPL._jsonToASCII(formula.kno_start.group_end[1])); + let n = this.addSingleExtension(term, node) + const leafs = this.getLeafs(node); + leafs.forEach(leaf => { + const branch = this.getBranchFromLeaf(leaf) + const exts = branch.getSimpleExtensions(node.label) + if (exts.length === 0){ + return + } + exts.forEach(newLabel =>{ + // RULE K + var newId = parseInt(leaf.id + '1'); + let newNode = leaf.addSingleChild(newId,term,newLabel); + // RULE 4 + var newnewId = parseInt(newNode.id + '1'); + let newnewNode = newNode.addSingleChild(newnewId,formula1, newLabel) + this.addAvailableNode(newNode) + this.addAvailableNode(newnewNode) + }) + }); + //REGLA T + } else if(formula.neg){ + if (formula.neg.kno_start){ + const agents = formula.neg.kno_start.group_end[0].prop.split(''); + var term = formula.neg.kno_start.group_end[1]; + const f1 = MPL.negateWff(term); + const leafs = this.getLeafs(node); + leafs.forEach(leaf => { + const branch = this.getBranchFromLeaf(leaf); + let labels = branch.getAllLabels().map(x=>x.simplify()) + var count = 1 + var newLabel = node.label.addExtension(agents,count.toString()) + var flag = (labels.includes(newLabel.simplify()) || branch.isSuplerflous(newLabel)) + while (flag){ + count += 1 + newLabel = node.label.addExtension(agents,count.toString()) + flag = branch.isSuplerflous(newLabel); + } + // RULE K + var newId = parseInt(leaf.id + '1'); + let newNode = leaf.addSingleChild(newId,f1, newLabel) + this.addAvailableNode(newNode); + this.updateNuGroup(); + }) + }else if(formula.neg.conj){ + const f1 = MPL.negateWff(formula.neg.conj[0]); + const f2 = MPL.negateWff(formula.neg.conj[1]); + this.addDoubleExtension(f1,f2, node); + }else if(formula.neg.disj){ + const f1 = MPL.negateWff(formula.neg.disj[0]); + const f2 = MPL.negateWff(formula.neg.disj[1]); + this.addSingleExtension(f1, node) + this.addSingleExtension(f2, node) + }else if(formula.neg.impl){ + const f1 = new MPL.Wff(MPL._jsonToASCII(formula.neg.impl[0])); + const f2 = MPL.negateWff(formula.neg.impl[1]); + this.addSingleExtension(f1, node) + this.addSingleExtension(f2, node) + }else if(formula.neg.neg){ + console.log("Doble negacion") + }else if(formula.neg.prop){ + console.log("No more rules applied here!") + } + } + let leafs = this.getLeafs(); + + const b = leafs[0]; + let leafsAva = leafs.filter((leaf) => this.isLeafAvailable(leaf)); + if (leafsAva.length === 0){ + this.alpha_group = [] + this.beta_group = [] + this.nu_group = [] + this.pi_group = [] + return this.getClosedLeafs(); + }else{ + return this.getClosedLeafs(); + } + } + + getClosedLeafs(){ + let closedLeafs = []; + let leafs = this.getLeafs(); + leafs.forEach(leaf =>{ + let branch = this.getBranchFromLeaf(leaf); + if (branch.isClosed()){ + closedLeafs.push(leaf); + } + }) + return closedLeafs; + } + + addSingleExtension(formula, node=this.root, label = node.label){ + const leafs = this.getLeafs(node); + leafs.forEach(node => { + var branch = this.getBranchFromLeaf(node) + var base = label.getBase(branch) + var flag = base.some(x=> x.unicode() === formula.unicode()) + if (branch.isClosed() | flag){ + return + } + var newId = parseInt(node.id + '1'); + const newNode = node.addSingleChild(newId, formula, label); + this.addAvailableNode(newNode); + }) + } + + addDoubleExtension(formula1, formula2, node=this.root,label=node.label){ + const leafs = this.getLeafs(node); + leafs.filter((leaf) => this.isLeafAvailable(leaf)) + leafs.forEach(node => { + var newId1 = parseInt(node.id + '1'); + var newId2 = parseInt(node.id + '2'); + let [newNode1, newNode2] = node.addTwoChildren(newId1, formula1, newId2, formula2, label); + this.addAvailableNode(newNode1) + this.addAvailableNode(newNode2) + }) + } + + + preOrderTraversal(node = this.root){ + if(node === null){ + return + } + console.log(node.value.unicode() + ", ") + this.preOrderTraversal(node.left); + this.preOrderTraversal(node.right); + } + + getBranchesFromNode(node){ + let branches = []; + if (node.left === null) { + return [this.getBranchFromLeaf(node)]; //devuelve un array con un unico elemento + } + let leafs = this.getLeafs(node); + leafs.forEach( x =>branches.push(this.getBranchFromLeaf(x))); + return branches + } + + getBranchFromLeaf(leafNode) { + // Verificar que el nodo sea una hoja + if (leafNode.left !== null) { + return null + } + + const branch = new Branch(); + let currentNode = leafNode; + + while (currentNode !== null) { + branch.addNode(currentNode); + currentNode = currentNode.parent; + } + branch.nodes.reverse(); + return branch; + } + + addAvailableNode(node){ + const type = node.typeOfRule() + switch (type){ + case "alpha": + this.alpha_group.push(node) + break; + case "beta": + this.beta_group.push(node) + break; + case "pi": + this.pi_group.push(node) + break; + case "nu": + this.nu_group.push(node) + break; + default: + return null; + } + } + + removeAvailableNode(node){ + const type = node.typeOfRule() + switch (type){ + case "alpha": + this.alpha_group = this.alpha_group.filter(item => item !== node) + break; + case "pi": + this.pi_group = this.pi_group.filter(item => item !== node) + break; + case "beta": + this.beta_group = this.beta_group.filter(item => item !== node) + break; + case "nu": + this.nu_group = this.nu_group.filter(item => item !== node) + break; + default: + return null + } + } + + toD3(node = this.root){ + if (!node) return null; + + const d3Node = { + name: node.value.toString(), + id: node.id.toString(), + value: node.value, + label: node.label, + children: [] + }; + if (node.left) { + d3Node.children.push(this.toD3(node.left)); + } + if (node.right) { + d3Node.children.push(this.toD3(node.right)); + } + if (d3Node.children.length === 0) { + delete d3Node.children; + } + return d3Node; + } + + //[FIX] Esta funcion podria hacerse desde el nodo que se actualiza y su rama en vez de iterar por todas. + updateNuGroup(node = this.root){ + if (!node) return; + if (node.typeOf() === 'kno'){ + const formula = node.value.json(); + const agents = formula.kno_start.group_end[0].prop.split(''); + var termascii = MPL._jsonToASCII(formula.kno_start.group_end[1]); + let branches = this.getBranchesFromNode(node); + let label = node.label; + branches.forEach(branch => { + let exts = branch.getSimpleExtensions(label); + if (exts.length === 0){ + this.nu_group = this.nu_group.filter(item => item !== node) + }else{ + exts.forEach(extLabel =>{ + let base = extLabel.getBase(branch); + let ascii = base.map((x) => x.ascii()) + const agentLabel = extLabel.value[extLabel.value.length - 2] + if (!ascii.includes(termascii) && agents.includes(agentLabel)){ + if (!this.nu_group.some(prevnode => prevnode.id === node.id)){ + this.nu_group.push(node); + } + }else{ + this.nu_group = this.nu_group.filter(item => item !== node) + } + }) + } + }) + } + this.updateNuGroup(node.left); + this.updateNuGroup(node.right); + } + + isAvailable(data){ + var node = data; + if (typeof data === "string"){ + node = this.getNodeFromId(data) + } + var inAlpha = this.alpha_group.some(x => x.id === node.id); + var inBeta = this.beta_group.some(x => x.id === node.id); + var inNu = this.nu_group.some(x => x.id === node.id); + var inPi = this.pi_group.some(x => x.id === node.id); + + return inAlpha || inBeta || inNu || inPi; + } + + runTableau(logger){ + while (this.alpha_group.length > 0 || this.beta_group.length > 0 || this.pi_group.length > 0 || this.nu_group.length >0 ){ + let leafs = this.getLeafs(); + let leafsAva = leafs.filter((leaf) => this.isLeafAvailable(leaf)); + if (leafsAva.length == 0){ + console.log("NO more leafs open") + break; + }else if(this.alpha_group.length > 0 ){ + this.alpha_group.forEach(node =>{ + // logger.addLog(`Applying rule on node ID: ${node.id}, formula: ${node.value.unicode()}`); + this.applyRule(node, logger); + }) + }else if(this.nu_group.length > 0 ){ + this.nu_group.forEach(node =>{ + // logger.addLog(`Applying rule on node ID: ${node.id}, formula: ${node.value.unicode()}`); + this.applyRule(node, logger); + }) + }else if(this.beta_group.length > 0 ){ + this.beta_group.forEach(node =>{ + // logger.addLog(`Applying rule on node ID: ${node.id}, formula: ${node.value.unicode()}`); + this.applyRule(node, logger); + }) + }else if(this.pi_group.length > 0 ){ + this.pi_group.forEach(node =>{ + // logger.addLog(`Applying rule on node ID: ${node.id}, formula: ${node.value.unicode()}`); + this.applyRule(node, logger); + }) + } + } + logger.addLog(`Tableau ended`); + console.log(this.isEnded()); + return logger; + } + + isEnded(){ + const leafs = this.getLeafs(); + return leafs.every(x => !this.isLeafAvailable(x)) + } + + isClosed(){ + const leafs = this.getLeafs(); + return leafs.some(leaf =>{ + const branch = this.getBranchFromLeaf(leaf); + return branch.isClosed() + }) + } + + isLeafAvailable(leaf){ + const branch = this.getBranchFromLeaf(leaf) + return !branch.isClosed(); + } + + getNodeFromLeafId(id){ + const searchId = Number(id); + const leafs = this.getLeafs(); + return leafs.filter(d => Number(d.id) === searchId)[0]; + } + + getNodeFromId(id, node=this.root) { + if (node === null) return null; + if (node.id === Number(id)) { + return node; + } + const leftResult = this.getNodeFromId(id, node.left); + if (leftResult) return leftResult; + + // Search right subtree + return this.getNodeFromId(id, node.right); + } + +} + +class Label { + constructor(labelStr){ + this.value = this._parseLabel(labelStr); // Almacena el string directamente + } + + _parseLabel(labelStr){ + return labelStr.split('') + } + + addExtension(agent, number){ + const newArray = [...this.value, agent, number]; + return new Label(newArray.join("")); + } + + toString(){ + return this.value.join("") + } + + equal(label2){ + return this.toString() === label2.toString() + } + + getBase(branch){ + let baseFormulas = []; + branch.nodes.forEach(node => { + if (this.equal(node.label)){ + baseFormulas.push(node.value) + } + + }) + return baseFormulas; + } + + // 1a2b3a4 >> "1234" + simplify(){ + const simplified = this.value.filter(elemento => !isNaN(Number(elemento))); + return simplified.join("") + } + + lenght(){ + return this.value.lenght; + } + + + isSublabel(label){ + let l1 = this + let l2 = label + let l1simp = l1.simplify() + let l2simp = l2.simplify() + if (label.simplify().length <=this.simplify().length){ + return false + }else{ + let sub = l2simp.substring(0,l1simp.length); + return sub === l1simp; + } + } + + + isSimpleExtension(label){ + let l1 = label + let l2 = this + let l1simp = l1.simplify() + let l2simp = l2.simplify() + return l1simp.length+1 === l2simp.length && l1.isSublabel(l2); + } +} + +class Branch { + constructor() { + this.nodes = []; + } + + getLeaf(){ + return this.nodes.reduce((max, currentNode) => { + return (currentNode.id > max.id) ? currentNode : max; + }); + } + + addNode(node) { + this.nodes.push(node); + } + + isClosed(){ + return this.nodes.some((a, i) => + this.nodes.slice(i + 1).some(b => { + const aLabel = a.label.simplify(); + const bLabel = b.label.simplify(); + const aType = a.typeOf(); + const bType = b.typeOf(); + if ( aLabel === bLabel && + (aType === 'prop' || aType === 'neg_prop') && + (bType === 'prop' || bType === 'neg_prop')) { + var neg = MPL.negateWff(b.value.json()).ascii(); + var current = a.value.ascii(); + return (neg === current); + } + return false + }) + ); + } + + getAllLabels(){ + let labels = [] + this.nodes.forEach(x=> labels.push(x.label)); + labels = labels.filter((value, index, array) => //remove duplicates + array.indexOf(value) === index + ) + return labels + } + + isSuplerflous(label){ + const labelSet = this.getAllLabels() + var currentBase = label.getBase(this) + labelSet.some(labelPrima =>{ + let basePrima = labelPrima.getBase(this); + return currentBase.every(element => basePrima.includes(element)) + }) + } + + getSimpleExtensions(label){ + const labelSet = this.getAllLabels(); + const filtered = labelSet.filter((x) => x.isSimpleExtension(label)) + return filtered; + } + + getSimpleExtensionsAgent(label, agent){ + const labelSet = this.getAllLabels(); + const filtered = labelSet.filter((x) => x.isSimpleExtension(label)) + return filtered; + } + + +} + + +class Logger { + constructor() { + this.logs = []; + } + + addLog(message, type = 'info') { + const timestamp = new Date().toISOString(); + this.logs.push({ timestamp, type, message }); + } + + getLogs() { + return this.logs; + } + + clearLogs() { + this.logs = []; + } +} + +function toD3(node){ + if (!node) return null; + + const d3Node = { + name: node.value.toString(), + id: node.id.toString(), + value: node.value, + label: node.label, + children: [] + }; + if (node.left) { + d3Node.children.push(toD3(node.left)); + } + if (node.right) { + d3Node.children.push(toD3(node.right)); + } + if (d3Node.children.length === 0) { + delete d3Node.children; + } + return d3Node; +} + + +window.Node = Node; +window.Tableau = Tableau; +window.Branch = Branch; +window.Label = Label; +window.Logger = Logger; +window.toD3 = toD3; + + diff --git a/tree/style.css b/tree/style.css new file mode 100644 index 0000000..f2bc1ab --- /dev/null +++ b/tree/style.css @@ -0,0 +1,131 @@ +svg{ + /*background:gray;*/ + display: block; + margin: auto; +} + + +.node { + pointer +} +/* Nodes */ +.clickable { + fill: #fff; + stroke: steelblue; + stroke-width: 3px; +} + +.non-cickable { + fill: #fff; + stroke: gray; + stroke-width: 3px; +} + +.node text{ + font: 12px sans-serif; + background-color: #fff; +} + + +/* Links */ +.link{ + fill: none; + stroke: #ccc; + stroke-width: 2px; +} + + +.close-leaf{ + fill: Red; +} + +.open-leaf{ + fill: Green; +} + +#app-body { + border: 2px solid #ddd; + border-radius: 4px; + margin:100px; + display:flex; + /* align-content:stretch; */ +} + +#tab-content{ + width:15%; + padding: 10px; + background-color:#ddd +} + +.eval-input{ + margin-bottom: 15px; +} + +.eval-input input { + width: 100%; + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; + font-size: 12px; + border: 1px solid #ddd; + padding: 10px; + margin-bottom: 10px; +} + +#tree-container{ + width:85%; + height:100%; +} + +.selectedNode circle{ + fill:gray; +} + +#log-container { + font-family: monospace; + max-height: 1000px; + overflow-y: auto; + border: 1px solid #ccc; + padding: 10px; + background: #f9f9f9; + font-size:9px; +} + +.log-entry { + margin-bottom: 5px; + padding: 3px; +} + +.log-info { + color: #2e86c1; +} + +.log-error { + color: #c0392b; + font-weight: bold; +} + +.timestamp { + color: #7f8c8d; + margin-right: 10px; + +} + + +.node.clickable circle { + fill: #4CAF50; /* verde */ + cursor: pointer; + stroke: #2e7d32; + stroke-width: 2px; + transition: fill 0.2s; +} + +.node.clickable:hover circle { + fill: #66bb6a; +} + +.node.disabled circle { + fill: #ccc; /* gris */ + stroke: #999; + stroke-width: 1px; + cursor: not-allowed; + opacity: 0.6; +} From 17c3c204d77e7cd51771e0e1ed9de0bd8587801a Mon Sep 17 00:00:00 2001 From: karu Date: Wed, 4 Feb 2026 13:22:24 +0100 Subject: [PATCH 43/68] Implementing simple tab + tree style --- css/app.css | 48 +++ index.html | 14 +- js/MPL.js | 27 +- js/app.js | 7 +- js/tree.js | 926 +++++++++++++++++++++++++++++++++++++++++++++++++++- js/utils.js | 3 + tree/d3.js | 12 +- 7 files changed, 1017 insertions(+), 20 deletions(-) diff --git a/css/app.css b/css/app.css index 62ec41c..21f6072 100644 --- a/css/app.css +++ b/css/app.css @@ -435,3 +435,51 @@ footer { .atom-button, .monadic-button, .modal-button {} .diadic-button, .agent-button {display:none} + + + +/*-------------------------------------------------------*/ +svg.tree-graph { + background: #f9f9f9; /* fondo suave */ + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +/* Nodos */ +svg.tree-graph circle { + fill: #4a90e2; /* azul elegante */ + stroke: #ffffff; /* borde blanco */ + stroke-width: 2px; + transition: fill 0.3s; +} + +/* Nodos clicables (reglas aplicables) */ +svg.tree-graph circle.clickable { + fill: #50e3c2; /* verde suave para destacar */ + cursor: pointer; +} + +/* Líneas que conectan nodos */ +svg.tree-graph path.link { + stroke: #999; /* gris claro */ + stroke-width: 2px; + fill: none; +} + +/* Texto de los nodos */ +svg.tree-graph text { + fill: #333; /* gris oscuro legible */ + font-size: 14px; + font-weight: 500; +} + +/* Hover en nodos */ +svg.tree-graph g.node:hover circle { + fill: #f5a623; /* naranja suave al pasar el mouse */ + stroke-width: 3px; +} + +svg.tree-graph g.node:hover text { + fill: #000; /* texto más visible al hover */ + font-weight: 600; +} + diff --git a/index.html b/index.html index b033d4a..184bd0b 100644 --- a/index.html +++ b/index.html @@ -8,8 +8,8 @@ - + +
@@ -196,7 +196,7 @@

placeholder="(p -> K{a}p)" style="width: 180px;">

@@ -223,7 +223,7 @@

Transitive

-
+
@@ -688,12 +688,12 @@

- - + diff --git a/js/MPL.js b/js/MPL.js index 13764ca..9861f2f 100644 --- a/js/MPL.js +++ b/js/MPL.js @@ -45,8 +45,25 @@ var MPL = (function (FormulaParser) { function _asciiToJSON(ascii) { return MPLParser.parse(ascii); } - + // MIA + function negateWff(json){ + var simply = simplifyWff(json) + var ascii = _jsonToASCII(simply) + var f = '~('+ascii+')' + var result = _jsonToASCII(simplifyWff(new Wff(f).json())) + return new Wff(result) + } + + // MIA + function simplifyWff(json){ + if (json.neg){ + if(json.neg.neg){ + return json.neg.neg + } + } + return json + } /** * Converts an MPL wff from JSON to ASCII. * @private @@ -730,7 +747,13 @@ var MPL = (function (FormulaParser) { Wff: Wff, Model: Model, truth: truth, - subformulas: subformulas + subformulas: subformulas, + negateWff: negateWff, + simplifyWff: simplifyWff, + _jsonToASCII: _jsonToASCII, + _asciiToJSON: _asciiToJSON, + _asciiToUnicode: _asciiToUnicode, + _asciiToLaTeX: _asciiToLaTeX }; })(FormulaParser); diff --git a/js/app.js b/js/app.js index c61757e..4b13a6a 100644 --- a/js/app.js +++ b/js/app.js @@ -1233,10 +1233,11 @@ function setAppMode(newMode) { circle.classed('waiting', true); evalOutput.classed('inactive', true); if (newMode === MODE.TREE){ - d3.select('#app-body .graph').style('display', 'none'); + d3.select("#graph-container").select("svg").remove(); + // d3.select('#app-body .graph').style('display', 'none'); d3.select('#info-box').style('display', 'none'); - currentFormula.classed('inactive', true); - currentSubformula.classed('inactive', true); + // currentFormula.classed('inactive', true); + // currentSubformula.classed('inactive', true); } } else return; diff --git a/js/tree.js b/js/tree.js index eaf9cfb..a5a1aee 100644 --- a/js/tree.js +++ b/js/tree.js @@ -1,3 +1,925 @@ -function runTableau(){ - console.log("HOLA") +import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm"; + +// const MPL = require('MPL.js'); // [TEST] +class Logger { + constructor() { + this.logs = []; + } + + addLog(message, type = 'info') { + const timestamp = new Date().toISOString(); + this.logs.push({ timestamp, type, message }); + } + + getLogs() { + return this.logs; + } + + clearLogs() { + this.logs = []; + } } + + +class Node { + constructor(id,value, label, parent = null) { + this.id = id; + this.parent = parent; + this.right = null; + this.left = null; + this.value = value; + this.label = label; + } + + isRoot(){ + return this.parent === null; + } + + + //formula = MLP formula + addSingleChild(id, formula, label = this.label){ + if (this.left === null){ + let node = new Node(id, formula, label, this) + this.left = node + return node; + }else{ + this.left.addSingleChild(id, formula, label) + } + } + + addTwoChildren(id1, formula1, id2, formula2, label=this.label){ + const node1 = new Node(id1, formula1, label, this); + const node2 = new Node(id2, formula2, label, this); + this.left = node1 + this.right = node2 + return [node1, node2] + } + + typeOf(){ + const formula = this.value.json(); + if (formula.prop){ + return "prop" + }else if(formula.conj){ + return "conj" + }else if(formula.impl){ + return "impl" + }else if(formula.disj){ + return "disj" + }else if(formula.kno_start){ + return "kno" + } else if(formula.neg){ + if (formula.neg.impl){ + return "neg_impl" + } else if (formula.neg.kno_start){ + return "neg_kno" + }else if(formula.neg.conj){ + return "neg_conj" + }else if(formula.neg.disj){ + return "neg_disj" + }else if(formula.neg.neg){ + return "neg_neg" + }else if(formula.neg.prop){ + return "neg_prop" + } + }else{ + return null + } + } + + typeOfRule(){ + const type = this.typeOf() + switch (type) { + case "prop": + return "prop" + case "conj": + case "neg_impl": + case "neg_disj": + return "alpha" + case "impl": + case "disj": + case "neg_conj": + return "beta" + case "neg_kno": + return "pi" + case "kno": + return "nu" + } + } +} + + +class Tableau { + constructor(data) { + if (typeof data === 'string') { + // Si formula es un string, usamos MPL.Wff + var formula = new MPL.Wff(data) + this.root = new Node(1, formula, new Label('1')); + } else { + // Si formula no es un string, directamente la pasamos o la procesamos como corresponda + this.root = this.fromD3(data) + } + this.alpha_group = [] + this.beta_group = [] + this.nu_group = [] + this.nu_disable = [] + this.pi_group = [] + this.logs = []; + this.addAvailableNode(this.root) + } + + fromD3(data, parentNode = null) { + const node = new Node( + data.id, + new MPL.Wff(data.value.json()), + data.label, + parentNode + ); + if (data.children && data.children.length > 0) { + if (data.children.length === 1) { + const child = this.fromD3(data.children[0], node); + node.left = child; + } else if (data.children.length === 2) { + const leftChild = this.fromD3(data.children[0], node); + const rightChild = this.fromD3(data.children[1], node); + node.left = leftChild; + node.right = rightChild; + } + } + return node; + } + + + + addLog(message, type = 'info') { + const timestamp = new Date().toISOString(); + this.logs.push({ timestamp, type, message }); + } + + getLeafs(node = this.root, leafs=null){ + if (leafs === null){ + leafs = [] + } + + if (node === null){ + return; + } + if (node.left === null && node.right === null){ + if (!leafs.some(leaf => leaf.id === node.id)) { + leafs.push(node); + } + }else{ + this.getLeafs(node.left, leafs) + if(node.right !== null){ + this.getLeafs(node.right, leafs) + } + } + return leafs; + } + + applyRule(data, logger = null){ + var node = data; + if (typeof data === "string"){ + node = this.getNodeFromId(data) + if (!this.isAvailable(node)){ + return null + } + } + logger.addLog(`Applying rule on node ID: ${node.id}, formula: ${node.value.unicode()}`); + this.removeAvailableNode(node) + const formula = node.value.json(); + if (formula.prop){ + console.log("No more rules applied here") + }else if(formula.conj){ + const formula1 = new MPL.Wff(MPL._jsonToASCII(formula.conj[0])) + const formula2 = new MPL.Wff(MPL._jsonToASCII(formula.conj[1])) + this.addSingleExtension(formula1, node) + this.addSingleExtension(formula2, node) + }else if(formula.impl){ + const formula1 = MPL.negateWff(formula.impl[0]) + const formula2 = new MPL.Wff(MPL._jsonToASCII(formula.impl[1])) + this.addDoubleExtension(formula1,formula2, node); + }else if(formula.disj){ + const formula1 = new MPL.Wff(MPL._jsonToASCII(formula.disj[0])) + const formula2 = new MPL.Wff(MPL._jsonToASCII(formula.disj[1])) + this.addDoubleExtension(formula1,formula2, node); + }else if(formula.kno_start){ + const formula1 = new MPL.Wff(MPL._jsonToASCII(formula)) + var term = new MPL.Wff(MPL._jsonToASCII(formula.kno_start.group_end[1])); + let n = this.addSingleExtension(term, node) + const leafs = this.getLeafs(node); + leafs.forEach(leaf => { + const branch = this.getBranchFromLeaf(leaf) + const exts = branch.getSimpleExtensions(node.label) + if (exts.length === 0){ + return + } + exts.forEach(newLabel =>{ + // RULE K + var newId = parseInt(leaf.id + '1'); + let newNode = leaf.addSingleChild(newId,term,newLabel); + // RULE 4 + var newnewId = parseInt(newNode.id + '1'); + let newnewNode = newNode.addSingleChild(newnewId,formula1, newLabel) + this.addAvailableNode(newNode) + this.addAvailableNode(newnewNode) + }) + }); + //REGLA T + } else if(formula.neg){ + if (formula.neg.kno_start){ + const agents = formula.neg.kno_start.group_end[0].prop.split(''); + var term = formula.neg.kno_start.group_end[1]; + const f1 = MPL.negateWff(term); + const leafs = this.getLeafs(node); + leafs.forEach(leaf => { + const branch = this.getBranchFromLeaf(leaf); + let labels = branch.getAllLabels().map(x=>x.simplify()) + var count = 1 + var newLabel = node.label.addExtension(agents,count.toString()) + var flag = (labels.includes(newLabel.simplify()) || branch.isSuplerflous(newLabel)) + while (flag){ + count += 1 + newLabel = node.label.addExtension(agents,count.toString()) + flag = branch.isSuplerflous(newLabel); + } + // RULE K + var newId = parseInt(leaf.id + '1'); + let newNode = leaf.addSingleChild(newId,f1, newLabel) + this.addAvailableNode(newNode); + this.updateNuGroup(); + }) + }else if(formula.neg.conj){ + const f1 = MPL.negateWff(formula.neg.conj[0]); + const f2 = MPL.negateWff(formula.neg.conj[1]); + this.addDoubleExtension(f1,f2, node); + }else if(formula.neg.disj){ + const f1 = MPL.negateWff(formula.neg.disj[0]); + const f2 = MPL.negateWff(formula.neg.disj[1]); + this.addSingleExtension(f1, node) + this.addSingleExtension(f2, node) + }else if(formula.neg.impl){ + const f1 = new MPL.Wff(MPL._jsonToASCII(formula.neg.impl[0])); + const f2 = MPL.negateWff(formula.neg.impl[1]); + this.addSingleExtension(f1, node) + this.addSingleExtension(f2, node) + }else if(formula.neg.neg){ + console.log("Doble negacion") + }else if(formula.neg.prop){ + console.log("No more rules applied here!") + } + } + let leafs = this.getLeafs(); + + const b = leafs[0]; + let leafsAva = leafs.filter((leaf) => this.isLeafAvailable(leaf)); + if (leafsAva.length === 0){ + this.alpha_group = [] + this.beta_group = [] + this.nu_group = [] + this.pi_group = [] + return this.getClosedLeafs(); + }else{ + return this.getClosedLeafs(); + } + } + + getClosedLeafs(){ + let closedLeafs = []; + let leafs = this.getLeafs(); + leafs.forEach(leaf =>{ + let branch = this.getBranchFromLeaf(leaf); + if (branch.isClosed()){ + closedLeafs.push(leaf); + } + }) + return closedLeafs; + } + + addSingleExtension(formula, node=this.root, label = node.label){ + const leafs = this.getLeafs(node); + leafs.forEach(node => { + var branch = this.getBranchFromLeaf(node) + var base = label.getBase(branch) + var flag = base.some(x=> x.unicode() === formula.unicode()) + if (branch.isClosed() | flag){ + return + } + var newId = parseInt(node.id + '1'); + const newNode = node.addSingleChild(newId, formula, label); + this.addAvailableNode(newNode); + }) + } + + addDoubleExtension(formula1, formula2, node=this.root,label=node.label){ + const leafs = this.getLeafs(node); + leafs.filter((leaf) => this.isLeafAvailable(leaf)) + leafs.forEach(node => { + var newId1 = parseInt(node.id + '1'); + var newId2 = parseInt(node.id + '2'); + let [newNode1, newNode2] = node.addTwoChildren(newId1, formula1, newId2, formula2, label); + this.addAvailableNode(newNode1) + this.addAvailableNode(newNode2) + }) + } + + + preOrderTraversal(node = this.root){ + if(node === null){ + return + } + console.log(node.value.unicode() + ", ") + this.preOrderTraversal(node.left); + this.preOrderTraversal(node.right); + } + + getBranchesFromNode(node){ + let branches = []; + if (node.left === null) { + return [this.getBranchFromLeaf(node)]; //devuelve un array con un unico elemento + } + let leafs = this.getLeafs(node); + leafs.forEach( x =>branches.push(this.getBranchFromLeaf(x))); + return branches + } + + getBranchFromLeaf(leafNode) { + // Verificar que el nodo sea una hoja + if (leafNode.left !== null) { + return null + } + + const branch = new Branch(); + let currentNode = leafNode; + + while (currentNode !== null) { + branch.addNode(currentNode); + currentNode = currentNode.parent; + } + branch.nodes.reverse(); + return branch; + } + + addAvailableNode(node){ + const type = node.typeOfRule() + switch (type){ + case "alpha": + this.alpha_group.push(node) + break; + case "beta": + this.beta_group.push(node) + break; + case "pi": + this.pi_group.push(node) + break; + case "nu": + this.nu_group.push(node) + break; + default: + return null; + } + } + + removeAvailableNode(node){ + const type = node.typeOfRule() + switch (type){ + case "alpha": + this.alpha_group = this.alpha_group.filter(item => item !== node) + break; + case "pi": + this.pi_group = this.pi_group.filter(item => item !== node) + break; + case "beta": + this.beta_group = this.beta_group.filter(item => item !== node) + break; + case "nu": + this.nu_group = this.nu_group.filter(item => item !== node) + break; + default: + return null + } + } + + toD3(node = this.root){ + if (!node) return null; + + const d3Node = { + name: node.value.toString(), + id: node.id.toString(), + value: node.value, + label: node.label, + children: [] + }; + if (node.left) { + d3Node.children.push(this.toD3(node.left)); + } + if (node.right) { + d3Node.children.push(this.toD3(node.right)); + } + if (d3Node.children.length === 0) { + delete d3Node.children; + } + return d3Node; + } + + //[FIX] Esta funcion podria hacerse desde el nodo que se actualiza y su rama en vez de iterar por todas. + updateNuGroup(node = this.root){ + if (!node) return; + if (node.typeOf() === 'kno'){ + const formula = node.value.json(); + const agents = formula.kno_start.group_end[0].prop.split(''); + var termascii = MPL._jsonToASCII(formula.kno_start.group_end[1]); + let branches = this.getBranchesFromNode(node); + let label = node.label; + branches.forEach(branch => { + let exts = branch.getSimpleExtensions(label); + if (exts.length === 0){ + this.nu_group = this.nu_group.filter(item => item !== node) + }else{ + exts.forEach(extLabel =>{ + let base = extLabel.getBase(branch); + let ascii = base.map((x) => x.ascii()) + const agentLabel = extLabel.value[extLabel.value.length - 2] + if (!ascii.includes(termascii) && agents.includes(agentLabel)){ + if (!this.nu_group.some(prevnode => prevnode.id === node.id)){ + this.nu_group.push(node); + } + }else{ + this.nu_group = this.nu_group.filter(item => item !== node) + } + }) + } + }) + } + this.updateNuGroup(node.left); + this.updateNuGroup(node.right); + } + + isAvailable(data){ + var node = data; + if (typeof data === "string"){ + node = this.getNodeFromId(data) + } + var inAlpha = this.alpha_group.some(x => x.id === node.id); + var inBeta = this.beta_group.some(x => x.id === node.id); + var inNu = this.nu_group.some(x => x.id === node.id); + var inPi = this.pi_group.some(x => x.id === node.id); + + return inAlpha || inBeta || inNu || inPi; + } + + runTableau(logger){ + while (this.alpha_group.length > 0 || this.beta_group.length > 0 || this.pi_group.length > 0 || this.nu_group.length >0 ){ + let leafs = this.getLeafs(); + let leafsAva = leafs.filter((leaf) => this.isLeafAvailable(leaf)); + if (leafsAva.length == 0){ + console.log("NO more leafs open") + break; + }else if(this.alpha_group.length > 0 ){ + this.alpha_group.forEach(node =>{ + // logger.addLog(`Applying rule on node ID: ${node.id}, formula: ${node.value.unicode()}`); + this.applyRule(node, logger); + }) + }else if(this.nu_group.length > 0 ){ + this.nu_group.forEach(node =>{ + // logger.addLog(`Applying rule on node ID: ${node.id}, formula: ${node.value.unicode()}`); + this.applyRule(node, logger); + }) + }else if(this.beta_group.length > 0 ){ + this.beta_group.forEach(node =>{ + // logger.addLog(`Applying rule on node ID: ${node.id}, formula: ${node.value.unicode()}`); + this.applyRule(node, logger); + }) + }else if(this.pi_group.length > 0 ){ + this.pi_group.forEach(node =>{ + // logger.addLog(`Applying rule on node ID: ${node.id}, formula: ${node.value.unicode()}`); + this.applyRule(node, logger); + }) + } + } + logger.addLog(`Tableau ended`); + console.log(this.isEnded()); + return logger; + } + + isEnded(){ + const leafs = this.getLeafs(); + return leafs.every(x => !this.isLeafAvailable(x)) + } + + isClosed(){ + const leafs = this.getLeafs(); + return leafs.some(leaf =>{ + const branch = this.getBranchFromLeaf(leaf); + return branch.isClosed() + }) + } + + isLeafAvailable(leaf){ + const branch = this.getBranchFromLeaf(leaf) + return !branch.isClosed(); + } + + getNodeFromLeafId(id){ + const searchId = Number(id); + const leafs = this.getLeafs(); + return leafs.filter(d => Number(d.id) === searchId)[0]; + } + + getNodeFromId(id, node=this.root) { + if (node === null) return null; + if (node.id === Number(id)) { + return node; + } + const leftResult = this.getNodeFromId(id, node.left); + if (leftResult) return leftResult; + + // Search right subtree + return this.getNodeFromId(id, node.right); + } + +} + +class Label { + constructor(labelStr){ + this.value = this._parseLabel(labelStr); // Almacena el string directamente + } + + _parseLabel(labelStr){ + return labelStr.split('') + } + + addExtension(agent, number){ + const newArray = [...this.value, agent, number]; + return new Label(newArray.join("")); + } + + toString(){ + return this.value.join("") + } + + equal(label2){ + return this.toString() === label2.toString() + } + + getBase(branch){ + let baseFormulas = []; + branch.nodes.forEach(node => { + if (this.equal(node.label)){ + baseFormulas.push(node.value) + } + + }) + return baseFormulas; + } + + // 1a2b3a4 >> "1234" + simplify(){ + const simplified = this.value.filter(elemento => !isNaN(Number(elemento))); + return simplified.join("") + } + + lenght(){ + return this.value.lenght; + } + + + isSublabel(label){ + let l1 = this + let l2 = label + let l1simp = l1.simplify() + let l2simp = l2.simplify() + if (label.simplify().length <=this.simplify().length){ + return false + }else{ + let sub = l2simp.substring(0,l1simp.length); + return sub === l1simp; + } + } + + + isSimpleExtension(label){ + let l1 = label + let l2 = this + let l1simp = l1.simplify() + let l2simp = l2.simplify() + return l1simp.length+1 === l2simp.length && l1.isSublabel(l2); + } +} + +class Branch { + constructor() { + this.nodes = []; + } + + getLeaf(){ + return this.nodes.reduce((max, currentNode) => { + return (currentNode.id > max.id) ? currentNode : max; + }); + } + + addNode(node) { + this.nodes.push(node); + } + + isClosed(){ + return this.nodes.some((a, i) => + this.nodes.slice(i + 1).some(b => { + const aLabel = a.label.simplify(); + const bLabel = b.label.simplify(); + const aType = a.typeOf(); + const bType = b.typeOf(); + if ( aLabel === bLabel && + (aType === 'prop' || aType === 'neg_prop') && + (bType === 'prop' || bType === 'neg_prop')) { + var neg = MPL.negateWff(b.value.json()).ascii(); + var current = a.value.ascii(); + return (neg === current); + } + return false + }) + ); + } + + getAllLabels(){ + let labels = [] + this.nodes.forEach(x=> labels.push(x.label)); + labels = labels.filter((value, index, array) => //remove duplicates + array.indexOf(value) === index + ) + return labels + } + + isSuplerflous(label){ + const labelSet = this.getAllLabels() + var currentBase = label.getBase(this) + labelSet.some(labelPrima =>{ + let basePrima = labelPrima.getBase(this); + return currentBase.every(element => basePrima.includes(element)) + }) + } + + getSimpleExtensions(label){ + const labelSet = this.getAllLabels(); + const filtered = labelSet.filter((x) => x.isSimpleExtension(label)) + return filtered; + } + + getSimpleExtensionsAgent(label, agent){ + const labelSet = this.getAllLabels(); + const filtered = labelSet.filter((x) => x.isSimpleExtension(label)) + return filtered; + } + + +} + +function toD3(node){ + if (!node) return null; + + const d3Node = { + name: node.value.toString(), + id: node.id.toString(), + value: node.value, + label: node.label, + children: [] + }; + if (node.left) { + d3Node.children.push(toD3(node.left)); + } + if (node.right) { + d3Node.children.push(toD3(node.right)); + } + if (d3Node.children.length === 0) { + delete d3Node.children; + } + return d3Node; +} + +function computeRadius(d) { + return (d.children || d._children) ? radius + (radius * nbEndNodes(d) / 10) : radius; +} + +function nbEndNodes(d) { + if (d.children) return d.children.reduce((acc, c) => acc + nbEndNodes(c), 0); + if (d._children) return d._children.reduce((acc, c) => acc + nbEndNodes(c), 0); + return 1; +} +function getVisibleDepth(node, depth = 0) { + if (!node.children) return depth; + return Math.max(...node.children.map(child => getVisibleDepth(child, depth + 1))); +} + +function click(event, d) { + if (d.children) { + d._children = d.children; + d.children = null; + } else { + d.children = d._children; + d._children = null; + } + update(d); + // highlightLink(d) + +} + +function dblClick(event, d) { + columnAttribute.push(d.data.name); +} + +function rclick(event, d) { + event.preventDefault(); + if (currentTableau) { + let closedLeafs = currentTableau.applyRule(d.id, logger); + const newTreeData = currentTableau.toD3(); + root = d3.hierarchy(newTreeData, (d) => d.children); + root.each(function(d) { + d.id = d.data.id || d.id; // Ensure IDs are not overwritten + }); + root.x0 = container.clientWidth / 2; + root.y0 = 0; + // TODO: UNIFY IN THE BRAIN + if (closedLeafs == null){ + logger.addLog(`[Error] Can not apply rule to ID: ${d.id})}`); + } + if(currentTableau.isEnded()){ + logger.addLog("Tableau finished"); + } + update(d); + } +} + + +let maxLabel = 150; +let duration = 500; +let radius = 5; +let tree, diagonal; +let i = 0; +let root; +let columnAttribute = []; +let currentTableau = null; +const logger = new Logger(); +let container = document.getElementById('graph-container'); + +function runxx(){ + const formula = document.getElementById('treeFormulaInput').value; + const f = new MPL.Wff(formula); + const tableau = new Tableau(formula); + tableau.runTableau(logger); + const treeData = tableau.toD3(); + currentTableau = tableau; + columnAttribute = []; + i = 0; + + d3.select("#graph-container").selectAll("*").remove(); + + // Set up SVG with dynamic width and height based on the container size + svg = d3.select("#graph-container") + .append("svg") + .attr("class", "tree-graph") + .attr("width", width) + .attr("height", height) + .append("g") + .attr("transform", `translate(0, ${maxLabel})`); + + // Set up tree layout + tree = d3.tree().size([width, height - maxLabel * 2]); + diagonal = d3.linkVertical() + .x(d => d.x) + .y(d => d.y); + + root = d3.hierarchy(treeData, (d) => d.children); + root.each(function(d) { + d.id = d.data.id || d.id; // Ensure IDs are not overwritten + }); + root.x0 = width / 2; + root.y0 = 0; + + // displayLogsInHTML(logger); + update(root); +} + +function update(source) { + // displayLogsInHTML(logger); + + // Get the container element again in case it was resized + container = document.getElementById('graph-container'); + width = container.clientWidth - 40; // Adjust for padding/margin + height = container.clientHeight - 100; // Adjust for padding/margin + + // Set the size of the tree layout based on the container size + const treeData = tree(root); + const nodes = treeData.descendants(); + const links = treeData.links(); + + let visibleDepth = getVisibleDepth(root); + height = (visibleDepth + 2) * maxLabel; // Adjust height based on visible depth + tree.size([width, height - maxLabel * 2]); + + // Update SVG height dynamically based on the new tree size + d3.select("svg").transition().duration(duration).attr("height", height); + + nodes.forEach(d => d.y = d.depth * maxLabel); + + const node = svg.selectAll("g.node") + .data(nodes, d => d.id || (d.id = ++i)); + + const nodeEnter = node.enter().append("g") + .attr("class", "node") + .attr("transform", d => `translate(${source.x0},${source.y0})`) + .on("click", click) + .on("contextmenu", rclick) + .on("dblclick", dblClick); + + nodeEnter.append("circle") + .attr("r", 0) + .attr("class", d => currentTableau.isAvailable(d.id) ? "clickable" : "non-cickable"); + + nodeEnter.append("text") + .attr("x", d => { + const spacing = computeRadius(d.data) + 5; + return d.children || d._children ? -spacing : spacing; + }) + .attr("dy", "3") + .attr("text-anchor", d => d.children || d._children ? "end" : "start") + .text(d => `(${d.id}) ${d.data.label}: ${d.data.value.unicode()}`) + .style("fill-opacity", 0); + + const nodeUpdate = node.merge(nodeEnter).transition() + .duration(duration) + .attr("transform", d => `translate(${d.x},${d.y})`); + + nodeUpdate.select("circle") + .attr("r", d => computeRadius(d.data)) + .attr("class", d => currentTableau.isAvailable(d.id) ? "clickable" : "non-cickable"); + + nodeUpdate.select("text").style("fill-opacity", 1); + + const nodeExit = node.exit().transition() + .duration(duration) + .attr("transform", d => `translate(${source.x},${source.y})`) + .remove(); + + nodeExit.select("circle").attr("r", 0); + nodeExit.select("text").style("fill-opacity", 0); + + const link = svg.selectAll("path.link") + .data(links, d => d.target.id); + + link.enter().insert("path", "g") + .attr("class", "link") + .attr("d", d => { + const o = { x: source.x0, y: source.y0 }; + return diagonal({ source: o, target: o }); + }) + .merge(link) + .transition().duration(duration) + .attr("d", diagonal); + + link.exit().transition().duration(duration) + .attr("d", d => { + const o = { x: source.x, y: source.y }; + return diagonal({ source: o, target: o }); + }) + .remove(); + + nodes.forEach(d => { + d.x0 = d.x; + d.y0 = d.y; + }); + + // Verificar si el tableau está cerrado + // [FiX] Mejorar + // const isClosed = currentTableau.isClosed(); + // if (isClosed){ + // setTimeout(() => { + // console.log(svg.selectAll("circle")); + // svg.selectAll("circle") + // .transition().duration(duration) + // .style("fill", 'red'); + // + // svg.selectAll("path.link") + // .transition().duration(duration) + // .style("stroke", 'red'); + // + // }, 600); + // } +} + +export { + Node, + Tableau, + Branch, + Label, + Logger, + runxx, + toD3 +}; + +window.Node = Node; +window.Tableau = Tableau; +window.Branch = Branch; +window.Label = Label; +window.Logger = Logger; +window.toD3 = toD3; +window.runxx = runxx; + diff --git a/js/utils.js b/js/utils.js index f50f55c..4b9180c 100644 --- a/js/utils.js +++ b/js/utils.js @@ -64,3 +64,6 @@ function applyStyles(show, hide) { styleScript.innerHTML += `.${clase} { display:inline; }`; }); } + + + diff --git a/tree/d3.js b/tree/d3.js index 1853606..5fe64bb 100644 --- a/tree/d3.js +++ b/tree/d3.js @@ -1,4 +1,4 @@ -import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm"; +// import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm"; document.addEventListener('DOMContentLoaded', () => { @@ -25,7 +25,7 @@ let columnAttribute = []; let svg, tree, diagonal; let currentTableau = null; const logger = new Logger(); -let container = document.getElementById('tree-container'); +let container = document.getElementById('graph-container'); let width = container.clientWidth - 40; let height = container.clientHeight - 100; @@ -44,10 +44,10 @@ function run(ezmode=false) { columnAttribute = []; i = 0; - d3.select("#tree-container").selectAll("*").remove(); + d3.select("#graph-container").selectAll("*").remove(); // Set up SVG with dynamic width and height based on the container size - svg = d3.select("#tree-container").append("svg") + svg = d3.select("#graph-container").append("svg") .attr("width", width) .attr("height", height) .append("g") @@ -75,7 +75,7 @@ function update(source) { displayLogsInHTML(logger); // Get the container element again in case it was resized - container = document.getElementById('tree-container'); + container = document.getElementById('graph-container'); width = container.clientWidth - 40; // Adjust for padding/margin height = container.clientHeight - 100; // Adjust for padding/margin @@ -276,6 +276,6 @@ function getPathToRoot(node) { function clear(){ logger.clearLogs(); document.getElementById('formulaInput').value = ''; - document.getElementById('tree-container').innerHTML = ""; + document.getElementById('graph-container').innerHTML = ""; displayLogsInHTML(logger) } From fc439a1fdf9245d655acb32a4bd1a828de61ddfd Mon Sep 17 00:00:00 2001 From: karu Date: Wed, 4 Feb 2026 13:49:18 +0100 Subject: [PATCH 44/68] styles --- css/app.css | 39 +++++++++++++++++++++++++++++++++++++++ index.html | 6 +++++- js/tree.js | 46 ++++++++++++++++++++++++++++++++++++---------- 3 files changed, 80 insertions(+), 11 deletions(-) diff --git a/css/app.css b/css/app.css index 21f6072..695b11e 100644 --- a/css/app.css +++ b/css/app.css @@ -483,3 +483,42 @@ svg.tree-graph g.node:hover text { font-weight: 600; } + + +/* LOGGER */ +/* Contenedor del logger dentro del tree-input */ +#log-container { + width: 100%; + max-height: 120px; /* altura limitada para que no crezca demasiado */ + overflow-y: auto; + background-color: #f8f9fa; /* fondo suave, combina con Bootstrap */ + font-family: monospace; + font-size: 0.75rem; /* texto pequeño */ + padding: 4px 6px; + border-radius: 4px; + border: 1px solid #dee2e6; /* borde gris suave */ +} + +/* Cada línea de log */ +#log-container .log-line { + margin: 1px 0; + line-height: 1.2; +} + +/* Colores según tipo de log */ +#log-container .log-line.info { + color: #495057; /* gris oscuro */ +} + +#log-container .log-line.success { + color: #198754; /* verde */ +} + +#log-container .log-line.warning { + color: #fd7e14; /* naranja */ +} + +#log-container .log-line.error { + color: #dc3545; /* rojo */ +} + diff --git a/index.html b/index.html index 184bd0b..027332e 100644 --- a/index.html +++ b/index.html @@ -186,7 +186,7 @@

-
+
Formula: @@ -200,6 +200,10 @@

Tree

+
+
+
+
diff --git a/js/tree.js b/js/tree.js index a5a1aee..367099c 100644 --- a/js/tree.js +++ b/js/tree.js @@ -695,6 +695,18 @@ function toD3(node){ return d3Node; } +function displayLogs(logger) { + const container = document.getElementById("log-container"); + container.innerHTML = ""; // limpiar logs anteriores + logger.getLogs().forEach(log => { + const div = document.createElement("div"); + div.className = `log-line ${log.type}`; + div.textContent = log.message; // SOLO el mensaje, sin fecha + container.appendChild(div); + }); + container.scrollTop = container.scrollHeight; // auto-scroll al último log +} + function computeRadius(d) { return (d.children || d._children) ? radius + (radius * nbEndNodes(d) / 10) : radius; } @@ -773,13 +785,27 @@ function runxx(){ d3.select("#graph-container").selectAll("*").remove(); // Set up SVG with dynamic width and height based on the container size + // + container = document.getElementById('graph-container'); + let width = container.clientWidth; + let height = container.clientHeight; + svg = d3.select("#graph-container") - .append("svg") - .attr("class", "tree-graph") - .attr("width", width) - .attr("height", height) - .append("g") - .attr("transform", `translate(0, ${maxLabel})`); + .append("svg") + .attr("class", "tree-graph") + .attr("width", "100%") + .attr("height", height) + .attr("viewBox", `0 0 ${width} ${height}`) // importante para escalar + .append("g") + .attr("transform", `translate(0, ${maxLabel})`); + + // svg = d3.select("#graph-container") + // .append("svg") + // .attr("class", "tree-graph") + // .attr("width", width) + // .attr("height", height) + // .append("g") + // .attr("transform", `translate(0, ${maxLabel})`); // Set up tree layout tree = d3.tree().size([width, height - maxLabel * 2]); @@ -794,17 +820,17 @@ function runxx(){ root.x0 = width / 2; root.y0 = 0; - // displayLogsInHTML(logger); + displayLogs(logger); update(root); } function update(source) { - // displayLogsInHTML(logger); + displayLogs(logger); // Get the container element again in case it was resized container = document.getElementById('graph-container'); - width = container.clientWidth - 40; // Adjust for padding/margin - height = container.clientHeight - 100; // Adjust for padding/margin + width = container.clientWidth; // Adjust for padding/margin + height = container.clientHeight; // Adjust for padding/margin // Set the size of the tree layout based on the container size const treeData = tree(root); From 5c352ee87899d07e820c337b31f2986c6eca0b44 Mon Sep 17 00:00:00 2001 From: karu Date: Tue, 10 Feb 2026 13:37:34 +0100 Subject: [PATCH 45/68] Regla T' --- css/app.css | 83 ---------------------------- css/tree.css | 87 ++++++++++++++++++++++++++++++ index.html | 15 +++++- js/tree.js | 143 ++++++++++++++++++++----------------------------- server.py | 15 ++++++ tree/style.css | 130 +++++++------------------------------------- 6 files changed, 193 insertions(+), 280 deletions(-) create mode 100644 css/tree.css create mode 100644 server.py diff --git a/css/app.css b/css/app.css index 695b11e..02a331c 100644 --- a/css/app.css +++ b/css/app.css @@ -438,87 +438,4 @@ footer { -/*-------------------------------------------------------*/ -svg.tree-graph { - background: #f9f9f9; /* fondo suave */ - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; -} - -/* Nodos */ -svg.tree-graph circle { - fill: #4a90e2; /* azul elegante */ - stroke: #ffffff; /* borde blanco */ - stroke-width: 2px; - transition: fill 0.3s; -} - -/* Nodos clicables (reglas aplicables) */ -svg.tree-graph circle.clickable { - fill: #50e3c2; /* verde suave para destacar */ - cursor: pointer; -} - -/* Líneas que conectan nodos */ -svg.tree-graph path.link { - stroke: #999; /* gris claro */ - stroke-width: 2px; - fill: none; -} - -/* Texto de los nodos */ -svg.tree-graph text { - fill: #333; /* gris oscuro legible */ - font-size: 14px; - font-weight: 500; -} - -/* Hover en nodos */ -svg.tree-graph g.node:hover circle { - fill: #f5a623; /* naranja suave al pasar el mouse */ - stroke-width: 3px; -} - -svg.tree-graph g.node:hover text { - fill: #000; /* texto más visible al hover */ - font-weight: 600; -} - - - -/* LOGGER */ -/* Contenedor del logger dentro del tree-input */ -#log-container { - width: 100%; - max-height: 120px; /* altura limitada para que no crezca demasiado */ - overflow-y: auto; - background-color: #f8f9fa; /* fondo suave, combina con Bootstrap */ - font-family: monospace; - font-size: 0.75rem; /* texto pequeño */ - padding: 4px 6px; - border-radius: 4px; - border: 1px solid #dee2e6; /* borde gris suave */ -} - -/* Cada línea de log */ -#log-container .log-line { - margin: 1px 0; - line-height: 1.2; -} - -/* Colores según tipo de log */ -#log-container .log-line.info { - color: #495057; /* gris oscuro */ -} - -#log-container .log-line.success { - color: #198754; /* verde */ -} - -#log-container .log-line.warning { - color: #fd7e14; /* naranja */ -} - -#log-container .log-line.error { - color: #dc3545; /* rojo */ -} diff --git a/css/tree.css b/css/tree.css new file mode 100644 index 0000000..ee874f9 --- /dev/null +++ b/css/tree.css @@ -0,0 +1,87 @@ +svg { + display: block; + margin: auto; +} + +.node-tableau { + cursor: default; +} + +.node-tableau.clickable { + cursor: pointer; +} + +.node-circle-active { + fill: #4CAF50 !important; + stroke: #2e7d32; + stroke-width: 3px; + transition: fill 0.2s; +} + +.node-circle-disabled { + fill: #fff !important; + stroke: #999; + stroke-width: 2px; +} + +.node-tableau.clickable:hover .node-circle-active { + fill: #66bb6a !important; +} + +.node-tableau text { + font: 12px sans-serif; + pointer-events: none; +} + +.link { + fill: none; + stroke: #ccc; + stroke-width: 2px; + transition: stroke 0.3s; +} + +.close-leaf { fill: Red; } +.open-leaf { fill: Green; } + + +/* LOGGER */ +#log-container { + width: 100%; + overflow-y: auto; + background-color: #f8f9fa; /* fondo suave, combina con Bootstrap */ + font-family: monospace; + font-size: 0.75rem; /* texto pequeño */ + padding: 4px 6px; + border-radius: 4px; + border: 1px solid #dee2e6; /* borde gris suave */ +} + +/* Cada línea de log */ +#log-container .log-line { + margin: 1px 0; + line-height: 1.2; +} + +/* Colores según tipo de log */ +#log-container .log-line.info { + color: #495057; /* gris oscuro */ +} + +#log-container .log-line.success { + color: #198754; /* verde */ +} + +#log-container .log-line.warning { + color: #fd7e14; /* naranja */ +} + +#log-container .log-line.error { + color: #dc3545; /* rojo */ +} + + + +#treeFormulaInput{ + margin-right:10px; + width: 180px; +} diff --git a/index.html b/index.html index 027332e..ede8986 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,7 @@ + @@ -186,7 +187,7 @@

-
+
Formula: @@ -194,12 +195,22 @@

id="treeFormulaInput" class="form-control border-0 bg-light" placeholder="(p -> K{a}p)" - style="width: 180px;"> + onkeydown="if (event.key === 'Enter') runxx()">

+ +
+
+ + +
+
+
diff --git a/js/tree.js b/js/tree.js index 367099c..6fc580c 100644 --- a/js/tree.js +++ b/js/tree.js @@ -36,15 +36,15 @@ class Node { } - //formula = MLP formula addSingleChild(id, formula, label = this.label){ + let node = null if (this.left === null){ - let node = new Node(id, formula, label, this) + node = new Node(id, formula, label, this) this.left = node - return node; }else{ this.left.addSingleChild(id, formula, label) } + return node; } addTwoChildren(id1, formula1, id2, formula2, label=this.label){ @@ -111,11 +111,9 @@ class Node { class Tableau { constructor(data) { if (typeof data === 'string') { - // Si formula es un string, usamos MPL.Wff var formula = new MPL.Wff(data) this.root = new Node(1, formula, new Label('1')); } else { - // Si formula no es un string, directamente la pasamos o la procesamos como corresponda this.root = this.fromD3(data) } this.alpha_group = [] @@ -203,32 +201,25 @@ class Tableau { const formula2 = new MPL.Wff(MPL._jsonToASCII(formula.disj[1])) this.addDoubleExtension(formula1,formula2, node); }else if(formula.kno_start){ - const formula1 = new MPL.Wff(MPL._jsonToASCII(formula)) var term = new MPL.Wff(MPL._jsonToASCII(formula.kno_start.group_end[1])); - let n = this.addSingleExtension(term, node) const leafs = this.getLeafs(node); + const isTActive = document.getElementById('ruleTToggle').checked; leafs.forEach(leaf => { const branch = this.getBranchFromLeaf(leaf) - const exts = branch.getSimpleExtensions(node.label) + const exts = branch.getSimpleExtensions(node.label, isTActive) // If t Active simple extension add current extension if (exts.length === 0){ return } - exts.forEach(newLabel =>{ - // RULE K + exts.forEach(label =>{ var newId = parseInt(leaf.id + '1'); - let newNode = leaf.addSingleChild(newId,term,newLabel); - // RULE 4 - var newnewId = parseInt(newNode.id + '1'); - let newnewNode = newNode.addSingleChild(newnewId,formula1, newLabel) + let newNode = leaf.addSingleChild(newId,term,label); this.addAvailableNode(newNode) - this.addAvailableNode(newnewNode) }) }); - //REGLA T } else if(formula.neg){ if (formula.neg.kno_start){ const agents = formula.neg.kno_start.group_end[0].prop.split(''); - var term = formula.neg.kno_start.group_end[1]; + var term = formula.neg.kno_start.group_end[1]; const f1 = MPL.negateWff(term); const leafs = this.getLeafs(node); leafs.forEach(leaf => { @@ -242,8 +233,8 @@ class Tableau { newLabel = node.label.addExtension(agents,count.toString()) flag = branch.isSuplerflous(newLabel); } - // RULE K - var newId = parseInt(leaf.id + '1'); + // RULE K + let newId = parseInt(leaf.id + '1'); let newNode = leaf.addSingleChild(newId,f1, newLabel) this.addAvailableNode(newNode); this.updateNuGroup(); @@ -360,6 +351,7 @@ class Tableau { } addAvailableNode(node){ + console.log(node) const type = node.typeOfRule() switch (type){ case "alpha": @@ -497,7 +489,6 @@ class Tableau { } } logger.addLog(`Tableau ended`); - console.log(this.isEnded()); return logger; } @@ -658,9 +649,13 @@ class Branch { }) } - getSimpleExtensions(label){ + getSimpleExtensions(label, isTActive){ const labelSet = this.getAllLabels(); const filtered = labelSet.filter((x) => x.isSimpleExtension(label)) + // Regla T + if (isTActive) { + filtered.push(label) + } return filtered; } @@ -761,6 +756,7 @@ function rclick(event, d) { } +const isTActive = document.getElementById('ruleTToggle').checked; let maxLabel = 150; let duration = 500; let radius = 5; @@ -771,8 +767,10 @@ let columnAttribute = []; let currentTableau = null; const logger = new Logger(); let container = document.getElementById('graph-container'); +let svgBase, mainGroup, svg, linkGroup; function runxx(){ + logger.clearLogs(); const formula = document.getElementById('treeFormulaInput').value; const f = new MPL.Wff(formula); const tableau = new Tableau(formula); @@ -784,28 +782,25 @@ function runxx(){ d3.select("#graph-container").selectAll("*").remove(); - // Set up SVG with dynamic width and height based on the container size - // container = document.getElementById('graph-container'); let width = container.clientWidth; let height = container.clientHeight; - - svg = d3.select("#graph-container") + + svgBase = d3.select("#graph-container") .append("svg") - .attr("class", "tree-graph") .attr("width", "100%") - .attr("height", height) - .attr("viewBox", `0 0 ${width} ${height}`) // importante para escalar - .append("g") - .attr("transform", `translate(0, ${maxLabel})`); - - // svg = d3.select("#graph-container") - // .append("svg") - // .attr("class", "tree-graph") - // .attr("width", width) - // .attr("height", height) - // .append("g") - // .attr("transform", `translate(0, ${maxLabel})`); + .attr("height", "100%") + .call(d3.zoom().on("zoom", (event) => { + mainGroup.attr("transform", event.transform); // Mueve TODO el contenido + })); + + mainGroup = svgBase.append("g"); + linkGroup = mainGroup.append("g") + .attr("class", "links-layer") + .attr("transform", `translate(0, ${maxLabel})`); + + svg = mainGroup.append("g") + .attr("transform", `translate(0, ${maxLabel})`); // Set up tree layout tree = d3.tree().size([width, height - maxLabel * 2]); @@ -827,38 +822,23 @@ function runxx(){ function update(source) { displayLogs(logger); - // Get the container element again in case it was resized - container = document.getElementById('graph-container'); - width = container.clientWidth; // Adjust for padding/margin - height = container.clientHeight; // Adjust for padding/margin - - // Set the size of the tree layout based on the container size const treeData = tree(root); const nodes = treeData.descendants(); const links = treeData.links(); - let visibleDepth = getVisibleDepth(root); - height = (visibleDepth + 2) * maxLabel; // Adjust height based on visible depth - tree.size([width, height - maxLabel * 2]); - - // Update SVG height dynamically based on the new tree size - d3.select("svg").transition().duration(duration).attr("height", height); - - nodes.forEach(d => d.y = d.depth * maxLabel); + nodes.forEach(d => { + d.y = d.depth * maxLabel; + }); const node = svg.selectAll("g.node") .data(nodes, d => d.id || (d.id = ++i)); const nodeEnter = node.enter().append("g") - .attr("class", "node") - .attr("transform", d => `translate(${source.x0},${source.y0})`) - .on("click", click) - .on("contextmenu", rclick) - .on("dblclick", dblClick); + .attr("class", d => "node-tableau " + (currentTableau.isAvailable(d.id) ? "clickable" : "non-clickable")) + .attr("transform", d => `translate(${source.x0},${source.y0})`); nodeEnter.append("circle") - .attr("r", 0) - .attr("class", d => currentTableau.isAvailable(d.id) ? "clickable" : "non-cickable"); + .attr("r", 0); nodeEnter.append("text") .attr("x", d => { @@ -875,8 +855,17 @@ function update(source) { .attr("transform", d => `translate(${d.x},${d.y})`); nodeUpdate.select("circle") - .attr("r", d => computeRadius(d.data)) - .attr("class", d => currentTableau.isAvailable(d.id) ? "clickable" : "non-cickable"); + .attr("r", d => computeRadius(d.data)) + // .attr("class", d => currentTableau.isAvailable(d.id) ? "node-circle-active" : "node-circle-disabled"); + .attr("class", d => { + if (!d.children && !d._children) { + const leafs = currentTableau.getClosedLeafs().map((leaf) => leaf.id) + const isClosed = leafs.includes(Number(d.id)) + if (isClosed) return "close-leaf"; + if (!isClosed) return "open-leaf" + } + return currentTableau.isAvailable(d.id) ? "node-circle-active" : "node-circle-disabled"; + }); nodeUpdate.select("text").style("fill-opacity", 1); @@ -888,20 +877,22 @@ function update(source) { nodeExit.select("circle").attr("r", 0); nodeExit.select("text").style("fill-opacity", 0); - const link = svg.selectAll("path.link") + const link = linkGroup.selectAll("path.link") .data(links, d => d.target.id); - link.enter().insert("path", "g") + const linkEnter = link.enter().insert("path", "g") .attr("class", "link") .attr("d", d => { const o = { x: source.x0, y: source.y0 }; return diagonal({ source: o, target: o }); - }) - .merge(link) - .transition().duration(duration) + }); + + link.merge(linkEnter).transition() + .duration(duration) .attr("d", diagonal); - link.exit().transition().duration(duration) + link.exit().transition() + .duration(duration) .attr("d", d => { const o = { x: source.x, y: source.y }; return diagonal({ source: o, target: o }); @@ -912,23 +903,7 @@ function update(source) { d.x0 = d.x; d.y0 = d.y; }); - - // Verificar si el tableau está cerrado - // [FiX] Mejorar - // const isClosed = currentTableau.isClosed(); - // if (isClosed){ - // setTimeout(() => { - // console.log(svg.selectAll("circle")); - // svg.selectAll("circle") - // .transition().duration(duration) - // .style("fill", 'red'); - // - // svg.selectAll("path.link") - // .transition().duration(duration) - // .style("stroke", 'red'); - // - // }, 600); - // } + } export { diff --git a/server.py b/server.py new file mode 100644 index 0000000..17b6c92 --- /dev/null +++ b/server.py @@ -0,0 +1,15 @@ +import http.server +import socketserver + +PORT = 8000 + +class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): + def end_headers(self): + self.send_header("Cache-Control", "no-cache, no-store, must-revalidate") + self.send_header("Pragma", "no-cache") + self.send_header("Expires", "0") + super().end_headers() + +with socketserver.TCPServer(("", PORT), MyHTTPRequestHandler) as httpd: + print("serving at port", PORT) + httpd.serve_forever() diff --git a/tree/style.css b/tree/style.css index f2bc1ab..8d5787e 100644 --- a/tree/style.css +++ b/tree/style.css @@ -4,128 +4,36 @@ svg{ margin: auto; } - -.node { - pointer -} -/* Nodes */ -.clickable { +/* Estilo base para todos los círculos de nodo */ +.node circle { fill: #fff; - stroke: steelblue; - stroke-width: 3px; + stroke: #999; + stroke-width: 2px; } -.non-cickable { - fill: #fff; - stroke: gray; +/* Cuando el padre es .clickable */ +.node.clickable circle { + fill: #4CAF50 !important; + stroke: #2e7d32; stroke-width: 3px; + cursor: pointer; } -.node text{ - font: 12px sans-serif; - background-color: #fff; -} - - -/* Links */ -.link{ - fill: none; +/* Cuando el padre es .non-cickable (manteniendo tu errata de la 'i') */ +.node.non-cickable circle { + fill: #fff; stroke: #ccc; stroke-width: 2px; } - -.close-leaf{ - fill: Red; -} - -.open-leaf{ - fill: Green; -} - -#app-body { - border: 2px solid #ddd; - border-radius: 4px; - margin:100px; - display:flex; - /* align-content:stretch; */ -} - -#tab-content{ - width:15%; - padding: 10px; - background-color:#ddd -} - -.eval-input{ - margin-bottom: 15px; -} - -.eval-input input { - width: 100%; - font-family: Monaco, Menlo, Consolas, "Courier New", monospace; - font-size: 12px; - border: 1px solid #ddd; - padding: 10px; - margin-bottom: 10px; -} - -#tree-container{ - width:85%; - height:100%; -} - -.selectedNode circle{ - fill:gray; -} - -#log-container { - font-family: monospace; - max-height: 1000px; - overflow-y: auto; - border: 1px solid #ccc; - padding: 10px; - background: #f9f9f9; - font-size:9px; -} - -.log-entry { - margin-bottom: 5px; - padding: 3px; -} - -.log-info { - color: #2e86c1; -} - -.log-error { - color: #c0392b; - font-weight: bold; -} - -.timestamp { - color: #7f8c8d; - margin-right: 10px; - -} - - -.node.clickable circle { - fill: #4CAF50; /* verde */ - cursor: pointer; - stroke: #2e7d32; - stroke-width: 2px; - transition: fill 0.2s; -} - +/* Hover solo para los clickables */ .node.clickable:hover circle { - fill: #66bb6a; + fill: #66bb6a !important; } -.node.disabled circle { - fill: #ccc; /* gris */ - stroke: #999; - stroke-width: 1px; - cursor: not-allowed; - opacity: 0.6; +/* Estilo para los links (asegúrate de que esto exista) */ +.link { + fill: none; + stroke: #ccc; + stroke-width: 2px; } From 2e5c77136d8c7afe961af3b18439db9b738b8e30 Mon Sep 17 00:00:00 2001 From: karu Date: Tue, 10 Feb 2026 14:41:21 +0100 Subject: [PATCH 46/68] Add tree container diff from graphh container --- index.html | 4 +++- js/app.js | 38 +++++++++++++++++++++++++++----------- js/tree.js | 49 +++++++++++++++++++++++++++---------------------- 3 files changed, 57 insertions(+), 34 deletions(-) diff --git a/index.html b/index.html index ede8986..eda2183 100644 --- a/index.html +++ b/index.html @@ -212,7 +212,7 @@

-
+
@@ -240,6 +240,8 @@

+
+
-
-

- New things -

-
    -
  • - Insert model using JSON -
  • -
-

Editing Instructions diff --git a/js/app.js b/js/app.js index 8f9d8cd..27eeec0 100644 --- a/js/app.js +++ b/js/app.js @@ -1293,3 +1293,17 @@ function setActive(pane){ .classed("inactive", false); } } + + +function toggleFullScreen() { + const elem = document.getElementById("tree-container") + + if (!document.fullscreenElement) { + elem.requestFullscreen().catch(err => { + alert(`Error intentando entrar en pantalla completa: ${err.message}`); + }); + } else { + document.exitFullscreen(); + } +} + diff --git a/js/tree.js b/js/tree.js index b549568..d552e06 100644 --- a/js/tree.js +++ b/js/tree.js @@ -789,6 +789,11 @@ function runxx(){ columnAttribute = []; i = 0; + const btnFullscreen = document.getElementById('btn-fullscreen'); + if (btnFullscreen) { + btnFullscreen.style.display = "inline-block"; + } + svgBase = d3.select("#tree-container") @@ -911,6 +916,9 @@ function update(source) { } + + + export { Node, Tableau, @@ -929,3 +937,4 @@ window.Logger = Logger; window.toD3 = toD3; window.runxx = runxx; + From 461cf9011427177bb28b3cffaf0ceec5d33e7d70 Mon Sep 17 00:00:00 2001 From: karu Date: Tue, 10 Feb 2026 15:04:35 +0100 Subject: [PATCH 48/68] remove old stuff --- js/utils.js | 138 ++++++++++++++++++++++++++-------------------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/js/utils.js b/js/utils.js index 4b9180c..07d74c1 100644 --- a/js/utils.js +++ b/js/utils.js @@ -1,69 +1,69 @@ -function addText(conector, element=null) { - var text = document.getElementById('formulaInput'); - - text.focus(); - if (conector === "delete"){ - text.value = ''; - return; - }else{ - text.value += conector; - } - if (element===null){ - return - } - const className = element.className; - - let styleScript = document.getElementById('button-style'); - if (!styleScript) { - styleScript = document.createElement('style'); - styleScript.id = 'button-style'; // Asigna el id - document.head.appendChild(styleScript); - } - - switch(className){ - case "atom-button": - hide = ["atom-button", "monadic-button", "modal-button", "agent-button"] - show = ["diadic-button"] - break; - case "monadic-button": - hide = ["diadic-button","agent-button"] - show = ["monadic-button", "atom-button", "modal-button"] - break; - case "modal-button": - hide = ["diadic-button"] - show = ["monadic-button", "atom-button", "modal-button"] - break; - case "group-button": - hide = ["monadic-button", "atom-button", "modal-button", "diadic-button"] - show = ["agent-button"] - break; - case "agent-button": - hide = ["diadic-button"] - show = ["agent-button", "monadic-button", "atom-button", "modal-button"] - break; - case "diadic-button": - hide = ["diadic-button"] - show = ["monadic-button", "atom-button", "modal-button"] - break; - } - - styleScript.innerHTML = ''; // Elimina todas las reglas CSS previas - applyStyles(show, hide); -} - - - - -// Función para aplicar los estilos (mostrar/ocultar los botones) -function applyStyles(show, hide) { - let styleScript = document.getElementById('button-style'); - hide.forEach(clase => { - styleScript.innerHTML += `.${clase} { display:none; }`; - }); - show.forEach(clase => { - styleScript.innerHTML += `.${clase} { display:inline; }`; - }); -} - - - +// function addText(conector, element=null) { +// var text = document.getElementById('formulaInput'); +// +// text.focus(); +// if (conector === "delete"){ +// text.value = ''; +// return; +// }else{ +// text.value += conector; +// } +// if (element===null){ +// return +// } +// const className = element.className; +// +// let styleScript = document.getElementById('button-style'); +// if (!styleScript) { +// styleScript = document.createElement('style'); +// styleScript.id = 'button-style'; // Asigna el id +// document.head.appendChild(styleScript); +// } +// +// switch(className){ +// case "atom-button": +// hide = ["atom-button", "monadic-button", "modal-button", "agent-button"] +// show = ["diadic-button"] +// break; +// case "monadic-button": +// hide = ["diadic-button","agent-button"] +// show = ["monadic-button", "atom-button", "modal-button"] +// break; +// case "modal-button": +// hide = ["diadic-button"] +// show = ["monadic-button", "atom-button", "modal-button"] +// break; +// case "group-button": +// hide = ["monadic-button", "atom-button", "modal-button", "diadic-button"] +// show = ["agent-button"] +// break; +// case "agent-button": +// hide = ["diadic-button"] +// show = ["agent-button", "monadic-button", "atom-button", "modal-button"] +// break; +// case "diadic-button": +// hide = ["diadic-button"] +// show = ["monadic-button", "atom-button", "modal-button"] +// break; +// } +// +// styleScript.innerHTML = ''; // Elimina todas las reglas CSS previas +// applyStyles(show, hide); +// } +// +// +// +// +// // Función para aplicar los estilos (mostrar/ocultar los botones) +// function applyStyles(show, hide) { +// let styleScript = document.getElementById('button-style'); +// hide.forEach(clase => { +// styleScript.innerHTML += `.${clase} { display:none; }`; +// }); +// show.forEach(clase => { +// styleScript.innerHTML += `.${clase} { display:inline; }`; +// }); +// } +// +// +// From dbc03d193b6cb70f50a265b31b83a7722d9cd6a6 Mon Sep 17 00:00:00 2001 From: karu Date: Mon, 27 Apr 2026 09:16:30 +0200 Subject: [PATCH 49/68] Fix current and subformula display --- css/app.css | 6 +++++- js/app.js | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/css/app.css b/css/app.css index 02a331c..a96e488 100644 --- a/css/app.css +++ b/css/app.css @@ -12,8 +12,12 @@ body { margin: 50px auto 0; } +.current-subformula.dropdown.inactive { + display: none !important; +} + .inactive { - display: none; + display: none !important; } .show { display: inline; diff --git a/js/app.js b/js/app.js index 27eeec0..802f2e4 100644 --- a/js/app.js +++ b/js/app.js @@ -353,9 +353,12 @@ function evaluateFormula() { currentSubformula.selectAll("*").remove(); + // Mostramos formulas + d3.select('#subformula-container').style('display', 'inline'); currentSubformula .classed('inactive', false); + currentSubformula .append("button") .attr("class", "btn btn-primary") @@ -1202,6 +1205,7 @@ function setAppMode(newMode) { } else if(newMode === MODE.EVAL || newMode === MODE.TREE) { if (newMode === MODE.EVAL) { setActive('graph')} + resetGraph(); d3.select('#info-box').style('display', 'block'); svg.classed('edit', false) .on('mousedown', function() { d3.event.preventDefault(); }) @@ -1231,7 +1235,10 @@ function setAppMode(newMode) { evalOutput.classed('inactive', true); if (newMode === MODE.TREE){ setActive('tree') + currentFormula.classed('inactive', true); + currentSubformula.classed('inactive', true); d3.select('#info-box').style('display', 'none'); + d3.select('#subformula-container').style('display', 'none'); } } else return; @@ -1245,7 +1252,6 @@ function setAppMode(newMode) { else d3.select(this).classed('active', true); }); appMode = newMode; - restart(); } From a44daa9c39c3af5652175357f03371a346c19177 Mon Sep 17 00:00:00 2001 From: karu Date: Mon, 27 Apr 2026 10:25:56 +0200 Subject: [PATCH 50/68] fix if superflous is empty --- css/app.css | 2 +- index.html | 1 + js/tree.js | 7 ++++++- server.py | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/css/app.css b/css/app.css index a96e488..dfa1f77 100644 --- a/css/app.css +++ b/css/app.css @@ -189,7 +189,7 @@ svg.edit:not(.active):not(.ctrl) { } path.link { - fill: none; + /* fill: none; */ stroke-width: 3px; cursor: default; } diff --git a/index.html b/index.html index 3506321..27a3205 100644 --- a/index.html +++ b/index.html @@ -195,6 +195,7 @@