|
|
- ;(function(undefined) {
- 'use strict';
-
- var _methods = Object.create(null),
- _indexes = Object.create(null),
- _initBindings = Object.create(null),
- _methodBindings = Object.create(null),
- _methodBeforeBindings = Object.create(null),
- _defaultSettings = {
- immutable: true,
- clone: true
- },
- _defaultSettingsFunction = function(key) {
- return _defaultSettings[key];
- };
-
- /**
- * The graph constructor. It initializes the data and the indexes, and binds
- * the custom indexes and methods to its own scope.
- *
- * Recognized parameters:
- * **********************
- * Here is the exhaustive list of every accepted parameters in the settings
- * object:
- *
- * {boolean} clone Indicates if the data have to be cloned in methods
- * to add nodes or edges.
- * {boolean} immutable Indicates if nodes "id" values and edges "id",
- * "source" and "target" values must be set as
- * immutable.
- *
- * @param {?configurable} settings Eventually a settings function.
- * @return {graph} The new graph instance.
- */
- var graph = function(settings) {
- var k,
- fn,
- data;
-
- /**
- * DATA:
- * *****
- * Every data that is callable from graph methods are stored in this "data"
- * object. This object will be served as context for all these methods,
- * and it is possible to add other type of data in it.
- */
- data = {
- /**
- * SETTINGS FUNCTION:
- * ******************
- */
- settings: settings || _defaultSettingsFunction,
-
- /**
- * MAIN DATA:
- * **********
- */
- nodesArray: [],
- edgesArray: [],
-
- /**
- * GLOBAL INDEXES:
- * ***************
- * These indexes just index data by ids.
- */
- nodesIndex: Object.create(null),
- edgesIndex: Object.create(null),
-
- /**
- * LOCAL INDEXES:
- * **************
- * These indexes refer from node to nodes. Each key is an id, and each
- * value is the array of the ids of related nodes.
- */
- inNeighborsIndex: Object.create(null),
- outNeighborsIndex: Object.create(null),
- allNeighborsIndex: Object.create(null),
-
- inNeighborsCount: Object.create(null),
- outNeighborsCount: Object.create(null),
- allNeighborsCount: Object.create(null)
- };
-
- // Execute bindings:
- for (k in _initBindings)
- _initBindings[k].call(data);
-
- // Add methods to both the scope and the data objects:
- for (k in _methods) {
- fn = __bindGraphMethod(k, data, _methods[k]);
- this[k] = fn;
- data[k] = fn;
- }
- };
-
-
-
-
- /**
- * A custom tool to bind methods such that function that are bound to it will
- * be executed anytime the method is called.
- *
- * @param {string} methodName The name of the method to bind.
- * @param {object} scope The scope where the method must be executed.
- * @param {function} fn The method itself.
- * @return {function} The new method.
- */
- function __bindGraphMethod(methodName, scope, fn) {
- var result = function() {
- var k,
- res;
-
- // Execute "before" bound functions:
- for (k in _methodBeforeBindings[methodName])
- _methodBeforeBindings[methodName][k].apply(scope, arguments);
-
- // Apply the method:
- res = fn.apply(scope, arguments);
-
- // Execute bound functions:
- for (k in _methodBindings[methodName])
- _methodBindings[methodName][k].apply(scope, arguments);
-
- // Return res:
- return res;
- };
-
- return result;
- }
-
- /**
- * This custom tool function removes every pair key/value from an hash. The
- * goal is to avoid creating a new object while some other references are
- * still hanging in some scopes...
- *
- * @param {object} obj The object to empty.
- * @return {object} The empty object.
- */
- function __emptyObject(obj) {
- var k;
-
- for (k in obj)
- if (!('hasOwnProperty' in obj) || obj.hasOwnProperty(k))
- delete obj[k];
-
- return obj;
- }
-
-
-
-
- /**
- * This global method adds a method that will be bound to the futurly created
- * graph instances.
- *
- * Since these methods will be bound to their scope when the instances are
- * created, it does not use the prototype. Because of that, methods have to
- * be added before instances are created to make them available.
- *
- * Here is an example:
- *
- * > graph.addMethod('getNodesCount', function() {
- * > return this.nodesArray.length;
- * > });
- * >
- * > var myGraph = new graph();
- * > console.log(myGraph.getNodesCount()); // outputs 0
- *
- * @param {string} methodName The name of the method.
- * @param {function} fn The method itself.
- * @return {object} The global graph constructor.
- */
- graph.addMethod = function(methodName, fn) {
- if (
- typeof methodName !== 'string' ||
- typeof fn !== 'function' ||
- arguments.length !== 2
- )
- throw 'addMethod: Wrong arguments.';
-
- if (_methods[methodName] || graph[methodName])
- throw 'The method "' + methodName + '" already exists.';
-
- _methods[methodName] = fn;
- _methodBindings[methodName] = Object.create(null);
- _methodBeforeBindings[methodName] = Object.create(null);
-
- return this;
- };
-
- /**
- * This global method returns true if the method has already been added, and
- * false else.
- *
- * Here are some examples:
- *
- * > graph.hasMethod('addNode'); // returns true
- * > graph.hasMethod('hasMethod'); // returns true
- * > graph.hasMethod('unexistingMethod'); // returns false
- *
- * @param {string} methodName The name of the method.
- * @return {boolean} The result.
- */
- graph.hasMethod = function(methodName) {
- return !!(_methods[methodName] || graph[methodName]);
- };
-
- /**
- * This global methods attaches a function to a method. Anytime the specified
- * method is called, the attached function is called right after, with the
- * same arguments and in the same scope. The attached function is called
- * right before if the last argument is true, unless the method is the graph
- * constructor.
- *
- * To attach a function to the graph constructor, use 'constructor' as the
- * method name (first argument).
- *
- * The main idea is to have a clean way to keep custom indexes up to date,
- * for instance:
- *
- * > var timesAddNodeCalled = 0;
- * > graph.attach('addNode', 'timesAddNodeCalledInc', function() {
- * > timesAddNodeCalled++;
- * > });
- * >
- * > var myGraph = new graph();
- * > console.log(timesAddNodeCalled); // outputs 0
- * >
- * > myGraph.addNode({ id: '1' }).addNode({ id: '2' });
- * > console.log(timesAddNodeCalled); // outputs 2
- *
- * The idea for calling a function before is to provide pre-processors, for
- * instance:
- *
- * > var colorPalette = { Person: '#C3CBE1', Place: '#9BDEBD' };
- * > graph.attach('addNode', 'applyNodeColorPalette', function(n) {
- * > n.color = colorPalette[n.category];
- * > }, true);
- * >
- * > var myGraph = new graph();
- * > myGraph.addNode({ id: 'n0', category: 'Person' });
- * > console.log(myGraph.nodes('n0').color); // outputs '#C3CBE1'
- *
- * @param {string} methodName The name of the related method or
- * "constructor".
- * @param {string} key The key to identify the function to attach.
- * @param {function} fn The function to bind.
- * @param {boolean} before If true the function is called right before.
- * @return {object} The global graph constructor.
- */
- graph.attach = function(methodName, key, fn, before) {
- if (
- typeof methodName !== 'string' ||
- typeof key !== 'string' ||
- typeof fn !== 'function' ||
- arguments.length < 3 ||
- arguments.length > 4
- )
- throw 'attach: Wrong arguments.';
-
- var bindings;
-
- if (methodName === 'constructor')
- bindings = _initBindings;
- else {
- if (before) {
- if (!_methodBeforeBindings[methodName])
- throw 'The method "' + methodName + '" does not exist.';
-
- bindings = _methodBeforeBindings[methodName];
- }
- else {
- if (!_methodBindings[methodName])
- throw 'The method "' + methodName + '" does not exist.';
-
- bindings = _methodBindings[methodName];
- }
- }
-
- if (bindings[key])
- throw 'A function "' + key + '" is already attached ' +
- 'to the method "' + methodName + '".';
-
- bindings[key] = fn;
-
- return this;
- };
-
- /**
- * Alias of attach(methodName, key, fn, true).
- */
- graph.attachBefore = function(methodName, key, fn) {
- return this.attach(methodName, key, fn, true);
- };
-
- /**
- * This methods is just an helper to deal with custom indexes. It takes as
- * arguments the name of the index and an object containing all the different
- * functions to bind to the methods.
- *
- * Here is a basic example, that creates an index to keep the number of nodes
- * in the current graph. It also adds a method to provide a getter on that
- * new index:
- *
- * > sigma.classes.graph.addIndex('nodesCount', {
- * > constructor: function() {
- * > this.nodesCount = 0;
- * > },
- * > addNode: function() {
- * > this.nodesCount++;
- * > },
- * > dropNode: function() {
- * > this.nodesCount--;
- * > }
- * > });
- * >
- * > sigma.classes.graph.addMethod('getNodesCount', function() {
- * > return this.nodesCount;
- * > });
- * >
- * > var myGraph = new sigma.classes.graph();
- * > console.log(myGraph.getNodesCount()); // outputs 0
- * >
- * > myGraph.addNode({ id: '1' }).addNode({ id: '2' });
- * > console.log(myGraph.getNodesCount()); // outputs 2
- *
- * @param {string} name The name of the index.
- * @param {object} bindings The object containing the functions to bind.
- * @return {object} The global graph constructor.
- */
- graph.addIndex = function(name, bindings) {
- if (
- typeof name !== 'string' ||
- Object(bindings) !== bindings ||
- arguments.length !== 2
- )
- throw 'addIndex: Wrong arguments.';
-
- if (_indexes[name])
- throw 'The index "' + name + '" already exists.';
-
- var k;
-
- // Store the bindings:
- _indexes[name] = bindings;
-
- // Attach the bindings:
- for (k in bindings)
- if (typeof bindings[k] !== 'function')
- throw 'The bindings must be functions.';
- else
- graph.attach(k, name, bindings[k]);
-
- return this;
- };
-
-
-
-
- /**
- * This method adds a node to the graph. The node must be an object, with a
- * string under the key "id". Except for this, it is possible to add any
- * other attribute, that will be preserved all along the manipulations.
- *
- * If the graph option "clone" has a truthy value, the node will be cloned
- * when added to the graph. Also, if the graph option "immutable" has a
- * truthy value, its id will be defined as immutable.
- *
- * @param {object} node The node to add.
- * @return {object} The graph instance.
- */
- graph.addMethod('addNode', function(node) {
- // Check that the node is an object and has an id:
- if (Object(node) !== node || arguments.length !== 1)
- throw 'addNode: Wrong arguments.';
-
- if (typeof node.id !== 'string' && typeof node.id !== 'number')
- throw 'The node must have a string or number id.';
-
- if (this.nodesIndex[node.id])
- throw 'The node "' + node.id + '" already exists.';
-
- var k,
- id = node.id,
- validNode = Object.create(null);
-
- // Check the "clone" option:
- if (this.settings('clone')) {
- for (k in node)
- if (k !== 'id')
- validNode[k] = node[k];
- } else
- validNode = node;
-
- // Check the "immutable" option:
- if (this.settings('immutable'))
- Object.defineProperty(validNode, 'id', {
- value: id,
- enumerable: true
- });
- else
- validNode.id = id;
-
- // Add empty containers for edges indexes:
- this.inNeighborsIndex[id] = Object.create(null);
- this.outNeighborsIndex[id] = Object.create(null);
- this.allNeighborsIndex[id] = Object.create(null);
-
- this.inNeighborsCount[id] = 0;
- this.outNeighborsCount[id] = 0;
- this.allNeighborsCount[id] = 0;
-
- // Add the node to indexes:
- this.nodesArray.push(validNode);
- this.nodesIndex[validNode.id] = validNode;
-
- // Return the current instance:
- return this;
- });
-
- /**
- * This method adds an edge to the graph. The edge must be an object, with a
- * string under the key "id", and strings under the keys "source" and
- * "target" that design existing nodes. Except for this, it is possible to
- * add any other attribute, that will be preserved all along the
- * manipulations.
- *
- * If the graph option "clone" has a truthy value, the edge will be cloned
- * when added to the graph. Also, if the graph option "immutable" has a
- * truthy value, its id, source and target will be defined as immutable.
- *
- * @param {object} edge The edge to add.
- * @return {object} The graph instance.
- */
- graph.addMethod('addEdge', function(edge) {
- // Check that the edge is an object and has an id:
- if (Object(edge) !== edge || arguments.length !== 1)
- throw 'addEdge: Wrong arguments.';
-
- if (typeof edge.id !== 'string' && typeof edge.id !== 'number')
- throw 'The edge must have a string or number id.';
-
- if ((typeof edge.source !== 'string' && typeof edge.source !== 'number') ||
- !this.nodesIndex[edge.source])
- throw 'The edge source must have an existing node id.';
-
- if ((typeof edge.target !== 'string' && typeof edge.target !== 'number') ||
- !this.nodesIndex[edge.target])
- throw 'The edge target must have an existing node id.';
-
- if (this.edgesIndex[edge.id])
- throw 'The edge "' + edge.id + '" already exists.';
-
- var k,
- validEdge = Object.create(null);
-
- // Check the "clone" option:
- if (this.settings('clone')) {
- for (k in edge)
- if (k !== 'id' && k !== 'source' && k !== 'target')
- validEdge[k] = edge[k];
- } else
- validEdge = edge;
-
- // Check the "immutable" option:
- if (this.settings('immutable')) {
- Object.defineProperty(validEdge, 'id', {
- value: edge.id,
- enumerable: true
- });
-
- Object.defineProperty(validEdge, 'source', {
- value: edge.source,
- enumerable: true
- });
-
- Object.defineProperty(validEdge, 'target', {
- value: edge.target,
- enumerable: true
- });
- } else {
- validEdge.id = edge.id;
- validEdge.source = edge.source;
- validEdge.target = edge.target;
- }
-
- // Add the edge to indexes:
- this.edgesArray.push(validEdge);
- this.edgesIndex[validEdge.id] = validEdge;
-
- if (!this.inNeighborsIndex[validEdge.target][validEdge.source])
- this.inNeighborsIndex[validEdge.target][validEdge.source] =
- Object.create(null);
- this.inNeighborsIndex[validEdge.target][validEdge.source][validEdge.id] =
- validEdge;
-
- if (!this.outNeighborsIndex[validEdge.source][validEdge.target])
- this.outNeighborsIndex[validEdge.source][validEdge.target] =
- Object.create(null);
- this.outNeighborsIndex[validEdge.source][validEdge.target][validEdge.id] =
- validEdge;
-
- if (!this.allNeighborsIndex[validEdge.source][validEdge.target])
- this.allNeighborsIndex[validEdge.source][validEdge.target] =
- Object.create(null);
- this.allNeighborsIndex[validEdge.source][validEdge.target][validEdge.id] =
- validEdge;
-
- if (validEdge.target !== validEdge.source) {
- if (!this.allNeighborsIndex[validEdge.target][validEdge.source])
- this.allNeighborsIndex[validEdge.target][validEdge.source] =
- Object.create(null);
- this.allNeighborsIndex[validEdge.target][validEdge.source][validEdge.id] =
- validEdge;
- }
-
- // Keep counts up to date:
- this.inNeighborsCount[validEdge.target]++;
- this.outNeighborsCount[validEdge.source]++;
- this.allNeighborsCount[validEdge.target]++;
- this.allNeighborsCount[validEdge.source]++;
-
- return this;
- });
-
- /**
- * This method drops a node from the graph. It also removes each edge that is
- * bound to it, through the dropEdge method. An error is thrown if the node
- * does not exist.
- *
- * @param {string} id The node id.
- * @return {object} The graph instance.
- */
- graph.addMethod('dropNode', function(id) {
- // Check that the arguments are valid:
- if ((typeof id !== 'string' && typeof id !== 'number') ||
- arguments.length !== 1)
- throw 'dropNode: Wrong arguments.';
-
- if (!this.nodesIndex[id])
- throw 'The node "' + id + '" does not exist.';
-
- var i, k, l;
-
- // Remove the node from indexes:
- delete this.nodesIndex[id];
- for (i = 0, l = this.nodesArray.length; i < l; i++)
- if (this.nodesArray[i].id === id) {
- this.nodesArray.splice(i, 1);
- break;
- }
-
- // Remove related edges:
- for (i = this.edgesArray.length - 1; i >= 0; i--)
- if (this.edgesArray[i].source === id || this.edgesArray[i].target === id)
- this.dropEdge(this.edgesArray[i].id);
-
- // Remove related edge indexes:
- delete this.inNeighborsIndex[id];
- delete this.outNeighborsIndex[id];
- delete this.allNeighborsIndex[id];
-
- delete this.inNeighborsCount[id];
- delete this.outNeighborsCount[id];
- delete this.allNeighborsCount[id];
-
- for (k in this.nodesIndex) {
- delete this.inNeighborsIndex[k][id];
- delete this.outNeighborsIndex[k][id];
- delete this.allNeighborsIndex[k][id];
- }
-
- return this;
- });
-
- /**
- * This method drops an edge from the graph. An error is thrown if the edge
- * does not exist.
- *
- * @param {string} id The edge id.
- * @return {object} The graph instance.
- */
- graph.addMethod('dropEdge', function(id) {
- // Check that the arguments are valid:
- if ((typeof id !== 'string' && typeof id !== 'number') ||
- arguments.length !== 1)
- throw 'dropEdge: Wrong arguments.';
-
- if (!this.edgesIndex[id])
- throw 'The edge "' + id + '" does not exist.';
-
- var i, l, edge;
-
- // Remove the edge from indexes:
- edge = this.edgesIndex[id];
- delete this.edgesIndex[id];
- for (i = 0, l = this.edgesArray.length; i < l; i++)
- if (this.edgesArray[i].id === id) {
- this.edgesArray.splice(i, 1);
- break;
- }
-
- delete this.inNeighborsIndex[edge.target][edge.source][edge.id];
- if (!Object.keys(this.inNeighborsIndex[edge.target][edge.source]).length)
- delete this.inNeighborsIndex[edge.target][edge.source];
-
- delete this.outNeighborsIndex[edge.source][edge.target][edge.id];
- if (!Object.keys(this.outNeighborsIndex[edge.source][edge.target]).length)
- delete this.outNeighborsIndex[edge.source][edge.target];
-
- delete this.allNeighborsIndex[edge.source][edge.target][edge.id];
- if (!Object.keys(this.allNeighborsIndex[edge.source][edge.target]).length)
- delete this.allNeighborsIndex[edge.source][edge.target];
-
- if (edge.target !== edge.source) {
- delete this.allNeighborsIndex[edge.target][edge.source][edge.id];
- if (!Object.keys(this.allNeighborsIndex[edge.target][edge.source]).length)
- delete this.allNeighborsIndex[edge.target][edge.source];
- }
-
- this.inNeighborsCount[edge.target]--;
- this.outNeighborsCount[edge.source]--;
- this.allNeighborsCount[edge.source]--;
- this.allNeighborsCount[edge.target]--;
-
- return this;
- });
-
- /**
- * This method destroys the current instance. It basically empties each index
- * and methods attached to the graph.
- */
- graph.addMethod('kill', function() {
- // Delete arrays:
- this.nodesArray.length = 0;
- this.edgesArray.length = 0;
- delete this.nodesArray;
- delete this.edgesArray;
-
- // Delete indexes:
- delete this.nodesIndex;
- delete this.edgesIndex;
- delete this.inNeighborsIndex;
- delete this.outNeighborsIndex;
- delete this.allNeighborsIndex;
- delete this.inNeighborsCount;
- delete this.outNeighborsCount;
- delete this.allNeighborsCount;
- });
-
- /**
- * This method empties the nodes and edges arrays, as well as the different
- * indexes.
- *
- * @return {object} The graph instance.
- */
- graph.addMethod('clear', function() {
- this.nodesArray.length = 0;
- this.edgesArray.length = 0;
-
- // Due to GC issues, I prefer not to create new object. These objects are
- // only available from the methods and attached functions, but still, it is
- // better to prevent ghost references to unrelevant data...
- __emptyObject(this.nodesIndex);
- __emptyObject(this.edgesIndex);
- __emptyObject(this.nodesIndex);
- __emptyObject(this.inNeighborsIndex);
- __emptyObject(this.outNeighborsIndex);
- __emptyObject(this.allNeighborsIndex);
- __emptyObject(this.inNeighborsCount);
- __emptyObject(this.outNeighborsCount);
- __emptyObject(this.allNeighborsCount);
-
- return this;
- });
-
- /**
- * This method reads an object and adds the nodes and edges, through the
- * proper methods "addNode" and "addEdge".
- *
- * Here is an example:
- *
- * > var myGraph = new graph();
- * > myGraph.read({
- * > nodes: [
- * > { id: 'n0' },
- * > { id: 'n1' }
- * > ],
- * > edges: [
- * > {
- * > id: 'e0',
- * > source: 'n0',
- * > target: 'n1'
- * > }
- * > ]
- * > });
- * >
- * > console.log(
- * > myGraph.nodes().length,
- * > myGraph.edges().length
- * > ); // outputs 2 1
- *
- * @param {object} g The graph object.
- * @return {object} The graph instance.
- */
- graph.addMethod('read', function(g) {
- var i,
- a,
- l;
-
- a = g.nodes || [];
- for (i = 0, l = a.length; i < l; i++)
- this.addNode(a[i]);
-
- a = g.edges || [];
- for (i = 0, l = a.length; i < l; i++)
- this.addEdge(a[i]);
-
- return this;
- });
-
- /**
- * This methods returns one or several nodes, depending on how it is called.
- *
- * To get the array of nodes, call "nodes" without argument. To get a
- * specific node, call it with the id of the node. The get multiple node,
- * call it with an array of ids, and it will return the array of nodes, in
- * the same order.
- *
- * @param {?(string|array)} v Eventually one id, an array of ids.
- * @return {object|array} The related node or array of nodes.
- */
- graph.addMethod('nodes', function(v) {
- // Clone the array of nodes and return it:
- if (!arguments.length)
- return this.nodesArray.slice(0);
-
- // Return the related node:
- if (arguments.length === 1 &&
- (typeof v === 'string' || typeof v === 'number'))
- return this.nodesIndex[v];
-
- // Return an array of the related node:
- if (
- arguments.length === 1 &&
- Object.prototype.toString.call(v) === '[object Array]'
- ) {
- var i,
- l,
- a = [];
-
- for (i = 0, l = v.length; i < l; i++)
- if (typeof v[i] === 'string' || typeof v[i] === 'number')
- a.push(this.nodesIndex[v[i]]);
- else
- throw 'nodes: Wrong arguments.';
-
- return a;
- }
-
- throw 'nodes: Wrong arguments.';
- });
-
- /**
- * This methods returns the degree of one or several nodes, depending on how
- * it is called. It is also possible to get incoming or outcoming degrees
- * instead by specifying 'in' or 'out' as a second argument.
- *
- * @param {string|array} v One id, an array of ids.
- * @param {?string} which Which degree is required. Values are 'in',
- * 'out', and by default the normal degree.
- * @return {number|array} The related degree or array of degrees.
- */
- graph.addMethod('degree', function(v, which) {
- // Check which degree is required:
- which = {
- 'in': this.inNeighborsCount,
- 'out': this.outNeighborsCount
- }[which || ''] || this.allNeighborsCount;
-
- // Return the related node:
- if (typeof v === 'string' || typeof v === 'number')
- return which[v];
-
- // Return an array of the related node:
- if (Object.prototype.toString.call(v) === '[object Array]') {
- var i,
- l,
- a = [];
-
- for (i = 0, l = v.length; i < l; i++)
- if (typeof v[i] === 'string' || typeof v[i] === 'number')
- a.push(which[v[i]]);
- else
- throw 'degree: Wrong arguments.';
-
- return a;
- }
-
- throw 'degree: Wrong arguments.';
- });
-
- /**
- * This methods returns one or several edges, depending on how it is called.
- *
- * To get the array of edges, call "edges" without argument. To get a
- * specific edge, call it with the id of the edge. The get multiple edge,
- * call it with an array of ids, and it will return the array of edges, in
- * the same order.
- *
- * @param {?(string|array)} v Eventually one id, an array of ids.
- * @return {object|array} The related edge or array of edges.
- */
- graph.addMethod('edges', function(v) {
- // Clone the array of edges and return it:
- if (!arguments.length)
- return this.edgesArray.slice(0);
-
- // Return the related edge:
- if (arguments.length === 1 &&
- (typeof v === 'string' || typeof v === 'number'))
- return this.edgesIndex[v];
-
- // Return an array of the related edge:
- if (
- arguments.length === 1 &&
- Object.prototype.toString.call(v) === '[object Array]'
- ) {
- var i,
- l,
- a = [];
-
- for (i = 0, l = v.length; i < l; i++)
- if (typeof v[i] === 'string' || typeof v[i] === 'number')
- a.push(this.edgesIndex[v[i]]);
- else
- throw 'edges: Wrong arguments.';
-
- return a;
- }
-
- throw 'edges: Wrong arguments.';
- });
-
-
- /**
- * EXPORT:
- * *******
- */
- if (typeof sigma !== 'undefined') {
- sigma.classes = sigma.classes || Object.create(null);
- sigma.classes.graph = graph;
- } else if (typeof exports !== 'undefined') {
- if (typeof module !== 'undefined' && module.exports)
- exports = module.exports = graph;
- exports.graph = graph;
- } else
- this.graph = graph;
- }).call(this);
|