Index: Orange/OrangeWidgets/OWNxHist.py
===================================================================
--- Orange/OrangeWidgets/OWNxHist.py	(revision 10516)
+++ Orange/OrangeWidgets/OWNxHist.py	(revision 10499)
@@ -30,9 +30,6 @@
         self.andor = 0
         self.matrix = None
-        self.excludeLimit = 2
+        self.excludeLimit = 1
         self.percentil = 0
-
-        self.graph = None
-        self.graph_matrix = None
 
         if parent is None:
@@ -61,5 +58,5 @@
         hb = OWGUI.widgetBox(ribg, None, orientation="horizontal", addSpace=False)
         OWGUI.appendRadioButton(ribg, self, "netOption", "Large components only. Min nodes:", insertInto=hb, callback=self.generateGraph)
-        OWGUI.spin(hb, self, "excludeLimit", 2, 100, 1, callback=(lambda h=True: self.generateGraph(h)))
+        OWGUI.spin(hb, self, "excludeLimit", 1, 100, 1, callback=(lambda h=True: self.generateGraph(h)))
         OWGUI.appendRadioButton(ribg, self, "netOption", "Largest connected component only", callback=self.generateGraph)
         OWGUI.appendRadioButton(ribg, self, "netOption", "Connected component with vertex")
@@ -81,7 +78,4 @@
 
     def setPercentil(self):
-        if self.matrix is None or self.percentil <= 0:
-            return
-
         self.spinLowerThreshold = self.histogram.minValue
         # flatten matrix, sort values and remove identities (self.matrix[i][i])
@@ -100,7 +94,4 @@
     def setMatrix(self, data):
         if data == None: return
-
-        if not hasattr(data, "items") or data.items is None:
-            setattr(data, "items", [i for i in range(data.dim)])
 
         self.matrix = data
@@ -114,5 +105,5 @@
         upp = max(values)
         self.spinLowerThreshold = self.spinUpperThreshold = math.floor(low - (0.03 * (upp - low)))
-
+        self.generateGraph()
         self.attributeCombo.clear()
         vars = []
@@ -134,7 +125,4 @@
             except:
                 print "error adding ", var, " to the attribute combo"
-
-        self.setPercentil()
-        self.generateGraph()
 
     def changeLowerSpin(self):
@@ -192,5 +180,5 @@
             matrix = self.matrix
 
-            if hasattr(self.matrix, "items") and self.matrix.items is not None:
+            if hasattr(self.matrix, "items"):
                 if type(self.matrix.items) == Orange.data.Table:
                     graph.set_items(self.matrix.items)
@@ -214,5 +202,5 @@
             # exclude unconnected
             if str(self.netOption) == '1':
-                components = [x for x in Orange.network.nx.algorithms.components.connected_components(graph) if len(x) >= self.excludeLimit]
+                components = [x for x in Orange.network.nx.algorithms.components.connected_components(graph) if len(x) > self.excludeLimit]
                 if len(components) > 0:
                     include = reduce(lambda x, y: x + y, components)
@@ -230,5 +218,5 @@
                 component = Orange.network.nx.algorithms.components.connected_components(graph)[0]
                 if len(component) > 1:
-                    self.graph = graph.subgraph(component)
+                    self.graph = graph.subgraph(include)
                     matrix = self.matrix.getitems(component)
                 else:
Index: Orange/OrangeWidgets/Prototypes/OWBR.py
===================================================================
--- Orange/OrangeWidgets/Prototypes/OWBR.py	(revision 10502)
+++ Orange/OrangeWidgets/Prototypes/OWBR.py	(revision 9671)
@@ -59,6 +59,5 @@
 
         if not Orange.multilabel.is_multilabel(data):
-            self.warning(0, "Multi-label data with class values 0 and 1 is "
-                            "expected on the input.")
+            self.warning(0, "Multi-label data is expected on the input.")
             return
         self.warning(0, None)
Index: Orange/OrangeWidgets/Prototypes/OWBRkNN.py
===================================================================
--- Orange/OrangeWidgets/Prototypes/OWBRkNN.py	(revision 10502)
+++ Orange/OrangeWidgets/Prototypes/OWBRkNN.py	(revision 9671)
@@ -63,6 +63,5 @@
 
         if not Orange.multilabel.is_multilabel(data):
-            self.warning(0, "Multi-label data with class values 0 and 1 is "
-                            "expected on the input.")
+            self.warning(0, "Multi-label data is expected on the input.")
             return
         self.warning(0, None)
Index: range/OrangeWidgets/Prototypes/OWCSVFileImport.py
===================================================================
--- Orange/OrangeWidgets/Prototypes/OWCSVFileImport.py	(revision 10529)
+++ 	(revision )
@@ -1,310 +1,0 @@
-"""
-<name>CSV File import</name>
-<description>Import .csv file</description>
-
-"""
-import os
-import csv
-from StringIO import StringIO
-
-from PyQt4 import QtCore, QtGui
-
-from OWWidget import *
-import OWGUI
-import Orange
-
-#from OWFile import FileNameContextHandler as PathContextHandler
-from OWDataTable import ExampleTableModel
-
-DEFAULT_OPTIONS = {"delimiter":",", 
-                   "quote":"'", 
-                   "has_header": True,
-                   "has_orange_definitions": False,
-                   }
-
-Slot = pyqtSlot
-
-class standard_icons(object):
-    def __init__(self, qwidget=None, style=None):
-        self.qwidget = qwidget
-        if qwidget is None:
-            self.style = QApplication.instance().style()
-        else:
-            self.style = qwidget.style()
-    
-    @property
-    def dir_open_icon(self):
-        return self.style.standardIcon(QStyle.SP_DirOpenIcon)
-    
-    @property
-    def reload_icon(self):
-        return self.style.standardIcon(QStyle.SP_BrowserReload)
-    
-    
-            
-            
-class OWCSVFileImport(OWWidget):
-#    contextHandlers = {"": PathContextHandler("")}
-    settingsList = ["recent_files"]
-    
-    DELIMITERS = [("Tab", "\t"),
-                  ("Comma", ","),
-                  ("Semicolon", ";"),
-                  ("Space", " "),
-                  ("Others", None),
-                  ]
-    def __init__(self, parent=None, signalManager=None, 
-                 title="CSV File Import"):
-        
-        OWWidget.__init__(self, parent, signalManager, title, 
-                          wantMainArea=False)
-        
-        self.inputs = []
-        self.outputs = [("Data", Orange.data.Table)]
-        
-        # Settings
-        self.delimiter = ","
-        self.quote = '"'
-        
-        self.has_header = True
-        self.has_orange_header = True
-        
-        self.recent_files = []
-        self.hints = {}
-        
-        self.loadSettings()
-        
-        self.recent_file = filter(os.path.exists, self.recent_files)
-        
-        self.csv_options = dict(DEFAULT_OPTIONS)
-        
-        layout = QHBoxLayout()
-        box = OWGUI.widgetBox(self.controlArea, "File", orientation=layout)
-        self.style().standardIcon(QStyle.SP_DirOpenIcon)
-        icons = standard_icons(self)
-        
-        self.recent_combo = QComboBox(self, objectName="recent_combo",
-                                      toolTip="Recent files.",
-                                      activated=self.on_select_recent)
-        self.recent_combo.addItems([os.path.basename(p) for p in self.recent_files])
-        
-        self.browse_button = QPushButton("...", icon=icons.dir_open_icon,
-                                         toolTip="Browse filesystem",
-                                         clicked=self.on_open_dialog)
-        
-#        self.reload_button = QPushButton("Reload", icon=icons.reload_icon,
-#                                         clicked=self.reload_file)
-        
-        layout.addWidget(self.recent_combo, 2)
-        layout.addWidget(self.browse_button)
-#        layout.addWidget(self.reload_button)
-
-        form_left = QFormLayout()
-        form_right = QFormLayout()
-        h_layout = QHBoxLayout()
-        grid_layout = QGridLayout()
-        grid_layout.setVerticalSpacing(4)
-        grid_layout.setHorizontalSpacing(4)
-        box = OWGUI.widgetBox(self.controlArea, "Cell Separator",
-                              orientation=grid_layout)
-        
-        button_group = QButtonGroup(box)
-        QObject.connect(button_group, 
-                        SIGNAL("buttonPressed(int)"),
-                        self.delimiter_changed)
-#        button_group.buttonPressed.connect(self.delimiter_changed)
-        
-        for i, (name, char) in  enumerate(self.DELIMITERS[:-1]):
-            button = QRadioButton(name, box,
-                                  toolTip="Use %r as cell separator" % char)
-            
-            button_group.addButton(button, i)
-            grid_layout.addWidget(button, i / 3, i % 3)
-            
-        button = QRadioButton("Other", box,
-                              toolTip="Use other character")
-        
-        button_group.addButton(button, i + 1)
-        grid_layout.addWidget(button, i / 3 + 1, 0)
-        self.delimiter_button_group = button_group
-            
-        self.delimiter_edit = QLineEdit(objectName="delimiter_edit",
-                                        text=self.delimiter,
-                                        editingFinished=self.delimiter_changed,
-                                        toolTip="Cell delimiter character.")
-        grid_layout.addWidget(self.delimiter_edit, i / 3 + 1, 1, -1, -1)
-        
-        self.quote_edit = QLineEdit(objectName="quote_edit",
-                                    text=self.quote,
-                                    editingFinished=self.quote_changed,
-                                    toolTip="Text quote character.")
-        
-        form = QFormLayout()
-        box = OWGUI.widgetBox(self.controlArea, "Other Options",
-                              orientation=form)
-        
-#        form_left.addRow("Delimiter", self.delimiter_edit)
-        form.addRow("Quote", self.quote_edit)
-        
-        self.has_header_check = \
-                QCheckBox(objectName="has_header_check",
-                          checked=self.has_header,
-                          text="Header line",
-                          toolTip="Use the first line as a header",
-                          toggled=self.has_header_changed
-                          )
-        
-        form.addRow(self.has_header_check)
-        
-        self.has_orange_header_check = \
-                QCheckBox(objectName="has_orange_header_check",
-                          checked=self.has_orange_header,
-                          text="Has orange variable type definitions",
-                          toolTip="Use second and third line as a orange style '.tab' format feature definitions.",
-                          toggled=self.has_orange_header_changed
-                          )
-                
-        form.addRow(self.has_orange_header_check)
-        
-        box = OWGUI.widgetBox(self.controlArea, "Preview")
-        self.preview_view = QTableView()
-        box.layout().addWidget(self.preview_view)
-        
-        OWGUI.button(self.controlArea, self, "Send", callback=self.send_data)
-        
-        self.selected_file = None
-        self.data = None
-        
-        self.resize(400, 350)
-        
-    def on_select_recent(self, recent):
-        if isinstance(recent, int):
-            recent = self.recent_files[recent]
-        
-        self.set_selected_file(recent)
-    
-    def on_open_dialog(self): 
-        last = os.path.expanduser("~/Documents")
-        path = QFileDialog.getOpenFileName(self, "Open File", last)
-        path = unicode(path)
-        if path:
-            basedir, name = os.path.split(path)
-            self.recent_combo.insertItem(0, name)
-            self.recent_files.insert(0, path)
-            self.set_selected_file(path)
-    
-    @Slot(int)
-    def delimiter_changed(self, index):
-        self.delimiter = self.DELIMITERS[index][1]
-        if self.delimiter is None:
-            self.other_delimiter = str(self.delimiter_edit.text())
-        self.update_preview()
-    
-    def quote_changed(self):
-        if self.quote_edit.text():
-            self.quote = str(self.quote_edit.text())
-            self.update_preview()
-            
-    def has_header_changed(self):
-        self.has_header = self.has_header_check.isChecked()
-        self.update_preview()
-        
-    def has_orange_header_changed(self):
-        self.has_orange_header = self.has_orange_header_check.isChecked()
-        self.update_preview()
-            
-    def set_selected_file(self, filename):
-        if filename in self.hints:
-            hints = self.hints[filename]
-        else:
-            hints = sniff_csv(filename)
-            self.hints[filename] = hints
-        
-        delimiter = hints["delimiter"]
-        preset = [d[1] for d in self.DELIMITERS[:-1]]
-        if delimiter not in preset:
-            self.delimiter = None
-            self.other_delimiter = delimiter
-            self.delimiter_edit.setText(self.other_delimiter)
-            self.delimiter_edit.setEnabled(True)
-        else:
-            index = preset.index(delimiter)
-            button = self.delimiter_button_group.button(index)
-            button.setChecked(True)
-            self.delimiter_edit.setEnabled(False)
-        
-        self.quote = hints["quotechar"]
-        self.quote_edit.setText(self.quote)
-        
-        self.has_header = hints["has_header"]
-        self.has_header_check.setChecked(self.has_header)
-        
-        self.has_orange_header = hints["has_orange_header"]
-        self.has_orange_header_check.setChecked(self.has_orange_header)
-        
-        self.selected_file = filename
-        self.selected_file_head = []
-        with open(self.selected_file, "rb") as f:
-            for i, line in zip(range(30), f):
-                self.selected_file_head.append(line)
-        
-        self.update_preview()
-        
-    def update_preview(self):
-        if self.selected_file:
-            head = StringIO("".join(self.selected_file_head))
-            hints = self.hints[self.selected_file]
-            
-            hints["quote"] = self.quote
-            hints["delimiter"] = self.delimiter or self.other_delimiter
-            hints["has_header"] = self.has_header
-            hints["has_orange_header"] = self.has_orange_header 
-            
-            try:
-                data = Orange.data.io.load_csv(head, delimiter=self.delimiter,
-                                               quotechar=self.quote,
-                                               has_header=self.has_header,
-                                               has_types=self.has_orange_header,
-                                               has_annotations=self.has_orange_header,
-                                               )
-            except Exception, ex:
-                self.error(0, "Cannot parse (%r)" % ex)
-                self.data = None
-                return
-            model = ExampleTableModel(data, None, self)
-            self.preview_view.setModel(model)
-            self.data = data
-            
-    def send_data(self):
-        self.send("Data", self.data)
-        
-        
-def sniff_csv(file):
-    snifer = csv.Sniffer()
-    if isinstance(file, basestring):
-        file = open(file, "rb")
-    
-    sample = file.read(2 ** 20) # max 1MB sample
-    dialect = snifer.sniff(sample)
-    has_header = snifer.has_header(sample)
-    
-    return {"delimiter": dialect.delimiter,
-            "doublequote": dialect.doublequote,
-            "escapechar": dialect.escapechar,
-            "quotechar": dialect.quotechar,
-            "quoting": dialect.quoting,
-            "skipinitialspace": dialect.skipinitialspace,
-            "has_header": has_header,
-            "has_orange_header": False}
-    
-if __name__ == "__main__":
-    import sys
-    app = QApplication(sys.argv)
-    w = OWCSVFileImport()
-    w.show()
-    app.exec_()
-    w.saveSettings()
-        
-        
-        
-        
Index: Orange/OrangeWidgets/Prototypes/OWLP.py
===================================================================
--- Orange/OrangeWidgets/Prototypes/OWLP.py	(revision 10502)
+++ Orange/OrangeWidgets/Prototypes/OWLP.py	(revision 9671)
@@ -59,6 +59,5 @@
 
         if not Orange.multilabel.is_multilabel(data):
-            self.warning(0, "Multi-label data with class values 0 and 1 is "
-                            "expected on the input.")
+            self.warning(0, "Multi-label data is expected on the input.")
             return
         self.warning(0, None)
Index: Orange/OrangeWidgets/Prototypes/OWMLkNN.py
===================================================================
--- Orange/OrangeWidgets/Prototypes/OWMLkNN.py	(revision 10502)
+++ Orange/OrangeWidgets/Prototypes/OWMLkNN.py	(revision 9671)
@@ -72,6 +72,5 @@
 
         if not Orange.multilabel.is_multilabel(data):
-            self.warning(0, "Multi-label data with class values 0 and 1 is "
-                            "expected on the input.")
+            self.warning(0, "Multi-label data is expected on the input.")
             return
         self.warning(0, None)
Index: Orange/OrangeWidgets/Unsupervised/OWNetClustering.py
===================================================================
--- Orange/OrangeWidgets/Unsupervised/OWNetClustering.py	(revision 9671)
+++ Orange/OrangeWidgets/Unsupervised/OWNetClustering.py	(revision 9671)
@@ -0,0 +1,49 @@
+"""
+THIS WIDGET IS OBSOLETE; USE OWNxClustering.py
+"""
+
+import orange
+import orngNetwork
+import OWGUI
+
+from OWWidget import *
+
+class OWNetClustering(OWWidget):
+    
+    settingsList = ['method', 'iterationHistory', "autoApply"]
+    
+    def __init__(self, parent=None, signalManager=None):
+        OWWidget.__init__(self, parent, signalManager, 'Network Clustering')
+        
+        self.inputs = [("Network", orngNetwork.Network, self.setNetwork, Default)]
+        self.outputs = [("Network", orngNetwork.Network)]
+        
+        self.net = None
+        self.method = 0
+        self.iterationHistory = 0
+        self.autoApply = 0
+        
+        self.loadSettings()
+        
+        ribg = OWGUI.radioButtonsInBox(self.controlArea, self, "method", [], "Method", callback = self.cluster)
+        OWGUI.appendRadioButton(ribg, self, "method", "Label propagation clustering (Raghavan et al., 2007)", callback = self.cluster)
+        OWGUI.checkBox(OWGUI.indentedBox(ribg), self, "iterationHistory", "Append clustering data on each iteration", callback = self.cluster)
+        self.info = OWGUI.widgetLabel(self.controlArea, ' ')
+        autoApplyCB = OWGUI.checkBox(self.controlArea, self, "autoApply", "Commit automatically")
+        OWGUI.button(self.controlArea, self, "Commit", callback=self.cluster)
+        
+    def setNetwork(self, net):
+        self.net = net
+        if self.autoApply:
+            self.cluster()
+        
+    def cluster(self):
+        self.info.setText(' ')
+        
+        if self.net == None:
+            self.send("Network", None)
+            return
+        
+        labels = self.net.clustering.labelPropagation(results2items=1, resultHistory2items=self.iterationHistory)
+        self.info.setText('%d clusters found' % len(set(labels)))        
+        self.send("Network", self.net)
Index: Orange/OrangeWidgets/Unsupervised/OWNetExplorer.py
===================================================================
--- Orange/OrangeWidgets/Unsupervised/OWNetExplorer.py	(revision 10466)
+++ Orange/OrangeWidgets/Unsupervised/OWNetExplorer.py	(revision 10466)
@@ -0,0 +1,1791 @@
+"""
+THIS WIDGET IS OBSOLETE; USE OWNxExplorer.py
+"""
+import orange
+import OWGUI
+import OWColorPalette
+import orngNetwork
+import OWToolbars
+import math
+import operator
+import orngMDS
+
+from OWWidget import *
+from OWNetworkCanvas import *
+from time import *
+from statc import mean
+from operator import itemgetter
+
+dir = os.path.dirname(__file__) + "/../icons/"
+dlg_mark2sel = dir + "Dlg_Mark2Sel.png"
+dlg_sel2mark = dir + "Dlg_Sel2Mark.png"
+dlg_selIsmark = dir + "Dlg_SelisMark.png"
+dlg_selected = dir + "Dlg_SelectedNodes.png"
+dlg_unselected = dir + "Dlg_UnselectedNodes.png"
+dlg_showall = dir + "Dlg_clear.png"
+
+class OWNetExplorer(OWWidget):
+    settingsList = ["autoSendSelection", "spinExplicit", "spinPercentage",
+    "maxLinkSize", "minVertexSize", "maxVertexSize", "renderAntialiased",
+    "invertSize", "optMethod", "lastVertexSizeColumn", "lastColorColumn",
+    "lastNameComponentAttribute", "lastLabelColumns", "lastTooltipColumns",
+    "showWeights", "showIndexes",  "showEdgeLabels", "colorSettings", 
+    "selectedSchemaIndex", "edgeColorSettings", "selectedEdgeSchemaIndex",
+    "showMissingValues", "fontSize", "mdsTorgerson", "mdsAvgLinkage",
+    "mdsSteps", "mdsRefresh", "mdsStressDelta", "organism","showTextMiningInfo", 
+    "toolbarSelection", "minComponentEdgeWidth", "maxComponentEdgeWidth",
+    "mdsFromCurrentPos", "labelsOnMarkedOnly", "tabIndex"] 
+    
+    def __init__(self, parent=None, signalManager=None, name = 'Net Explorer', 
+                 NetworkCanvas=OWNetworkCanvas):
+        OWWidget.__init__(self, parent, signalManager, name)
+        #self.contextHandlers = {"": DomainContextHandler("", [ContextField("attributes", selected="markerAttributes"), ContextField("attributes", selected="tooltipAttributes"), "color"])}
+        self.inputs = [("Network", orngNetwork.Network, self.setGraph, Default), 
+                       ("Items", orange.ExampleTable, self.setItems),
+                       ("Marked Items", orange.ExampleTable, self.markItems), 
+                       ("Item Subset", orange.ExampleTable, self.setExampleSubset), 
+                       ("Vertex Distance", orange.SymMatrix, self.setVertexDistance)]
+        
+        self.outputs = [("Selected Network", orngNetwork.Network),
+                        ("Selected Distance Matrix", orange.SymMatrix),
+                        ("Selected Data", ExampleTable), 
+                        ("Other Data", ExampleTable), 
+                        ("Marked Data", ExampleTable),
+                        ("Features", AttributeList)]
+        
+        self.markerAttributes = []
+        self.tooltipAttributes = []
+        self.edgeLabelAttributes = []
+        self.attributes = []
+        self.edgeAttributes = []
+        self.autoSendSelection = False
+        self.graphShowGrid = 1  # show gridlines in the graph
+        
+        self.markNConnections = 2
+        self.markNumber = 0
+        self.markProportion = 0
+        self.markSearchString = ""
+        self.markDistance = 2
+        self.frSteps = 1
+        self.hubs = 0
+        self.color = 0
+        self.edgeColor = 0
+        self.vertexSize = 0
+        self.nVertices = self.nShown = self.nHidden = self.nMarked = self.nSelected = self.nEdges = self.verticesPerEdge = self.edgesPerVertex = self.diameter = self.clustering_coefficient = 0
+        self.optimizeWhat = 1
+        self.stopOptimization = 0
+        self.maxLinkSize = 3
+        self.maxVertexSize = 5
+        self.minVertexSize = 5
+        self.renderAntialiased = 1
+        self.labelsOnMarkedOnly = 0
+        self.invertSize = 0
+        self.optMethod = 0
+        self.lastVertexSizeColumn = ''
+        self.lastColorColumn = ''
+        self.lastNameComponentAttribute = ''
+        self.lastLabelColumns = set()
+        self.lastTooltipColumns = set()
+        self.showWeights = 0
+        self.showIndexes = 0
+        self.showEdgeLabels = 0
+        self.colorSettings = None
+        self.selectedSchemaIndex = 0
+        self.edgeColorSettings = [('net_edges', [[], [('contPalette', (4294967295L, 4278190080L, 0))], [('discPalette', [(204, 204, 204), (179, 226, 205), (253, 205, 172), (203, 213, 232), (244, 202, 228), (230, 245, 201), (255, 242, 174), (241, 226, 204)])]]), ('Default', [[], [('contPalette', (4294967295L, 4278190080L, 0))], [('discPalette', [(0, 0, 255), (255, 0, 0), (0, 255, 0), (255, 128, 0), (255, 255, 0), (255, 0, 255), (0, 255, 255), (128, 0, 255), (0, 128, 255), (255, 223, 128), (127, 111, 64), (92, 46, 0), (0, 84, 0), (192, 192, 0), (0, 127, 127), (128, 0, 0), (127, 0, 127)])]])]
+        self.selectedEdgeSchemaIndex = 0
+        self.vertexDistance = None
+        self.showDistances = 0
+        self.showMissingValues = 0
+        self.fontSize = 12
+        self.mdsTorgerson = 0
+        self.mdsAvgLinkage = 0
+        self.mdsSteps = 120
+        self.mdsRefresh = 30
+        self.mdsStressDelta = 0.00001
+        self.organism = 'goa_human'
+        self.showTextMiningInfo = 0
+        self.toolbarSelection = 0
+        self.minComponentEdgeWidth = 0
+        self.maxComponentEdgeWidth = 0
+        self.mdsFromCurrentPos = 0
+        self.tabIndex = 0
+        
+        self.loadSettings()
+        
+        self.optimization = None
+        self.markInputItems = None
+        
+        self.mainArea.layout().setContentsMargins(0,4,4,4)
+        self.controlArea.layout().setContentsMargins(4,4,0,4)
+        
+        self.networkCanvas = NetworkCanvas(self, self.mainArea, "Net Explorer")
+        self.networkCanvas.showMissingValues = self.showMissingValues
+        self.mainArea.layout().addWidget(self.networkCanvas)
+        
+        self.networkCanvas.maxLinkSize = self.maxLinkSize
+        self.networkCanvas.minVertexSize = self.minVertexSize
+        self.networkCanvas.maxVertexSize = self.maxVertexSize
+        
+        self.hcontroArea = OWGUI.widgetBox(self.controlArea, orientation='horizontal')
+        
+        self.tabs = OWGUI.tabWidget(self.hcontroArea)
+        self.connect(self.tabs, SIGNAL("currentChanged(int)"), self.currentTabChanged)
+        
+        self.verticesTab = OWGUI.createTabPage(self.tabs, "Vertices")
+        self.edgesTab = OWGUI.createTabPage(self.tabs, "Edges")
+        self.markTab = OWGUI.createTabPage(self.tabs, "Mark")
+        self.infoTab = OWGUI.createTabPage(self.tabs, "Info")
+        #self.editTab = OWGUI.createTabPage(self.tabs, "Edit")
+        
+
+        self.optimizeBox = OWGUI.radioButtonsInBox(self.verticesTab, self, "optimizeWhat", [], "Optimize", addSpace=False)
+        
+        self.optCombo = OWGUI.comboBox(self.optimizeBox, self, "optMethod", label='Method:     ', orientation='horizontal', callback=self.setOptMethod)
+        self.optCombo.addItem("No optimization")
+        self.optCombo.addItem("Random")
+        self.optCombo.addItem("Fruchterman Reingold")
+        self.optCombo.addItem("Fruchterman Reingold Weighted")
+        self.optCombo.addItem("Fruchterman Reingold Radial")
+        self.optCombo.addItem("Circular Crossing Reduction")
+        self.optCombo.addItem("Circular Original")
+        self.optCombo.addItem("Circular Random")
+        self.optCombo.addItem("Pivot MDS")
+        self.optCombo.setCurrentIndex(self.optMethod)
+        self.stepsSpin = OWGUI.spin(self.optimizeBox, self, "frSteps", 1, 100000, 1, label="Iterations: ")
+        self.stepsSpin.setEnabled(False)
+        
+        self.optButton = OWGUI.button(self.optimizeBox, self, "Optimize layout", callback=self.optLayout, toggleButton=1)
+        
+        colorBox = OWGUI.widgetBox(self.verticesTab, "Vertex color attribute", orientation="horizontal", addSpace = False)
+        self.colorCombo = OWGUI.comboBox(colorBox, self, "color", callback=self.setVertexColor)
+        self.colorCombo.addItem("(same color)")
+        OWGUI.button(colorBox, self, "Set vertex color palette", self.setColors, tooltip = "Set vertex color palette", debuggingEnabled = 0)
+        
+        self.vertexSizeCombo = OWGUI.comboBox(self.verticesTab, self, "vertexSize", box = "Vertex size attribute", callback=self.setVertexSize)
+        self.vertexSizeCombo.addItem("(none)")
+        
+        OWGUI.spin(self.vertexSizeCombo.box, self, "minVertexSize", 5, 200, 1, label="Min vertex size:", callback = self.setVertexSize)
+        OWGUI.spin(self.vertexSizeCombo.box, self, "maxVertexSize", 5, 200, 1, label="Max vertex size:", callback = self.setVertexSize)
+        OWGUI.checkBox(self.vertexSizeCombo.box, self, "invertSize", "Invert vertex size", callback = self.setVertexSize)
+        
+        colorBox = OWGUI.widgetBox(self.edgesTab, "Edge color attribute", orientation="horizontal", addSpace = False)
+        self.edgeColorCombo = OWGUI.comboBox(colorBox, self, "edgeColor", callback=self.setEdgeColor)
+        self.edgeColorCombo.addItem("(same color)")
+        OWGUI.button(colorBox, self, "Set edge color palette", self.setEdgeColorPalette, tooltip = "Set edge color palette", debuggingEnabled = 0)
+        
+        self.attBox = OWGUI.widgetBox(self.verticesTab, "Vertex labels | tooltips", orientation="vertical", addSpace = False)
+        OWGUI.spin(self.attBox, self, "fontSize", 4, 30, 1, label="Set font size:", callback = self.setFontSize)
+        
+        self.attBox = OWGUI.widgetBox(self.attBox, orientation="horizontal", addSpace = False)
+        self.attListBox = OWGUI.listBox(self.attBox, self, "markerAttributes", "attributes", selectionMode=QListWidget.MultiSelection, callback=self.clickedAttLstBox)
+        self.tooltipListBox = OWGUI.listBox(self.attBox, self, "tooltipAttributes", "attributes", selectionMode=QListWidget.MultiSelection, callback=self.clickedTooltipLstBox)
+        
+        self.edgeLabelBox = OWGUI.widgetBox(self.edgesTab, "Edge labels", addSpace = False)
+        self.edgeLabelListBox = OWGUI.listBox(self.edgeLabelBox, self, "edgeLabelAttributes", "edgeAttributes", selectionMode=QListWidget.MultiSelection, callback=self.clickedEdgeLabelListBox)
+        self.edgeLabelBox.setEnabled(False)
+        
+        ib = OWGUI.widgetBox(self.edgesTab, "General", orientation="vertical")
+        OWGUI.checkBox(ib, self, 'showWeights', 'Show weights', callback = self.showWeightLabels)
+        OWGUI.checkBox(ib, self, 'showEdgeLabels', 'Show labels on edges', callback = self.showEdgeLabelsClick)
+        OWGUI.spin(ib, self, "maxLinkSize", 1, 50, 1, label="Max edge width:", callback = self.setMaxLinkSize)
+        OWGUI.checkBox(ib, self, 'showDistances', 'Explore vertex distances', callback = self.showDistancesClick)
+        
+        ib = OWGUI.widgetBox(self.verticesTab, "General", orientation="vertical")
+        OWGUI.checkBox(ib, self, 'showIndexes', 'Show indexes', callback = self.showIndexLabels)
+        OWGUI.checkBox(ib, self, 'labelsOnMarkedOnly', 'Show labels on marked vertices only', callback = self.labelsOnMarked)
+        OWGUI.checkBox(ib, self, 'renderAntialiased', 'Render antialiased', callback = self.setRenderAntialiased)
+        self.insideView = 0
+        self.insideViewNeighbours = 2
+        OWGUI.spin(ib, self, "insideViewNeighbours", 1, 6, 1, label="Inside view (neighbours): ", checked = "insideView", checkCallback = self.insideview, callback = self.insideviewneighbours)
+        OWGUI.checkBox(ib, self, 'showMissingValues', 'Show missing values', callback = self.setShowMissingValues)
+        
+        ib = OWGUI.widgetBox(self.markTab, "Info", orientation="vertical")
+        OWGUI.label(ib, self, "Vertices (shown/hidden): %(nVertices)i (%(nShown)i/%(nHidden)i)")
+        OWGUI.label(ib, self, "Selected and marked vertices: %(nSelected)i - %(nMarked)i")
+        
+        ribg = OWGUI.radioButtonsInBox(self.markTab, self, "hubs", [], "Method", callback = self.setMarkMode)
+        OWGUI.appendRadioButton(ribg, self, "hubs", "None", callback = self.setMarkMode)
+        OWGUI.appendRadioButton(ribg, self, "hubs", "Find vertices", callback = self.setMarkMode)
+        self.ctrlMarkSearchString = OWGUI.lineEdit(OWGUI.indentedBox(ribg), self, "markSearchString", callback=self.setSearchStringTimer, callbackOnType=True)
+        self.searchStringTimer = QTimer(self)
+        self.connect(self.searchStringTimer, SIGNAL("timeout()"), self.setMarkMode)
+        
+        OWGUI.appendRadioButton(ribg, self, "hubs", "Mark neighbours of focused vertices", callback = self.setMarkMode)
+        OWGUI.appendRadioButton(ribg, self, "hubs", "Mark neighbours of selected vertices", callback = self.setMarkMode)
+        ib = OWGUI.indentedBox(ribg, orientation = 0)
+        self.ctrlMarkDistance = OWGUI.spin(ib, self, "markDistance", 0, 100, 1, label="Distance ", callback=(lambda h=2: self.setMarkMode(3 if self.hubs==3 else h)))
+        #self.ctrlMarkFreeze = OWGUI.button(ib, self, "&Freeze", value="graph.freezeNeighbours", toggleButton = True)
+        OWGUI.widgetLabel(ribg, "Mark  vertices with ...")
+        OWGUI.appendRadioButton(ribg, self, "hubs", "at least N connections", callback = self.setMarkMode)
+        OWGUI.appendRadioButton(ribg, self, "hubs", "at most N connections", callback = self.setMarkMode)
+        self.ctrlMarkNConnections = OWGUI.spin(OWGUI.indentedBox(ribg), self, "markNConnections", 0, 1000000, 1, label="N ", callback=(lambda h=4: self.setMarkMode(h)))
+        OWGUI.appendRadioButton(ribg, self, "hubs", "more connections than any neighbour", callback = self.setMarkMode)
+        OWGUI.appendRadioButton(ribg, self, "hubs", "more connections than avg neighbour", callback = self.setMarkMode)
+        OWGUI.appendRadioButton(ribg, self, "hubs", "most connections", callback = self.setMarkMode)
+        ib = OWGUI.indentedBox(ribg)
+        self.ctrlMarkNumber = OWGUI.spin(ib, self, "markNumber", 0, 1000000, 1, label="Number of vertices" + ": ", callback=(lambda h=8: self.setMarkMode(h)))
+        OWGUI.widgetLabel(ib, "(More vertices are marked in case of ties)")
+        self.markInputRadioButton = OWGUI.appendRadioButton(ribg, self, "hubs", "Mark vertices given in the input signal", callback = self.setMarkMode)
+        ib = OWGUI.indentedBox(ribg)
+        self.markInput = 0
+        self.markInputCombo = OWGUI.comboBox(ib, self, "markInput", callback=(lambda h=9: self.setMarkMode(h)))
+        self.markInputRadioButton.setEnabled(False)
+        
+        ib = OWGUI.widgetBox(self.markTab, "General", orientation="vertical")
+        self.checkSendMarkedNodes = 0
+        OWGUI.checkBox(ib, self, 'checkSendMarkedNodes', 'Send marked vertices', callback = self.setSendMarkedNodes, disabled=0)
+        
+        
+        T = OWToolbars.NavigateSelectToolbar
+        self.zoomSelectToolbar = T(self, self.hcontroArea, self.networkCanvas, self.autoSendSelection,
+                                  buttons = (T.IconZoom, 
+                                             T.IconZoomExtent, 
+                                             T.IconZoomSelection, 
+                                             T.IconPan, 
+                                             ("", "", "", None, None, 0),
+                                             #("Move selection", "buttonMoveSelection", "activateMoveSelection", QIcon(OWToolbars.dlg_select), Qt.ArrowCursor, 1),
+                                             T.IconRectangle, 
+                                             #T.IconPolygon,  
+                                             T.IconSendSelection,
+                                             ("", "", "", None, None, 0, "select"),
+                                             ("Add marked to selection", "buttonM2S", "markedToSelection", QIcon(dlg_mark2sel), Qt.ArrowCursor, 0),
+                                             ("Add selection to marked", "buttonS2M", "selectionToMarked", QIcon(dlg_sel2mark), Qt.ArrowCursor, 0),
+                                             ("Remove selection", "buttonRMS", "removeSelection", QIcon(dlg_selIsmark), Qt.ArrowCursor, 0),
+                                             ("", "", "", None, None, 0, "select"),
+                                             ("Hide selected", "buttonSEL", "hideSelectedVertices", QIcon(dlg_selected), Qt.ArrowCursor, 0),
+                                             ("Hide unselected", "buttonUN", "hideUnSelectedVertices", QIcon(dlg_unselected), Qt.ArrowCursor, 0),
+                                             ("Show all nodes", "buttonSW", "showAllVertices", QIcon(dlg_showall), Qt.ArrowCursor, 0)))
+                        
+        OWGUI.rubber(self.zoomSelectToolbar)
+        
+        ib = OWGUI.widgetBox(self.infoTab, "General")
+        OWGUI.label(ib, self, "Number of vertices: %(nVertices)i")
+        OWGUI.label(ib, self, "Number of edges: %(nEdges)i")
+        OWGUI.label(ib, self, "Vertices per edge: %(verticesPerEdge).2f")
+        OWGUI.label(ib, self, "Edges per vertex: %(edgesPerVertex).2f")
+        OWGUI.label(ib, self, "Diameter: %(diameter)i")
+        OWGUI.label(ib, self, "Clustering Coefficient: %(clustering_coefficient).1f%%")
+        
+        ib = OWGUI.widgetBox(self.infoTab, orientation="horizontal")
+        
+        OWGUI.button(ib, self, "Degree distribution", callback=self.showDegreeDistribution, debuggingEnabled=False)
+        OWGUI.button(ib, self, "Save network", callback=self.saveNetwork, debuggingEnabled=False)
+        OWGUI.button(ib, self, "Save image", callback=self.networkCanvas.saveToFile, debuggingEnabled=False)
+        
+        #OWGUI.button(self.edgesTab, self, "Clustering", callback=self.clustering)
+        
+        ib = OWGUI.widgetBox(self.infoTab, "Prototype")
+        #OWGUI.button(ib, self, "Collapse", callback=self._collapse)
+        
+        #ib = OWGUI.widgetBox(ibProto, "Name components")
+        OWGUI.lineEdit(ib, self, "organism", "Organism:", orientation='horizontal')
+        
+        self.nameComponentAttribute = 0
+        self.nameComponentCombo = OWGUI.comboBox(ib, self, "nameComponentAttribute", callback=self.nameComponents, label="Name components:", orientation="horizontal")
+        self.nameComponentCombo.addItem("Select attribute")
+        
+        self.showComponentAttribute = 0
+        self.showComponentCombo = OWGUI.comboBox(ib, self, "showComponentAttribute", callback=self.showComponents, label="Labels on components:", orientation="horizontal")
+        self.showComponentCombo.addItem("Select attribute")
+        OWGUI.checkBox(ib, self, 'showTextMiningInfo', "Show text mining info")
+        
+        #ib = OWGUI.widgetBox(ibProto, "Distance Matrix")
+        ibs = OWGUI.widgetBox(ib, orientation="horizontal")
+        self.btnMDS = OWGUI.button(ibs, self, "Fragviz", callback=self.mdsComponents, toggleButton=1)
+        self.btnESIM = OWGUI.button(ibs, self, "eSim", callback=self.exactSimulation, toggleButton=1)
+        self.btnMDSv = OWGUI.button(ibs, self, "MDS", callback=self.mdsVertices, toggleButton=1)
+        ibs = OWGUI.widgetBox(ib, orientation="horizontal")
+        self.btnRotate = OWGUI.button(ibs, self, "Rotate", callback=self.rotateComponents, toggleButton=1)
+        self.btnRotateMDS = OWGUI.button(ibs, self, "Rotate (MDS)", callback=self.rotateComponentsMDS, toggleButton=1)
+        self.btnForce = OWGUI.button(ibs, self, "Draw Force", callback=self.drawForce, toggleButton=1)
+        self.scalingRatio = 0
+        OWGUI.spin(ib, self, "scalingRatio", 0, 9, 1, label="Set scalingRatio: ")
+        OWGUI.doubleSpin(ib, self, "mdsStressDelta", 0, 10, 0.0000000000000001, label="Min stress change: ")
+        OWGUI.spin(ib, self, "mdsSteps", 1, 100000, 1, label="MDS steps: ")
+        OWGUI.spin(ib, self, "mdsRefresh", 1, 100000, 1, label="MDS refresh steps: ")
+        ibs = OWGUI.widgetBox(ib, orientation="horizontal")
+        OWGUI.checkBox(ibs, self, 'mdsTorgerson', "Torgerson's approximation")
+        OWGUI.checkBox(ibs, self, 'mdsAvgLinkage', "Use average linkage")
+        OWGUI.checkBox(ib, self, 'mdsFromCurrentPos', "MDS from current positions")
+        self.mdsInfoA=OWGUI.widgetLabel(ib, "Avg. stress:")
+        self.mdsInfoB=OWGUI.widgetLabel(ib, "Num. steps:")
+        self.rotateSteps = 100
+        
+        OWGUI.spin(ib, self, "rotateSteps", 1, 10000, 1, label="Rotate max steps: ")
+        OWGUI.spin(ib, self, "minComponentEdgeWidth", 0, 100, 1, label="Min component edge width: ", callback=self.setComponentEdgeWidth)
+        OWGUI.spin(ib, self, "maxComponentEdgeWidth", 0, 200, 1, label="Max component edge width: ", callback=self.setComponentEdgeWidth)
+        
+        self.attSelectionAttribute = 0
+        self.comboAttSelection = OWGUI.comboBox(ib, self, "attSelectionAttribute", label='Send attribute selection list:', orientation='horizontal', callback=self.sendAttSelectionList)
+        self.comboAttSelection.addItem("Select attribute")
+        self.autoSendAttributes = 0
+        OWGUI.checkBox(ib, self, 'autoSendAttributes', "auto send attributes", callback=self.setAutoSendAttributes)
+        
+        self.icons = self.createAttributeIconDict()
+        self.setMarkMode()
+        
+        self.editAttribute = 0
+        self.editCombo = OWGUI.comboBox(self.infoTab, self, "editAttribute", label="Edit attribute:", orientation="horizontal")
+        self.editCombo.addItem("Select attribute")
+        self.editValue = ''
+        OWGUI.lineEdit(self.infoTab, self, "editValue", "Value:", orientation='horizontal')
+        OWGUI.button(self.infoTab, self, "Edit", callback=self.edit)
+        
+        self.verticesTab.layout().addStretch(1)
+        self.edgesTab.layout().addStretch(1)
+        self.markTab.layout().addStretch(1)
+        self.infoTab.layout().addStretch(1)
+        
+        dlg = self.createColorDialog(self.colorSettings, self.selectedSchemaIndex)
+        self.networkCanvas.contPalette = dlg.getContinuousPalette("contPalette")
+        self.networkCanvas.discPalette = dlg.getDiscretePalette("discPalette")
+        
+        dlg = self.createColorDialog(self.edgeColorSettings, self.selectedEdgeSchemaIndex)
+        self.networkCanvas.contEdgePalette = dlg.getContinuousPalette("contPalette")
+        self.networkCanvas.discEdgePalette = dlg.getDiscretePalette("discPalette")
+        
+        self.setOptMethod()
+        self.setFontSize()
+        self.tabs.setCurrentIndex(self.tabIndex)
+        self.setGraph(None)
+        self.setMinimumWidth(900)
+        
+        #self.resize(1000, 600)
+        #self.controlArea.setEnabled(False)
+        
+    def currentTabChanged(self, index): 
+        self.tabIndex = index
+        
+    def setComponentEdgeWidth(self):
+        self.networkCanvas.minComponentEdgeWidth = self.minComponentEdgeWidth
+        self.networkCanvas.maxComponentEdgeWidth = self.maxComponentEdgeWidth
+        self.updateCanvas()
+    
+    def setAutoSendAttributes(self):
+        if self.autoSendAttributes:
+            self.networkCanvas.callbackSelectVertex = self.sendAttSelectionList
+        else:
+            self.networkCanvas.callbackSelectVertex = None
+
+    def sendAttSelectionList(self):
+        if self.optimization:
+            vars = [x.name for x in self.optimization.getVars()]
+            if not self.comboAttSelection.currentText() in vars:
+                return
+            att = str(self.comboAttSelection.currentText())
+            vertices = self.networkCanvas.networkCurve.getSelectedVertices()
+            
+            if len(vertices) != 1:
+                return
+            
+            attributes = str(self.optimization.graph.items[vertices[0]][att]).split(', ')
+        else:
+            attributes = None
+        self.send("Features", attributes)
+        
+    def edit(self):
+        if self.optimization is None:
+            return
+        
+        vars = [x.name for x in self.optimization.getVars()]
+        if not self.editCombo.currentText() in vars:
+            return
+        att = str(self.editCombo.currentText())
+        vertices = self.networkCanvas.networkCurve.getSelectedVertices()
+        
+        if len(vertices) == 0:
+            return
+        
+        if self.optimization.graph.items.domain[att].varType == orange.VarTypes.Continuous:
+            for v in vertices:
+                self.optimization.graph.items[v][att] = float(self.editValue)
+        else:
+            for v in vertices:
+                self.optimization.graph.items[v][att] = str(self.editValue)
+        
+        self.setItems(self.optimization.graph.items)
+        
+    def drawForce(self):
+        if self.btnForce.isChecked() and self.optimization is not None:
+            self.networkCanvas.forceVectors = self.optimization._computeForces() 
+        else:
+            self.networkCanvas.forceVectors = None
+            
+        self.updateCanvas()
+        
+    def rotateProgress(self, curr, max):
+        self.progressBarSet(int(curr * 100 / max))
+        qApp.processEvents()
+        
+    def rotateComponentsMDS(self):
+        print "rotate"
+        if self.vertexDistance is None:
+            self.information('Set distance matrix to input signal')
+            self.btnRotateMDS.setChecked(False)
+            return
+        
+        if self.optimization is None:
+            self.information('No network found')
+            self.btnRotateMDS.setChecked(False)
+            return
+        if self.vertexDistance.dim != self.optimization.graph.nVertices:
+            self.error('Distance matrix dimensionality must equal number of vertices')
+            self.btnRotateMDS.setChecked(False)
+            return
+        
+        if not self.btnRotateMDS.isChecked():
+          self.optimization.stopMDS = 1
+          #self.btnMDS.setChecked(False)
+          #self.btnMDS.setText("MDS on graph components")
+          return
+        
+        self.btnRotateMDS.setText("Stop")
+        qApp.processEvents()
+        
+        self.optimization.vertexDistance = self.vertexDistance
+        self.progressBarInit()
+        
+        self.optimization.mdsComponents(self.mdsSteps, self.mdsRefresh, self.mdsProgress, self.updateCanvas, self.mdsTorgerson, self.mdsStressDelta, rotationOnly=True, mdsFromCurrentPos=self.mdsFromCurrentPos)            
+            
+        self.btnRotateMDS.setChecked(False)
+        self.btnRotateMDS.setText("Rotate graph components (MDS)")
+        self.progressBarFinished()
+    
+    def rotateComponents(self):
+        if self.vertexDistance is None:
+            self.information('Set distance matrix to input signal')
+            self.btnRotate.setChecked(False)
+            return
+        
+        if self.optimization is None:
+            self.information('No network found')
+            self.btnRotate.setChecked(False)
+            return
+        
+        if self.vertexDistance.dim != self.optimization.graph.nVertices:
+            self.error('Distance matrix dimensionality must equal number of vertices')
+            self.btnRotate.setChecked(False)
+            return
+        
+        if not self.btnRotate.isChecked():
+          self.optimization.stopRotate = 1
+          return
+      
+        self.btnRotate.setText("Stop")
+        qApp.processEvents()
+        
+        self.optimization.vertexDistance = self.vertexDistance
+        self.progressBarInit()
+        self.optimization.rotateComponents(self.rotateSteps, 0.0001, self.rotateProgress, self.updateCanvas)
+        self.btnRotate.setChecked(False)
+        self.btnRotate.setText("Rotate graph components")
+        self.progressBarFinished()
+        
+    def mdsProgress(self, avgStress, stepCount):    
+        self.drawForce()
+
+        self.mdsInfoA.setText("Avg. Stress: %.20f" % avgStress)
+        self.mdsInfoB.setText("Num. steps: %i" % stepCount)
+        self.progressBarSet(int(stepCount * 100 / self.mdsSteps))
+        qApp.processEvents()
+        
+    def mdsComponents(self, mdsType=orngNetwork.MdsType.componentMDS):
+        if mdsType == orngNetwork.MdsType.componentMDS:
+            btn = self.btnMDS
+        elif mdsType == orngNetwork.MdsType.exactSimulation:
+            btn = self.btnESIM
+        elif mdsType == orngNetwork.MdsType.MDS:
+            btn = self.btnMDSv
+        
+        btnCaption = btn.text()
+        
+        if self.vertexDistance is None:
+            self.information('Set distance matrix to input signal')
+            btn.setChecked(False)
+            return
+        
+        if self.optimization is None:
+            self.information('No network found')
+            btn.setChecked(False)
+            return
+        
+        if self.vertexDistance.dim != self.optimization.graph.nVertices:
+            self.error('Distance matrix dimensionality must equal number of vertices')
+            btn.setChecked(False)
+            return
+        
+        if not btn.isChecked():
+            self.optimization.stopMDS = 1
+            btn.setChecked(False)
+            btn.setText(btnCaption)
+            return
+        
+        btn.setText("Stop")
+        qApp.processEvents()
+        
+        self.optimization.vertexDistance = self.vertexDistance
+        self.progressBarInit()
+        
+        if self.mdsAvgLinkage:
+            self.optimization.mdsComponentsAvgLinkage(self.mdsSteps, self.mdsRefresh, self.mdsProgress, self.updateCanvas, self.mdsTorgerson, self.mdsStressDelta, scalingRatio = self.scalingRatio, mdsFromCurrentPos=self.mdsFromCurrentPos)
+        else:
+            self.optimization.mdsComponents(self.mdsSteps, self.mdsRefresh, self.mdsProgress, self.updateCanvas, self.mdsTorgerson, self.mdsStressDelta, mdsType=mdsType, scalingRatio=self.scalingRatio, mdsFromCurrentPos=self.mdsFromCurrentPos)            
+        
+        btn.setChecked(False)
+        btn.setText(btnCaption)
+        self.progressBarFinished()
+        
+    def exactSimulation(self):
+        self.mdsComponents(orngNetwork.MdsType.exactSimulation)
+        
+    def mdsVertices(self):
+        self.mdsComponents(orngNetwork.MdsType.MDS)
+        
+    def setVertexDistance(self, matrix):
+        self.error('')
+        self.information('')
+        
+        if matrix is None or self.optimization is None or self.optimization.graph is None:
+            self.vertexDistance = None
+            if self.optimization: self.optimization.vertexDistance = None
+            if self.networkCanvas: self.networkCanvas.vertexDistance = None
+            return
+
+        if matrix.dim != self.optimization.graph.nVertices:
+            self.error('Distance matrix dimensionality must equal number of vertices')
+            self.vertexDistance = None
+            if self.optimization: self.optimization.vertexDistance = None
+            if self.networkCanvas: self.networkCanvas.vertexDistance = None
+            return
+        
+        self.vertexDistance = matrix
+        if self.optimization: self.optimization.vertexDistance = matrix
+        if self.networkCanvas: self.networkCanvas.vertexDistance = matrix
+        
+        self.updateCanvas()
+            
+    def setSendMarkedNodes(self):
+        if self.checkSendMarkedNodes:
+            self.networkCanvas.sendMarkedNodes = self.sendMarkedNodes
+            self.sendMarkedNodes(self.networkCanvas.getMarkedVertices())
+        else:
+            self.send("Marked Data", None)
+            self.networkCanvas.sendMarkedNodes = None
+        
+    def sendMarkedNodes(self, markedNodes):        
+        if len(markedNodes) == 0:
+            self.send("Marked Data", None)
+            return
+        
+        if self.optimization != None and self.optimization.graph != None and self.optimization.graph.items != None:
+            items = self.optimization.graph.items.getitems(markedNodes)
+            self.send("Marked Data", items)
+            return
+        
+        self.send("Marked Data", None)
+
+    def _collapse(self):
+        #print "collapse"
+        self.optimization.collapse()
+        self.networkCanvas.addVisualizer(self.optimization)
+        #if not nodes is None:
+        #    self.networkCanvas.updateData()
+        #    self.networkCanvas.addSelection(nodes, False)
+        self.updateCanvas()
+        
+    def clustering(self):
+        #print "clustering"
+        self.optimization.graph.getClusters()
+        
+    def insideviewneighbours(self):
+        if self.networkCanvas.insideview == 1:
+            self.networkCanvas.insideviewNeighbours = self.insideViewNeighbours
+            self.optButton.setChecked(True)
+            self.fr(False)
+        
+    def insideview(self):
+        print self.networkCanvas.getSelectedVertices()
+        if len(self.networkCanvas.getSelectedVertices()) == 1:
+            if self.networkCanvas.insideview == 1:
+                print "insideview: 1"
+                self.networkCanvas.insideview = 0
+                self.networkCanvas.showAllVertices()
+                self.updateCanvas()
+            else:
+                print "insideview: 0"
+                self.networkCanvas.insideview = 1
+                self.networkCanvas.insideviewNeighbors = self.insideViewNeighbours
+                self.optButton.setChecked(True)
+                self.fr(False)
+    
+        else:
+            print "One node must be selected!"
+        
+    def showComponents(self):
+        if self.optimization is None or self.optimization.graph is None or self.optimization.graph.items is None:
+            return
+        
+        vars = [x.name for x in self.optimization.getVars()]
+        
+        if not self.showComponentCombo.currentText() in vars:
+            self.networkCanvas.showComponentAttribute = None
+            self.lastNameComponentAttribute = ''
+        else:
+            self.networkCanvas.showComponentAttribute = self.showComponentCombo.currentText()     
+            
+        self.networkCanvas.drawPlotItems()
+        
+    def nameComponents(self):
+        """Names connected components of genes according to GO terms."""
+        self.progressBarFinished()
+        self.lastNameComponentAttribute = None
+        
+        if self.optimization is None or self.optimization.graph is None or self.optimization.graph.items is None:
+            return
+        
+        vars = [x.name for x in self.optimization.getVars()]
+        if not self.nameComponentCombo.currentText() in vars:
+            return
+        
+        self.progressBarInit()
+        components = [c for c in self.optimization.graph.getConnectedComponents() if len(c) > 1]
+        if 'component name' in self.optimization.graph.items.domain:
+            keyword_table = self.optimization.graph.items
+        else:
+            keyword_table = orange.ExampleTable(orange.Domain(orange.StringVariable('component name')), [[''] for i in range(len(self.optimization.graph.items))]) 
+        
+        import obiGO 
+        ontology = obiGO.Ontology.Load(progressCallback=self.progressBarSet) 
+        annotations = obiGO.Annotations.Load(self.organism, ontology=ontology, progressCallback=self.progressBarSet)
+
+        allGenes = set([e[str(self.nameComponentCombo.currentText())].value for e in self.optimization.graph.items])
+        foundGenesets = False
+        if len(annotations.geneNames & allGenes) < 1:
+            allGenes = set(reduce(operator.add, [e[str(self.nameComponentCombo.currentText())].value.split(', ') for e in self.optimization.graph.items]))
+            if len(annotations.geneNames & allGenes) < 1:            
+                self.warning('no genes found')
+                return
+            else:
+                foundGenesets = True
+            
+        def rank(a, j, reverse=False):                    
+            if len(a) <= 0: return
+            
+            if reverse:                
+                a.sort(lambda x, y: 1 if x[j] > y[j] else -1 if x[j] < y[j] else 0)
+                top_value = a[0][j]
+                top_rank = len(a)
+                max_rank = float(len(a))
+                int_ndx = 0
+                for k in range(len(a)):
+                    if top_value < a[k][j]:
+                        top_value = a[k][j] 
+                        if k - int_ndx > 1:
+                            avg_rank = (a[int_ndx][j] + a[k-1][j]) / 2
+                            for l in range(int_ndx, k):
+                                a[l][j] = avg_rank
+                        
+                        int_ndx = k
+
+                    a[k][j] = top_rank / max_rank
+                    top_rank -= 1
+                
+                k += 1
+                if k - int_ndx > 1:
+                    avg_rank = (a[int_ndx][j] + a[k-1][j]) / 2
+                    for l in range(int_ndx, k):
+                        a[l][j] = avg_rank    
+                
+            else:
+                a.sort(lambda x, y: 1 if x[j] < y[j] else -1 if x[j] > y[j] else 0)
+                top_value = a[0][j]
+                top_rank = len(a)
+                max_rank = float(len(a))
+                int_ndx = 0
+                for k in range(len(a)):
+                    if top_value > a[k][j]:
+                        top_value = a[k][j] 
+                        if k - int_ndx > 1:
+                            avg_rank = (a[int_ndx][j] + a[k-1][j]) / 2
+                            for l in range(int_ndx, k):
+                                a[l][j] = avg_rank
+                        
+                        int_ndx = k
+
+                    a[k][j] = top_rank / max_rank
+                    top_rank -= 1
+                
+                k += 1
+                if k - int_ndx > 1:
+                    avg_rank = (a[int_ndx][j] + a[k-1][j]) / 2
+                    for l in range(int_ndx, k):
+                        a[l][j] = avg_rank
+        
+        for i in range(len(components)):
+            component = components[i]
+            if len(component) <= 1:
+                continue
+            
+            if foundGenesets:
+                genes = reduce(operator.add, [self.optimization.graph.items[v][str(self.nameComponentCombo.currentText())].value.split(', ') for v in component])
+            else:
+                genes = [self.optimization.graph.items[v][str(self.nameComponentCombo.currentText())].value for v in component]
+                    
+            res1 = annotations.GetEnrichedTerms(genes, aspect="P")
+            res2 = annotations.GetEnrichedTerms(genes, aspect="F")
+            res = res1.items() + res2.items()
+            #namingScore = [[(1-p_value) * (float(len(g)) / len(genes)) / (float(ref) / len(annotations.geneNames)), ontology.terms[GOId].name, len(g), ref, p_value] for GOId, (g, p_value, ref) in res.items() if p_value < 0.1]
+            #namingScore = [[(1-p_value) * len(g) / ref, ontology.terms[GOId].name, len(g), ref, p_value] for GOId, (g, p_value, ref) in res.items() if p_value < 0.1]
+            
+            namingScore = [[len(g), ref, p_value, ontology[GOId].name, len(g), ref, p_value] for GOId, (g, p_value, ref) in res if p_value < 0.1]
+            if len(namingScore) == 0:
+                continue
+            
+            annotated_genes = max([a[0] for a in namingScore])
+            
+            rank(namingScore, 1, reverse=True)
+            rank(namingScore, 2, reverse=True)
+            rank(namingScore, 0)
+            
+            namingScore = [[10 * rank_genes + 0.5 * rank_ref + rank_p_value, name, g, ref, p_value] for rank_genes, rank_ref, rank_p_value, name, g, ref, p_value in namingScore]
+            namingScore.sort(reverse=True)
+            
+            if len(namingScore) < 1:
+                print "warning. no annotations found for group of genes: " + ", ".join(genes)
+                continue
+            elif len(namingScore[0]) < 2:
+                print "warning. error computing score for group of genes: " + ", ".join(genes)
+                continue
+            
+            for v in component:
+                name = str(namingScore[0][1])
+                attrs = "%d/%d, %d, %lf" % (namingScore[0][2], annotated_genes, namingScore[0][3], namingScore[0][4])
+                info = ''
+                if self.showTextMiningInfo:
+                    info = "\n" + attrs + "\n" + str(namingScore[0][0])
+                keyword_table[v]['component name'] = name + info
+            
+            self.progressBarSet(i*100.0/len(components))
+                
+        self.lastNameComponentAttribute = self.nameComponentCombo.currentText()
+        self.setItems(orange.ExampleTable([self.optimization.graph.items, keyword_table]))
+        self.progressBarFinished()   
+        
+    def nameComponents_old(self):
+        if self.optimization is None or self.optimization.graph is None or self.optimization.graph.items is None:
+            return
+        
+        vars = [x.name for x in self.optimization.getVars()]
+        
+        if not self.nameComponentCombo.currentText() in vars:
+            return
+        
+        components = self.optimization.graph.getConnectedComponents()
+        keyword_table = orange.ExampleTable(orange.Domain(orange.StringVariable('component name')), [[''] for i in range(len(self.optimization.graph.items))]) 
+        
+        excludeWord = ["AND", "OF", "KEGG", "ST", "IN", "SIG"]
+        excludePart = ["HSA"]
+        keywords = set()
+        sameKeywords = set()
+        
+        for component in components:
+            words = []
+            all_values = []
+            for vertex in component:
+                values = []
+                value =  str(self.optimization.graph.items[vertex][str(self.nameComponentCombo.currentText())])
+                
+                value = value.replace(" ", ",")
+                value_top = value.split(",")
+                
+                for value in value_top:
+                    if len(value) > 0:
+                        tmp = value.split("_")
+                        tmp = [value.strip() for value in tmp if len(value) > 0]
+                        all_values.append(tmp)
+                        values.extend(tmp)
+                                
+                values = [value.strip() for value in values if len(value) > 0]
+                words.extend(values)
+                
+                
+                #value =  str(self.optimization.graph.items[vertex][str(self.nameComponentCombo.currentText())])
+                #value = value.replace(" ", "_")
+                #value = value.replace(",", "_")
+                #values = value.split("_")
+                #values = [value.strip() for value in values if len(value) > 0]
+                #print "values:", values
+                #all_values.append(values)
+                
+                #words.extend(values)
+            #print "all_values:", all_values
+            toExclude = []
+            
+            words = [word for word in words if not word.upper() in excludeWord]
+            toExclude = [word for word in words for part in excludePart if word.find(part) != -1]
+            
+            for word in toExclude:
+                try:
+                    while True:
+                        words.remove(word)
+                except:
+                    pass
+            
+            counted_words = {}
+            for word in words:
+                if word in counted_words:
+                    count = counted_words[word]
+                    counted_words[word] = count + 1
+                else:
+                    counted_words[word] = 1
+            
+            words = sorted(counted_words.items(), key=itemgetter(1), reverse=True)
+            keyword = ""
+            keyword_words = []
+            max_count = 0
+            i = 0
+            
+            while i < len(words) and words[i][1] >= max_count:
+                max_count = words[i][1]
+                keyword += words[i][0] + " "
+                keyword_words.append(words[i][0])
+                i += 1
+            
+            if len(keyword_words) > 1:
+                new_all_values = []
+                for values in all_values:
+                    new_values = [value for value in values if value in keyword_words]
+                    new_all_values.append(new_values) 
+                     
+                #print new_all_values
+                word_position = []
+                
+                for word in keyword_words:
+                    sum = 0
+                    for v in new_all_values:
+                        if word in v:
+                            sum += v.index(word)
+                            
+                    word_position.append((word, sum))
+                 
+                words = sorted(word_position, key=itemgetter(1))
+                #print "words:", words
+                #print all_values
+                #print new_all_values
+                
+                keyword = ""
+                for word in words:
+                    keyword += word[0] + " "
+                    
+            keyword = keyword.strip()
+            
+            for vertex in component:
+                keyword_table[vertex]['component name'] = keyword
+                
+            if keyword in keywords:
+                sameKeywords.add(keyword)
+            else:
+                keywords.add(keyword)
+        #print "sameKeywords:", sameKeywords       
+        sameComponents = [component for component in components if str(keyword_table[component[0]]['component name']) in sameKeywords]
+        #print "same components:", sameComponents
+        
+        for component in sameComponents:
+            words = []
+            all_values = []
+            for vertex in component:
+                values = []
+                value =  str(self.optimization.graph.items[vertex][str(self.nameComponentCombo.currentText())])
+                
+                value = value.replace(" ", ",")
+                value_top = value.split(",")
+                
+                for value in value_top:
+                    if len(value) > 0:
+                        tmp = value.split("_")
+                        tmp = [value.strip() for value in tmp if len(value) > 0]
+                        all_values.append(tmp)
+                        values.extend(tmp)
+                                
+                values = [value.strip() for value in values if len(value) > 0]
+                words.extend(values)
+            
+            toExclude = []
+            
+            words = [word for word in words if not word.upper() in excludeWord]
+            toExclude = [word for word in words for part in excludePart if word.find(part) != -1]
+            
+            for word in toExclude:
+                try:
+                    while True:
+                        words.remove(word)
+                except:
+                    pass
+            
+            counted_words = {}
+            for word in words:
+                if word in counted_words:
+                    count = counted_words[word]
+                    counted_words[word] = count + 1
+                else:
+                    counted_words[word] = 1
+            
+            words = sorted(counted_words.items(), key=itemgetter(1), reverse=True)
+            keyword = ""
+            counts = [int(word[1]) for word in words] 
+            max_count = max(counts)
+            
+            try:
+                while True and len(counts) > 1:
+                    counts.remove(max_count)
+            except:
+                pass
+            max_count = max(counts)
+            i = 0
+            keyword_words = []
+            while i < len(words) and words[i][1] >= max_count:
+                keyword += words[i][0] + " "
+                keyword_words.append(words[i][0])
+                i += 1
+                
+            if len(keyword_words) > 1:
+                new_all_values = []
+                for values in all_values:
+                    new_values = [value for value in values if value in keyword_words]
+                    new_all_values.append(new_values) 
+                     
+                #print new_all_values
+                word_position = []
+                
+                for word in keyword_words:
+                    sum = 0
+                    for v in new_all_values:
+                        if word in v:
+                            sum += v.index(word)
+                            
+                    word_position.append((word, sum))
+                 
+                words = sorted(word_position, key=itemgetter(1))
+                #print "words:", words
+                #print all_values
+                #print new_all_values
+                
+                keyword = ""
+                for word in words:
+                    keyword += word[0] + " "
+                 
+            keyword = keyword.strip()
+            for vertex in component:
+                keyword_table[vertex]['component name'] = keyword
+        
+        self.lastNameComponentAttribute = self.nameComponentCombo.currentText()
+        #print "self.lastNameComponentAttribute:", self.lastNameComponentAttribute
+        items = orange.ExampleTable([self.optimization.graph.items, keyword_table])
+        self.setItems(items)
+        
+        #for item in items:
+        #    print item
+                        
+    def showIndexLabels(self):
+        self.networkCanvas.showIndexes = self.showIndexes
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+        
+    def showWeightLabels(self):
+        self.networkCanvas.showWeights = self.showWeights
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+        
+    def showDistancesClick(self):
+        if self.visualize and self.visualize.vertexDistance is None:
+            self.warning("Vertex distance signal is not set. Distances are not known.")
+        self.networkCanvas.showDistances = self.showDistances
+        
+    def showEdgeLabelsClick(self):
+        self.networkCanvas.showEdgeLabels = self.showEdgeLabels
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+        
+    def labelsOnMarked(self):
+        self.networkCanvas.labelsOnMarkedOnly = self.labelsOnMarkedOnly
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+    
+    def setSearchStringTimer(self):
+        self.hubs = 1
+        self.searchStringTimer.stop()
+        self.searchStringTimer.start(1000)
+         
+    def setMarkMode(self, i = None):
+        self.searchStringTimer.stop()
+        if not i is None:
+            self.hubs = i
+        
+        #print self.hubs
+        self.networkCanvas.tooltipNeighbours = self.hubs == 2 and self.markDistance or 0
+        self.networkCanvas.markWithRed = False
+
+        if not self.optimization or not self.optimization.graph:
+            return
+        
+        hubs = self.hubs
+        vgraph = self.optimization.graph
+
+        if hubs == 0:
+            self.networkCanvas.setMarkedVertices([])
+            self.networkCanvas.replot()
+            return
+        
+        elif hubs == 1:
+            #print "mark on given label"
+            txt = self.markSearchString
+            labelText = self.networkCanvas.labelText
+            self.networkCanvas.markWithRed = self.networkCanvas.nVertices > 200
+            
+            toMark = [i for i, values in enumerate(vgraph.items) if txt.lower() in " ".join([str(values[ndx]).decode("ascii", "ignore").lower() for ndx in range(len(vgraph.items.domain)) + vgraph.items.domain.getmetas().keys()])]
+            self.networkCanvas.setMarkedVertices(toMark)
+            self.networkCanvas.replot()
+            return
+        
+        elif hubs == 2:
+            #print "mark on focus"
+            self.networkCanvas.unMark()
+            self.networkCanvas.tooltipNeighbours = self.markDistance
+            return
+
+        elif hubs == 3:
+            #print "mark selected"
+            self.networkCanvas.unMark()
+            self.networkCanvas.selectionNeighbours = self.markDistance
+            self.networkCanvas.markSelectionNeighbours()
+            return
+        
+        self.networkCanvas.tooltipNeighbours = self.networkCanvas.selectionNeighbours = 0
+        powers = vgraph.getDegrees()
+        
+        if hubs == 4: # at least N connections
+            #print "mark at least N connections"
+            N = self.markNConnections
+            self.networkCanvas.setMarkedVertices([i for i, power in enumerate(powers) if power >= N])
+            self.networkCanvas.replot()
+        elif hubs == 5:
+            #print "mark at most N connections"
+            N = self.markNConnections
+            self.networkCanvas.setMarkedVertices([i for i, power in enumerate(powers) if power <= N])
+            self.networkCanvas.replot()
+        elif hubs == 6:
+            #print "mark more than any"
+            self.networkCanvas.setMarkedVertices([i for i, power in enumerate(powers) if power > max([0]+[powers[nn] for nn in vgraph.getNeighbours(i)])])
+            self.networkCanvas.replot()
+        elif hubs == 7:
+            #print "mark more than avg"
+            self.networkCanvas.setMarkedVertices([i for i, power in enumerate(powers) if power > mean([0]+[powers[nn] for nn in vgraph.getNeighbours(i)])])
+            self.networkCanvas.replot()
+        elif hubs == 8:
+            #print "mark most"
+            sortedIdx = range(len(powers))
+            sortedIdx.sort(lambda x,y: -cmp(powers[x], powers[y]))
+            cutP = self.markNumber - 1
+            cutPower = powers[sortedIdx[cutP]]
+            while cutP < len(powers) and powers[sortedIdx[cutP]] == cutPower:
+                cutP += 1
+            self.networkCanvas.setMarkedVertices(sortedIdx[:cutP])
+            self.networkCanvas.replot()
+        elif hubs == 9:
+            self.setMarkInput()
+       
+    def testRefresh(self):
+        start = time()
+        self.networkCanvas.replot()
+        stop = time()    
+        print "replot in " + str(stop - start)
+        
+    def saveNetwork(self):
+        if self.networkCanvas is None or self.networkCanvas.visualizer is None:
+            return
+        
+        filename = QFileDialog.getSaveFileName(self, 'Save Network File', '', 'PAJEK network (*.net)\nGML network (*.gml)')
+        filename = unicode(filename)
+        if filename:
+            fn = ""
+            head, tail = os.path.splitext(filename)
+            if not tail:
+                fn = head + ".net"
+            else:
+                fn = filename
+            
+            self.optimization.graph.save(fn)
+                    
+    def sendData(self):
+        graph = self.networkCanvas.getSelectedGraph()
+        vertices = self.networkCanvas.getSelectedVertices()
+        
+        if graph != None:
+            if graph.items != None:
+                self.send("Selected Data", graph.items)
+            else:
+                self.send("Selected Data", self.networkCanvas.getSelectedExamples())
+            
+            #print "sendData:", self.visualize.graph.items.domain
+            self.send("Other Data", self.networkCanvas.getUnselectedExamples())    
+            self.send("Selected Network", graph)
+        else:
+            items = self.networkCanvas.getSelectedExamples()
+            self.send("Selected Data", items)
+                
+            items = self.networkCanvas.getUnselectedExamples()
+            self.send("Other Data", items)
+        
+        matrix = None
+        if self.vertexDistance != None:
+            matrix = self.vertexDistance.getitems(vertices)
+
+        self.send("Selected Distance Matrix", matrix)
+                
+    def setCombos(self):
+        vars = self.optimization.getVars()
+        edgeVars = self.optimization.getEdgeVars()
+        lastLabelColumns = self.lastLabelColumns
+        lastTooltipColumns = self.lastTooltipColumns
+        
+        self.clearCombos()
+        
+        self.attributes = [(var.name, var.varType) for var in vars]
+        self.edgeAttributes = [(var.name, var.varType) for var in edgeVars]
+        
+        for var in vars:
+            if var.varType in [orange.VarTypes.Discrete, orange.VarTypes.Continuous]:
+                self.colorCombo.addItem(self.icons[var.varType], unicode(var.name))
+                
+            if var.varType in [orange.VarTypes.String] and hasattr(self.optimization.graph, 'items') and self.optimization.graph.items != None and len(self.optimization.graph.items) > 0:
+                
+                value = self.optimization.graph.items[0][var].value
+                
+                # can value be a list?
+                try:
+                    if type(eval(value)) == type([]):
+                        self.vertexSizeCombo.addItem(self.icons[var.varType], unicode(var.name))
+                        continue
+                except:
+                    pass
+                
+                if len(value.split(',')) > 1:
+                    self.vertexSizeCombo.addItem(self.icons[var.varType], "num of " + unicode(var.name))
+                
+            elif var.varType in [orange.VarTypes.Continuous]:
+                self.vertexSizeCombo.addItem(self.icons[var.varType], unicode(var.name))
+
+            self.nameComponentCombo.addItem(self.icons[var.varType], unicode(var.name))
+            self.showComponentCombo.addItem(self.icons[var.varType], unicode(var.name))
+            self.editCombo.addItem(self.icons[var.varType], unicode(var.name))
+            self.comboAttSelection.addItem(self.icons[var.varType], unicode(var.name))
+        
+        for var in edgeVars:
+            if var.varType in [orange.VarTypes.Discrete, orange.VarTypes.Continuous]:
+                self.edgeColorCombo.addItem(self.icons[var.varType], unicode(var.name))
+                
+        for i in range(self.vertexSizeCombo.count()):
+            if self.lastVertexSizeColumn == self.vertexSizeCombo.itemText(i):
+                self.vertexSize = i
+                break
+            
+        for i in range(self.colorCombo.count()):
+            if self.lastColorColumn == self.colorCombo.itemText(i):
+                self.color = i
+                break
+
+        for i in range(self.attListBox.count()):
+            if str(self.attListBox.item(i).text()) in lastLabelColumns:
+                self.attListBox.item(i).setSelected(1)
+                
+        for i in range(self.tooltipListBox.count()):
+            if str(self.tooltipListBox.item(i).text()) in lastTooltipColumns:
+                self.tooltipListBox.item(i).setSelected(1)
+            
+        self.lastLabelColumns = lastLabelColumns
+        self.lastTooltipColumns = lastTooltipColumns
+        
+    def clearCombos(self):
+        self.attributes = []
+        self.edgeAttributes = []
+        
+        self.colorCombo.clear()
+        self.vertexSizeCombo.clear()
+        self.nameComponentCombo.clear()
+        self.showComponentCombo.clear()
+        self.edgeColorCombo.clear()
+        self.editCombo.clear()
+        self.comboAttSelection.clear()
+        
+        self.colorCombo.addItem("(same color)")
+        self.edgeColorCombo.addItem("(same color)")
+        self.vertexSizeCombo.addItem("(same size)")
+        self.nameComponentCombo.addItem("Select attribute")
+        self.showComponentCombo.addItem("Select attribute")
+        self.editCombo.addItem("Select attribute")
+        self.comboAttSelection.addItem("Select attribute")
+      
+    def setGraph(self, graph):      
+        if graph is None:
+            self.optimization = None
+            self.networkCanvas.addVisualizer(self.optimization)
+            self.clearCombos()
+            return
+        
+        #print "OWNetwork/setGraph: new visualizer..."
+        self.optimization = orngNetwork.NetworkOptimization(graph)
+        self.networkCanvas.addVisualizer(self.optimization)
+        self.networkCanvas.renderAntialiased = self.renderAntialiased
+        self.networkCanvas.showEdgeLabels = self.showEdgeLabels
+        self.networkCanvas.minVertexSize = self.minVertexSize
+        self.networkCanvas.maxVertexSize = self.maxVertexSize
+        self.networkCanvas.maxEdgeSize = self.maxLinkSize
+        self.lastVertexSizeColumn = self.vertexSizeCombo.currentText()
+        self.lastColorColumn = self.colorCombo.currentText()
+        self.networkCanvas.minComponentEdgeWidth = self.minComponentEdgeWidth
+        self.networkCanvas.maxComponentEdgeWidth = self.maxComponentEdgeWidth
+        
+        
+
+        #for i in range(graph.nVertices):
+        #    print "x:", graph.coors[0][i], " y:", graph.coors[1][i]
+
+        self.nVertices = graph.nVertices
+        self.nShown = graph.nVertices
+        
+        if graph.directed:
+            self.nEdges = len(graph.getEdges())
+        else:
+            self.nEdges = len(graph.getEdges()) / 2
+        
+        if self.nEdges > 0:
+            self.verticesPerEdge = float(self.nVertices) / float(self.nEdges)
+        else:
+            self.verticesPerEdge = 0
+            
+        if self.nVertices > 0:
+            self.edgesPerVertex = float(self.nEdges) / float(self.nVertices)
+        else:
+            self.edgesPerVertex = 0
+            
+        self.diameter = graph.getDiameter()
+        self.clustering_coefficient = graph.getClusteringCoefficient() * 100
+        
+        self.setCombos()
+        
+        lastNameComponentAttributeFound = False
+        for i in range(self.nameComponentCombo.count()):
+            if self.lastNameComponentAttribute == self.nameComponentCombo.itemText(i):
+                lastNameComponentAttributeFound = True
+                self.nameComponentAttribute = i
+                self.nameComponents()
+                self.showComponentAttribute = self.showComponentCombo.count() - 1
+                self.showComponents()
+                break
+            
+        if not lastNameComponentAttributeFound:
+            self.lastNameComponentAttribute = ''
+        
+        self.showComponentAttribute = None
+
+        k = 1.13850193174e-008
+        nodes = self.optimization.nVertices()
+        t = k * nodes * nodes
+        self.frSteps = int(5.0 / t)
+        if self.frSteps <   1: self.frSteps = 1;
+        if self.frSteps > 1500: self.frSteps = 1500;
+        
+        self.networkCanvas.labelsOnMarkedOnly = self.labelsOnMarkedOnly
+        self.networkCanvas.showWeights = self.showWeights
+        self.networkCanvas.showIndexes = self.showIndexes
+        # if graph is large, set random layout, min vertex size, min edge size
+        if self.frSteps < 10:
+            self.renderAntialiased = 0
+            self.minVertexSize = 5
+            self.maxVertexSize = 5
+            self.maxLinkSize = 1
+            self.optMethod = 0
+            self.setOptMethod()            
+            
+        if self.vertexSize > 0:
+            self.networkCanvas.setVerticesSize(self.vertexSizeCombo.currentText(), self.invertSize)
+        else:
+            self.networkCanvas.setVerticesSize()
+            
+        self.setVertexColor()
+        self.setEdgeColor()
+            
+        self.networkCanvas.setEdgesSize()
+        self.clickedAttLstBox()
+        self.clickedTooltipLstBox()
+        self.clickedEdgeLabelListBox()
+        
+        self.optButton.setChecked(1)
+        self.optLayout()        
+        self.information(0)
+        #self.controlArea.setEnabled(True)
+        self.updateCanvas()
+        
+    def setItems(self, items=None):
+        self.error('')
+        
+        if self.optimization is None or self.optimization.graph is None or items is None:
+            return
+        
+        if len(items) != self.optimization.graph.nVertices:
+            self.error('ExampleTable items must have one example for each vertex.')
+            return
+        
+        self.optimization.graph.setattr("items", items)
+        
+        self.setVertexSize()
+        self.showIndexLabels()
+        self.showWeightLabels()
+        self.showEdgeLabelsClick()
+        
+        self.setCombos()
+        self.networkCanvas.updateData()
+        
+    def setMarkInput(self):
+        var = str(self.markInputCombo.currentText())
+        #print 'combo:',self.markInputCombo.currentText()
+        if self.markInputItems != None and len(self.markInputItems) > 0:
+            values = [str(x[var]).strip().upper() for x in self.markInputItems]
+            toMark = [i for (i,x) in enumerate(self.optimization.graph.items) if str(x[var]).strip().upper() in values]
+            #print "mark:", toMark
+            self.networkCanvas.setMarkedVertices(list(toMark))
+            self.networkCanvas.replot()
+            
+        else:
+            self.networkCanvas.setMarkedVertices([])
+            self.networkCanvas.replot()            
+    
+    def markItems(self, items):
+        self.markInputCombo.clear()
+        self.markInputRadioButton.setEnabled(False)
+        self.markInputItems = items
+        
+        if self.optimization is None or self.optimization.graph is None or self.optimization.graph.items is None or items is None:
+            return
+        
+        if len(items) > 0:
+            lstOrgDomain = [x.name for x in self.optimization.graph.items.domain] + [self.optimization.graph.items.domain[x].name for x in self.optimization.graph.items.domain.getmetas()]
+            lstNewDomain = [x.name for x in items.domain] + [items.domain[x].name for x in items.domain.getmetas()]
+            commonVars = set(lstNewDomain) & set(lstOrgDomain)
+
+            if len(commonVars) > 0:
+                for var in commonVars:
+                    orgVar = self.optimization.graph.items.domain[var]
+                    mrkVar = items.domain[var]
+
+                    if orgVar.varType == mrkVar.varType and orgVar.varType == orange.VarTypes.String:
+                        self.markInputCombo.addItem(self.icons[orgVar.varType], unicode(orgVar.name))
+                        self.markInputRadioButton.setEnabled(True)
+                
+                        self.setMarkMode(9)
+              
+    def setExampleSubset(self, subset):
+        if self.networkCanvas is None:
+            return
+        
+        self.warning('')
+        hiddenNodes = []
+        
+        if subset != None:
+            try:
+                expected = 1
+                for row in subset:
+                    index = int(row['index'].value)
+                    if expected != index:
+                        hiddenNodes += range(expected-1, index-1)
+                        expected = index + 1
+                    else:
+                        expected += 1
+                        
+                hiddenNodes += range(expected-1, self.networkCanvas.nVertices)
+                
+                self.networkCanvas.setHiddenNodes(hiddenNodes)
+            except:
+                self.warning('"index" attribute does not exist in "items" table.')
+                            
+    def updateCanvas(self):
+        # if network exists
+        if self.optimization != None:
+            self.networkCanvas.updateCanvas()
+
+    def showDegreeDistribution(self):
+        if self.optimization is None:
+            return
+        
+        from matplotlib import rcParams
+        import pylab as p
+        
+        x = self.optimization.graph.getDegrees()
+        nbins = len(set(x))
+        if nbins > 500:
+          bbins = 500
+        #print len(x)
+        print x
+        # the histogram of the data
+        n, bins, patches = p.hist(x, nbins)
+        
+        p.xlabel('Degree')
+        p.ylabel('No. of nodes')
+        p.title(r'Degree distribution')
+        
+        p.show()
+        
+    def setColors(self):
+        dlg = self.createColorDialog(self.colorSettings, self.selectedSchemaIndex)
+        if dlg.exec_():
+            self.colorSettings = dlg.getColorSchemas()
+            self.selectedSchemaIndex = dlg.selectedSchemaIndex
+            self.networkCanvas.contPalette = dlg.getContinuousPalette("contPalette")
+            self.networkCanvas.discPalette = dlg.getDiscretePalette("discPalette")
+            
+            self.setVertexColor()
+            
+    def setEdgeColorPalette(self):
+        dlg = self.createColorDialog(self.edgeColorSettings, self.selectedEdgeSchemaIndex)
+        if dlg.exec_():
+            self.edgeColorSettings = dlg.getColorSchemas()
+            self.selectedEdgeSchemaIndex = dlg.selectedSchemaIndex
+            self.networkCanvas.contEdgePalette = dlg.getContinuousPalette("contPalette")
+            self.networkCanvas.discEdgePalette = dlg.getDiscretePalette("discPalette")
+            
+            self.setEdgeColor()
+    
+    def createColorDialog(self, colorSettings, selectedSchemaIndex):
+        c = OWColorPalette.ColorPaletteDlg(self, "Color Palette")
+        c.createDiscretePalette("discPalette", "Discrete Palette")
+        c.createContinuousPalette("contPalette", "Continuous Palette")
+        c.setColorSchemas(colorSettings, selectedSchemaIndex)
+        return c
+    """
+    Layout Optimization
+    """
+    def optLayout(self):
+        if self.optimization is None:   #grafa se ni
+            self.optButton.setChecked(False)
+            return
+        
+        if not self.optButton.isChecked():
+            self.optButton.setChecked(False)
+            return
+        
+        qApp.processEvents()
+            
+        if self.optMethod == 1:
+            self.random()
+        elif self.optMethod == 2:
+            self.fr(False)
+        elif self.optMethod == 3:
+            self.fr(True)
+        elif self.optMethod == 4:
+            self.frRadial()
+        elif self.optMethod == 5:
+            self.circularCrossingReduction()
+        elif self.optMethod == 6:
+            self.circularOriginal()
+        elif self.optMethod == 7:
+            self.circularRandom()
+        elif self.optMethod == 8:
+            self.pivotMDS()
+            
+        self.optButton.setChecked(False)
+        qApp.processEvents()
+        
+    def setOptMethod(self, method=None):
+        self.stepsSpin.label.setText('Iterations: ')
+        
+        if method != None:
+            self.optMethod = method
+            
+        if str(self.optMethod) == '0':
+            self.optButton.setEnabled(False)
+        else:
+            self.optButton.setEnabled(True)
+            
+        if str(self.optMethod) in ['2', '3', '4']:
+            self.stepsSpin.setEnabled(True)
+        elif str(self.optMethod) == '8':
+            self.stepsSpin.label.setText('Pivots: ')
+            self.stepsSpin.setEnabled(True)
+        else:
+            self.stepsSpin.setEnabled(False)
+            self.optButton.setChecked(True)
+            self.optLayout()
+
+    def random(self):
+        #print "OWNetwork/random.."
+        if self.optimization is None:   #grafa se ni
+            return    
+            
+        self.optimization.random()
+        #print self.optimization.coors
+        #print "OWNetwork/random: updating canvas..."
+        self.updateCanvas();
+        
+    def fr(self, weighted):
+        if self.optimization is None:   #grafa se ni
+            return
+              
+        if not self.optButton.isChecked():
+          #print "not"
+          self.stopOptimization = 1
+          self.optButton.setChecked(False)
+          self.optButton.setText("Optimize layout")
+          return
+        
+        self.optButton.setText("Stop")
+        qApp.processEvents()
+        self.stopOptimization = 0
+        tolerance = 5
+        initTemp = 1000
+        breakpoints = 6
+        k = int(self.frSteps / breakpoints)
+        o = self.frSteps % breakpoints
+        iteration = 0
+        coolFactor = math.exp(math.log(10.0/10000.0) / self.frSteps)
+
+        if k > 0:
+            while iteration < breakpoints:
+                #print "iteration, initTemp: " + str(initTemp)
+                if self.stopOptimization:
+                    return
+                initTemp = self.optimization.fruchtermanReingold(k, initTemp, coolFactor, self.networkCanvas.hiddenNodes, weighted)
+                iteration += 1
+                qApp.processEvents()
+                self.updateCanvas()
+            
+            #print "ostanek: " + str(o) + ", initTemp: " + str(initTemp)
+            if self.stopOptimization:
+                    return
+            initTemp = self.optimization.fruchtermanReingold(o, initTemp, coolFactor, self.networkCanvas.hiddenNodes, weighted)
+            qApp.processEvents()
+            self.updateCanvas()
+        else:
+            while iteration < o:
+                #print "iteration ostanek, initTemp: " + str(initTemp)
+                if self.stopOptimization:
+                    return
+                initTemp = self.optimization.fruchtermanReingold(1, initTemp, coolFactor, self.networkCanvas.hiddenNodes, weighted)
+                iteration += 1
+                qApp.processEvents()
+                self.updateCanvas()
+                
+        self.optButton.setChecked(False)
+        self.optButton.setText("Optimize layout")
+        
+    def frSpecial(self):
+        if self.optimization is None:   #grafa se ni
+            return
+        
+        steps = 100
+        initTemp = 1000
+        coolFactor = math.exp(math.log(10.0/10000.0) / steps)
+        oldXY = []
+        for rec in self.optimization.network.coors:
+            oldXY.append([rec[0], rec[1]])
+        #print oldXY
+        initTemp = self.optimization.fruchtermanReingold(steps, initTemp, coolFactor, self.networkCanvas.hiddenNodes)
+        #print oldXY
+        self.networkCanvas.updateDataSpecial(oldXY)
+        self.networkCanvas.replot()
+                
+    def frRadial(self):
+        if self.optimization is None:   #grafa se ni
+            return
+        
+        #print "F-R Radial"
+        k = 1.13850193174e-008
+        nodes = self.optimization.nVertices()
+        t = k * nodes * nodes
+        refreshRate = int(5.0 / t)
+        if refreshRate <    1: refreshRate = 1;
+        if refreshRate > 1500: refreshRate = 1500;
+        #print "refreshRate: " + str(refreshRate)
+        
+        tolerance = 5
+        initTemp = 100
+        centerNdx = 0
+        
+        selection = self.networkCanvas.getSelection()
+        if len(selection) > 0:
+            centerNdx = selection[0]
+            
+        #print "center ndx: " + str(centerNdx)
+        initTemp = self.optimization.radialFruchtermanReingold(centerNdx, refreshRate, initTemp)
+        self.networkCanvas.circles = [10000 / 12, 10000/12*2, 10000/12*3]#, 10000/12*4, 10000/12*5]
+        #self.networkCanvas.circles = [100, 200, 300]
+        self.updateCanvas()
+        self.networkCanvas.circles = []
+        
+    def circularOriginal(self):
+        #print "Circular Original"
+        if self.optimization != None:
+            self.optimization.circularOriginal()
+            self.updateCanvas()
+           
+    def circularRandom(self):
+        #print "Circular Random"
+        if self.optimization != None:
+            self.optimization.circularRandom()
+            self.updateCanvas()
+
+    def circularCrossingReduction(self):
+        #print "Circular Crossing Reduction"
+        if self.optimization != None:
+            self.optimization.circularCrossingReduction()
+            self.updateCanvas()
+            
+    def pivotMDS(self):
+        if self.vertexDistance is None:
+            self.information('Set distance matrix to input signal')
+            return
+        
+        if self.optimization is None:
+            self.information('No network found')
+            return
+        
+        if self.vertexDistance.dim != self.optimization.graph.nVertices:
+            self.error('Distance matrix dimensionality must equal number of vertices')
+            return
+        
+        self.frSteps = min(self.frSteps, self.vertexDistance.dim)
+        qApp.processEvents()
+        mds = orngMDS.PivotMDS(self.vertexDistance, self.frSteps)
+        x,y = mds.optimize()
+        self.optimization.graph.coors[0] = x
+        self.optimization.graph.coors[1] = y
+        self.updateCanvas()
+    
+      
+    """
+    Network Visualization
+    """
+       
+    def clickedAttLstBox(self):
+        if self.optimization is None:
+            return
+        
+        self.lastLabelColumns = set([self.attributes[i][0] for i in self.markerAttributes])
+        self.networkCanvas.setLabelText(self.lastLabelColumns)
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+  
+    def clickedTooltipLstBox(self):
+        if self.optimization is None:
+            return
+        
+        self.lastTooltipColumns = set([self.attributes[i][0] for i in self.tooltipAttributes])
+        self.networkCanvas.setTooltipText(self.lastTooltipColumns)
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+        
+    def clickedEdgeLabelListBox(self):
+        if self.optimization is None:
+            return
+        
+        self.lastEdgeLabelAttributes = set([self.edgeAttributes[i][0] for i in self.edgeLabelAttributes])
+        self.networkCanvas.setEdgeLabelText(self.lastEdgeLabelAttributes)
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+
+    def setVertexColor(self):
+        if self.optimization is None:
+            return
+        
+        self.networkCanvas.setVertexColor(self.colorCombo.currentText())
+        self.lastColorColumn = self.colorCombo.currentText()
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+        
+    def setEdgeColor(self):
+        if self.optimization is None:
+            return
+        
+        self.networkCanvas.setEdgeColor(self.edgeColorCombo.currentText())
+        self.lastEdgeColorColumn = self.edgeColorCombo.currentText()
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+                  
+    def setGraphGrid(self):
+        self.networkCanvas.enableGridY(self.networkCanvasShowGrid)
+        self.networkCanvas.enableGridX(self.networkCanvasShowGrid)
+    
+    def selectAllConnectedNodes(self):
+        self.networkCanvas.selectConnectedNodes(1000000)
+        
+    def setShowMissingValues(self):
+        self.networkCanvas.showMissingValues = self.showMissingValues
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+        
+    def setMaxLinkSize(self):
+        if self.optimization is None:
+            return
+        
+        self.networkCanvas.maxEdgeSize = self.maxLinkSize
+        self.networkCanvas.setEdgesSize()
+        self.networkCanvas.replot()
+    
+    def setVertexSize(self):
+        if self.optimization is None or self.networkCanvas is None:
+            return
+        
+        if self.minVertexSize > self.maxVertexSize:
+            self.maxVertexSize = self.minVertexSize
+        
+        self.networkCanvas.minVertexSize = self.minVertexSize
+        self.networkCanvas.maxVertexSize = self.maxVertexSize
+        self.lastVertexSizeColumn = self.vertexSizeCombo.currentText()
+        
+        if self.vertexSize > 0:
+            self.networkCanvas.setVerticesSize(self.lastVertexSizeColumn, self.invertSize)
+        else:
+            self.networkCanvas.setVerticesSize()
+            
+        self.networkCanvas.replot()
+        
+    def setFontSize(self):
+        if self.networkCanvas is None:
+            return
+        
+        self.networkCanvas.fontSize = self.fontSize
+        self.networkCanvas.drawPlotItems()
+        
+    def setRenderAntialiased(self):
+        self.networkCanvas.renderAntialiased = self.renderAntialiased
+        self.networkCanvas.updateData()
+        self.networkCanvas.replot()
+        
+    def sendReport(self):
+        self.reportSettings("Graph data",
+                            [("Number of vertices", self.nVertices),
+                             ("Number of edges", self.nEdges),
+                             ("Vertices per edge", "%.3f" % self.verticesPerEdge),
+                             ("Edges per vertex", "%.3f" % self.edgesPerVertex),
+                             ("Diameter", self.diameter),
+                             ("Clustering Coefficient", "%.1f%%" % self.clustering_coefficient)
+                             ])
+        if self.color or self.vertexSize or self.markerAttributes or self.edgeColor:
+            self.reportSettings("Visual settings",
+                                [self.color and ("Vertex color", self.colorCombo.currentText()),
+                                 self.vertexSize and ("Vertex size", str(self.vertexSizeCombo.currentText()) + " (inverted)" if self.invertSize else ""),
+                                 self.markerAttributes and ("Labels", ", ".join(self.attributes[i][0] for i in self.markerAttributes)),
+                                 self.edgeColor and ("Edge colors", self.edgeColorCombo.currentText()),
+                                ])
+        self.reportSettings("Optimization",
+                            [("Method", self.optCombo.currentText()),
+                             ("Iterations", self.frSteps)])
+        self.reportSection("Graph")
+        self.reportImage(self.networkCanvas.saveToFileDirect)        
+        
+        
+if __name__=="__main__":    
+    appl = QApplication(sys.argv)
+    ow = OWNetExplorer()
+    ow.show()
+    appl.exec_()
+    
Index: Orange/OrangeWidgets/Unsupervised/OWNetworkCanvas.py
===================================================================
--- Orange/OrangeWidgets/Unsupervised/OWNetworkCanvas.py	(revision 9671)
+++ Orange/OrangeWidgets/Unsupervised/OWNetworkCanvas.py	(revision 9671)
@@ -0,0 +1,1280 @@
+CIRCLE = 0
+SQUARE = 1
+ROUND_RECT = 2
+
+NOTHING = 0
+ZOOMING = 1
+SELECT_RECTANGLE = 2
+SELECT_POLYGON = 3
+MOVE_SELECTION = 100
+
+from OWGraph import *
+from numpy import *
+from orngNetwork import Network
+from orngScaleScatterPlotData import *
+
+class NetworkVertex():
+    def __init__(self):
+        self.index = -1
+        self.marked = False
+        self.show = True
+        self.highlight = False
+        self.selected = False
+        self.label = []
+        self.tooltip = []
+        self.uuid = None
+        
+        self.image = None
+        self.pen = QPen(Qt.blue, 1)
+        self.pen.setJoinStyle(Qt.RoundJoin)
+        self.nocolor = Qt.white
+        self.color = Qt.blue
+        self.size = 5
+        self.style = 1
+    
+class NetworkEdge():
+    def __init__(self):
+        self.u = None
+        self.v = None
+        self.links_index = None
+        self.arrowu = 0
+        self.arrowv = 0
+        self.weight = 0
+        self.label = []
+
+        self.pen = QPen(Qt.lightGray, 1)
+        self.pen.setCapStyle(Qt.RoundCap)
+
+class NetworkCurve(QwtPlotCurve):
+  def __init__(self, parent, pen=QPen(Qt.black), xData=None, yData=None):
+      QwtPlotCurve.__init__(self, "Network Curve")
+
+      self.coors = None
+      self.vertices = []
+      self.edges = []
+      self.setItemAttribute(QwtPlotItem.Legend, 0)
+      self.showEdgeLabels = 0
+
+  def moveSelectedVertices(self, dx, dy):
+    selected = self.getSelectedVertices()
+    
+    self.coors[0][selected] = self.coors[0][selected] + dx
+    self.coors[1][selected] = self.coors[1][selected] + dy
+      
+    self.setData(self.coors[0], self.coors[1])
+    return selected
+  
+  def setVertexColor(self, v, color):
+      pen = self.vertices[v].pen
+      self.vertices[v].color = color
+      self.vertices[v].pen = QPen(color, pen.width())
+      
+  def setEdgeColor(self, index, color, nocolor=0):
+      pen = self.edges[index].pen
+      if nocolor:
+        color.setAlpha(0)
+      self.edges[index].pen = QPen(color, pen.width())
+      self.edges[index].pen.setCapStyle(Qt.RoundCap)
+  
+  def getSelectedVertices(self):
+    return [vertex.index for vertex in self.vertices if vertex.selected]
+
+  def getUnselectedVertices(self):
+    return [vertex.index for vertex in self.vertices if not vertex.selected]
+
+  def getMarkedVertices(self):
+    return [vertex.index for vertex in self.vertices if vertex.marked]
+  
+  def setMarkedVertices(self, vertices):
+    for vertex in self.vertices:
+      if vertex.index in vertices:
+        vertex.marked = True
+      else:
+        vertex.marked = False
+        
+  def markToSel(self):
+    for vertex in self.vertices:
+      if vertex.marked == True:
+          vertex.selected = True
+          
+  def selToMark(self):
+    for vertex in self.vertices:
+      if vertex.selected == True:
+          vertex.selected = False
+          vertex.marked = True
+  
+  def unMark(self):
+    for vertex in self.vertices:
+      vertex.marked = False
+      
+  def unSelect(self):
+    for vertex in self.vertices:
+        vertex.selected = False
+        
+  def setHiddenVertices(self, nodes):
+    for vertex in self.vertices:
+      if vertex.index in nodes:
+        vertex.show = False
+      else:
+        vertex.show = True
+      
+  def hideSelectedVertices(self):
+    for vertex in self.vertices:
+      if vertex.selected:
+        vertex.show = False
+  
+  def hideUnSelectedVertices(self):
+    for vertex in self.vertices:
+      if not vertex.selected:
+        vertex.show = False
+    
+  def showAllVertices(self):
+    for vertex in self.vertices:
+      vertex.show = True
+    
+  def changed(self):
+      self.itemChanged()
+
+  def draw(self, painter, xMap, yMap, rect):
+    for edge in self.edges:
+      if edge.u.show and edge.v.show:
+        painter.setPen(edge.pen)
+
+        px1 = xMap.transform(self.coors[0][edge.u.index])   #ali pa tudi self.x1, itd
+        py1 = yMap.transform(self.coors[1][edge.u.index])
+        px2 = xMap.transform(self.coors[0][edge.v.index])
+        py2 = yMap.transform(self.coors[1][edge.v.index])
+        
+        painter.drawLine(px1, py1, px2, py2)
+        
+        d = 12
+        #painter.setPen(QPen(Qt.lightGray, 1))
+        painter.setBrush(Qt.lightGray)
+        if edge.arrowu:
+            x = px1 - px2
+            y = py1 - py2
+            
+            fi = math.atan2(y, x) * 180 * 16 / math.pi 
+
+            if not fi is None:
+                # (180*16) - fi - (20*16), (40*16)
+                painter.drawPie(px1 - d, py1 - d, 2 * d, 2 * d, 2560 - fi, 640)
+                
+        if edge.arrowv:
+            x = px1 - px2
+            y = py1 - py2
+            
+            fi = math.atan2(y, x) * 180 * 16 / math.pi 
+            if not fi is None:
+                # (180*16) - fi - (20*16), (40*16)
+                painter.drawPie(px1 - d, py1 - d, 2 * d, 2 * d, 2560 - fi, 640)
+                
+        if self.showEdgeLabels and len(edge.label) > 0:
+            lbl = ', '.join(edge.label)
+            x = (px1 + px2) / 2
+            y = (py1 + py2) / 2
+            
+            th = painter.fontMetrics().height()
+            tw = painter.fontMetrics().width(lbl)
+            r = QRect(x - tw / 2, y - th / 2, tw, th)
+            painter.fillRect(r, QBrush(Qt.white))
+            painter.drawText(r, Qt.AlignHCenter + Qt.AlignVCenter, lbl)
+    
+    for vertex in self.vertices:
+      if vertex.show:
+        pX = xMap.transform(self.coors[0][vertex.index])   #dobimo koordinati v pikslih (tipa integer)
+        pY = yMap.transform(self.coors[1][vertex.index])   #ki se stejeta od zgornjega levega kota canvasa
+        if vertex.selected:    
+          painter.setPen(QPen(Qt.yellow, 3))
+          painter.setBrush(vertex.color)
+          painter.drawEllipse(pX - (vertex.size + 4) / 2, pY - (vertex.size + 4) / 2, vertex.size + 4, vertex.size + 4)
+        elif vertex.marked:
+          painter.setPen(vertex.pen)
+          painter.setBrush(vertex.color)
+          painter.drawEllipse(pX - vertex.size / 2, pY - vertex.size / 2, vertex.size, vertex.size)
+        else:
+          painter.setPen(vertex.pen)
+          painter.setBrush(vertex.nocolor)
+          #print pX - vertex.size / 2, pY - vertex.size / 2, vertex.size
+          painter.drawEllipse(pX - vertex.size / 2, pY - vertex.size / 2, vertex.size, vertex.size)
+        
+class OWNetworkCanvas(OWGraph):
+  def __init__(self, master, parent=None, name="None"):
+      OWGraph.__init__(self, parent, name)
+      self.master = master
+      self.parent = parent
+      self.labelText = []
+      self.tooltipText = []
+      self.vertices_old = {}         # distionary of nodes (orngIndex: vertex_objekt)
+      self.edges_old = {}            # distionary of edges (curveKey: edge_objekt)
+      self.vertices = []
+      self.edges = []
+      self.indexPairs = {}       # distionary of type CurveKey: orngIndex   (for nodes)
+      #self.selection = []        # list of selected nodes (indices)
+      self.markerKeys = {}       # dictionary of type NodeNdx : markerCurveKey
+      self.tooltipKeys = {}      # dictionary of type NodeNdx : tooltipCurveKey
+      self.visualizer = None
+      self.vertexDegree = []     # seznam vozlisc oblike (vozlisce, stevilo povezav), sortiran po stevilu povezav
+      self.edgesKey = -1
+      #self.vertexSize = 6
+      self.nVertices = 0
+      self.enableXaxis(0)
+      self.enableYLaxis(0)
+      self.state = NOTHING  #default je rocno premikanje
+      self.hiddenNodes = []
+      self.markedNodes = set()
+      self.markWithRed = False
+      self.circles = []
+      self.tooltipNeighbours = 2
+      self.selectionNeighbours = 2
+      self.freezeNeighbours = False
+      self.labelsOnMarkedOnly = 0
+      self.enableWheelZoom = 1
+      self.optimizing = 0
+      self.stopOptimizing = 0
+      self.insideview = 0
+      self.insideviewNeighbours = 2
+      self.enableGridXB(False)
+      self.enableGridYL(False)
+      self.renderAntialiased = 1
+      self.sendMarkedNodes = None
+      self.showEdgeLabels = 0
+      self.showDistances = 0
+      self.showMissingValues = 0
+      
+      self.showWeights = 0
+      self.showIndexes = 0
+      self.minEdgeWeight = sys.maxint
+      self.maxEdgeWeight = 0
+      self.maxEdgeSize = 1
+      
+      self.maxVertexSize = 5
+      self.minVertexSize = 5
+      self.invertEdgeSize = 0
+      self.showComponentAttribute = None
+      self.forceVectors = None
+      self.appendToSelection = 1
+      self.fontSize = 12
+           
+      self.setAxisAutoScale(self.xBottom)
+      self.setAxisAutoScale(self.yLeft)
+      
+      self.networkCurve = NetworkCurve(self)
+      self.callbackMoveVertex = None
+      self.callbackSelectVertex = None
+      self.minComponentEdgeWidth = 0
+      self.maxComponentEdgeWidth = 0
+      self.vertexDistance = None
+      self.controlPressed = False
+      self.altPressed = False
+      
+      self.setFocusPolicy(Qt.StrongFocus)
+      
+  def getSelection(self):
+    return self.networkCurve.getSelectedVertices()
+
+  def getMarkedVertices(self):
+    return self.networkCurve.getMarkedVertices()
+      
+  def getVertexSize(self, index):
+      return 6
+      
+  def setHiddenVertices(self, nodes):
+      self.networkCurve.setHiddenVertices(nodes)
+  
+  def hideSelectedVertices(self):
+    self.networkCurve.hideSelectedVertices()
+    self.drawPlotItems()
+    
+  def hideUnSelectedVertices(self):
+    self.networkCurve.hideUnSelectedVertices()
+    self.drawPlotItems()
+    
+  def showAllVertices(self):
+    self.networkCurve.showAllVertices()
+    self.drawPlotItems()
+    
+  def optimize(self, frSteps):
+      qApp.processEvents()
+      tolerance = 5
+      initTemp = 100
+      breakpoints = 20
+      k = int(frSteps / breakpoints)
+      o = frSteps % breakpoints
+      iteration = 0
+      coolFactor = exp(log(10.0 / 10000.0) / frSteps)
+      #print coolFactor
+      if k > 0:
+          while iteration < breakpoints:
+              initTemp = self.visualizer.fruchtermanReingold(k, initTemp, coolFactor, self.hiddenNodes)
+              iteration += 1
+              qApp.processEvents()
+              self.updateCanvas()
+
+          initTemp = self.visualizer.fruchtermanReingold(o, initTemp, coolFactor, self.hiddenNodes)
+          qApp.processEvents()
+          self.updateCanvas()
+      else:
+          while iteration < o:
+              initTemp = self.visualizer.fruchtermanReingold(1, initTemp, coolFactor, self.hiddenNodes)
+              iteration += 1
+              qApp.processEvents()
+              self.updateCanvas()
+              
+  def markedToSelection(self):
+      self.networkCurve.markToSel()
+      self.drawPlotItems()
+      
+  def selectionToMarked(self):
+      self.networkCurve.selToMark()
+      self.drawPlotItems()
+      
+      if self.sendMarkedNodes != None:
+          self.sendMarkedNodes(self.networkCurve.getMarkedVertices())
+      
+  def removeSelection(self, replot=True):
+      self.networkCurve.unSelect()
+      
+      if replot:
+        self.replot()
+  
+  def selectNeighbours(self, sel, nodes, depth, maxdepth):
+      #print "list: " + str(sel)
+      #print "nodes: " + str(nodes)
+      sel.update(nodes)
+      if depth < maxdepth:
+          for i in nodes:
+              neighbours = set(self.visualizer.graph.getNeighbours(i))
+              #print "neighbours: " + str(neighbours)
+              self.selectNeighbours(sel, neighbours - sel, depth + 1, maxdepth)
+      
+  def getSelectedExamples(self):
+      selection = self.networkCurve.getSelectedVertices()
+      
+      if len(selection) == 0:
+          return None
+      
+      if self.visualizer.graph.items != None:
+          return self.visualizer.graph.items.getitems(selection)
+      else:
+          return None
+      
+  def getUnselectedExamples(self):
+      unselection = self.networkCurve.getUnselectedVertices()
+      
+      if len(unselection) == 0:
+          return None
+      
+      if self.visualizer.graph.items != None:
+          return self.visualizer.graph.items.getitems(unselection)
+      else:
+          return None
+
+  def getSelectedGraph(self):
+    selection = self.networkCurve.getSelectedVertices()
+    
+    if len(selection) == 0:
+        return None
+    
+    print self.visualizer.graph
+    subgraph = self.visualizer.graph.getSubGraph(selection)
+    subnet = Network(subgraph)
+    return subnet
+ 
+  def getSelectedVertices(self):
+    return self.networkCurve.getSelectedVertices()
+  
+  def getNeighboursUpTo(self, ndx, dist):
+      newNeighbours = neighbours = set([ndx])
+      for d in range(dist):
+          tNewNeighbours = set()
+          for v in newNeighbours:
+              tNewNeighbours |= set(self.visualizer.graph.getNeighbours(v))
+          newNeighbours = tNewNeighbours - neighbours
+          neighbours |= newNeighbours
+      return neighbours
+   
+  def markSelectionNeighbours(self):
+      if not self.freezeNeighbours and self.selectionNeighbours:
+          toMark = set()
+          for ndx in self.networkCurve.getSelectedVertices():
+              toMark |= self.getNeighboursUpTo(ndx, self.selectionNeighbours)
+          
+          self.networkCurve.setMarkedVertices(toMark)
+          self.drawPlotItems()
+              
+      elif not self.freezeNeighbours and self.selectionNeighbours == 0:
+          self.networkCurve.setMarkedVertices(self.networkCurve.getSelectedVertices())
+          self.drawPlotItems()
+          
+      if self.sendMarkedNodes != None:
+          self.sendMarkedNodes(self.networkCurve.getMarkedVertices())
+              
+  def unMark(self):
+    self.networkCurve.unMark()
+    self.drawPlotItems(replot=0)
+    
+    if self.sendMarkedNodes != None:
+          self.sendMarkedNodes([])
+          
+  def setMarkedVertices(self, vertices):
+    self.networkCurve.setMarkedVertices(vertices)
+    self.drawPlotItems(replot=0)
+    
+    if self.sendMarkedNodes != None:
+          self.sendMarkedNodes(self.networkCurve.getMarkedVertices())
+      
+  def activateMoveSelection(self):
+      self.state = MOVE_SELECTION
+
+  def mouseMoveEvent(self, event):
+      if not self.visualizer:
+        return
+        
+      if self.mouseCurrentlyPressed and self.state == MOVE_SELECTION and self.GMmouseMoveEvent != None:
+          newX = self.invTransform(2, event.pos().x())
+          newY = self.invTransform(0, event.pos().y())
+          
+          dx = newX - self.invTransform(2, self.GMmouseMoveEvent.x())
+          dy = newY - self.invTransform(0, self.GMmouseMoveEvent.y())
+          movedVertices = self.networkCurve.moveSelectedVertices(dx, dy)
+          
+          self.GMmouseMoveEvent.setX(event.pos().x())  #zacetni dogodek postane trenutni
+          self.GMmouseMoveEvent.setY(event.pos().y())
+          
+          self.drawPlotItems(replot=1, vertices=movedVertices)
+          if self.callbackMoveVertex:
+              self.callbackMoveVertex()
+      else:
+          OWGraph.mouseMoveEvent(self, event)
+              
+      if not self.freezeNeighbours and self.tooltipNeighbours:
+          px = self.invTransform(2, event.x())
+          py = self.invTransform(0, event.y())   
+          ndx, mind = self.visualizer.closestVertex(px, py)
+          dX = self.transform(QwtPlot.xBottom, self.visualizer.graph.coors[0][ndx]) - event.x()
+          dY = self.transform(QwtPlot.yLeft,   self.visualizer.graph.coors[1][ndx]) - event.y()
+          # transform to pixel distance
+          distance = math.sqrt(dX**2 + dY**2) 
+            
+          if ndx != -1 and distance <= self.vertices[ndx].size / 2:
+              toMark = set(self.getNeighboursUpTo(ndx, self.tooltipNeighbours))
+              self.networkCurve.setMarkedVertices(toMark)
+              self.drawPlotItems()
+              
+              if self.sendMarkedNodes != None:
+                  self.sendMarkedNodes(self.networkCurve.getMarkedVertices())
+          else:
+              self.networkCurve.unMark()
+              self.drawPlotItems()
+              
+              if self.sendMarkedNodes != None:
+                  self.sendMarkedNodes([])
+      
+      if self.showDistances:
+          selection = self.networkCurve.getSelectedVertices()
+          if len(selection) > 0:
+              px = self.invTransform(2, event.x())
+              py = self.invTransform(0, event.y())  
+               
+              v, mind = self.visualizer.closestVertex(px, py)
+              dX = self.transform(QwtPlot.xBottom, self.visualizer.graph.coors[0][v]) - event.x()
+              dY = self.transform(QwtPlot.yLeft,   self.visualizer.graph.coors[1][v]) - event.y()
+              # transform to pixel distance
+              distance = math.sqrt(dX**2 + dY**2)               
+              if v != -1 and distance <= self.vertices[v].size / 2:
+                  if self.visualizer.vertexDistance == None:
+                      dst = 'vertex distance signal not set'
+                  else:
+                      dst = 0
+                      for u in selection:
+                          dst += self.visualizer.vertexDistance[u, v]
+                      dst = dst / len(selection)
+                      
+                  self.showTip(event.pos().x(), event.pos().y(), str(dst))
+                  self.replot()
+
+  def mousePressEvent(self, event):
+    if not self.visualizer:
+        return
+        
+    #self.grabKeyboard()
+    self.mouseSelectedVertex = 0
+    self.GMmouseMoveEvent = None
+    
+    if self.state == MOVE_SELECTION:
+      self.mouseCurrentlyPressed = 1
+      #if self.isPointSelected(self.invTransform(self.xBottom, event.pos().x()), self.invTransform(self.yLeft, event.pos().y())) and self.selection != []:
+      #  self.GMmouseStartEvent = QPoint(event.pos().x(), event.pos().y())
+      #else:
+        # button pressed outside selected area or there is no area
+      self.selectVertex(event.pos())
+      self.GMmouseStartEvent = QPoint(event.pos().x(), event.pos().y())
+      self.replot()
+    elif self.state == SELECT_RECTANGLE:
+        self.GMmouseStartEvent = QPoint(event.pos().x(), event.pos().y())
+        
+        if self.clickedSelectedOnVertex(event.pos()):
+            self.mouseSelectedVertex = 1
+            self.mouseCurrentlyPressed = 1
+            self.state = MOVE_SELECTION
+            self.GMmouseMoveEvent = QPoint(event.pos().x(), event.pos().y())
+        elif self.clickedOnVertex(event.pos()):
+            self.mouseSelectedVertex = 1
+            self.mouseCurrentlyPressed = 1
+        else:
+            OWGraph.mousePressEvent(self, event)  
+    else:
+        OWGraph.mousePressEvent(self, event)     
+
+  def mouseReleaseEvent(self, event):  
+      if not self.visualizer:
+        return
+        
+      #self.releaseKeyboard()
+      if self.state == MOVE_SELECTION:
+          self.state = SELECT_RECTANGLE
+          self.mouseCurrentlyPressed = 0
+          
+          self.moveGroup = False
+          #self.GMmouseStartEvent=None
+          
+      if self.state == SELECT_RECTANGLE:
+          x1 = self.invTransform(2, self.GMmouseStartEvent.x())
+          y1 = self.invTransform(0, self.GMmouseStartEvent.y())
+          
+          x2 = self.invTransform(2, event.pos().x())
+          y2 = self.invTransform(0, event.pos().y())
+          
+          
+          if self.mouseSelectedVertex == 1 and x1 == x2 and y1 == y2 and self.selectVertex(self.GMmouseStartEvent):
+              QwtPlot.mouseReleaseEvent(self, event)
+          elif self.mouseSelectedVertex == 0:
+               
+              selection = self.visualizer.getVerticesInRect(x1, y1, x2, y2)
+
+              def selectVertex(ndx):
+                  if self.vertices[ndx].show:
+                      self.vertices[ndx].selected = True
+                      
+              map(selectVertex, selection)
+              
+              if len(selection) == 0 and x1 == x2 and y1 == y2:
+                  self.removeSelection()
+                  self.unMark()
+          
+              self.markSelectionNeighbours()
+              OWGraph.mouseReleaseEvent(self, event)
+              self.removeAllSelections()
+
+      elif self.state == SELECT_POLYGON:
+              OWGraph.mouseReleaseEvent(self, event)
+              if self.tempSelectionCurve == None:   #if OWVisGraph closed polygon
+                  self.selectVertices()
+      else:
+          OWGraph.mouseReleaseEvent(self, event)
+          
+      self.mouseCurrentlyPressed = 0
+      self.moveGroup = False
+          
+      if self.callbackSelectVertex != None:
+          self.callbackSelectVertex()
+
+  def keyPressEvent(self, e):
+      if not self.visualizer:
+        return
+        
+      if e.key() == 87 or e.key() == 81:
+          selection = [v.index for v in self.vertices if v.selected]
+          if len(selection) > 0:
+              phi = [math.pi / -180 if e.key() == 87 else math.pi / 180]
+              self.visualizer.rotateVertices([selection], phi)
+              self.drawPlotItems(replot=1)
+          
+      if e.key() == Qt.Key_Control:
+          self.controlPressed = True
+      
+      elif e.key() == Qt.Key_Alt:
+          self.altPressed = True
+          
+      if e.text() == "f":
+          self.graph.freezeNeighbours = not self.graph.freezeNeighbours
+      
+      OWGraph.keyPressEvent(self, e)
+          
+  def keyReleaseEvent(self, e):
+      if e.key() == Qt.Key_Control:
+          self.controlPressed = False
+      
+      elif e.key() == Qt.Key_Alt:
+          self.altPressed = False
+      
+      OWGraph.keyReleaseEvent(self, e)
+      
+
+  def clickedSelectedOnVertex(self, pos):
+      min = 1000000
+      ndx = -1
+
+      px = self.invTransform(2, pos.x())
+      py = self.invTransform(0, pos.y())   
+
+      ndx, min = self.visualizer.closestVertex(px, py)
+      dX = self.transform(QwtPlot.xBottom, self.visualizer.graph.coors[0][ndx]) - pos.x()
+      dY = self.transform(QwtPlot.yLeft,   self.visualizer.graph.coors[1][ndx]) - pos.y()
+      # transform to pixel distance
+      distance = math.sqrt(dX**2 + dY**2)
+      if ndx != -1 and distance <= self.vertices[ndx].size / 2:
+          return self.vertices[ndx].selected
+      else:
+          return False
+      
+  def clickedOnVertex(self, pos):
+      min = 1000000
+      ndx = -1
+
+      px = self.invTransform(2, pos.x())
+      py = self.invTransform(0, pos.y())   
+
+      ndx, min = self.visualizer.closestVertex(px, py)
+      dX = self.transform(QwtPlot.xBottom, self.visualizer.graph.coors[0][ndx]) - pos.x()
+      dY = self.transform(QwtPlot.yLeft,   self.visualizer.graph.coors[1][ndx]) - pos.y()
+      # transform to pixel distance
+      distance = math.sqrt(dX**2 + dY**2)
+      if ndx != -1 and distance <= self.vertices[ndx].size / 2:
+          return True
+      else:
+          return False
+              
+  def selectVertex(self, pos):
+      min = 1000000
+      ndx = -1
+
+      px = self.invTransform(2, pos.x())
+      py = self.invTransform(0, pos.y())   
+
+      ndx, min = self.visualizer.closestVertex(px, py)
+      
+      dX = self.transform(QwtPlot.xBottom, self.visualizer.graph.coors[0][ndx]) - pos.x()
+      dY = self.transform(QwtPlot.yLeft,   self.visualizer.graph.coors[1][ndx]) - pos.y()
+      # transform to pixel distance
+      distance = math.sqrt(dX**2 + dY**2)
+      if ndx != -1 and distance <= self.vertices[ndx].size / 2:
+          if not self.appendToSelection and not self.controlPressed:
+              self.removeSelection()
+                    
+          if self.insideview:
+              self.networkCurve.unSelect()
+              self.vertices[ndx].selected = not self.vertices[ndx].selected
+              self.optimize(100)
+              
+              self.markSelectionNeighbours()
+          else:
+              self.vertices[ndx].selected = not self.vertices[ndx].selected
+              self.markSelectionNeighbours()
+          
+          return True  
+      else:
+          return False
+          self.removeSelection()
+          self.unMark()
+  
+  def updateData(self):
+      if self.visualizer == None:
+          return
+      
+      self.removeDrawingCurves(removeLegendItems=0)
+      self.tips.removeAll()
+      
+      if self.vertexDistance and self.minComponentEdgeWidth > 0 and self.maxComponentEdgeWidth > 0:          
+          components = self.visualizer.graph.getConnectedComponents()
+          matrix = self.vertexDistance.avgLinkage(components)
+          
+          edges = set()
+          for u in range(matrix.dim):
+              neighbours = matrix.getKNN(u, 2)
+              for v in neighbours:
+                  if v < u:
+                      edges.add((v, u))
+                  else:
+                      edges.add((u, v))
+          edges = list(edges)
+# show 2n strongest edges
+#          vals = matrix.getValues()
+#          vals = zip(vals, range(len(vals)))
+#          count = 0
+#          add = 0
+#          for i in range(matrix.dim):
+#              add += i + 1
+#              for j in range(i+1, matrix.dim):
+#                  v, ind = vals[count]
+#                  ind += add
+#                  vals[count] = (v, ind)
+#                  count += 1
+#          vals.sort(reverse=0)
+#          vals = vals[:2 * matrix.dim]
+#          edges = [(ind / matrix.dim, ind % matrix.dim) for v, ind in vals]
+#          print "number of component edges:", len(edges), "number of components:", len(components)
+          components_c = [(sum(self.visualizer.graph.coors[0][c]) / len(c), sum(self.visualizer.graph.coors[1][c]) / len(c)) for c in components]
+          weights = [1 - matrix[u,v] for u,v in edges]
+          
+          max_weight = max(weights)
+          min_weight = min(weights)
+          span_weights = max_weight - min_weight
+        
+          for u,v in edges:
+              x = [components_c[u][0], components_c[v][0]]
+              y = [components_c[u][1], components_c[v][1]]
+              w = ((1 - matrix[u,v]) - min_weight) / span_weights * (self.maxComponentEdgeWidth - self.minComponentEdgeWidth) + self.minComponentEdgeWidth
+              
+              pen = QPen()
+              pen.setWidth(w)
+              pen.setBrush(QColor(50,200,255,15))
+              pen.setCapStyle(Qt.FlatCap)
+              pen.setJoinStyle(Qt.RoundJoin)
+              self.addCurve("component_edges", Qt.green, Qt.green, 0, style=QwtPlotCurve.Lines, symbol = QwtSymbol.NoSymbol, xData=x, yData=y, pen=pen, showFilledSymbols=False)
+      
+      
+      self.networkCurve.setData(self.visualizer.network.coors[0], self.visualizer.network.coors[1])
+      
+      if self.insideview == 1:
+          selection = self.networkCurve.getSelectedVertices()
+          if len(selection) >= 1:
+              visible = set()
+              visible |= set(selection)
+              visible |= self.getNeighboursUpTo(selection[0], self.insideviewNeighbours)
+              self.networkCurve.setHiddenVertices(set(range(self.nVertices)) - visible)
+
+      edgesCount = 0
+      
+      if self.forceVectors != None:
+          for v in self.forceVectors:
+              self.addCurve("force", Qt.white, Qt.green, 1, style=QwtPlotCurve.Lines, xData=v[0], yData=v[1], showFilledSymbols=False)
+      
+      for r in self.circles:
+          step = 2 * pi / 64;
+          fi = 0
+          x = []
+          y = []
+          for i in range(65):
+              x.append(r * cos(fi) + 5000)
+              y.append(r * sin(fi) + 5000)
+              fi += step
+              
+          self.addCurve("radius", Qt.white, Qt.green, 1, style=QwtPlotCurve.Lines, xData=x, yData=y, showFilledSymbols=False)
+      
+      if self.renderAntialiased:
+          self.networkCurve.setRenderHint(QwtPlotItem.RenderAntialiased)
+      else:
+          self.networkCurve.setRenderHint(QwtPlotItem.RenderAntialiased, False)
+    
+      self.networkCurve.showEdgeLabels = self.showEdgeLabels
+      self.networkCurve.attach(self)
+      self.drawPlotItems(replot=0)
+      
+      #self.zoomExtent()
+      
+  def drawPlotItems(self, replot=1, vertices=[]):
+      if len(vertices) > 0:
+          for vertex in vertices:
+              x1 = float(self.visualizer.network.coors[0][vertex])
+              y1 = float(self.visualizer.network.coors[1][vertex])
+              
+              if vertex in self.markerKeys:
+                  mkey = self.markerKeys[vertex]
+                  mkey.setValue(x1, y1)
+            
+              if 'index ' + str(vertex) in self.markerKeys:
+                  mkey = self.markerKeys['index ' + str(vertex)]
+                  mkey.setValue(x1, y1)
+              
+              if vertex in self.tooltipKeys:
+                  tkey = self.tooltipKeys[vertex]
+                  self.tips.positions[tkey] = (x1, y1, 0, 0)
+      else:
+          self.markerKeys = {}
+          self.removeMarkers()
+          self.drawLabels()
+          self.drawToolTips()
+          self.drawWeights()
+          self.drawIndexes()
+          self.drawComponentKeywords()
+      
+      if replot:
+          self.replot()
+          
+  def drawComponentKeywords(self):
+      if self.showComponentAttribute == None:
+          return
+      
+      if self.visualizer == None or self.visualizer.graph == None or self.visualizer.graph.items == None:
+          return
+      
+      if str(self.showComponentAttribute) not in self.visualizer.graph.items.domain:
+          self.showComponentAttribute = None
+          return
+      
+      components = self.visualizer.graph.getConnectedComponents()
+      
+      for component in components:
+          if len(component) == 0:
+              continue
+          
+          vertices = [vertex for vertex in component if self.vertices[vertex].show]
+
+          if len(vertices) == 0:
+              continue
+          
+          xes = [self.visualizer.network.coors[0][vertex] for vertex in vertices]  
+          yes = [self.visualizer.network.coors[1][vertex] for vertex in vertices]  
+                                
+          x1 = sum(xes) / len(xes)
+          y1 = sum(yes) / len(yes)
+          
+          lbl = str(self.visualizer.graph.items[component[0]][str(self.showComponentAttribute)])
+          
+          mkey = self.addMarker(lbl, float(x1), float(y1), alignment=Qt.AlignCenter, size=self.fontSize)
+ 
+  def drawToolTips(self):
+    # add ToolTips
+    self.tooltipData = []
+    self.tooltipKeys = {}
+    self.tips.removeAll()
+    if len(self.tooltipText) > 0:
+      for vertex in self.vertices:
+        if not vertex.show:
+          continue
+        
+        x1 = self.visualizer.network.coors[0][vertex.index]
+        y1 = self.visualizer.network.coors[1][vertex.index]
+        lbl = ""
+        values = self.visualizer.graph.items[vertex.index]
+        for ndx in self.tooltipText:
+            if not ndx in self.visualizer.graph.items.domain:
+                continue
+            
+            value = str(values[ndx])
+            # wrap text
+            i = 0
+            while i < len(value) / 100:
+                value = value[:((i + 1) * 100) + i] + "\n" + value[((i + 1) * 100) + i:]
+                i += 1
+                
+            lbl = lbl + str(value) + "\n"
+  
+        if lbl != '':
+          lbl = lbl[:-1]
+          self.tips.addToolTip(x1, y1, lbl)
+          self.tooltipKeys[vertex.index] = len(self.tips.texts) - 1
+                 
+  def drawLabels(self):
+      if len(self.labelText) > 0:
+          for vertex in self.vertices:
+              if not vertex.show:
+                  continue
+              
+              if self.labelsOnMarkedOnly and not (vertex.marked):
+                  continue
+                                
+              x1 = self.visualizer.network.coors[0][vertex.index]
+              y1 = self.visualizer.network.coors[1][vertex.index]
+              lbl = ""
+              values = self.visualizer.graph.items[vertex.index]
+              if self.showMissingValues:
+                  lbl = ", ".join([str(values[ndx]) for ndx in self.labelText])
+              else:
+                  lbl = ", ".join([str(values[ndx]) for ndx in self.labelText if str(values[ndx]) != '?'])
+              #if not self.showMissingValues and lbl == '':
+              #    continue 
+              
+              if lbl:
+                  vertex.label = lbl
+                  mkey = self.addMarker(lbl, float(x1), float(y1), alignment=Qt.AlignBottom, size=self.fontSize)
+                  self.markerKeys[vertex.index] = mkey    
+                   
+  def drawIndexes(self):
+      if self.showIndexes:
+          for vertex in self.vertices:
+              if not vertex.show:
+                  continue
+              
+              if self.labelsOnMarkedOnly and not (vertex.marked):
+                  continue
+                                
+              x1 = self.visualizer.network.coors[0][vertex.index]
+              y1 = self.visualizer.network.coors[1][vertex.index]
+
+              lbl = str(vertex.index)
+              mkey = self.addMarker(lbl, float(x1), float(y1), alignment=Qt.AlignTop, size=self.fontSize)
+              self.markerKeys['index ' + str(vertex.index)] = mkey         
+
+  def drawWeights(self):
+      if self.showWeights:
+          for edge in self.edges:
+              if not (edge.u.show and edge.v.show):
+                  continue
+              
+              if self.labelsOnMarkedOnly and not (edge.u.marked and edge.v.marked):
+                  continue
+                                
+              x1 = (self.visualizer.network.coors[0][edge.u.index] + self.visualizer.network.coors[0][edge.v.index]) / 2
+              y1 = (self.visualizer.network.coors[1][edge.u.index] + self.visualizer.network.coors[1][edge.v.index]) / 2
+              
+              if edge.weight == None:
+                  lbl = "None"
+              else:
+                  lbl = "%.2f" % float(edge.weight)
+              
+              mkey = self.addMarker(lbl, float(x1), float(y1), alignment=Qt.AlignCenter, size=self.fontSize)
+              self.markerKeys[(edge.u, edge.v)] = mkey
+                          
+  def getColorIndeces(self, table, attribute, palette):
+      colorIndices = {}
+      colorIndex = None
+      minValue = None
+      maxValue = None
+      
+      if attribute[0] != "(" or attribute[ -1] != ")":
+          i = 0
+          for var in table.domain.variables:
+              if var.name == attribute:
+                  colorIndex = i
+                  if var.varType == orange.VarTypes.Discrete: 
+                      colorIndices = getVariableValueIndices(var, colorIndex)
+                      
+              i += 1
+          metas = table.domain.getmetas()
+          for i, var in metas.iteritems():
+              if var.name == attribute:
+                  colorIndex = i
+                  if var.varType == orange.VarTypes.Discrete: 
+                      colorIndices = getVariableValueIndices(var, colorIndex)
+
+      colorIndices['?'] = len(colorIndices)
+      palette.setNumberOfColors(len(colorIndices))
+      
+      if colorIndex != None and table.domain[colorIndex].varType == orange.VarTypes.Continuous:
+          minValue = float(min([x[colorIndex].value for x in table if x[colorIndex].value != "?"] or [0.0]))
+          maxValue = float(max([x[colorIndex].value for x in table if x[colorIndex].value != "?"] or [0.0]))
+          
+      return colorIndices, colorIndex, minValue, maxValue
+  
+  def setEdgeColor(self, attribute):
+      if self.visualizer == None:
+          return
+      
+      colorIndices, colorIndex, minValue, maxValue = self.getColorIndeces(self.visualizer.graph.links, attribute, self.discEdgePalette)
+
+      for index in range(self.nEdges):
+          if colorIndex != None:
+              links_index = self.networkCurve.edges[index].links_index
+              if links_index == None:
+                  continue
+              
+              if self.visualizer.graph.links.domain[colorIndex].varType == orange.VarTypes.Continuous:
+                  newColor = self.discEdgePalette[0]
+                  if str(self.visualizer.graph.links[links_index][colorIndex]) != "?":
+                      if maxValue == minValue:
+                          newColor = self.discEdgePalette[0]
+                      else:
+                          value = (float(self.visualizer.graph.links[links_index][colorIndex].value) - minValue) / (maxValue - minValue)
+                          newColor = self.contEdgePalette[value]
+                      
+                  self.networkCurve.setEdgeColor(index, newColor)
+                  
+              elif self.visualizer.graph.links.domain[colorIndex].varType == orange.VarTypes.Discrete:
+                  newColor = self.discEdgePalette[colorIndices[self.visualizer.graph.links[links_index][colorIndex].value]]
+                  if self.visualizer.graph.links[links_index][colorIndex].value == "0":
+                    self.networkCurve.setEdgeColor(index, newColor, nocolor=1)
+                  else:
+                    self.networkCurve.setEdgeColor(index, newColor)
+                  
+          else:
+              newColor = self.discEdgePalette[0]
+              self.networkCurve.setEdgeColor(index, newColor)
+      
+      self.replot()
+  
+  def setVertexColor(self, attribute):
+      if self.visualizer == None:
+          return
+      
+      colorIndices, colorIndex, minValue, maxValue = self.getColorIndeces(self.visualizer.graph.items, attribute, self.discPalette)
+
+      for v in range(self.nVertices):
+          if colorIndex != None:    
+              if self.visualizer.graph.items.domain[colorIndex].varType == orange.VarTypes.Continuous:
+                  newColor = self.discPalette[0]
+                  
+                  if str(self.visualizer.graph.items[v][colorIndex]) != "?":
+                      if maxValue == minValue:
+                          newColor = self.discPalette[0]
+                      else:
+                          value = (float(self.visualizer.graph.items[v][colorIndex].value) - minValue) / (maxValue - minValue)
+                          newColor = self.contPalette[value]
+                      
+                  self.networkCurve.setVertexColor(v, newColor)
+                  
+              elif self.visualizer.graph.items.domain[colorIndex].varType == orange.VarTypes.Discrete:
+                  newColor = self.discPalette[colorIndices[self.visualizer.graph.items[v][colorIndex].value]]
+                  #print newColor
+                  self.networkCurve.setVertexColor(v, newColor)
+                  
+          else:
+              newColor = self.discPalette[0]
+              self.networkCurve.setVertexColor(v, newColor)
+      
+      self.replot()
+      
+  def setLabelText(self, attributes):
+      self.labelText = []
+      if self.visualizer == None or self.visualizer.graph == None or self.visualizer.graph.items == None:
+          return
+      
+      if isinstance(self.visualizer.graph.items, orange.ExampleTable):
+          data = self.visualizer.graph.items
+          for att in attributes:
+              for i in range(len(data.domain)):
+                  if data.domain[i].name == att:
+                      self.labelText.append(i)
+                      
+              if self.visualizer.graph.items.domain.hasmeta(att):
+                      self.labelText.append(self.visualizer.graph.items.domain.metaid(att))
+  
+  def setTooltipText(self, attributes):
+      self.tooltipText = []
+      if self.visualizer == None or self.visualizer.graph == None or self.visualizer.graph.items == None:
+          return
+      
+      if isinstance(self.visualizer.graph.items, orange.ExampleTable):
+          data = self.visualizer.graph.items
+          for att in attributes:
+              for i in range(len(data.domain)):
+                  if data.domain[i].name == att:
+                      self.tooltipText.append(i)
+                      
+              if self.visualizer.graph.items.domain.hasmeta(att):
+                      self.tooltipText.append(self.visualizer.graph.items.domain.metaid(att))
+                      
+  def setEdgeLabelText(self, attributes):
+      self.edgeLabelText = []
+      if self.visualizer == None or self.visualizer.graph == None or self.visualizer.graph.items == None:
+          return
+      
+  def edgesContainsEdge(self, i, j):
+      for e in range(self.nEdges):
+          (key, iTmp, jTmp) = self.edges_old[e]
+          
+          if (iTmp == i and jTmp == j) or (iTmp == j and jTmp == i):
+              return True
+      return False
+      
+  def addVisualizer(self, visualizer, curve=None):
+      self.visualizer = visualizer
+      self.clear()
+      
+      self.nVertices = 0
+      self.nEdges = 0
+      self.vertexDegree = []
+      self.vertices_old = {}
+      self.vertices = []
+      self.edges_old = {}
+      self.nEdges = 0
+      if curve is None:
+          self.networkCurve = NetworkCurve(self)
+      else:
+          self.networkCurve = curve
+          
+      self.edges = []
+      self.minEdgeWeight = sys.maxint
+      self.maxEdgeWeight = 0
+      
+      if visualizer == None:
+          xMin = self.axisScaleDiv(QwtPlot.xBottom).interval().minValue()
+          xMax = self.axisScaleDiv(QwtPlot.xBottom).interval().maxValue()
+          yMin = self.axisScaleDiv(QwtPlot.yLeft).interval().minValue()
+          yMax = self.axisScaleDiv(QwtPlot.yLeft).interval().maxValue()
+          self.addMarker("no network", (xMax - xMin) / 2, (yMax - yMin) / 2, alignment=Qt.AlignCenter, size=self.fontSize)
+          self.tooltipNeighbours = 0
+          self.replot()
+          return
+      
+      self.nVertices = visualizer.graph.nVertices
+      #add nodes
+      for v in range(0, self.nVertices):
+          self.vertices_old[v] = (None, [])
+          vertex = NetworkVertex()
+          vertex.index = v
+          self.vertices.append(vertex)
+      
+      #build edge index
+      row_ind = {}
+      if visualizer.graph.links != None and len(visualizer.graph.links) > 0:
+        for i, r in enumerate(visualizer.graph.links):
+            u = int(r['u'].value)
+            v = int(r['v'].value)
+            u_dict = row_ind.get(u, {})
+            v_dict = row_ind.get(v, {})
+            u_dict[v] = i
+            v_dict[u] = i
+            row_ind[u] = u_dict
+            row_ind[v] = v_dict
+            
+      #add edges
+      for (i, j) in visualizer.graph.getEdges():
+          self.edges_old[self.nEdges] = (None, i, j)
+          edge = NetworkEdge()
+          edge.u = self.vertices[i]
+          edge.v = self.vertices[j]
+          
+          edge.weight = float(str(visualizer.graph[i, j][0]))  
+              
+          #print "weight:", edge.weight
+          
+          self.edges.append(edge)
+          self.nEdges += 1
+          
+          if edge.weight != None and self.minEdgeWeight > edge.weight:
+              self.minEdgeWeight = edge.weight
+              
+          elif edge.weight != None and self.maxEdgeWeight < edge.weight:
+              self.maxEdgeWeight = edge.weight
+            
+          if visualizer.graph.directed:
+              edge.arrowu = 0
+              edge.arrowv = 1
+          
+          if not hasattr(visualizer.graph, 'links'):
+            visualizer.graph.links = None
+            
+          if visualizer.graph.links != None and len(visualizer.graph.links) > 0:
+              edge.links_index = row_ind[i + 1][j + 1]
+              row = visualizer.graph.links[edge.links_index]
+              edge.label = [str(row[r].value) for r in range(2, len(row))]
+
+              #indexes = [k for k, x in enumerate(visualizer.graph.links) if (str(int(x[0])) == str(j + 1) and str(int(x[1])) == str(int(i + 1)))]
+              #for k in range(2, len(row[0])):
+              #    edge.label.append(str(row[0][k]))
+              #else:
+              #    print i, j, "not found"
+              
+              #if len(indexes) == 1:
+              #    edge.links_index = indexes[0]
+                        
+      if self.maxEdgeWeight < 10:
+          self.maxEdgeSize = self.maxEdgeWeight
+      else:
+          self.maxEdgeSize = 10
+          
+      self.setEdgesSize()
+      self.setVerticesSize()
+      
+      self.networkCurve.coors = visualizer.network.coors
+      self.networkCurve.vertices = self.vertices
+      self.networkCurve.edges = self.edges
+      self.networkCurve.changed()
+      
+  def setEdgesSize(self):
+      if self.maxEdgeWeight > self.minEdgeWeight:
+          #print 'maxEdgeSize',self.maxEdgeSize
+          #print 'maxEdgeWeight',self.maxEdgeWeight
+          #print 'minEdgeWeight',self.minEdgeWeight
+          k = (self.maxEdgeSize - 1) / (self.maxEdgeWeight - self.minEdgeWeight)
+          for edge in self.edges:
+              if edge.weight == None:
+                  size = 1
+                  edge.pen = QPen(edge.pen.color(), size)
+                  edge.pen.setCapStyle(Qt.RoundCap)
+              else:
+                  if self.invertEdgeSize:
+                      size = (self.maxEdgeWeight - edge.weight - self.minEdgeWeight) * k + 1
+                  else:
+                      size = (edge.weight - self.minEdgeWeight) * k + 1
+                  edge.pen = QPen(edge.pen.color(), size)
+                  edge.pen.setCapStyle(Qt.RoundCap)
+      else:
+          for edge in self.edges:
+              edge.pen = QPen(edge.pen.color(), 1)
+              edge.pen.setCapStyle(Qt.RoundCap)
+              
+  def setVerticesSize(self, column=None, inverted=0):
+      if self.visualizer == None or self.visualizer.graph == None or self.visualizer.graph.items == None:
+          return
+      
+      column = str(column)
+      
+      if column in self.visualizer.graph.items.domain or (column.startswith("num of ") and column.replace("num of ", "") in self.visualizer.graph.items.domain):
+          values = []
+          
+          if column in self.visualizer.graph.items.domain:
+              values = [x[column].value for x in self.visualizer.graph.items if not x[column].isSpecial()]
+          else:
+              values = [len(x[column.replace("num of ", "")].value.split(',')) for x in self.visualizer.graph.items]
+        
+          minVertexWeight = float(min(values or [0]))
+          maxVertexWeight = float(max(values or [0]))
+          
+          if maxVertexWeight - minVertexWeight == 0:
+              k = 1 #doesn't matter
+          else:
+              k = (self.maxVertexSize - self.minVertexSize) / (maxVertexWeight - minVertexWeight)
+          
+          def getValue(v):
+              if v.isSpecial():
+                  return minVertexWeight
+              else:
+                  return float(v)
+               
+          if inverted:
+              for vertex in self.vertices:
+                  if column in self.visualizer.graph.items.domain:
+                      vertex.size = self.maxVertexSize - ((getValue(self.visualizer.graph.items[vertex.index][column]) - minVertexWeight) * k)
+                  else:
+                      vertex.size = self.maxVertexSize - ((len(self.visualizer.graph.items[vertex.index][column.replace("num of ", "")].value.split(',')) - minVertexWeight) * k)
+                  
+                  
+                  vertex.pen.setWidthF(1 + float(vertex.size) / 20)
+          else:
+              for vertex in self.vertices:
+                  if column in self.visualizer.graph.items.domain:
+                      vertex.size = (getValue(self.visualizer.graph.items[vertex.index][column]) - minVertexWeight) * k + self.minVertexSize
+                  else:
+                      vertex.size = (float(len(self.visualizer.graph.items[vertex.index][column.replace("num of ", "")].value.split(','))) - minVertexWeight) * k + self.minVertexSize
+                      
+                  #print vertex.size
+                  vertex.pen.setWidthF(1 + float(vertex.size) / 20)
+      else:
+          for vertex in self.vertices:
+              vertex.size = self.maxVertexSize
+              vertex.pen.setWidthF(1 + float(vertex.size) / 20)
+    
+  def updateCanvas(self):
+      self.setAxisAutoScale(self.xBottom)
+      self.setAxisAutoScale(self.yLeft)
+      self.updateData()
+      self.replot()  
+  
+  def zoomExtent(self):
+      self.setAxisAutoScale(self.xBottom)
+      self.setAxisAutoScale(self.yLeft)
+      self.replot()
+      
+  def zoomSelection(self):
+      selection = self.networkCurve.getSelectedVertices()
+      if len(selection) > 0: 
+          x = [self.visualizer.network.coors[0][v] for v in selection]
+          y = [self.visualizer.network.coors[1][v] for v in selection]
+
+          oldXMin = self.axisScaleDiv(QwtPlot.xBottom).interval().minValue()
+          oldXMax = self.axisScaleDiv(QwtPlot.xBottom).interval().maxValue()
+          oldYMin = self.axisScaleDiv(QwtPlot.yLeft).interval().minValue()
+          oldYMax = self.axisScaleDiv(QwtPlot.yLeft).interval().maxValue()
+          newXMin = min(x)
+          newXMax = max(x)
+          newYMin = min(y)
+          newYMax = max(y)
+          self.zoomStack.append((oldXMin, oldXMax, oldYMin, oldYMax))
+          self.setAxisScale(QwtPlot.xBottom, newXMin - 100, newXMax + 100)
+          self.setAxisScale(QwtPlot.yLeft, newYMin - 100, newYMax + 100)
+          self.replot()
+                  
Index: Orange/OrangeWidgets/Unsupervised/OWNetworkFile.py
===================================================================
--- Orange/OrangeWidgets/Unsupervised/OWNetworkFile.py	(revision 10466)
+++ Orange/OrangeWidgets/Unsupervised/OWNetworkFile.py	(revision 10466)
@@ -0,0 +1,452 @@
+"""
+THIS WIDGET IS OBSOLETE; USE OWNxFile.py
+"""
+
+#
+# OWNetworkFile.py
+# The Network File Widget
+# A widget for opening Network related files
+#
+import OWGUI, string, os.path, user, sys
+import orngNetwork
+
+from OWWidget import *
+from orange import Graph
+from orange import GraphAsList
+
+class OWNetworkFile(OWWidget):
+    
+    settingsList=["recentFiles", "recentDataFiles", "recentEdgesFiles"]
+    
+    def __init__(self,parent=None, signalManager = None):
+        OWWidget.__init__(self, parent, signalManager, "Network File", wantMainArea=False)
+
+        self.inputs = []
+        self.outputs = [("Network", orngNetwork.Network), ("Items", ExampleTable)]
+    
+        #set default settings
+        self.recentFiles = ["(none)"]
+        self.recentDataFiles = ["(none)"]
+        self.recentEdgesFiles = ["(none)"]
+        
+        self.domain = None
+        self.graph = None
+        #get settings from the ini file, if they exist
+        self.loadSettings()
+
+        #GUI
+        self.controlArea.layout().setMargin(4)
+        self.box = OWGUI.widgetBox(self.controlArea, box = "Graph File", orientation = "horizontal")
+        self.filecombo = OWGUI.comboBox(self.box, self, "filename")
+        self.filecombo.setMinimumWidth(250)
+        button = OWGUI.button(self.box, self, '...', callback = self.browseNetFile, disabled=0)
+        button.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon))
+        button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
+        
+        self.databox = OWGUI.widgetBox(self.controlArea, box = "Vertices Data File", orientation = "horizontal")
+        self.datacombo = OWGUI.comboBox(self.databox, self, "dataname")
+        self.datacombo.setMinimumWidth(250)
+        button = OWGUI.button(self.databox, self, '...', callback = self.browseDataFile, disabled=0)
+        button.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon))
+        button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
+        
+        self.edgesbox = OWGUI.widgetBox(self.controlArea, box = "Edges Data File", orientation = "horizontal")
+        self.edgescombo = OWGUI.comboBox(self.edgesbox, self, "edgesname")
+        self.edgescombo.setMinimumWidth(250)
+        button = OWGUI.button(self.edgesbox, self, '...', callback = self.browseEdgesFile, disabled=0)
+        button.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon))
+        button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
+        
+        # info
+        box = OWGUI.widgetBox(self.controlArea, "Info")
+        self.infoa = OWGUI.widgetLabel(box, 'No data loaded.')
+        self.infob = OWGUI.widgetLabel(box, ' ')
+        self.infoc = OWGUI.widgetLabel(box, ' ')
+        self.infod = OWGUI.widgetLabel(box, ' ')
+
+        OWGUI.rubber(self.controlArea)
+        self.resize(150,100)
+        self.activateLoadedSettings()
+
+        # connecting GUI to code
+        self.connect(self.filecombo, SIGNAL('activated(int)'), self.selectNetFile)
+        self.connect(self.datacombo, SIGNAL('activated(int)'), self.selectDataFile)
+        self.connect(self.edgescombo, SIGNAL('activated(int)'), self.selectEdgesFile)
+        
+    # set the comboboxes
+    def setFileLists(self):
+        self.filecombo.clear()
+        if not self.recentFiles:
+            self.filecombo.addItem("(none)")
+        for file in self.recentFiles:
+            if file == "(none)":
+                self.filecombo.addItem("(none)")
+            else:
+                self.filecombo.addItem(os.path.split(file)[1])
+        self.filecombo.addItem("Browse documentation networks...")
+        
+        self.datacombo.clear()
+        if not self.recentDataFiles:
+            self.datacombo.addItem("(none)")
+        for file in self.recentDataFiles:
+            if file == "(none)":
+                self.datacombo.addItem("(none)")
+            else:
+                self.datacombo.addItem(os.path.split(file)[1])
+                
+        self.edgescombo.clear()
+        if not self.recentEdgesFiles:
+            self.edgescombo.addItem("(none)")
+        for file in self.recentEdgesFiles:
+            if file == "(none)":
+                self.edgescombo.addItem("(none)")
+            else:
+                self.edgescombo.addItem(os.path.split(file)[1])
+            
+        self.filecombo.updateGeometry()
+        self.datacombo.updateGeometry()
+        self.edgescombo.updateGeometry()
+     
+    def activateLoadedSettings(self):
+        # remove missing data set names
+        self.recentFiles = filter(os.path.exists, self.recentFiles)
+        self.recentDataFiles = filter(os.path.exists, self.recentDataFiles)
+        self.recentEdgesFiles = filter(os.path.exists, self.recentEdgesFiles)
+        
+        self.recentFiles.append("(none)")
+        self.recentDataFiles.append("(none)")
+        self.recentEdgesFiles.append("(none)")
+        self.setFileLists()
+        
+        if len(self.recentFiles) > 0 and os.path.exists(self.recentFiles[0]):
+            self.selectNetFile(0)
+
+        if len(self.recentDataFiles) > 1 and os.path.exists(self.recentDataFiles[1]):
+            self.selectDataFile(1)
+            
+        if len(self.recentEdgesFiles) > 1 and os.path.exists(self.recentEdgesFiles[1]):
+            self.selectEdgesFile(1)
+        
+    # user selected a graph file from the combo box
+    def selectNetFile(self, n):
+        if n < len(self.recentFiles) :
+            name = self.recentFiles[n]
+            self.recentFiles.remove(name)
+            self.recentFiles.insert(0, name)
+        elif n:
+            self.browseNetFile(1)
+            
+        if len(self.recentFiles) > 0:
+            self.setFileLists()  
+            self.openFile(self.recentFiles[0])
+    
+    # user selected a data file from the combo box
+    def selectEdgesFile(self, n):
+        if n < len(self.recentEdgesFiles) :
+            name = self.recentEdgesFiles[n]
+            self.recentEdgesFiles.remove(name)
+            self.recentEdgesFiles.insert(0, name)
+
+        if len(self.recentEdgesFiles) > 0:
+            self.setFileLists()
+            self.addEdgesFile(self.recentEdgesFiles[0])
+    
+    def selectDataFile(self, n):
+        if n < len(self.recentDataFiles) :
+            name = self.recentDataFiles[n]
+            self.recentDataFiles.remove(name)
+            self.recentDataFiles.insert(0, name)
+
+        if len(self.recentDataFiles) > 0:
+            self.setFileLists()
+            self.addDataFile(self.recentDataFiles[0])
+    
+    def openFile(self, fn):
+        """Read network from file."""
+        
+        # read network file
+        if fn != "(none)":
+            fileExt = lower(os.path.splitext(fn)[1])
+            if not fileExt in (".net", ".gml"):
+                self.graph = None
+                self.send("Network", None)
+                self.send("Items", None)
+                self.infoa.setText('No data loaded')
+                self.infob.setText('File extension does not match')
+                self.infoc.setText('')            
+                self.infod.setText('')
+                return
+            
+            data = self.readNetFile(fn)
+            
+            if data == None:
+                self.graph = None
+                self.send("Network", None)
+                self.send("Items", None)
+                self.infoa.setText('No data loaded')
+                self.infob.setText('Error reading file')
+                self.infoc.setText('')            
+                self.infod.setText('')
+                return
+
+            self.infoa.setText("%d nodes" % data.nVertices)
+            
+            if data.directed:
+                self.infob.setText("Directed graph")
+            else:
+                self.infob.setText("Undirected graph")
+            
+            # make new data and send it
+            fName = os.path.split(fn)[1]
+            if "." in fName:
+                #data.name = string.join(string.split(fName, '.')[:-1], '.')
+                pass
+            else:
+                #data.name = fName
+                pass
+                
+            self.graph = data
+        else:
+            self.graph = None
+            self.send("Network", None)
+            self.send("Items", None)
+            self.infoa.setText('No data loaded')
+            self.infob.setText('')
+            self.infoc.setText('')            
+            self.infod.setText('')
+        
+        # Find items data file for selected network
+        items_candidate = os.path.splitext(fn)[0] + ".tab"
+        if os.path.exists(items_candidate):
+            self.readDataFile(items_candidate)
+            self.recentDataFiles.insert(0, items_candidate)
+        elif os.path.exists(os.path.splitext(fn)[0] + "_items.tab"):
+            items_candidate = os.path.splitext(fn)[0] + "_items.tab"
+            self.readDataFile(items_candidate)
+            self.recentDataFiles.insert(0, items_candidate)
+        else:
+            if '(none)' in self.recentDataFiles: 
+                self.recentDataFiles.remove('(none)')
+            self.recentDataFiles.insert(0, '(none)')
+        
+        # Find links data file for selected network
+        links_candidate = os.path.splitext(fn)[0] + "_links.tab" 
+        if os.path.exists(links_candidate):
+            self.readEdgesFile(links_candidate)
+            self.recentEdgesFiles.insert(0, links_candidate)
+        else:
+            if '(none)' in self.recentEdgesFiles: 
+                self.recentEdgesFiles.remove('(none)')
+            self.recentEdgesFiles.insert(0, '(none)')
+        
+        self.setFileLists()
+        
+        self.send("Network", self.graph)
+        if self.graph != None and self.graph.items != None:
+            self.send("Items", self.graph.items)
+        else:
+            self.send("Items", None)
+        
+    def addDataFile(self, fn):
+        if fn == "(none)" or self.graph == None:
+            self.infoc.setText("No vertices data file specified")
+            self.send("Network", None)
+            self.send("Items", None)
+            return
+         
+        self.readDataFile(fn)
+        
+        self.send("Network", self.graph)
+        self.send("Items", self.graph.items)
+        
+    def readDataFile(self, fn):
+        table = ExampleTable(fn)
+        
+        if len(table) != self.graph.nVertices:
+            self.infoc.setText("Vertices data length does not match number of vertices")
+            
+            if '(none)' in self.recentDataFiles: 
+                self.recentDataFiles.remove('(none)')
+                
+            self.recentDataFiles.insert(0, '(none)')
+            self.setFileLists()
+            return
+        
+        self.graph.setattr("items", table)
+        self.infoc.setText("Vertices data file added")
+        
+    def addEdgesFile(self, fn):
+        if fn == "(none)" or self.graph == None:
+            self.infod.setText("No edges data file specified")
+            #self.graph.setattr("links", None)
+            self.send("Network", self.graph)
+            self.send("Items", None)
+            return
+        
+        self.readEdgesFile(fn)
+        
+        self.send("Network", self.graph)
+        self.send("Items", self.graph.items)
+        
+    def readEdgesFile(self, fn):
+        table = ExampleTable(fn)
+        if self.graph.directed:
+            nEdges = len(self.graph.getEdges())
+        else:
+            nEdges = len(self.graph.getEdges()) / 2
+            
+        if len(table) != nEdges:
+            self.infod.setText("Edges data length does not match number of edges")
+            
+            if '(none)' in self.recentEdgesFiles: 
+                self.recentEdgesFiles.remove('(none)')
+                
+            self.recentEdgesFiles.insert(0, '(none)')
+            self.setFileLists()
+            return
+        
+        self.graph.setattr("links", table)
+        self.infod.setText("Edges data file added")
+        
+    def browseNetFile(self, inDemos=0):
+        """user pressed the '...' button to manually select a file to load"""
+        
+        "Display a FileDialog and select a file"
+        if inDemos:
+            import os
+            try:
+                import orngConfiguration
+                startfile = orngConfiguration.datasetsPath
+            except:
+                startfile = ""
+                
+            if not startfile or not os.path.exists(startfile):
+                try:
+                    import win32api, win32con
+                    t = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SOFTWARE\\Python\\PythonCore\\%i.%i\\PythonPath\\Orange" % sys.version_info[:2], 0, win32con.KEY_READ)
+                    t = win32api.RegQueryValueEx(t, "")[0]
+                    startfile = t[:t.find("orange")] + "orange\\doc\\networks"
+                except:
+                    startfile = ""
+
+            if not startfile or not os.path.exists(startfile):
+                d = OWGUI.__file__
+                if d[-8:] == "OWGUI.py":
+                    startfile = d[:-22] + "doc/networks"
+                elif d[-9:] == "OWGUI.pyc":
+                    startfile = d[:-23] + "doc/networks"
+
+            if not startfile or not os.path.exists(startfile):
+                d = os.getcwd()
+                if d[-12:] == "OrangeCanvas":
+                    startfile = d[:-12]+"doc/networks"
+                else:
+                    if d[-1] not in ["/", "\\"]:
+                        d+= "/"
+                    startfile = d+"doc/networks"
+
+            if not os.path.exists(startfile):
+                QMessageBox.information( None, "File", "Cannot find the directory with example networks", QMessageBox.Ok + QMessageBox.Default)
+                return
+        else:
+            if len(self.recentFiles) == 0 or self.recentFiles[0] == "(none)":
+                if sys.platform == "darwin":
+                    startfile = user.home
+                else:
+                    startfile = "."
+            else:
+                startfile = self.recentFiles[0]
+                
+        filename = unicode(QFileDialog.getOpenFileName(self, 'Open a Network File', 
+                    startfile, "Pajek files (*.net)\nGML files (*.gml)\nAll files (*.*)"))
+        
+        if filename == "": return
+        if filename in self.recentFiles: self.recentFiles.remove(filename)
+        self.recentFiles.insert(0, filename)
+        self.setFileLists()
+        self.selectNetFile(0)
+        
+    def browseDataFile(self, inDemos=0):
+        if self.graph == None:
+            return
+        
+        #Display a FileDialog and select a file
+        if len(self.recentDataFiles) == 0 or self.recentDataFiles[0] == "(none)":
+            if len(self.recentFiles) == 0 or self.recentFiles[0] == "(none)":
+                if sys.platform == "darwin":
+                    startfile = user.home
+                else:
+                    startfile="."
+            else:
+                startfile = os.path.dirname(self.recentFiles[0])
+                
+        else:
+            startfile = self.recentDataFiles[0]
+                
+        filename = unicode(QFileDialog.getOpenFileName(self, 'Open a Vertices Data File', startfile, 'Data files (*.tab)\nAll files(*.*)'))
+    
+        if filename == "": return
+        if filename in self.recentDataFiles: self.recentDataFiles.remove(filename)
+        self.recentDataFiles.insert(0, filename)
+        self.setFileLists()
+        self.addDataFile(self.recentDataFiles[0])
+        
+    def browseEdgesFile(self, inDemos=0):
+        if self.graph == None:
+            return
+        
+        #Display a FileDialog and select a file
+        if len(self.recentEdgesFiles) == 0 or self.recentEdgesFiles[0] == "(none)":
+            if len(self.recentFiles) == 0 or self.recentFiles[0] == "(none)":
+                if sys.platform == "darwin":
+                    startfile = user.home
+                else:
+                    startfile="."
+            else:
+                startfile = os.path.dirname(self.recentFiles[0])
+                
+        else:
+            startfile = self.recentEdgesFiles[0]
+                
+        filename = unicode(QFileDialog.getOpenFileName(self, 'Open a Edges Data File', startfile, 'Data files (*.tab)\nAll files(*.*)'))
+    
+        if filename == "": return
+        if filename in self.recentEdgesFiles: self.recentEdgesFiles.remove(filename)
+        self.recentEdgesFiles.insert(0, filename)
+        self.setFileLists()
+        self.addEdgesFile(self.recentEdgesFiles[0])
+
+    def setInfo(self, info):
+        for (i, s) in enumerate(info):
+            self.info[i].setText(s)            
+
+    def readNetFile(self, fn):
+        try:
+            net = orngNetwork.Network.read(fn)
+            self.infoc.setText("Vertices data generated and added automatically")
+        except:
+            self.infoa.setText("Could not read file")
+            self.infob.setText("")
+            self.infoc.setText("")
+            self.infod.setText("")
+            return None
+        
+        return net
+
+    def sendReport(self):
+        self.reportSettings("Network file",
+                            [("File name", self.filecombo.currentText()),
+                             ("Vertices", self.graph.nVertices),
+                             hasattr(self.graph, "directed") and ("Directed", OWGUI.YesNo[self.graph.directed])])
+        self.reportSettings("Vertices meta data", [("File name", self.datacombo.currentText())])
+        self.reportData(self.graph.items, None)
+        self.reportSettings("Edges meta data", [("File name", self.edgescombo.currentText())])
+        self.reportData(self.graph.links, None, None)
+        
+if __name__ == "__main__":
+    a=QApplication(sys.argv)
+    owf=OWNetworkFile()
+    owf.activateLoadedSettings()
+    owf.show()  
+    a.exec_()
+    owf.saveSettings()
Index: Orange/OrangeWidgets/Unsupervised/OWNetworkFromDistances.py
===================================================================
--- Orange/OrangeWidgets/Unsupervised/OWNetworkFromDistances.py	(revision 9671)
+++ Orange/OrangeWidgets/Unsupervised/OWNetworkFromDistances.py	(revision 9671)
@@ -0,0 +1,85 @@
+"""
+THIS WIDGET IS OBSOLETE; USE OWNxFromDistances.py
+"""
+
+#
+# OWNetworkFromDistances.py
+#
+
+import OWGUI
+import orange
+import orngNetwork
+import copy, random
+
+from OWNetworkHist import *
+from OWWidget import *
+from OWGraph import *
+from OWHist import *
+
+class OWNetworkFromDistances(OWWidget, OWNetworkHist):
+    settingsList=["spinLowerThreshold", "spinUpperThreshold", "netOption", "dstWeight", "kNN", "andor", "excludeLimit"]
+    
+    def __init__(self, parent=None, signalManager=None):
+        OWWidget.__init__(self, parent, signalManager, "Network from Distances")
+        OWNetworkHist.__init__(self)
+        
+        self.inputs = [("Distances", orange.SymMatrix, self.setMatrix)]
+        self.outputs = [("Network", orngNetwork.Network), ("Data", ExampleTable), ("Distances", orange.SymMatrix)]
+
+        self.addHistogramControls()
+        
+        # get settings from the ini file, if they exist
+        self.loadSettings()
+        
+        # GUI
+        # general settings
+        boxHistogram = OWGUI.widgetBox(self.mainArea, box = "Distance histogram")
+        self.histogram = OWHist(self, boxHistogram)
+        boxHistogram.layout().addWidget(self.histogram)
+
+        boxHistogram.setMinimumWidth(500)
+        boxHistogram.setMinimumHeight(300)
+        
+        # info
+        boxInfo = OWGUI.widgetBox(self.controlArea, box = "Network info")
+        self.infoa = OWGUI.widgetLabel(boxInfo, "No data loaded.")
+        self.infob = OWGUI.widgetLabel(boxInfo, '')
+        self.infoc = OWGUI.widgetLabel(boxInfo, '')
+        
+        OWGUI.rubber(self.controlArea)
+        
+        self.resize(700, 100)
+
+    def sendReport(self):
+        self.reportSettings("Settings",
+                            [("Edge thresholds", "%.5f - %.5f" % (self.spinLowerThreshold, self.spinUpperThreshold)),
+                             ("Selected vertices", ["All", "Without isolated vertices", "Largest component", "Connected with vertex"][self.netOption]),
+                             ("Weight", ["Distance", "1 - Distance"][self.dstWeight])])
+        self.reportSection("Histogram")
+        self.reportImage(self.histogram.saveToFileDirect, QSize(400,300))
+        self.reportSettings("Output graph",
+                            [("Vertices", self.matrix.dim),
+                             ("Edges", self.nedges),
+                             ("Connected vertices", "%i (%.1f%%)" % (self.pconnected, self.pconnected / max(1, float(self.matrix.dim))*100)),
+                             ])
+        
+    def sendSignals(self):
+        if self.graph != None:
+            #setattr(matrix, "items", self.graph.items)
+            self.matrix.items = self.graph.items
+        
+        self.send("Network", self.graph)
+        
+        if self.matrix:
+            self.send("Distances", self.matrix)
+            
+        if self.graph == None:
+            self.send("Data", None)
+        else:
+            self.send("Data", self.graph.items)
+                                                                     
+if __name__ == "__main__":    
+    appl = QApplication(sys.argv)
+    ow = OWNetworkFromDistances()
+    ow.show()
+    appl.exec_()
Index: Orange/OrangeWidgets/Unsupervised/OWNxAnalysis.py
===================================================================
--- Orange/OrangeWidgets/Unsupervised/OWNxAnalysis.py	(revision 10510)
+++ Orange/OrangeWidgets/Unsupervised/OWNxAnalysis.py	(revision 10046)
@@ -6,5 +6,4 @@
 <priority>6425</priority>
 """
-from PyQt4.QtCore import QMutex
 import numpy
 import networkx as nx
@@ -67,5 +66,5 @@
         self.outputs = [("Network", Orange.network.Graph), 
                         ("Items", Orange.data.Table)]
-
+    
         self.methods = [
             ("number_of_nodes", True, "Number of nodes", GRAPHLEVEL, lambda G: G.number_of_nodes()),
@@ -76,17 +75,10 @@
             ("average_shortest_path_length", False, "Average shortest path length", GRAPHLEVEL, nx.average_shortest_path_length),
             ("density", True, "Density", GRAPHLEVEL, nx.density),
-            ("degree_assortativity_coefficient", False, \
-                "Degree assortativity coefficient", GRAPHLEVEL, \
-                    nx.degree_assortativity_coefficient if \
-                    hasattr(nx, "degree_assortativity_coefficient") else None),
+            ("degree_assortativity_coefficient", False, "Degree assortativity coefficient", GRAPHLEVEL, nx.degree_assortativity_coefficient),
             # additional attr needed
             #("attribute_assortativity_coefficient", False, "Attribute assortativity coefficient", GRAPHLEVEL, nx.attribute_assortativity_coefficient),
             #("numeric_assortativity_coefficient", False, "Numeric assortativity coefficient", GRAPHLEVEL, nx.numeric_assortativity_coefficient),
-            ("degree_pearson_correlation_coefficient", False, \
-                "Degree pearson correlation coefficient", GRAPHLEVEL, \
-                nx.degree_pearson_correlation_coefficient if\
-                hasattr(nx, "degree_pearson_correlation_coefficient") else None),
-            ("estrada_index", False, "Estrada index", GRAPHLEVEL, \
-                nx.estrada_index if hasattr(nx, "estrada_index") else None),
+            ("degree_pearson_correlation_coefficient", False, "Degree pearson correlation coefficient", GRAPHLEVEL, nx.degree_pearson_correlation_coefficient),
+            ("estrada_index", False, "Estrada index", GRAPHLEVEL, nx.estrada_index),
             ("graph_clique_number", False, "Graph clique number", GRAPHLEVEL, nx.graph_clique_number),
             ("graph_number_of_cliques", False, "Graph number of cliques", GRAPHLEVEL, nx.graph_number_of_cliques),
@@ -120,9 +112,5 @@
             ("current_flow_closeness_centrality", False, "Information centrality", NODELEVEL, nx.current_flow_closeness_centrality),
             ("current_flow_betweenness_centrality", False, "Random-walk betweenness centrality", NODELEVEL, nx.current_flow_betweenness_centrality),
-            ("approximate_current_flow_betweenness_centrality", False, \
-                "Approx. random-walk betweenness centrality", NODELEVEL, \
-                nx.approximate_current_flow_betweenness_centrality if \
-                hasattr(nx, "approximate_current_flow_betweenness_centrality") \
-                    else None),
+            ("approximate_current_flow_betweenness_centrality", False, "Approx. random-walk betweenness centrality", NODELEVEL, nx.approximate_current_flow_betweenness_centrality),
             ("eigenvector_centrality", False, "Eigenvector centrality", NODELEVEL, nx.eigenvector_centrality),
             ("eigenvector_centrality_numpy", False, "Eigenvector centrality (NumPy)", NODELEVEL, nx.eigenvector_centrality_numpy),
@@ -132,6 +120,4 @@
             ("closeness_vitality", False, "Closeness vitality", NODELEVEL, nx.closeness_vitality),                    
         ]
-
-        self.methods = [method for method in self.methods if method[-1] is not None]
         
         self.auto_commit = False
Index: Orange/__init__.py
===================================================================
--- Orange/__init__.py	(revision 10540)
+++ Orange/__init__.py	(revision 10491)
@@ -80,5 +80,4 @@
 _import("ensemble.boosting")
 _import("ensemble.forest")
-_import("ensemble.stacking")
 
 _import("regression")
Index: Orange/classification/rules.py
===================================================================
--- Orange/classification/rules.py	(revision 10519)
+++ Orange/classification/rules.py	(revision 10407)
@@ -39,11 +39,36 @@
 Validator_LRS = Orange.core.RuleValidator_LRS
     
-from Orange.orng.orngABML import \
-    ArgumentFilter_hasSpecial, \
-    create_dichotomous_class, \
-    evaluateAndSortArguments
 from Orange.misc import deprecated_keywords
 from Orange.misc import deprecated_members
 
+
+class ConvertClass:
+    """ Converting class variables into dichotomous class variable. """
+    def __init__(self, classAtt, classValue, newClassAtt):
+        self.classAtt = classAtt
+        self.classValue = classValue
+        self.newClassAtt = newClassAtt
+
+    def __call__(self, example, returnWhat):
+        if example[self.classAtt] == self.classValue:
+            return Orange.data.Value(self.newClassAtt, self.classValue + "_")
+        else:
+            return Orange.data.Value(self.newClassAtt, "not " + self.classValue)
+
+
+def create_dichotomous_class(domain, att, value, negate, removeAtt=None):
+    # create new variable
+    newClass = Orange.feature.Discrete(att.name + "_", values=[str(value) + "_", "not " + str(value)])
+    positive = Orange.data.Value(newClass, str(value) + "_")
+    negative = Orange.data.Value(newClass, "not " + str(value))
+    newClass.getValueFrom = ConvertClass(att, str(value), newClass)
+
+    att = [a for a in domain.attributes]
+    newDomain = Orange.data.Domain(att + [newClass])
+    newDomain.addmetas(domain.getmetas())
+    if negate == 1:
+        return (newDomain, negative)
+    else:
+        return (newDomain, positive)
 
 
@@ -534,5 +559,5 @@
                  rule_sig=1.0, att_sig=1.0, postpruning=None, min_quality=0., min_coverage=1, min_improved=1, min_improved_perc=0.0,
                  learn_for_class=None, learn_one_rule=False, evd=None, evd_arguments=None, prune_arguments=False, analyse_argument= -1,
-                 alternative_learner=None, min_cl_sig=0.5, min_beta=0.0, set_prefix_rules=False, add_sub_rules=True, debug=False,
+                 alternative_learner=None, min_cl_sig=0.5, min_beta=0.0, set_prefix_rules=False, add_sub_rules=False, debug=False,
                  **kwds):
 
@@ -627,5 +652,5 @@
             while aes:
                 if self.analyse_argument > -1 and \
-                   (isinstance(self.analyse_argument, Orange.core.Example) and not Orange.core.Example(dich_data.domain, self.analyse_argument) == aes[0] or \
+                   (isinstance(self.analyse_argument, Orange.data.Instance) and not Orange.data.Instance(dich_data.domain, self.analyse_argument) == aes[0] or \
                     isinstance(self.analyse_argument, int) and not dich_data[self.analyse_argument] == aes[0]):
                     aes = aes[1:]
@@ -642,4 +667,5 @@
                 else:
                     aes = aes[1:]
+                aes = aes[1:]
 
             if not progress and self.debug:
@@ -648,5 +674,5 @@
             # remove all examples covered by rules
             for rule in rules:
-                dich_data = self.remove_covered_examples(rule, dich_data, weight_id, True)
+                dich_data = self.remove_covered_examples(rule, dich_data, weight_id)
             if progress:
                 progress(self.remaining_probability(dich_data), None)
@@ -657,19 +683,13 @@
                 while dich_data:
                     # learn a rule
-                    rule, good_rule = self.learn_normal_rule(dich_data, weight_id, self.apriori)
+                    rule = self.learn_normal_rule(dich_data, weight_id, self.apriori)
                     if not rule:
                         break
                     if self.debug:
-                        if good_rule:
-                            print "rule learned: ", rule_to_string(rule), rule.quality
-                        else:
-                            print "rule only to influence learning: ", rule_to_string(rule), rule.quality
-                            
-                    dich_data = self.remove_covered_examples(rule, dich_data, weight_id, good_rule)
-
+                        print "rule learned: ", Orange.classification.rules.rule_to_string(rule), rule.quality
+                    dich_data = self.remove_covered_examples(rule, dich_data, weight_id)
                     if progress:
                         progress(self.remaining_probability(dich_data), None)
-                    if good_rule:
-                        rules.append(rule)
+                    rules.append(rule)
                     if self.learn_one_rule:
                         break
@@ -695,7 +715,4 @@
         if not positive_args: # something wrong
             raise "There is a problem with argumented example %s" % str(ae)
-            return None
-        if False in [p(ae) for p in positive_args]: # a positive argument is not covering this example
-            raise "One argument does not cover critical example: %s!"%str(ae)
             return None
         negative_args = self.init_neg_args(ae, examples, weight_id)
@@ -790,20 +807,14 @@
         if hasattr(self.rule_finder.evaluator, "bestRule"):
             self.rule_finder.evaluator.bestRule = None
-        rule = self.rule_finder(examples,weight_id,0,RuleList())
+        rule = self.rule_finder(examples, weight_id, 0, RuleList())
         if hasattr(self.rule_finder.evaluator, "bestRule") and self.rule_finder.evaluator.returnExpectedProb:
-            if not self.rule_finder.evaluator.bestRule and rule.quality > 0:
-                return (rule, False)
             rule = self.rule_finder.evaluator.bestRule
             self.rule_finder.evaluator.bestRule = None
         if self.postpruning:
-            rule = self.postpruning(rule,examples,weight_id,0, aprior)
-        return (rule, True)
-    
-
-    def remove_covered_examples(self, rule, examples, weight_id, good_rule):
-        if good_rule:
-            nexamples, nweight = self.cover_and_remove(rule, examples, weight_id, 0)
-        else:
-            nexamples, nweight = self.cover_and_remove.mark_examples_solved(rule,examples,weight_id,0)
+            rule = self.postpruning(rule, examples, weight_id, 0, aprior)
+        return rule
+
+    def remove_covered_examples(self, rule, examples, weight_id):
+        nexamples, nweight = self.cover_and_remove(rule, examples, weight_id, 0)
         return nexamples
 
@@ -848,5 +859,5 @@
                     self.rule_finder.evaluator.returnExpectedProb = oldREP
                 tmpList.sort(lambda x, y:-cmp(x.quality, y.quality))
-                tmpList = tmpList[:self.ruleFilter.width]
+                tmpList = tmpList[:self.rule_filter.width]
 
                 for tmpRule in tmpList:
@@ -862,5 +873,5 @@
                             tmpRule2.filterAndStore(examples, weight_id, r.classifier.default_val)
                             tmpRule2.complexity += 1
-                            if tmpRule2.class_distribution.abs < tmpRule.class_distribution.abs:
+                            if tmpRule2.class_distribution.abs < tmprule.class_distribution.abs:
                                 tmpList2.append(tmpRule2)
                 tmpList = tmpList2
@@ -1214,7 +1225,7 @@
             if r and not rule_in_set(r, best_rules) and int(examples[r_i].getclass()) == int(r.classifier.default_value):
                 if hasattr(r.learner, "arg_example"):
-                    r.setattr("best_example", r.learner.arg_example)
+                    setattr(r, "best_example", r.learner.arg_example)
                 else:
-                    r.setattr("best_example", examples[r_i])
+                    setattr(r, "best_example", examples[r_i])
                 best_rules.append(r)
         return best_rules
@@ -1223,21 +1234,44 @@
         """ if example has an argument, then the rule must be consistent with the argument. """
         example = getattr(rule.learner, "arg_example", None)
-        if example:
-            for ei, e in enumerate(examples):
-                if e == example:
-                    e[self.prob_attribute] = rule.quality+0.001 # 0.001 is added to avoid numerical errors
-                    self.best_rule[ei]=rule
-        else:        
-            for ei, e in enumerate(examples):
-                if rule(e) and rule.quality>e[self.prob_attribute]:
-                    e[self.prob_attribute] = rule.quality+0.001 # 0.001 is added to avoid numerical errors
-                    self.best_rule[ei]=rule
+        for ei, e in enumerate(examples):
+            if e == example:
+                e[self.prob_attribute] = 1.0
+                self.best_rule[ei] = rule
+            elif rule(e) and rule.quality > e[self.prob_attribute]:
+                e[self.prob_attribute] = rule.quality + 0.001 # 0.001 is added to avoid numerical errors
+                self.best_rule[ei] = rule
         return (examples, weights)
 
-    def mark_examples_solved(self, rule, examples, weights, target_class):
-        for ei, e in enumerate(examples):
-            if rule(e):
-                e[self.prob_attribute] = 1.0
-        return (examples, weights)
+    def filter_covers_example(self, example, filter):
+        filter_indices = CoversArguments.filterIndices(filter)
+        if filter(example):
+            try:
+                if example[self.argument_id].value and len(example[self.argument_id].value.positive_arguments) > 0: # example has positive arguments
+                    # conditions should cover at least one of the positive arguments
+                    one_arg_covered = False
+                    for pA in example[self.argument_id].value.positive_arguments:
+                        arg_covered = [self.condIn(c, filter_indices) for c in pA.filter.conditions]
+                        one_arg_covered = one_arg_covered or len(arg_covered) == sum(arg_covered) #arg_covered
+                        if one_arg_covered:
+                            break
+                    if not one_arg_covered:
+                        return False
+                if example[self.argument_id].value and len(example[self.argument_id].value.negative_arguments) > 0: # example has negative arguments
+                    # condition should not cover neither of negative arguments
+                    for pN in example[self.argument_id].value.negative_arguments:
+                        arg_covered = [self.condIn(c, filter_indices) for c in pN.filter.conditions]
+                        if len(arg_covered) == sum(arg_covered):
+                            return False
+            except:
+                return True
+            return True
+        return False
+
+    def condIn(self, cond, filter_indices): # is condition in the filter?
+        condInd = CoversArguments.conditionIndex(cond)
+        if operator.or_(condInd, filter_indices[cond.position]) == filter_indices[cond.position]:
+            return True
+        return False
+
 
     def covered_percentage(self, examples):
@@ -1708,52 +1742,58 @@
 # This filter is the ugliest code ever! Problem is with Orange, I had some problems with inheriting deepCopy
 # I should take another look at it.
-class ArgFilter(Orange.core.Filter):
+class ArgFilter(Orange.data.filter.Filter):
     """ This class implements AB-covering principle. """
-    def __init__(self, argument_id=None, filter = Orange.core.Filter_values(), arg_example = None):
+    def __init__(self, argument_id=None, filter=Orange.data.filter.Values(), arg_example=None):
         self.filter = filter
-        self.indices = getattr(filter,"indices",[])
-        if not self.indices and len(filter.conditions)>0:
-            self.indices = RuleCoversArguments.filterIndices(filter)
+        self.indices = getattr(filter, "indices", [])
+        if not self.indices and len(filter.conditions) > 0:
+            self.indices = CoversArguments.filterIndices(filter)
         self.argument_id = argument_id
         self.domain = self.filter.domain
         self.conditions = filter.conditions
         self.arg_example = arg_example
-        self.only_arg_example = True
-        
-    def condIn(self,cond): # is condition in the filter?
-        condInd = RuleCoversArguments.conditionIndex(cond)
-        if operator.or_(condInd,self.indices[cond.position]) == self.indices[cond.position]:
+
+    def condIn(self, cond): # is condition in the filter?
+        condInd = ruleCoversArguments.conditionIndex(cond)
+        if operator.or_(condInd, self.indices[cond.position]) == self.indices[cond.position]:
             return True
         return False
-    
-    def __call__(self,example):
-        if not self.filter(example):
+
+    def __call__(self, example):
+##        print "in", self.filter(example)#, self.filter.conditions[0](example)
+##        print self.filter.conditions[1].values
+        if self.filter(example) and example != self.arg_example:
+            return True
+        elif self.filter(example):
+            try:
+                if example[self.argument_id].value and len(example[self.argument_id].value.positiveArguments) > 0: # example has positive arguments
+                    # conditions should cover at least one of the positive arguments
+                    oneArgCovered = False
+                    for pA in example[self.argument_id].value.positiveArguments:
+                        argCovered = [self.condIn(c) for c in pA.filter.conditions]
+                        oneArgCovered = oneArgCovered or len(argCovered) == sum(argCovered) #argCovered
+                        if oneArgCovered:
+                            break
+                    if not oneArgCovered:
+                        return False
+                if example[self.argument_id].value and len(example[self.argument_id].value.negativeArguments) > 0: # example has negative arguments
+                    # condition should not cover neither of negative arguments
+                    for pN in example[self.argument_id].value.negativeArguments:
+                        argCovered = [self.condIn(c) for c in pN.filter.conditions]
+                        if len(argCovered) == sum(argCovered):
+                            return False
+            except:
+                return True
+            return True
+        else:
             return False
-        elif (not self.only_arg_example or example == self.arg_example):
-            if example[self.argument_id].value and len(example[self.argument_id].value.positive_arguments)>0: # example has positive arguments
-                # conditions should cover at least one of the positive arguments
-                oneArgCovered = False
-                for pA in example[self.argument_id].value.positive_arguments:
-                    argCovered = [self.condIn(c) for c in pA.filter.conditions]
-                    oneArgCovered = oneArgCovered or len(argCovered) == sum(argCovered) #argCovered
-                    if oneArgCovered:
-                        break
-                if not oneArgCovered:
-                    return False
-            if example[self.argument_id].value and len(example[self.argument_id].value.negative_arguments)>0: # example has negative arguments
-                # condition should not cover neither of negative arguments
-                for pN in example[self.argument_id].value.negative_arguments:
-                    argCovered = [self.condIn(c) for c in pN.filter.conditions]
-                    if len(argCovered)==sum(argCovered):
-                        return False
-        return True
-
-    def __setattr__(self,name,obj):
-        self.__dict__[name]=obj
-        self.filter.setattr(name,obj)
+
+    def __setattr__(self, name, obj):
+        self.__dict__[name] = obj
+        self.filter.setattr(name, obj)
 
     def deep_copy(self):
         newFilter = ArgFilter(argument_id=self.argument_id)
-        newFilter.filter = Orange.core.Filter_values() #self.filter.deepCopy()
+        newFilter.filter = Orange.data.filter.Values() #self.filter.deepCopy()
         newFilter.filter.conditions = self.filter.conditions[:]
         newFilter.domain = self.filter.domain
@@ -1763,6 +1803,6 @@
         newFilter.conditions = newFilter.filter.conditions
         newFilter.indices = self.indices[:]
-        newFilter.arg_example = self.arg_example
         return newFilter
+
 ArgFilter = deprecated_members({"argumentID": "argument_id"})(ArgFilter)
 
@@ -1841,5 +1881,5 @@
     PILAR (Probabilistic improvement of learning algorithms with rules).
     """
-    def __init__(self, alternative_learner=None, min_cl_sig=0.5, min_beta=0.0, penalty=0.01, set_prefix_rules=False, optimize_betas=True):
+    def __init__(self, alternative_learner=None, min_cl_sig=0.5, min_beta=0.0, set_prefix_rules=False, optimize_betas=True):
         self.alternative_learner = alternative_learner
         self.min_cl_sig = min_cl_sig
@@ -1848,5 +1888,4 @@
         self.optimize_betas = optimize_betas
         self.selected_evaluation = CrossValidation(folds=5)
-        self.penalty = penalty
 
     def __call__(self, rules, examples, weight=0):
@@ -1858,11 +1897,14 @@
 ##            for e in examples:
 ##                prob_dist.append(classifier(e,Orange.core.GetProbabilities))
-            cl = Orange.core.RuleClassifier_logit(rules, self.min_cl_sig, self.min_beta, self.penalty, examples, weight, self.set_prefix_rules, self.optimize_betas, classifier, prob_dist)
+            cl = RuleClassifier_logit(rules, self.min_cl_sig, self.min_beta, examples, weight, self.set_prefix_rules, self.optimize_betas, classifier, prob_dist)
         else:
-            cl = Orange.core.RuleClassifier_logit(rules, self.min_cl_sig, self.min_beta, self.penalty, examples, weight, self.set_prefix_rules, self.optimize_betas)
-
+            cl = RuleClassifier_logit(rules, self.min_cl_sig, self.min_beta, examples, weight, self.set_prefix_rules, self.optimize_betas)
+
+##        print "result"
         for ri, r in enumerate(cl.rules):
             cl.rules[ri].setattr("beta", cl.ruleBetas[ri])
-        cl.setattr("all_rules", cl.rules)
+##            if cl.ruleBetas[ri] > 0:
+##                print Orange.classification.rules.rule_to_string(r), r.quality, cl.ruleBetas[ri]
+        cl.all_rules = cl.rules
         cl.rules = self.sort_rules(cl.rules)
         cl.ruleBetas = [r.beta for r in cl.rules]
Index: Orange/data/io.py
===================================================================
--- Orange/data/io.py	(revision 10528)
+++ Orange/data/io.py	(revision 10255)
@@ -480,6 +480,6 @@
     elif cell == "":
         return variable.Descriptor
-    elif len(split_escaped_str(cell, " ")) > 1:
-        return variable.Discrete, split_escaped_str(cell, " ")
+    elif len(cell.split(",")) > 1:
+        return variable.Discrete, cell.split(",")
     else:
         raise ValueError("Unknown variable type definition %r." % cell)
@@ -581,7 +581,5 @@
     return False
 
-def load_csv(file, create_new_on=MakeStatus.Incompatible, 
-             delimiter=None, quotechar=None, escapechar=None,
-             has_header=None, has_types=None, has_annotations=None, **kwargs):
+def load_csv(file, create_new_on=MakeStatus.Incompatible, **kwargs):
     """ Load an Orange.data.Table from s csv file.
     """
@@ -591,72 +589,41 @@
     sample = file.read(5 * 2 ** 20) # max 5MB sample TODO: What if this is not enough. Try with a bigger sample
     dialect = snifer.sniff(sample)
-    
-    if has_header is None:
-        has_header = snifer.has_header(sample)
-    
+    has_header = snifer.has_header(sample)
     file.seek(0) # Rewind
-    
-    def kwparams(**kwargs):
-        """Return not None kwargs.
-        """
-        return dict([(k, v) for k, v in kwargs.items() if v is not None])
-    
-    fmtparam = kwparams(delimiter=delimiter,
-                        quotechar=quotechar,
-                        escapechar=escapechar)
-    
-    reader = csv.reader(file, dialect=dialect,
-                        **fmtparam)
+    reader = csv.reader(file, dialect=dialect)
 
     header = types = var_attrs = None
 
-    row = first_row = reader.next()
-    
-    if has_header:
-        header = row
-        # Eat this row and move to the next
-        row = reader.next()
-
-    # Guess types row
-    if has_types is None:
-        has_types = has_header and is_var_types_row(row)
-        
-    if has_types:
-        types = var_types(row)
-        # Eat this row and move to the next
-        row = reader.next()
-
-    # Guess variable annotations row
-    if has_annotations is None:
-        has_annotations = has_header and has_types and \
-                          is_var_attributes_row(row)
-        
-    if has_annotations:
-        labels_row = row
-        var_attrs = var_attributes(row)
-        # Eat this row and move to the next
-        row = reader.next()
-
-    if not header:
-        # Create a default header
-        header = ["F_%i" % i for i in range(len(first_row))]
-        
+#    if not has_header:
+#        raise ValueError("No header in the data file.")
+
+    header = reader.next()
+
+    if header:
+        # Try to get variable definitions
+        types_row = reader.next()
+        if is_var_types_row(types_row):
+            types = var_types(types_row)
+
+    if types:
+        # Try to get the variable attributes
+        # (third line in the standard orange tab format).
+        labels_row = reader.next()
+        if is_var_attributes_row(labels_row):
+            var_attrs = var_attributes(labels_row)
+
+    # If definitions not present fill with blanks
     if not types:
-        # Create blank variable types
         types = [None] * len(header)
-        
     if not var_attrs:
-        # Create blank variable attributes
         var_attrs = [None] * len(header)
 
     # start from the beginning
     file.seek(0)
-    reader = csv.reader(file, dialect=dialect, **fmtparam)
-    
-    for defined in [has_header, has_types, has_annotations]:
-        if defined: 
-            # skip definition rows if present in the file
+    reader = csv.reader(file, dialect=dialect)
+    for defined in [header, types, var_attrs]:
+        if any(defined): # skip definition rows if present in the file
             reader.next()
-    
+
     variables = []
     undefined_vars = []
Index: Orange/ensemble/__init__.py
===================================================================
--- Orange/ensemble/__init__.py	(revision 10540)
+++ Orange/ensemble/__init__.py	(revision 9994)
@@ -1,2 +1,188 @@
-__all__ = ["bagging", "boosting", "forest", "stacking"]
+"""
+
+.. index:: ensemble
+
+Module Orange.ensemble implements Breiman's bagging and Random Forest, 
+and Freund and Schapire's boosting algorithms.
+
+
+*******
+Bagging
+*******
+
+.. index:: bagging
+.. index::
+   single: ensemble; ensemble
+
+.. autoclass:: Orange.ensemble.bagging.BaggedLearner
+   :members:
+   :show-inheritance:
+
+.. autoclass:: Orange.ensemble.bagging.BaggedClassifier
+   :members:
+   :show-inheritance:
+
+********
+Boosting
+********
+
+.. index:: boosting
+.. index::
+   single: ensemble; boosting
+
+
+.. autoclass:: Orange.ensemble.boosting.BoostedLearner
+  :members:
+  :show-inheritance:
+
+.. autoclass:: Orange.ensemble.boosting.BoostedClassifier
+   :members:
+   :show-inheritance:
+
+Example
+=======
+Let us try boosting and bagging on Lymphography data set and use TreeLearner
+with post-pruning as a base learner. For testing, we use 10-fold cross
+validation and observe classification accuracy.
+
+:download:`ensemble.py <code/ensemble.py>`
+
+.. literalinclude:: code/ensemble.py
+  :lines: 7-
+
+Running this script, we may get something like::
+
+    Classification Accuracy:
+               tree: 0.764
+       boosted tree: 0.770
+        bagged tree: 0.790
+
+
+*************
+Random Forest
+*************
+
+.. index:: random forest
+.. index::
+   single: ensemble; random forest
+   
+.. autoclass:: Orange.ensemble.forest.RandomForestLearner
+  :members:
+  :show-inheritance:
+
+.. autoclass:: Orange.ensemble.forest.RandomForestClassifier
+  :members:
+  :show-inheritance:
+
+
+Example
+========
+
+The following script assembles a random forest learner and compares it
+to a tree learner on a liver disorder (bupa) and housing data sets.
+
+:download:`ensemble-forest.py <code/ensemble-forest.py>`
+
+.. literalinclude:: code/ensemble-forest.py
+  :lines: 7-
+
+Notice that our forest contains 50 trees. Learners are compared through 
+3-fold cross validation::
+
+    Classification: bupa.tab
+    Learner  CA     Brier  AUC
+    tree     0.586  0.829  0.575
+    forest   0.710  0.392  0.752
+    Regression: housing.tab
+    Learner  MSE    RSE    R2
+    tree     23.708  0.281  0.719
+    forest   11.988  0.142  0.858
+
+Perhaps the sole purpose of the following example is to show how to
+access the individual classifiers once they are assembled into the
+forest, and to show how we can assemble a tree learner to be used in
+random forests. In the following example the best feature for decision
+nodes is selected among three randomly chosen features, and maxDepth
+and minExamples are both set to 5.
+
+:download:`ensemble-forest2.py <code/ensemble-forest2.py>`
+
+.. literalinclude:: code/ensemble-forest2.py
+  :lines: 7-
+
+Running the above code would report on sizes (number of nodes) of the tree
+in a constructed random forest.
+
+    
+Score Feature
+=============
+
+L. Breiman (2001) suggested the possibility of using random forests as a
+non-myopic measure of feature importance.
+
+The assessment of feature relevance with random forests is based on the
+idea that randomly changing the value of an important feature greatly
+affects instance's classification, while changing the value of an
+unimportant feature does not affect it much. Implemented algorithm
+accumulates feature scores over given number of trees. Importance of
+all features for a single tree are computed as: correctly classified 
+OOB instances minus correctly classified OOB instances when the feature is
+randomly shuffled. The accumulated feature scores are divided by the
+number of used trees and multiplied by 100 before they are returned.
+
+.. autoclass:: Orange.ensemble.forest.ScoreFeature
+  :members:
+
+Computation of feature importance with random forests is rather slow and
+importances for all features need to be computes simultaneously. When it 
+is called to compute a quality of certain feature, it computes qualities
+for all features in the dataset. When called again, it uses the stored 
+results if the domain is still the same and the data table has not
+changed (this is done by checking the data table's version and is
+not foolproof; it will not detect if you change values of existing instances,
+but will notice adding and removing instances; see the page on 
+:class:`Orange.data.Table` for details).
+
+:download:`ensemble-forest-measure.py <code/ensemble-forest-measure.py>`
+
+.. literalinclude:: code/ensemble-forest-measure.py
+  :lines: 7-
+
+Corresponding output::
+
+    DATA:iris.tab
+
+    first: 3.91, second: 0.38
+
+    different random seed
+    first: 3.39, second: 0.46
+
+    All importances:
+       sepal length:   3.39
+        sepal width:   0.46
+       petal length:  30.15
+        petal width:  31.98
+
+References
+-----------
+* L Breiman. Bagging Predictors. `Technical report No. 421 \
+    <http://www.stat.berkeley.edu/tech-reports/421.ps.Z>`_. University of \
+    California, Berkeley, 1994.
+* Y Freund, RE Schapire. `Experiments with a New Boosting Algorithm \
+    <http://citeseer.ist.psu.edu/freund96experiments.html>`_. Machine \
+    Learning: Proceedings of the Thirteenth International Conference (ICML'96), 1996.
+* JR Quinlan. `Boosting, bagging, and C4.5 \
+    <http://www.rulequest.com/Personal/q.aaai96.ps>`_ . In Proc. of 13th \
+    National Conference on Artificial Intelligence (AAAI'96). pp. 725-730, 1996. 
+* L Brieman. `Random Forests \
+    <http://www.springerlink.com/content/u0p06167n6173512/>`_.\
+    Machine Learning, 45, 5-32, 2001. 
+* M Robnik-Sikonja. `Improving Random Forests \
+    <http://lkm.fri.uni-lj.si/rmarko/papers/robnik04-ecml.pdf>`_. In \
+    Proc. of European Conference on Machine Learning (ECML 2004),\
+    pp. 359-370, 2004.
+"""
+
+__all__ = ["bagging", "boosting", "forest"]
 __docformat__ = 'restructuredtext'
+import Orange.core as orange
Index: Orange/ensemble/forest.py
===================================================================
--- Orange/ensemble/forest.py	(revision 10540)
+++ Orange/ensemble/forest.py	(revision 9919)
@@ -34,6 +34,12 @@
     split is  (on average) as specified."""
 
-    __new__ = Orange.misc._orange__new__(Orange.core.Learner)
-
+    def __new__(cls, instances = None, weight_id = 0, **argkw):
+        self = Orange.core.Learner.__new__(cls, **argkw)
+        if instances:
+            self.__init__(**argkw)
+            return self.__call__(instances, weight_id)
+        else:
+            return self
+      
     def __init__(self, base, rand):
         self.base = base
@@ -48,15 +54,13 @@
         self.base.skip_prob, self.base.random_generator = osp, orand
         return r
-
 _RandomForestSimpleTreeLearner = Orange.misc.deprecated_members({"weightID":"weight_id", "examples":"instances"})(_RandomForestSimpleTreeLearner)
    
-class RandomForestLearner(Orange.core.Learner):
-    """
-    Trains an ensemble predictor consisting of trees trained
-    on bootstrap
-    samples of training data. To increase
-    randomness, the tree learner considers only a subset of
-    candidate features at each node. The algorithm closely follows
-    the original procedure (Brieman, 2001) both in implementation and parameter
+class RandomForestLearner(orange.Learner):
+    """
+    Just like in bagging, classifiers in random forests are trained from bootstrap
+    samples of training data. Here, the classifiers are trees. However, to increase
+    randomness, at each node of the tree the best feature is
+    chosen from a subset of features in the data. We closely follow the
+    original algorithm (Brieman, 2001) both in implementation and parameter
     defaults.
         
@@ -65,6 +69,6 @@
 
     :param attributes: number of randomly drawn features among
-            which to select the best one to split the data sets
-            in tree nodes. The default, None, means the square root of
+            which to select the best to split the nodes in tree
+            induction. The default, None, means the square root of
             the number of features in the training data. Ignored if
             :obj:`learner` is specified.
@@ -90,9 +94,8 @@
 
     :param callback: a function to be called after every iteration of
-            induction of classifier. The call includes a parameter
-            (from 0.0 to 1.0) that provides an estimate
-            of completion of the learning progress.
-
-    :param name: learner name.
+            induction of classifier. This is called with parameter 
+            (from 0.0 to 1.0) that gives estimates on learning progress.
+
+    :param name: name of the learner.
     :type name: string
 
@@ -102,5 +105,11 @@
     """
 
-    __new__ = Orange.misc._orange__new__(Orange.core.Learner)
+    def __new__(cls, instances=None, weight = 0, **kwds):
+        self = orange.Learner.__new__(cls, **kwds)
+        if instances:
+            self.__init__(**kwds)
+            return self.__call__(instances, weight)
+        else:
+            return self
 
     def __init__(self, trees=100, attributes=None,\
@@ -476,7 +485,13 @@
     a new split constructor.
     """
-
-    __new__ = Orange.misc._orange__new__(Orange.core.Learner)
-     
+    @deprecated_keywords({"weightID":"weight_id", "examples":"instances"})
+    def __new__(cls, instances = None, weight_id = 0, **argkw):
+        self = Orange.core.Learner.__new__(cls, **argkw)
+        if instances:
+            self.__init__(**argkw)
+            return self.__call__(instances, weight_id)
+        else:
+            return self
+      
     def __init__(self, base, rand):
         self.base = base
Index: range/ensemble/stacking.py
===================================================================
--- Orange/ensemble/stacking.py	(revision 10540)
+++ 	(revision )
@@ -1,67 +1,0 @@
-import Orange
-
-class StackedClassificationLearner(Orange.classification.Learner):
-    """Stacking by inference of meta classifier from class probability estimates
-    on cross-validation held-out data for level-0 classifiers developed on held-in data sets.
-
-    :param learners: level-0 learners.
-    :type learners: list
-
-    :param meta_learner: meta learner (default: :class:`~Orange.classification.bayes.NaiveLearner`).
-    :type meta_learner: :class:`~Orange.classification.Learner`
-
-    :param folds: number of iterations (folds) of cross-validation to assemble class probability data for meta learner.
-
-    :param name: learner name (default: stacking).
-    :type name: string
-
-    :rtype: :class:`~Orange.ensemble.stacking.StackedClassificationLearner` or
-        :class:`~Orange.ensemble.stacking.StackedClassifier`
-    """
-    def __new__(cls, learners, data=None, weight=0, **kwds):
-        if data is None:
-            self = Orange.classification.Learner.__new__(cls)
-            return self
-        else:
-            self = cls(learners, **kwds)
-            return self(data, weight)
-
-    def __init__(self, learners, meta_learner=Orange.classification.bayes.NaiveLearner(), folds=10, name='stacking'):
-        self.learners = learners
-        self.meta_learner = meta_learner
-        self.name = name
-        self.folds = folds
-
-    def __call__(self, data, weight=0):
-        res = Orange.evaluation.testing.cross_validation(self.learners, data, self.folds)
-        features = [Orange.feature.Continuous("%d" % i) for i in range(len(self.learners) * (len(data.domain.class_var.values) - 1))]
-        domain = Orange.data.Domain(features + [data.domain.class_var])
-        p_data = Orange.data.Table(domain)
-        for r in res.results:
-            p_data.append([p for ps in r.probabilities for p in ps[:-1]] + [r.actual_class])
-        meta_classifier = self.meta_learner(p_data)
-
-        classifiers = [l(data, weight) for l in self.learners]
-        feature_domain = Orange.data.Domain(features)
-        return StackedClassifier(classifiers, meta_classifier, name=self.name)
-
-class StackedClassifier:
-    """
-    A classifier for stacking. Uses a set of level-0 classifiers to induce class probabilities, which
-    are an input to a meta-classifier to predict class probability for a given data instance.
-
-    :param classifiers: a list of level-0 classifiers.
-    :type classifiers: list
-
-    :param meta_classifier: meta-classifier.
-    :type meta_classifier: :class:`~Orange.classification.Classifier`
-    """
-    def __init__(self, classifiers, meta_classifier, **kwds):
-        self.classifiers = classifiers
-        self.meta_classifier = meta_classifier
-        self.domain = Orange.data.Domain(self.meta_classifier.domain.features, False)
-        self.__dict__.update(kwds)
-
-    def __call__(self, instance, resultType=Orange.core.GetValue):
-        ps = Orange.data.Instance(self.domain, [p for cl in self.classifiers for p in list(cl(instance, Orange.core.GetProbabilities))[:-1]])
-        return self.meta_classifier(ps, resultType)
Index: Orange/feature/scoring.py
===================================================================
--- Orange/feature/scoring.py	(revision 10524)
+++ Orange/feature/scoring.py	(revision 10541)
@@ -1,14 +1,16 @@
-import Orange.core as orange
-import Orange.misc
-
-from orange import MeasureAttribute as Score
-from orange import MeasureAttributeFromProbabilities as ScoreFromProbabilities
-from orange import MeasureAttribute_info as InfoGain
-from orange import MeasureAttribute_gainRatio as GainRatio
-from orange import MeasureAttribute_gini as Gini
-from orange import MeasureAttribute_relevance as Relevance 
-from orange import MeasureAttribute_cost as Cost
-from orange import MeasureAttribute_relief as Relief
-from orange import MeasureAttribute_MSE as MSE
+from Orange import core, feature
+from Orange.statistics import contingency, distribution
+
+from Orange.misc import deprecated_keywords, deprecated_members
+
+Score = core.MeasureAttribute
+ScoreFromProbabilities = core.MeasureAttributeFromProbabilities
+InfoGain = core.MeasureAttribute_info
+GainRatio = core.MeasureAttribute_gainRatio
+Gini = core.MeasureAttribute_gini
+Relevance = core.MeasureAttribute_relevance
+Cost = core.MeasureAttribute_cost
+Relief = core.MeasureAttribute_relief
+MSE = core.MeasureAttribute_MSE
 
 ######
@@ -31,8 +33,8 @@
 
         :param data: a data table used to score features
-        :type data: Orange.data.Table
+        :type data: :obj:`~Orange.data.Table`
 
         :param weight: meta attribute that stores weights of instances
-        :type weight: Orange.feature.Descriptor
+        :type weight: :obj:`~Orange.feature.Descriptor`
 
         """
@@ -46,5 +48,5 @@
         return [x[0] for x in measured]
 
-OrderAttributes = Orange.misc.deprecated_members({
+OrderAttributes = deprecated_members({
           "measure": "score",
 }, wrap_methods=[])(OrderAttributes)
@@ -59,8 +61,8 @@
     """
 
-    @Orange.misc.deprecated_keywords({"aprioriDist": "apriori_dist"})
+    @deprecated_keywords({"aprioriDist": "apriori_dist"})
     def __new__(cls, attr=None, data=None, apriori_dist=None, weightID=None):
         self = Score.__new__(cls)
-        if attr != None and data != None:
+        if attr is not None and data is not None:
             #self.__init__(**argkw)
             return self.__call__(attr, data, apriori_dist, weightID)
@@ -68,13 +70,13 @@
             return self
 
-    @Orange.misc.deprecated_keywords({"aprioriDist": "apriori_dist"})
+    @deprecated_keywords({"aprioriDist": "apriori_dist"})
     def __call__(self, attr, data, apriori_dist=None, weightID=None):
         """Score the given feature.
 
         :param attr: feature to score
-        :type attr: Orange.feature.Descriptor
+        :type attr: :obj:`~Orange.feature.Descriptor`
 
         :param data: a data table used to score features
-        :type data: Orange.data.table
+        :type data: :obj:`~Orange.data.Table`
 
         :param apriori_dist: 
@@ -82,12 +84,12 @@
         
         :param weightID: meta feature used to weight individual data instances
-        :type weightID: Orange.feature.Descriptor
+        :type weightID: :obj:`~Orange.feature.Descriptor`
 
         """
         import numpy
-        from orngContingency import Entropy
+        from orngContingency import Entropy #TODO: Move to new hierarchy
         if attr in data.domain:  # if we receive attr as string we have to convert to variable
             attr = data.domain[attr]
-        attrClassCont = orange.ContingencyAttrClass(attr, data)
+        attrClassCont = contingency.VarClass(attr, data)
         dist = []
         for vals in attrClassCont.values():
@@ -116,8 +118,8 @@
     """
 
-    @Orange.misc.deprecated_keywords({"aprioriDist": "apriori_dist"})
+    @deprecated_keywords({"aprioriDist": "apriori_dist"})
     def __new__(cls, attr=None, data=None, apriori_dist=None, weightID=None):
         self = Score.__new__(cls)
-        if attr != None and data != None:
+        if attr is not None and data is not None:
             #self.__init__(**argkw)
             return self.__call__(attr, data, apriori_dist, weightID)
@@ -125,13 +127,13 @@
             return self
 
-    @Orange.misc.deprecated_keywords({"aprioriDist": "apriori_dist"})
+    @deprecated_keywords({"aprioriDist": "apriori_dist"})
     def __call__(self, attr, data, apriori_dist=None, weightID=None):
         """Score the given feature.
 
         :param attr: feature to score
-        :type attr: Orange.feature.Descriptor
+        :type attr: :obj:`~Orange.feature.Descriptor`
 
         :param data: a data table used to score the feature
-        :type data: Orange.data.table
+        :type data: :obj:`~Orange.data.Table`
 
         :param apriori_dist: 
@@ -139,9 +141,9 @@
         
         :param weightID: meta feature used to weight individual data instances
-        :type weightID: Orange.feature.Descriptor
+        :type weightID: :obj:`~Orange.feature.Descriptor`
 
         """
-        attrClassCont = orange.ContingencyAttrClass(attr, data)
-        classDist = orange.Distribution(data.domain.classVar, data).values()
+        attrClassCont = contingency.VarClass(attr, data)
+        classDist = distribution.Distribution(data.domain.classVar, data).values()
         nCls = len(classDist)
         nEx = len(data)
@@ -177,5 +179,5 @@
 
 
-@Orange.misc.deprecated_keywords({"attrList": "attr_list", "attrMeasure": "attr_score", "removeUnusedValues": "remove_unused_values"})
+@deprecated_keywords({"attrList": "attr_list", "attrMeasure": "attr_score", "removeUnusedValues": "remove_unused_values"})
 def merge_values(data, attr_list, attr_score, remove_unused_values = 1):
     import orngCI
@@ -183,5 +185,5 @@
     newData = data.select(attr_list + [data.domain.class_var])
     newAttr = orngCI.FeatureByCartesianProduct(newData, attr_list)[0]
-    dist = orange.Distribution(newAttr, newData)
+    dist = distribution.Distribution(newAttr, newData)
     activeValues = []
     for i in range(len(newAttr.values)):
@@ -213,5 +215,5 @@
         return newAttr
 
-    reducedAttr = orange.EnumVariable(newAttr.name, values = [newAttr.values[i] for i in activeValues])
+    reducedAttr = feature.Discrete.EnumVariable(newAttr.name, values = [newAttr.values[i] for i in activeValues])
     reducedAttr.get_value_from = newAttr.get_value_from
     reducedAttr.get_value_from.class_var = reducedAttr
@@ -220,5 +222,5 @@
 ######
 # from orngFSS
-@Orange.misc.deprecated_keywords({"measure": "score"})
+@deprecated_keywords({"measure": "score"})
 def score_all(data, score=Relief(k=20, m=50)):
     """Assess the quality of features using the given measure and return
@@ -226,11 +228,10 @@
 
     :param data: data table should include a discrete class.
-    :type data: :obj:`Orange.data.Table`
+    :type data: :obj:`~Orange.data.Table`
     :param score:  feature scoring function. Derived from
       :obj:`~Orange.feature.scoring.Score`. Defaults to 
       :obj:`~Orange.feature.scoring.Relief` with k=20 and m=50.
-    :type measure: :obj:`~Orange.feature.scoring.Score` 
-    :rtype: :obj:`list`; a sorted (by descending score) list of
-      tuples (feature name, score)
+    :type score: :obj:`~Orange.feature.scoring.Score`
+    :rtype: :obj:`list`; a sorted list of tuples (feature name, score)
 
     """
Index: Orange/feature/selection.py
===================================================================
--- Orange/feature/selection.py	(revision 10523)
+++ Orange/feature/selection.py	(revision 10172)
@@ -1,5 +1,3 @@
 __docformat__ = 'restructuredtext'
-
-from operator import itemgetter
 
 import Orange.core as orange
@@ -19,7 +17,5 @@
 
     """
-    return [x[0] for x in \
-            sorted(scores, key=itemgetter(1), reverse=True)[:n]
-            ]
+    return [x[0] for x in sorted(scores)[:n]]
 
 bestNAtts = best_n
Index: Orange/misc/__init__.py
===================================================================
--- Orange/misc/__init__.py	(revision 10521)
+++ Orange/misc/__init__.py	(revision 10327)
@@ -911,9 +911,5 @@
     @wraps(base.__new__)
     def _orange__new_wrapped(cls, data=None, **kwargs):
-        if base == object:
-            self = base.__new__(cls)
-        else:
-            self = base.__new__(cls, **kwargs)
-
+        self = base.__new__(cls, **kwargs)
         if data:
             self.__init__(**kwargs)
Index: Orange/multilabel/br.py
===================================================================
--- Orange/multilabel/br.py	(revision 10502)
+++ Orange/multilabel/br.py	(revision 9994)
@@ -75,6 +75,5 @@
     def __call__(self, instances, weight_id = 0, **kwds):
         if not Orange.multilabel.is_multilabel(instances):
-            raise TypeError("The given data set is not a multi-label data set"
-                            " with class values 0 and 1.")
+            raise TypeError("The given data set is not a multi-label data set.")
         
         for k in kwds.keys():
Index: Orange/multilabel/brknn.py
===================================================================
--- Orange/multilabel/brknn.py	(revision 10502)
+++ Orange/multilabel/brknn.py	(revision 9994)
@@ -94,6 +94,5 @@
     def __call__(self, instances, weight_id = 0, **kwds):
         if not Orange.multilabel.is_multilabel(instances):
-            raise TypeError("The given data set is not a multi-label data set"
-                            " with class values 0 and 1.")
+            raise TypeError("The given data set is not a multi-label data set.")
 
         for k in kwds.keys():
Index: Orange/multilabel/lp.py
===================================================================
--- Orange/multilabel/lp.py	(revision 10502)
+++ Orange/multilabel/lp.py	(revision 9994)
@@ -84,6 +84,5 @@
     def __call__(self, instances, base_learner = None, weight_id = 0, **kwds):
         if not Orange.multilabel.is_multilabel(instances):
-            raise TypeError("The given data set is not a multi-label data set"
-                            " with class values 0 and 1.")
+            raise TypeError("The given data set is not a multi-label data set.")
 
         self.__dict__.update(kwds)
Index: Orange/multilabel/mlknn.py
===================================================================
--- Orange/multilabel/mlknn.py	(revision 10502)
+++ Orange/multilabel/mlknn.py	(revision 10417)
@@ -143,6 +143,5 @@
     def __call__(self, instances, weight_id = 0, **kwds):
         if not Orange.multilabel.is_multilabel(instances):
-            raise TypeError("The given data set is not a multi-label data set"
-                            " with class values 0 and 1.")
+            raise TypeError("The given data set is not a multi-label data set.")
         
         self.__dict__.update(kwds)
Index: Orange/orng/orngABML.py
===================================================================
--- Orange/orng/orngABML.py	(revision 10518)
+++ Orange/orng/orngABML.py	(revision 9737)
@@ -9,4 +9,6 @@
 import math
 
+from Orange.classification.rules import create_dichotomous_class as createDichotomousClass
+from Orange.classification.rules import ConvertClass
 # regular expressions
 # exppression for testing validity of a set of arguments:
@@ -284,36 +286,4 @@
 
 
-
-class ConvertClass:
-    """ Converting class variables into dichotomous class variable. """
-    def __init__(self, classAtt, classValue, newClassAtt):
-        self.classAtt = classAtt
-        self.classValue = classValue
-        self.newClassAtt = newClassAtt
-
-    def __call__(self, example, returnWhat):
-        if example[self.classAtt] == self.classValue:
-            return Orange.data.Value(self.newClassAtt, self.classValue + "_")
-        else:
-            return Orange.data.Value(self.newClassAtt, "not " + self.classValue)
-
-
-def create_dichotomous_class(domain, att, value, negate, removeAtt=None):
-    # create new variable
-    newClass = Orange.feature.Discrete(att.name + "_", values=[str(value) + "_", "not " + str(value)])
-    positive = Orange.data.Value(newClass, str(value) + "_")
-    negative = Orange.data.Value(newClass, "not " + str(value))
-    newClass.getValueFrom = ConvertClass(att, str(value), newClass)
-
-    att = [a for a in domain.attributes]
-    newDomain = Orange.data.Domain(att + [newClass])
-    newDomain.addmetas(domain.getmetas())
-    if negate == 1:
-        return (newDomain, negative)
-    else:
-        return (newDomain, positive)
-
-
-
 def addErrors(test_data, classifier):
     """ Main task of this function is to add probabilistic errors to examples."""
Index: Orange/regression/lasso.py
===================================================================
--- Orange/regression/lasso.py	(revision 10535)
+++ Orange/regression/lasso.py	(revision 10314)
@@ -1,2 +1,102 @@
+"""\
+############################
+Lasso regression (``lasso``)
+############################
+
+.. index:: regression
+
+.. _`Lasso regression. Regression shrinkage and selection via the lasso`:
+    http://www-stat.stanford.edu/~tibs/lasso/lasso.pdf
+
+
+`The Lasso <http://www-stat.stanford.edu/~tibs/lasso/lasso.pdf>`_ is a shrinkage
+and selection method for linear regression. It minimizes the usual sum of squared
+errors, with a bound on the sum of the absolute values of the coefficients. 
+
+To fit the regression parameters on housing data set use the following code:
+
+.. literalinclude:: code/lasso-example.py
+   :lines: 7,9,10,11
+
+.. autoclass:: LassoRegressionLearner
+    :members:
+
+.. autoclass:: LassoRegression
+    :members:
+
+
+.. autoclass:: LassoRegressionLearner
+    :members:
+
+.. autoclass:: LassoRegression
+    :members:
+
+Utility functions
+-----------------
+
+.. autofunction:: center
+
+.. autofunction:: get_bootstrap_sample
+
+.. autofunction:: permute_responses
+
+
+========
+Examples
+========
+
+To predict values of the response for the first five instances
+use the code
+
+.. literalinclude:: code/lasso-example.py
+   :lines: 14,15
+
+Output
+
+::
+
+    Actual: 24.00, predicted: 24.58 
+    Actual: 21.60, predicted: 23.30 
+    Actual: 34.70, predicted: 24.98 
+    Actual: 33.40, predicted: 24.78 
+    Actual: 36.20, predicted: 24.66 
+
+To see the fitted regression coefficients, print the model
+
+.. literalinclude:: code/lasso-example.py
+   :lines: 17
+
+The output
+
+::
+
+    Variable  Coeff Est  Std Error          p
+     Intercept     22.533
+          CRIM     -0.000      0.023      0.480      
+         INDUS     -0.010      0.023      0.300      
+            RM      1.303      0.994      0.000   ***
+           AGE     -0.002      0.000      0.320      
+       PTRATIO     -0.191      0.209      0.050     .
+         LSTAT     -0.126      0.105      0.000   ***
+    Signif. codes:  0 *** 0.001 ** 0.01 * 0.05 . 0.1 empty 1
+
+
+    For 7 variables the regression coefficient equals 0: 
+    ZN
+    CHAS
+    NOX
+    DIS
+    RAD
+    TAX
+    B
+
+shows that some of the regression coefficients are equal to 0.    
+
+
+
+
+
+"""
+
 import Orange
 import numpy
Index: Orange/testing/regression/results_reference/selection-bayes.py.linux2.txt
===================================================================
--- Orange/testing/regression/results_reference/selection-bayes.py.linux2.txt	(revision 10290)
+++ Orange/testing/regression/results_reference/selection-bayes.py.linux2.txt	(revision 10290)
@@ -0,0 +1,3 @@
+Learner      CA
+Naive Bayes  0.903
+with FSS     0.867
Index: Orange/testing/regression/results_reference/selection-best3.py.linux2.txt
===================================================================
--- Orange/testing/regression/results_reference/selection-best3.py.linux2.txt	(revision 10290)
+++ Orange/testing/regression/results_reference/selection-best3.py.linux2.txt	(revision 10290)
@@ -0,0 +1,4 @@
+Best 3 features:
+adoption-of-the-budget-resolution
+aid-to-nicaraguan-contras
+anti-satellite-test-ban
Index: Orange/testing/regression/results_reference/selection-filtered-learner.py.linux2.txt
===================================================================
--- Orange/testing/regression/results_reference/selection-filtered-learner.py.linux2.txt	(revision 10290)
+++ Orange/testing/regression/results_reference/selection-filtered-learner.py.linux2.txt	(revision 10290)
@@ -0,0 +1,6 @@
+Learner      CA
+bayes        0.903
+filtered     0.874
+
+Number of times attributes were used in cross-validation:
+10 x adoption-of-the-budget-resolution
Index: Orange/testing/regression/results_tests_20/modules_abcn2-rules.py.txt
===================================================================
--- Orange/testing/regression/results_tests_20/modules_abcn2-rules.py.txt	(revision 10520)
+++ Orange/testing/regression/results_tests_20/modules_abcn2-rules.py.txt	(revision 9951)
@@ -1,11 +1,9 @@
 IF TRUE THEN survived=no<1490.000, 711.000>
 IF sex=['female'] THEN survived=yes<126.000, 344.000>
+IF status=['third'] THEN survived=no<528.000, 178.000>
 IF status=['first'] THEN survived=yes<122.000, 203.000>
-IF sex=['male'] THEN survived=no<1364.000, 367.000>
 IF status=['crew'] THEN survived=no<673.000, 212.000>
-IF status=['third'] THEN survived=no<528.000, 178.000>
 IF age=['adult'] THEN survived=no<1438.000, 654.000>
 IF age=['child'] THEN survived=yes<52.000, 57.000>
-IF status=['second'] THEN survived=yes<167.000, 118.000>
 IF status=['second'] AND age=['child'] THEN survived=yes<0.000, 24.000>
 IF sex=['female'] AND status=['first'] THEN survived=yes<4.000, 141.000>
@@ -14,5 +12,4 @@
 IF status=['first'] AND age=['child'] THEN survived=yes<0.000, 6.000>
 IF sex=['female'] AND age=['adult'] THEN survived=yes<109.000, 316.000>
-IF status=['second'] AND sex=['male'] THEN survived=no<154.000, 25.000>
 IF sex=['male'] AND age=['adult'] THEN survived=no<1329.000, 338.000>
 IF status=['third'] AND age=['adult'] THEN survived=no<476.000, 151.000>
@@ -30,6 +27,4 @@
 IF status=['third'] THEN survived=no<528.000, 178.000>
 IF status=['crew'] THEN survived=no<673.000, 212.000>
-IF sex=['male'] THEN survived=no<1364.000, 367.000>
-IF status=['second'] AND sex=['male'] THEN survived=no<154.000, 25.000>
 IF status=['first'] THEN survived=yes<122.000, 203.000>
 IF sex=['female'] AND status=['first'] THEN survived=yes<4.000, 141.000>
Index: Orange/testing/regression/results_tests_20/modules_fss1.py.linux2.txt
===================================================================
--- Orange/testing/regression/results_tests_20/modules_fss1.py.linux2.txt	(revision 10290)
+++ Orange/testing/regression/results_tests_20/modules_fss1.py.linux2.txt	(revision 10290)
@@ -0,0 +1,9 @@
+Attribute scores for best three attributes:
+0.613 physician-fee-freeze
+0.255 el-salvador-aid
+0.228 synfuels-corporation-cutback
+
+Best 3 attributes:
+adoption-of-the-budget-resolution
+aid-to-nicaraguan-contras
+anti-satellite-test-ban
Index: Orange/testing/regression/results_tests_20/modules_fss3.py.linux2.txt
===================================================================
--- Orange/testing/regression/results_tests_20/modules_fss3.py.linux2.txt	(revision 10290)
+++ Orange/testing/regression/results_tests_20/modules_fss3.py.linux2.txt	(revision 10290)
@@ -0,0 +1,3 @@
+Learner      CA
+Naive Bayes  0.903
+with FSS     0.867
Index: Orange/testing/regression/results_tests_20/modules_fss4.py.linux2.txt
===================================================================
--- Orange/testing/regression/results_tests_20/modules_fss4.py.linux2.txt	(revision 10290)
+++ Orange/testing/regression/results_tests_20/modules_fss4.py.linux2.txt	(revision 10290)
@@ -0,0 +1,6 @@
+Learner      CA
+bayes        0.903
+filtered     0.874
+
+Number of times attributes were used in cross-validation:
+10 x adoption-of-the-budget-resolution
Index: Orange/testing/regression/results_tests_20/modules_fss5.py.linux2.txt
===================================================================
--- Orange/testing/regression/results_tests_20/modules_fss5.py.linux2.txt	(revision 10290)
+++ Orange/testing/regression/results_tests_20/modules_fss5.py.linux2.txt	(revision 10290)
@@ -0,0 +1,17 @@
+Before feature subset selection:
+0.098 workclass
+0.056 marital-status
+0.049 relationship
+0.022 race
+0.019 capital-gain
+0.012 education-num
+0.002 capital-loss
+0.001 hours-per-week
+-0.002 age
+-0.006 native-country
+-0.011 occupation
+-0.014 education
+-0.022 fnlwgt
+-0.025 sex
+
+After feature subset selection with margin 0.010:
Index: Orange/testing/regression/results_tests_20/modules_fss6.py.linux2.txt
===================================================================
--- Orange/testing/regression/results_tests_20/modules_fss6.py.linux2.txt	(revision 10290)
+++ Orange/testing/regression/results_tests_20/modules_fss6.py.linux2.txt	(revision 10290)
@@ -0,0 +1,17 @@
+Before feature subset selection (14 attributes):
+0.098 workclass
+0.056 marital-status
+0.049 relationship
+0.022 race
+0.019 capital-gain
+0.012 education-num
+0.002 capital-loss
+0.001 hours-per-week
+-0.002 age
+-0.006 native-country
+-0.011 occupation
+-0.014 education
+-0.022 fnlwgt
+-0.025 sex
+
+After feature subset selection with margin 0.010 (0 attributes):
Index: Orange/testing/regression/results_tutorial/fss6.py.linux2.txt
===================================================================
--- Orange/testing/regression/results_tutorial/fss6.py.linux2.txt	(revision 10291)
+++ Orange/testing/regression/results_tutorial/fss6.py.linux2.txt	(revision 10291)
@@ -0,0 +1,17 @@
+Before feature subset selection (14 attributes):
+0.098 workclass
+0.056 marital-status
+0.049 relationship
+0.022 race
+0.019 capital-gain
+0.012 education-num
+0.002 capital-loss
+0.001 hours-per-week
+-0.002 age
+-0.006 native-country
+-0.011 occupation
+-0.014 education
+-0.022 fnlwgt
+-0.025 sex
+
+After feature subset selection with margin 0.010 (0 attributes):
Index: range/testing/unit/tests/test_feature_selection.py
===================================================================
--- Orange/testing/unit/tests/test_feature_selection.py	(revision 10522)
+++ 	(revision )
@@ -1,61 +1,0 @@
-import Orange.misc.testing as testing
-from Orange.feature import selection, scoring
-import Orange
-
-from operator import itemgetter
-
-try:
-    import unittest2 as unittest
-except ImportError:
-    import unittest
-
-class TestSelection(unittest.TestCase):
-    def setUp(self):
-        self.score = Orange.feature.scoring.Gini()
-        self.data = Orange.data.Table("lenses")
-        
-        self.scores = scoring.score_all(self.data, self.score)
-        
-    def test_best_n(self):
-        sorted_scores = sorted(self.scores, key=itemgetter(1),
-                               reverse=True)
-        # Test the descending order of scores
-        self.assertEqual(self.scores, sorted_scores)
-        
-        # best 3 scores
-        best_3 = map(itemgetter(0), sorted_scores[:3])
-        
-        # test best_n function
-        self.assertEqual(selection.best_n(self.scores, 3), best_3)
-        
-        self.assertTrue(len(selection.best_n(self.scores, 3)) == 3)
-        
-        # all returned values should be strings.
-        self.assertTrue(all(isinstance(item, basestring) for item in \
-                            selection.best_n(self.scores, 3)))
-        
-        new_data = selection.select_best_n(self.data, self.scores, 3)
-        self.assertEqual(best_3, [a.name for a in new_data.domain.attributes])
-        self.assertEqual(new_data.domain.class_var, self.data.domain.class_var)
-        
-    def test_above_threashold(self):
-        threshold = self.scores[len(self.scores) / 2][1]
-        above = [item[0] for item in self.scores if item[1] > threshold]
-        
-        self.assertEqual(above, 
-                         selection.above_threshold(self.scores, threshold)
-                         )
-        
-        new_data = selection.select_above_threshold(self.data, 
-                                                    self.scores, threshold)
-        self.assertEqual(above, [a.name for a in new_data.domain.attributes])
-        self.assertEqual(new_data.domain.class_var, self.data.domain.class_var)
-        
-        
-        
-        
-        
-    
-if __name__ == "__main__":
-    unittest.main()
-    
Index: docs/reference/rst/Orange.ensemble.rst
===================================================================
--- docs/reference/rst/Orange.ensemble.rst	(revision 10540)
+++ docs/reference/rst/Orange.ensemble.rst	(revision 9372)
@@ -3,230 +3,4 @@
 ##################################
 
-.. index:: ensemble
-
-`Ensembles <http://en.wikipedia.org/wiki/Ensemble_learning>`_ use
-multiple models to improve prediction performance. The module
-implements a number of popular approaches, including bagging,
-boosting, stacking and forest trees. Most of these are available both
-for classification and regression with exception of stacking, which
-with present implementation supports classification only.
-
-*******
-Bagging
-*******
-
-.. index:: bagging
-.. index::
-   single: ensemble; ensemble
-
-.. autoclass:: Orange.ensemble.bagging.BaggedLearner
-   :members:
-   :show-inheritance:
-
-.. autoclass:: Orange.ensemble.bagging.BaggedClassifier
-   :members:
-   :show-inheritance:
-
-********
-Boosting
-********
-
-.. index:: boosting
-.. index::
-   single: ensemble; boosting
-
-
-.. autoclass:: Orange.ensemble.boosting.BoostedLearner
-  :members:
-  :show-inheritance:
-
-.. autoclass:: Orange.ensemble.boosting.BoostedClassifier
-   :members:
-   :show-inheritance:
-
-Example
-=======
-
-The following script fits classification models by boosting and
-bagging on Lymphography data set with TreeLearner and post-pruning as
-a base learner. Classification accuracy of the methods is estimated by
-10-fold cross validation (:download:`ensemble.py <code/ensemble.py>`):
-
-.. literalinclude:: code/ensemble.py
-  :lines: 7-
-
-Running this script demonstrates some benefit of boosting and bagging
-over the baseline learner::
-
-    Classification Accuracy:
-               tree: 0.764
-       boosted tree: 0.770
-        bagged tree: 0.790
-
-********
-Stacking
-********
-
-.. index:: stacking
-.. index::
-   single: ensemble; stacking
-
-
-.. autoclass:: Orange.ensemble.stacking.StackedClassificationLearner
-  :members:
-  :show-inheritance:
-
-.. autoclass:: Orange.ensemble.stacking.StackedClassifier
-   :members:
-   :show-inheritance:
-
-Example
-=======
-
-Stacking often produces classifiers that are more predictive than
-individual classifiers in the ensemble. This effect is illustrated by
-a script that combines four different classification
-algorithms (:download:`ensemble-stacking.py <code/ensemble-stacking.py>`):
-
-.. literalinclude:: code/ensemble-stacking.py
-  :lines: 3-
-
-The benefits of stacking on this particular data set are
-substantial (numbers show classification accuracy)::
-
-   stacking: 0.934
-      bayes: 0.858
-       tree: 0.688
-         lr: 0.764
-        knn: 0.830
-
-*************
-Random Forest
-*************
-
-.. index:: random forest
-.. index::
-   single: ensemble; random forest
-   
-.. autoclass:: Orange.ensemble.forest.RandomForestLearner
-  :members:
-  :show-inheritance:
-
-.. autoclass:: Orange.ensemble.forest.RandomForestClassifier
-  :members:
-  :show-inheritance:
-
-
-Example
-========
-
-The following script assembles a random forest learner and compares it
-to a tree learner on a liver disorder (bupa) and housing data sets.
-
-:download:`ensemble-forest.py <code/ensemble-forest.py>`
-
-.. literalinclude:: code/ensemble-forest.py
-  :lines: 7-
-
-Notice that our forest contains 50 trees. Learners are compared through 
-3-fold cross validation::
-
-    Classification: bupa.tab
-    Learner  CA     Brier  AUC
-    tree     0.586  0.829  0.575
-    forest   0.710  0.392  0.752
-    Regression: housing.tab
-    Learner  MSE    RSE    R2
-    tree     23.708  0.281  0.719
-    forest   11.988  0.142  0.858
-
-Perhaps the sole purpose of the following example is to show how to
-access the individual classifiers once they are assembled into the
-forest, and to show how we can assemble a tree learner to be used in
-random forests. In the following example the best feature for decision
-nodes is selected among three randomly chosen features, and maxDepth
-and minExamples are both set to 5.
-
-:download:`ensemble-forest2.py <code/ensemble-forest2.py>`
-
-.. literalinclude:: code/ensemble-forest2.py
-  :lines: 7-
-
-Running the above code would report on sizes (number of nodes) of the tree
-in a constructed random forest.
-
-    
-Feature scoring
-===============
-
-L. Breiman (2001) suggested the possibility of using random forests as a
-non-myopic measure of feature importance.
-
-The assessment of feature relevance with random forests is based on the
-idea that randomly changing the value of an important feature greatly
-affects instance's classification, while changing the value of an
-unimportant feature does not affect it much. Implemented algorithm
-accumulates feature scores over given number of trees. Importance of
-all features for a single tree are computed as: correctly classified 
-OOB instances minus correctly classified OOB instances when the feature is
-randomly shuffled. The accumulated feature scores are divided by the
-number of used trees and multiplied by 100 before they are returned.
-
-.. autoclass:: Orange.ensemble.forest.ScoreFeature
-  :members:
-
-Computation of feature importance with random forests is rather slow
-and importances for all features need to be computes
-simultaneously. When it is called to compute a quality of certain
-feature, it computes qualities for all features in the dataset. When
-called again, it uses the stored results if the domain is still the
-same and the data table has not changed (this is done by checking the
-data table's version and is not foolproof; it will not detect if you
-change values of existing instances, but will notice adding and
-removing instances; see the page on :class:`Orange.data.Table` for
-details).
-
-:download:`ensemble-forest-measure.py <code/ensemble-forest-measure.py>`
-
-.. literalinclude:: code/ensemble-forest-measure.py
-  :lines: 7-
-
-The output of the above script is::
-
-    DATA:iris.tab
-
-    first: 3.91, second: 0.38
-
-    different random seed
-    first: 3.39, second: 0.46
-
-    All importances:
-       sepal length:   3.39
-        sepal width:   0.46
-       petal length:  30.15
-        petal width:  31.98
-
-References
-----------
-
-* L Breiman. Bagging Predictors. `Technical report No. 421
-  <http://www.stat.berkeley.edu/tech-reports/421.ps.Z>`_. University
-  of California, Berkeley, 1994.
-* Y Freund, RE Schapire. `Experiments with a New Boosting Algorithm
-  <http://citeseer.ist.psu.edu/freund96experiments.html>`_. Machine
-  Learning: Proceedings of the Thirteenth International Conference
-  (ICML'96), 1996. 
-* JR Quinlan. `Boosting, bagging, and C4.5
-  <http://www.rulequest.com/Personal/q.aaai96.ps>`_ . In Proc. of 13th
-  National Conference on Artificial Intelligence
-  (AAAI'96). pp. 725-730, 1996.
-* L Brieman. `Random Forests
-  <http://www.springerlink.com/content/u0p06167n6173512/>`_. Machine
-  Learning, 45, 5-32, 2001.
-* M Robnik-Sikonja. `Improving Random Forests
-  <http://lkm.fri.uni-lj.si/rmarko/papers/robnik04-ecml.pdf>`_. In
-  Proc. of European Conference on Machine Learning (ECML 2004),
-  pp. 359-370, 2004.
-
 .. automodule:: Orange.ensemble
 
Index: docs/reference/rst/Orange.regression.lasso.rst
===================================================================
--- docs/reference/rst/Orange.regression.lasso.rst	(revision 10536)
+++ docs/reference/rst/Orange.regression.lasso.rst	(revision 9372)
@@ -1,95 +1,1 @@
-############################
-Lasso regression (``lasso``)
-############################
-
 .. automodule:: Orange.regression.lasso
-
-.. index:: regression
-
-.. _`Lasso regression. Regression shrinkage and selection via the lasso`:
-    http://www-stat.stanford.edu/~tibs/lasso/lasso.pdf
-
-
-`The Lasso <http://www-stat.stanford.edu/~tibs/lasso/lasso.pdf>`_ is a shrinkage
-and selection method for linear regression. It minimizes the usual sum of squared
-errors, with a bound on the sum of the absolute values of the coefficients. 
-
-To fit the regression parameters on housing data set use the following code:
-
-.. literalinclude:: code/lasso-example.py
-   :lines: 9,10,11
-
-.. autoclass:: LassoRegressionLearner
-    :members:
-
-.. autoclass:: LassoRegression
-    :members:
-
-
-.. autoclass:: LassoRegressionLearner
-    :members:
-
-.. autoclass:: LassoRegression
-    :members:
-
-Utility functions
------------------
-
-.. autofunction:: center
-
-.. autofunction:: get_bootstrap_sample
-
-.. autofunction:: permute_responses
-
-
-========
-Examples
-========
-
-To predict values of the response for the first five instances
-use the code
-
-.. literalinclude:: code/lasso-example.py
-   :lines: 14,15
-
-Output
-
-::
-
-    Actual: 24.00, predicted: 24.58 
-    Actual: 21.60, predicted: 23.30 
-    Actual: 34.70, predicted: 24.98 
-    Actual: 33.40, predicted: 24.78 
-    Actual: 36.20, predicted: 24.66 
-
-To see the fitted regression coefficients, print the model
-
-.. literalinclude:: code/lasso-example.py
-   :lines: 17
-
-The output
-
-::
-
-    Variable  Coeff Est  Std Error          p
-     Intercept     22.533
-          CRIM     -0.000      0.023      0.480      
-         INDUS     -0.010      0.023      0.300      
-            RM      1.303      0.994      0.000   ***
-           AGE     -0.002      0.000      0.320      
-       PTRATIO     -0.191      0.209      0.050     .
-         LSTAT     -0.126      0.105      0.000   ***
-    Signif. codes:  0 *** 0.001 ** 0.01 * 0.05 . 0.1 empty 1
-
-
-    For 7 variables the regression coefficient equals 0: 
-    ZN
-    CHAS
-    NOX
-    DIS
-    RAD
-    TAX
-    B
-
-shows that some of the regression coefficients are equal to 0.    
-
Index: docs/reference/rst/Orange.regression.rst
===================================================================
--- docs/reference/rst/Orange.regression.rst	(revision 10537)
+++ docs/reference/rst/Orange.regression.rst	(revision 10396)
@@ -3,10 +3,19 @@
 ###########################
 
-Orange implements a set of methods for regression modeling, that is,
-where the outcome - dependent variable is real-valued:
+Orange uses the term `classification` to also denote the
+regression. For instance, the dependent variable is called a `class
+variable` even when it is continuous, and models are generally called
+classifiers. A part of the reason is that classification and
+regression rely on the same set of basic classes.
+
+Please see the documentation on :doc:`Orange.classification` for
+information on how to fit models in general.
+
+Orange contains a number of regression models which are listed below.
 
 .. toctree::
    :maxdepth: 1
 
+   Orange.regression.mean
    Orange.regression.linear
    Orange.regression.lasso
@@ -14,16 +23,4 @@
    Orange.regression.earth
    Orange.regression.tree
-   Orange.regression.mean
-
-Notice that the dependent variable is in this documentation and in the
-implementation referred to as `class variable`. See also the documentation
-on :doc:`Orange.classification` for information on how to fit models
-and use them for prediction.
-
-*************************
-Base class for regression
-*************************
-
-All regression learners are inherited from `BaseRegressionLearner`.
 
 .. automodule:: Orange.regression.base
Index: ocs/reference/rst/code/ensemble-stacking.py
===================================================================
--- docs/reference/rst/code/ensemble-stacking.py	(revision 10540)
+++ 	(revision )
@@ -1,15 +1,0 @@
-import Orange
-
-data = Orange.data.Table("promoters")
-
-bayes = Orange.classification.bayes.NaiveLearner(name="bayes")
-tree = Orange.classification.tree.SimpleTreeLearner(name="tree")
-lin = Orange.classification.svm.LinearLearner(name="lr")
-knn = Orange.classification.knn.kNNLearner(name="knn")
-
-base_learners = [bayes, tree, lin, knn]
-stack = Orange.ensemble.stacking.StackedClassificationLearner(base_learners)
-
-learners = [stack, bayes, tree, lin, knn]
-res = Orange.evaluation.testing.cross_validation(learners, data, 3)
-print "\n".join(["%8s: %5.3f" % (l.name, r) for r, l in zip(Orange.evaluation.scoring.CA(res), learners)])
Index: install-scripts/createSnapshot.btm
===================================================================
--- install-scripts/createSnapshot.btm	(revision 10503)
+++ install-scripts/createSnapshot.btm	(revision 10275)
@@ -9,4 +9,7 @@
 set ADDON_TEXT_SNAPSHOT=orangeAddOn-text-snapshot-hg-%daystr
 set SOURCE_SNAPSHOT=orange-source-snapshot-hg-%daystr.zip
+
+rem # update source(s) to revision HEAD
+cdd %TMPDIR
 
 rem # build core
@@ -24,5 +27,5 @@
 del /syeqtx sourcestopack
 
-call hg clone . sourcestopack
+call hg archive sourcestopack
 
 cd sourcestopack
@@ -30,35 +33,18 @@
 rem # build source distribution
 e:\Python27\python.exe setup.py sdist
-
 rem # build msi file
-rem # build_msi only handles StrictVersion so we change Orange\version.py
-rem # and remove the .hg dir so the short_version is used
-e:\Python27\python.exe -c"print open('Orange/version.py', 'rb').read().replace('if not release:', 'if not release and False:')" > version.py.1
-move /z version.py.1 Orange\version.py
-del /syeqtx .hg
-
 e:\Python27\python.exe setup.py bdist_msi
 
-break_on_error
-
-rem # if no errors then publish on web (everything at the same time)
-rem # remove any old files  
-rem # leave 10 latest versions. 
-e:\Python27\python.exe -c"import os,glob; [os.remove(f) for f in sorted(glob.glob('%DOWNLOADDIR\orange-win-snapshot-hg-*.exe'), reverse=True)[30:]]"
-e:\Python27\python.exe -c"import os,glob; [os.remove(f) for f in sorted(glob.glob('%DOWNLOADDIR\orange-win-w-python-snapshot-hg-*.exe'), reverse=True)[30:]]"
-e:\Python27\python.exe -c"import os,glob; [os.remove(f) for f in sorted(glob.glob('%DOWNLOADDIR\orangeAddOn-bioinformatics-snapshot-hg-*.exe'), reverse=True)[30:]]"
-e:\Python27\python.exe -c"import os,glob; [os.remove(f) for f in sorted(glob.glob('%DOWNLOADDIR\orangeAddOn-text-snapshot-hg-*.exe'), reverse=True)[30:]]"
-
-e:\Python27\python.exe -c"import os,glob; [os.remove(f) for f in sorted(glob.glob('%DOWNLOADDIR\orange-source-snapshot-hg-*.zip'), reverse=True)[10:]]"
-e:\Python27\python.exe -c"import os,glob; [os.remove(f) for f in sorted(glob.glob('%DOWNLOADDIR\orange-win-snapshot-hg-*.exe'), reverse=True)[10:]]"
-e:\Python27\python.exe -c"import os,glob; [os.remove(f) for f in sorted(glob.glob('%DOWNLOADDIR\orange-win-snapshot-hg-*.msi'), reverse=True)[10:]]"
-
-rem except (%DOWNLOADDIR\orange*-snapshot-%daystr-*.exe) del %DOWNLOADDIR\orange*-snapshot-????-??-??-*.exe
-
-rem # publish
-
+rem del %DOWNLOADDIR\orange-source-snapshot-????-??-??.zip
 move /z dist\Orange-?.*.zip %DOWNLOADDIR\%SOURCE_SNAPSHOT
 move /z dist\Orange-?.*.msi %DOWNLOADDIR\%WIN_SNAPSHOT.msi
 
+
+rem # if no errors then publish on web (everything at the same time)
+rem # remove any old files    
+
+except (%DOWNLOADDIR\orange*-snapshot-%daystr-*.exe) del %DOWNLOADDIR\orange*-snapshot-????-??-??-*.exe
+
+rem # publish
 cdd %TMPDIR
 move /z *.exe %DOWNLOADDIR
Index: install-scripts/mac/build-source.sh
===================================================================
--- install-scripts/mac/build-source.sh	(revision 10508)
+++ install-scripts/mac/build-source.sh	(revision 10445)
@@ -35,6 +35,6 @@
 
 # Build the source distribution
-BUILD_TAG=`hg parent --template=".dev-r{rev}-{node|short}"`
-python setup.py egg_info --tag-build=$BUILD_TAG sdist
+hg parent --template="{latesttag}{latesttagdistance}.dev-{node|short}" > VERSION.txt
+python setup.py sdist
 
 # Copy the source an egg info to workdir
Index: install-scripts/mac/bundle-build-hg.sh
===================================================================
--- install-scripts/mac/bundle-build-hg.sh	(revision 10504)
+++ install-scripts/mac/bundle-build-hg.sh	(revision 10488)
@@ -20,6 +20,5 @@
 
 echo "Preaparing the bundle template"
-TEMPLATE_VERSION=`curl --silent http://orange.biolab.si/download/bundle-templates/CURRENT.txt`
-curl --silent http://orange.biolab.si/download/bundle-templates/Orange-template-${TEMPLATE_VERSION}.tar.gz | tar -xz -C $WORK_DIR
+curl --silent http://orange.biolab.si/download/bundle-templates/Orange-template-2.0a2.tar.gz | tar -xz -C $WORK_DIR
 #svn export --non-interactive http://orange.biolab.si/svn/orange/externals/trunk/install-scripts/mac/bundle/ $TMP_BUNDLE_DIR
 
Index: install-scripts/mac/dailyrun.sh
===================================================================
--- install-scripts/mac/dailyrun.sh	(revision 10527)
+++ install-scripts/mac/dailyrun.sh	(revision 10345)
@@ -1,9 +1,6 @@
-#!/bin/bash -e
+#!/bin/bash
 #
 # Should be run as: sudo ./dailyrun.sh
 #
-
-#FORCE=true
-#LOCAL=true
 
 test -r /sw/bin/init.sh && . /sw/bin/init.sh
@@ -11,49 +8,29 @@
 export PATH=$HOME/bin:$PATH
 
-WORK_DIR=/private/tmp/repos
+STABLE_REVISION_1=`svn info --non-interactive http://orange.biolab.si/svn/orange/branches/ver1.0/ | grep 'Last Changed Rev:' | cut -d ' ' -f 4`
+# svn info does not return proper exit status on an error so we check it this way
+[ "$STABLE_REVISION_1" ] || exit 1
+STABLE_REVISION_2=`svn info --non-interactive http://orange.biolab.si/svn/orange/externals/branches/ver1.0/ | grep 'Last Changed Rev:' | cut -d ' ' -f 4`
+# svn info does not return proper exit status on an error so we check it this way
+[ "$STABLE_REVISION_2" ] || exit 1
 
-if [ $LOCAL ]; then
-	PUBLISH_DIR=/private/tmp/download
-	mkdir -p $PUBLISH_DIR
+if [[ $STABLE_REVISION_1 -gt $STABLE_REVISION_2 ]]; then
+    STABLE_REVISION=$STABLE_REVISION_1
 else
-	PUBLISH_DIR=/Volumes/download
+    STABLE_REVISION=$STABLE_REVISION_2
 fi
 
-if [ ! -e $WORK_DIR ]; then
-	mkdir -p $WORK_DIR
+DAILY_REVISION_1=`svn info --non-interactive http://orange.biolab.si/svn/orange/trunk/ | grep 'Last Changed Rev:' | cut -d ' ' -f 4`
+# svn info does not return proper exit status on an error so we check it this way
+[ "$DAILY_REVISION_1" ] || exit 1
+DAILY_REVISION_2=`svn info --non-interactive http://orange.biolab.si/svn/orange/externals/trunk/ | grep 'Last Changed Rev:' | cut -d ' ' -f 4`
+# svn info does not return proper exit status on an error so we check it this way
+[ "$DAILY_REVISION_2" ] || exit 1
+
+if [[ $DAILY_REVISION_1 -gt $DAILY_REVISION_2 ]]; then
+    DAILY_REVISION=$DAILY_REVISION_1
+else
+    DAILY_REVISION=$DAILY_REVISION_2
 fi
-
-SOURCE_LOG=/private/tmp/sources-daily-build.log
-
-# Build source packages
-./build-source.sh https://bitbucket.org/biolab/orange orange tip $WORK_DIR Orange > $SOURCE_LOG 2>&1
-EXIT_VALUE1=$?
-./build-source.sh https://bitbucket.org/biolab/orange-addon-bioinformatics bioinformatics tip $WORK_DIR Orange-Bioinformatics >> $SOURCE_LOG 2>&1
-EXIT_VALUE2=$?
-./build-source.sh https://bitbucket.org/biolab/orange-addon-text text tip $WORK_DIR Orange-Text-Mining >> $SOURCE_LOG 2>&1
-EXIT_VALUE3=$?
-
-echo "Orange (sources) [$EXIT_VALUE1 $EXIT_VALUE2 $EXIT_VALUE3]" > "/Volumes/download/buildLogs/osx/source-daily-build-hg.log"
-date >> "/Volumes/download/buildLogs/osx/source-daily-build-hg.log"
-cat $SOURCE_LOG > "/Volumes/download/buildLogs/osx/source-daily-build-hg.log"
-(($EXIT_VALUE1 + $EXIT_VALUE2 + $EXIT_VALUE3)) && echo "Daily sources failed"
-
-# Get versions from PKG-INFO files
-ORANGE_VERSION=`grep "^Version:" $WORK_DIR/Orange.egg-info/PKG-INFO | cut -d " " -f 2`
-BIOINFORMATICS_VERSION=`grep "^Version:" $WORK_DIR/Orange_Bioinformatics.egg-info/PKG-INFO | cut -d " " -f 2`
-TEXT_VERSION=`grep "^Version:" $WORK_DIR/Orange_Text_Mining.egg-info/PKG-INFO | cut -d " " -f 2`
-
-
-# Source filenames
-ORANGE_SOURCE="Orange-${ORANGE_VERSION}.tar.gz"
-BIOINFORMATICS_SOURCE="Orange-Bioinformatics-${BIOINFORMATICS_VERSION}.tar.gz"
-TEXT_SOURCE="Orange-Text-Mining-${TEXT_VERSION}.tar.gz"
-
-
-# Get source packages md5 checksum
-ORANGE_SOURCE_MD5=`md5 -q $WORK_DIR/$ORANGE_SOURCE`
-BIOINFORMATICS_SOURCE_MD5=`md5 -q $WORK_DIR/$BIOINFORMATICS_SOURCE`
-TEXT_SOURCE_MD5=`md5 -q $WORK_DIR/$TEXT_SOURCE`
-
 
 MAC_VERSION=`sw_vers -productVersion | cut -d '.' -f 2`
@@ -62,85 +39,11 @@
 defaults write com.apple.desktopservices DSDontWriteNetworkStores true
 
-if [ ! $LOCAL ]; then
-	/Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; }
-fi
+/Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; }
 
-# Base url for sources
-if [ $LOCAL ]; then
-	BASE_URL="file://$PUBLISH_DIR/sources"
-else
-	BASE_URL="http://orange.biolab.si/download/sources"
-fi
+## Daily build from hg
+/Users/ailabc/bundle-daily-build-hg.sh &> /private/tmp/bundle-daily-build.log
+EXIT_VALUE=$?
 
-# Base dir for sources
-SOURCES_DIR=$PUBLISH_DIR/sources
-
-
-# Publish sources
-
-if [ ! -e $SOURCES_DIR ]; then
-	mkdir -p $SOURCES_DIR
-fi
-
-if [[ ! -e $SOURCES_DIR/$ORANGE_SOURCE || $FORCE ]]; then
-	cp $WORK_DIR/$ORANGE_SOURCE $SOURCES_DIR/$ORANGE_SOURCE
-	NEW_ORANGE=1
-fi
-
-if [[ ! -e $SOURCES_DIR/BIOINFORMATICS_SOURCE || $FORCE ]]; then
-	cp $WORK_DIR/$BIOINFORMATICS_SOURCE $SOURCES_DIR/$BIOINFORMATICS_SOURCE
-	NEW_BIOINFORMATICS=1
-fi
-
-if [[ ! -e $SOURCES_DIR/TEXT_SOURCE || $FORCE ]]; then
-	cp $WORK_DIR/$TEXT_SOURCE $SOURCES_DIR/$TEXT_SOURCE
-	NEW_TEXT=1
-fi
-
-FINK_ROOT=/sw
-
-# Update the local finkinfo 
-# Local info files will be copied to biolab/main/finkinfo in fink-daily-build-packages.sh
-FINK_INFO_DIR="$FINK_ROOT/fink/dists/local/main/finkinfo"
-
-if [ ! -e $FINK_INFO_DIR ]; then
-	mkdir -p $FINK_INFO_DIR
-fi
-
-# Directory where fink .info templates are
-FINK_TEMPLATES=$WORK_DIR/orange/install-scripts/mac/fink
-
-FINK_LOG=/private/tmp/bundle-daily-build.log
-echo "" > $FINK_LOG
-
-if [[ $NEW_ORANGE || $FORCE ]]; then
-	FINK_ORANGE_SOURCE_TEMPLATE="Orange-%v.tar.gz"
-	./fink-register-info.sh "$FINK_TEMPLATES/orange-gui-hg-py.info" $BASE_URL/$FINK_ORANGE_SOURCE_TEMPLATE $ORANGE_SOURCE_MD5 $ORANGE_VERSION $FINK_INFO_DIR/orange-gui-hg-py.info >> $FINK_LOG 2>&1
-fi
-
-if [[ $NEW_BIOINFORMATICS || $FORCE ]]; then
-	FINK_BIOINFORMATICS_SOURCE_TEMPLATE="Orange-Bioinformatics-%v.tar.gz"
-	./fink-register-info.sh "$FINK_TEMPLATES/orange-bioinformatics-gui-hg-py.info" $BASE_URL/$FINK_BIOINFORMATICS_SOURCE_TEMPLATE $BIOINFORMATICS_SOURCE_MD5 $BIOINFORMATICS_VERSION $FINK_INFO_DIR/orange-bioinformatics-gui-hg-py.info >> $FINK_LOG 2>&1
-fi
-
-if [[ $NEW_TEXT || $FORCE ]]; then
-	FINK_TEXT_SOURCE_TEMPLATE="Orange-Text-Mining-%v.tar.gz"
-	./fink-register-info.sh "$FINK_TEMPLATES/orange-text-gui-hg-py.info" $BASE_URL/$FINK_TEXT_SOURCE_TEMPLATE $TEXT_SOURCE_MD5 $TEXT_VERSION $FINK_INFO_DIR/orange-text-gui-hg-py.info >> $FINK_LOG 2>&1
-fi
-
-if [ ! $LOCAL ]; then
-	/Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; }
-fi
-
-
-## Daily bundle build from hg
-if [[ $NEW_ORANGE || $NEW_BIOINFORMATICS || $NEW_TEXT || $FORCE ]]; then
-	/Users/ailabc/bundle-daily-build-hg.sh &> /private/tmp/bundle-daily-build.log
-	EXIT_VALUE=$?
-fi
-
-if [ ! $LOCAL ]; then
-	/Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; }
-fi
+/Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; }
 
 echo "Orange (bundle $MAC_VERSION from hg) [$EXIT_VALUE]" > "/Volumes/download/buildLogs/osx/bundle-$MAC_VERSION-daily-build-hg.log"
@@ -150,16 +53,32 @@
 
 
-## daily fink build
+#/Users/ailabc/bundle-daily-build.sh $STABLE_REVISION $DAILY_REVISION &> /private/tmp/bundle-daily-build.log
+#EXIT_VALUE=$?
+#
+#/Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; }
+#
+#echo "Orange (bundle $MAC_VERSION) [$EXIT_VALUE]" > "/Volumes/download/buildLogs/osx/bundle-$MAC_VERSION-daily-build.log"
+#date >> "/Volumes/download/buildLogs/osx/bundle-$MAC_VERSION-daily-build.log"
+#cat /private/tmp/bundle-daily-build.log >> "/Volumes/download/buildLogs/osx/bundle-$MAC_VERSION-daily-build.log"
+#(($EXIT_VALUE)) && echo "Running bundle-daily-build.sh failed"
+#
+#/Users/ailabc/bundle-64bit-daily-build.sh $DAILY_REVISION &> /private/tmp/bundle-64bit-daily-build.log
+#EXIT_VALUE=$?
 
-/Users/ailabc/fink-daily-build-packages.sh &> /private/tmp/fink-daily-build-packages.log
+#/Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; }
+#
+#echo "Orange (bundle $MAC_VERSION 64bit) [$EXIT_VALUE]" > "/Volumes/download/buildLogs/osx/bundle-$MAC_VERSION-64bit-daily-build.log"
+#date >> "/Volumes/download/buildLogs/osx/bundle-$MAC_VERSION-64bit-daily-build.log"
+#cat /private/tmp/bundle-64bit-daily-build.log >> "/Volumes/download/buildLogs/osx/bundle-$MAC_VERSION-64bit-daily-build.log"
+#(($EXIT_VALUE)) && echo "Running bundle-64bit-daily-build.sh failed"
+
+/Users/ailabc/fink-daily-build.sh $STABLE_REVISION $DAILY_REVISION &> /private/tmp/fink-daily-build.log
 EXIT_VALUE=$?
 
-if [ ! $LOCAL ]; then
-	/Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; }
-fi
+/Users/ailabc/mount-dirs.sh || { echo "Mounting failed." ; exit 1 ; }
 
 echo "Orange (fink $MAC_VERSION $ARCH) [$EXIT_VALUE]" > "/Volumes/download/buildLogs/osx/fink-$MAC_VERSION-$ARCH-daily-build.log"
 date >> "/Volumes/download/buildLogs/osx/fink-$MAC_VERSION-$ARCH-daily-build.log"
-cat /private/tmp/fink-daily-build-packages.log >> "/Volumes/download/buildLogs/osx/fink-$MAC_VERSION-$ARCH-daily-build.log"
+cat /private/tmp/fink-daily-build.log >> "/Volumes/download/buildLogs/osx/fink-$MAC_VERSION-$ARCH-daily-build.log"
 (($EXIT_VALUE)) && echo "Running fink-daily-build.sh failed"
 
Index: nstall-scripts/mac/fink-daily-build-packages.sh
===================================================================
--- install-scripts/mac/fink-daily-build-packages.sh	(revision 10500)
+++ 	(revision )
@@ -1,256 +1,0 @@
-#!/bin/bash -e
-#
-# Run daily fink build
-# 
-
-# Daily orange packages to build
-DAILY_PACKAGES="orange-hg-py26 orange-gui-hg-py26 orange-bioinformatics-hg-py26 orange-bioinformatics-gui-hg-py26 orange-text-hg-py26 orange-text-gui-hg-py26 orange-hg-py27 orange-gui-hg-py27 orange-bioinformatics-hg-py27 orange-bioinformatics-gui-hg-py27 orange-text-hg-py27 orange-text-gui-hg-py27"
-
-# Packages which, when installing, want special confirmation from the user
-# We keep those packages installed all the time
-SPECIAL_PACKAGES="passwd xinitrc"
-
-# A list of packages (dependencies) from which user can choose upon installing our packages
-# We would like to build all those so that it does not need to compile anything whichever packages he or she chooses
-# The problem is that they are often mutually conflicting so we cannot have them simply installed (so that update-all
-# would update them) but have to build them explicitly
-OTHER_PACKAGES="ghostscript ghostscript-esp ghostscript6 ghostscript-nox ghostscript6-nox gnuplot gnuplot-nox gnuplot-nogtk tetex-base tetex-nox-base texlive-nox-base texlive-base tetex-texmf texlive-texmf"
-
-
-# Miscellaneous extra packages which are maybe not really needed for Orange but are useful for CS research
-EXTRA_PACKAGES="fuse gcc42 gcc43 gcc44 gnuplot gnuplot-nox gnuplot-nogtk db48 db48-aes git imagemagick-nox rrdtool maxima nmap wireshark openssl pstree python26 python27 python3 rdiff-backup svn swi-prolog lynx links w3m elinks matplotlib-py26 matplotlib-py27 mercurial-py26 mercurial-py27"
-
-FINK_ARGS="--yes --build-as-nobody"
-FINK_SELFUPDATE_ARGS="--yes"
-APT_ARGS="--assume-yes"
-
-# Path to Fink root
-FINK_ROOT=/sw
-
-# Repo dir
-REPO_DIR=/private/tmp/repos
-
-ARCH=`perl -MFink::FinkVersion -e 'print Fink::FinkVersion::get_arch'`
-
-# Sets error handler
-trap "echo \"Script failed\"" ERR
-
-((`id -u` == 0)) || { echo "Must run as root user (use sudo)."; exit 1; }
-
-test -r $FINK_ROOT/bin/init.sh || { echo "Fink cannot be found." exit 2; }
-
-[ -e /Volumes/fink/ ] || { echo "/Volumes/fink/ not mounted."; exit 3; }
-
-# Configures environment for Fink
-. $FINK_ROOT/bin/init.sh
-
-if ! grep '^Trees:' $FINK_ROOT/etc/fink.conf | grep -q 'unstable/main' && grep '^SelfUpdateMethod:' $FINK_ROOT/etc/fink.conf | grep -q 'point'; then
-	echo "Fink does not seem to use unstable Fink packages tree with rsync or CVS updating."
-	exit 5
-fi
-
-if [ ! -x /usr/bin/xcodebuild ]; then
-	echo "It seems Xcode is not installed on a system."
-	exit 6
-fi
-
-MAC_VERSION=`sw_vers -productVersion | cut -d '.' -f 2`
-if [[ "$MAC_VERSION" -ne 5 && "$MAC_VERSION" -ne 6 ]]; then
-	echo "It seems system is not Mac OS X version 10.5 or 10.6."
-	exit 7
-fi
-
-if [ ! "`/usr/X11/bin/X -version 2>&1 | grep '^X.Org X Server' | grep -E -o '[0-9]+\.[0-9]+\.[0-9]+' | cut -d '.' -f 2`" -gt "3" ]; then
-	echo "It seems X11 version 2.3.0 or later is not installed on a system."
-	exit 8
-fi
-
-echo "Preparing local biolab Fink info files repository."
-mkdir -p $FINK_ROOT/fink/dists/biolab/main/finkinfo/
-rm -f $FINK_ROOT/fink/dists/biolab/main/finkinfo/*
-
-echo "Updating local biolab Fink info files repository."
-curl "http://orange.biolab.si/fink/dists/10.$MAC_VERSION/main/finkinfo/all.tgz" --output $FINK_ROOT/fink/dists/biolab/main/finkinfo/all.tgz
-tar -xzf $FINK_ROOT/fink/dists/biolab/main/finkinfo/all.tgz -C $FINK_ROOT/fink/dists/biolab/main/finkinfo/
-rm -f $FINK_ROOT/fink/dists/biolab/main/finkinfo/all.tgz
-
-# Copy info files from local/main/finkinfo
-echo "Updating new fink info files."
-mv $FINK_ROOT/fink/dists/local/main/finkinfo/*.info $FINK_ROOT/fink/dists/biolab/main/finkinfo/
-
-if ! grep '^Trees:' $FINK_ROOT/etc/fink.conf | grep -q 'biolab/main'; then
-	echo "Adding local biolab Fink info files repository to Fink configuration."
-	perl -p -i -l -e '$_ = "$_ biolab/main" if /^Trees/' $FINK_ROOT/etc/fink.conf
-fi
-
-# Adds our binary repository to local Fink (APT) configuration
-if ! grep -q "deb http://orange.biolab.si/fink 10.$MAC_VERSION main" $FINK_ROOT/etc/apt/sources.list; then
-	echo "Adding biolab Fink binary packages repository to Fink configuration."
-	echo "deb http://orange.biolab.si/fink 10.$MAC_VERSION main" >> $FINK_ROOT/etc/apt/sources.list
-fi
-
-if [ ! -e $FINK_ROOT/etc/apt/apt.conf.d/daily-build ]; then
-	echo "Configuring apt-get to assume yes to all questions."
-	echo 'APT::Get::Assume-Yes "true";' > $FINK_ROOT/etc/apt/apt.conf.d/daily-build
-fi
-
-# Configures any pending packages from possible interrupted past sessions
-dpkg --configure -a
-
-# Gets all official Fink package info files
-echo "Updating installed Fink packages."
-fink $FINK_SELFUPDATE_ARGS selfupdate --method=rsync
-fink $FINK_ARGS scanpackages
-
-# Updates everything (probably by compiling new packages)
-fink $FINK_ARGS update-all
-
-# Installs special packages (if they are not already installed)
-yes | fink $FINK_ARGS install $SPECIAL_PACKAGES
-
-# Removes possiblly installed packages which we want built
-fink $FINK_ARGS purge --recursive $DAILY_PACKAGES $OTHER_PACKAGES $EXTRA_PACKAGES
-# Sometimes Fink and APT are not in sync so we remove packages also directly
-for package in $DAILY_PACKAGES $OTHER_PACKAGES $EXTRA_PACKAGES ; do
-	echo $package "purge" | dpkg --set-selections
-done
-apt-get $APT_ARGS dselect-upgrade
-
-# Stores current packages status
-dpkg --get-selections '*' > /tmp/dpkg-selections.list
-
-for package in $OTHER_PACKAGES ; do
-	# Restores intitial packages status
-	dpkg --get-selections '*' | cut -f 1 | xargs -n 1 -J % echo % purge | dpkg --set-selections
-	dpkg --set-selections < /tmp/dpkg-selections.list
-	apt-get $APT_ARGS dselect-upgrade
-	
-	# Builds a package if it has not been rebuilt already (for example, as a dependency)
-	# We install it and not just build it because installation does not build package if it already exists as a binary package
-	echo "Specially building package $package."
-	fink $FINK_ARGS install $package
-done
-
-for package in $EXTRA_PACKAGES ; do
-	if fink $FINK_ARGS describe $package > /dev/null ; then
-		# Restores intitial packages status
-		dpkg --get-selections '*' | cut -f 1 | xargs -n 1 -J % echo % purge | dpkg --set-selections
-		dpkg --set-selections < /tmp/dpkg-selections.list
-		apt-get $APT_ARGS dselect-upgrade
-		
-		# Builds a package if it has not been rebuilt already (for example, as a dependency)
-		# We install it and not just build it because installation does not build package if it already exists as a binary package
-		echo "Specially building extra package $package."
-		fink $FINK_ARGS install $package
-	else
-		echo "Not building extra package $package."
-	fi
-done
-
-# We build our packages in "maintainer" mode - Fink makes tests and validates packages
-for package in $DAILY_PACKAGES ; do
-	DEPS=`perl -MFink -MFink::PkgVersion -l -e "Fink::Package->require_packages(); map { map { /(\\S+)/; print \\$1 } @\\$_ } @{Fink::PkgVersion->match_package('$package')->get_depends(1, 0)};"`
-	
-	# First builds all dependencies normally (so that we are not checking for others' errors)
-	for deps in $DEPS ; do
-		# Restores intitial packages status
-		dpkg --get-selections '*' | cut -f 1 | xargs -n 1 -J % echo % purge | dpkg --set-selections
-		dpkg --set-selections < /tmp/dpkg-selections.list
-		apt-get $APT_ARGS dselect-upgrade
-		
-		# We install it and not just build it because installation does not build package if it already exists as a binary package
-		echo "Specially building package $package dependency $deps."
-		fink $FINK_ARGS install $deps
-	done
-	
-	# Restores intitial packages status
-	dpkg --get-selections '*' | cut -f 1 | xargs -n 1 -J % echo % purge | dpkg --set-selections
-	dpkg --set-selections < /tmp/dpkg-selections.list
-	apt-get $APT_ARGS dselect-upgrade
-	
-	# Then builds a package
-	# We can just build it as our packages have been probably cached if they have been already built
-	echo "Specially building, testing and validating package $package."
-	fink $FINK_ARGS --maintainer build $package
-done
-
-echo "Restoring initial packages status."
-dpkg --get-selections '*' | cut -f 1 | xargs -n 1 -J % echo % purge | dpkg --set-selections
-dpkg --set-selections < /tmp/dpkg-selections.list
-apt-get $APT_ARGS dselect-upgrade
-rm -f /tmp/dpkg-selections.list
-
-# Cleans unncessary files (we cache them anyway in public repository)
-echo "Cleaning."
-fink $FINK_ARGS cleanup --all
-
-# TODO: Should be called only on a daily build server and not if building locally
-/Users/ailabc/mount-dirs.sh
-
-echo "Preparing public biolab Fink info and binary files repository."
-mkdir -p /Volumes/fink/dists/10.$MAC_VERSION/main/binary-darwin-$ARCH/
-chmod +rx /Volumes/fink/dists/10.$MAC_VERSION/main/binary-darwin-$ARCH/
-mkdir -p /Volumes/fink/dists/10.$MAC_VERSION/main/finkinfo/
-chmod +rx /Volumes/fink/dists/10.$MAC_VERSION/main/binary-darwin-$ARCH/
-
-echo "Copying to repository all binary packages."
-cp $FINK_ROOT/fink/debs/*.deb /Volumes/fink/dists/10.$MAC_VERSION/main/binary-darwin-$ARCH/
-if (shopt -s nullglob; f=($FINK_ROOT/var/cache/apt/archives/*.deb); ((${#f[@]}))); then
-	# We have to test if there are any deb files available as otherwise cp fails
-	cp $FINK_ROOT/var/cache/apt/archives/*.deb /Volumes/fink/dists/10.$MAC_VERSION/main/binary-darwin-$ARCH/
-fi
-
-cd /Volumes/fink/dists/10.$MAC_VERSION/main/binary-darwin-$ARCH/
-
-echo "Fixing possible problems with binary packages filenames."
-# Some packages include Fink epoch which uses colon as a delimiter and breaks package retrieval from the repository web server
-# We remove epoch as it should not be there in the first place
-perl -e '
-for (<*.deb>) {
-	if (m/^(.+)_\d+%3a(.+)$/) {
-		rename $_, "$1_$2";
-	}
-}
-'
-
-echo "Removing old binary packages."
-# (Versions of packages which have more then 5 versions and those old versions are more than one month old.)
-perl -e '
-for (<*.deb>) {
-	m/(.*?)_/;
-	$fs{$1}++;
-}
-while (($f,$n) = each(%fs)) {
-	next if $n <= 5;
-	unlink for grep {-M > 30} <$f_*.deb>;
-}
-'
-
-echo "Making packages list."
-cd /Volumes/fink/
-perl -MFink::Scanpackages -e "Fink::Scanpackages->scan('dists/10.$MAC_VERSION/main/binary-darwin-$ARCH/');" | gzip - > dists/10.$MAC_VERSION/main/binary-darwin-$ARCH/Packages.gz
-
-echo "Copying to repository all info files."
-rm -f /Volumes/fink/dists/10.$MAC_VERSION/main/finkinfo/*
-cp $FINK_ROOT/fink/dists/biolab/main/finkinfo/* /Volumes/fink/dists/10.$MAC_VERSION/main/finkinfo/
-
-echo "Making an archive of all info files."
-cd $FINK_ROOT/fink/dists/biolab/main/finkinfo/
-tar -czf /Volumes/fink/dists/10.$MAC_VERSION/main/finkinfo/all.tgz *
-
-echo "Setting permissions."
-chmod -R +r /Volumes/fink/dists/10.$MAC_VERSION/main/finkinfo/
-
-echo "Removing unnecessary source archives."
-perl -e "
-for (</Volumes/fink/dists/10.$MAC_VERSION/main/binary-darwin-$ARCH/orange-*.deb>) {
-	m/_(.+)-\\d+_darwin-$ARCH\\.deb/;
-	\$versions{\$1} = 1;
-}
-for (</Volumes/fink/dists/10.$MAC_VERSION/main/source/*.tgz>) {
-	m/.+-(.+)\\.tgz/;
-	next if \$versions{\$1} or -M() < 30;
-	unlink;
-}
-"
-
Index: install-scripts/mac/update-all-scripts.sh
===================================================================
--- install-scripts/mac/update-all-scripts.sh	(revision 10505)
+++ install-scripts/mac/update-all-scripts.sh	(revision 10342)
@@ -22,7 +22,4 @@
 curl --silent --output bundle-inject-pypi.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/bundle-inject-pypi.sh
 curl --silent --output dailyrun-bundleonly-hg.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/dailyrun-bundleonly-hg.sh
-curl --silent --output fink-daily-build-packages.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-daily-build-packages.sh
-curl --silent --output fink-register-info.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/fink-register-info.sh
-curl --silent --output build-source.sh https://bitbucket.org/biolab/orange/raw/tip/install-scripts/mac/build-source.sh
 
 chmod +x *.sh
Index: setup.py
===================================================================
--- setup.py	(revision 10507)
+++ setup.py	(revision 10471)
@@ -676,4 +676,6 @@
     version = full_version
 """
+    global VERSION
+    
     FULLVERSION = VERSION
     if os.path.exists('.hg'):
@@ -698,4 +700,7 @@
     finally:
         a.close()
+    
+    if not ISRELEASED:
+        VERSION = FULLVERSION 
 
 def setup_package():
Index: source/orange/lib_learner.cpp
===================================================================
--- source/orange/lib_learner.cpp	(revision 10517)
+++ source/orange/lib_learner.cpp	(revision 10377)
@@ -2099,10 +2099,9 @@
     bool setPrefixRules;
     bool optimizeBetasFlag;
-    float penalty = 0.01f;
-
-    if (!PyArg_ParseTuple(args, "O&fffO&|O&iiO&O&:RuleClassifier.call", cc_RuleList, &rules, &minSignificance, &minBeta, &penalty, pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID, &setPrefixRules, &optimizeBetasFlag, cc_Classifier, &classifier, cc_DistributionList, &probList))
-      return PYNULL;
-
-    TRuleClassifier *rc = new TRuleClassifier_logit(rules, minSignificance, minBeta, penalty, gen, weightID, classifier, probList, setPrefixRules, optimizeBetasFlag);
+
+    if (!PyArg_ParseTuple(args, "O&ffO&|O&iiO&O&:RuleClassifier.call", cc_RuleList, &rules, &minSignificance, &minBeta, pt_ExampleGenerator, &gen, pt_weightByGen(gen), &weightID, &setPrefixRules, &optimizeBetasFlag, cc_Classifier, &classifier, cc_DistributionList, &probList))
+      return PYNULL;
+
+    TRuleClassifier *rc = new TRuleClassifier_logit(rules, minSignificance, minBeta, gen, weightID, classifier, probList,setPrefixRules, optimizeBetasFlag);
     PRuleClassifier ruleClassifier = rc;
 //    ruleClassifier = new SELF_AS(TRuleClassifier)(rules, gen, weightID);
Index: source/orange/rulelearner.cpp
===================================================================
--- source/orange/rulelearner.cpp	(revision 10531)
+++ source/orange/rulelearner.cpp	(revision 8735)
@@ -45,5 +45,5 @@
 : weightID(0),
   quality(ILLEGAL_FLOAT),
-  complexity(0),
+  complexity(-1),
   coveredExamples(NULL),
   coveredExamplesLength(-1),
@@ -93,5 +93,5 @@
 
 TRule::~TRule()
-{   delete coveredExamples; }
+{ delete coveredExamples; }
 
 bool TRule::operator ()(const TExample &ex)
@@ -986,6 +986,6 @@
 	       improved/rule->classDistribution->atint(targetClass) > min_improved_perc*0.01 &&
            quality > (aprioriProb + 1e-3))
-//    futureQuality = quality;
-    futureQuality = 1.0 + quality;
+    futureQuality = quality;
+//    futureQuality = 1.0 + quality;
   else {
     PDistribution oldRuleDist = rule->classDistribution;
@@ -1016,5 +1016,5 @@
       futureQuality = -1.0;
     else {
-      futureQuality = 0.0; 
+      futureQuality = 0.0;
       PEITERATE(ei, rule->examples) {
         if ((*ei).getClass().intV != targetClass)
@@ -1023,22 +1023,11 @@
           continue;
         }
-      /*  float x = ((*ei)[probVar].floatV-quality); //*rule->classDistribution->abs;
-        if ((*ei)[probVar].floatV > quality) 
+        float x = ((*ei)[probVar].floatV-quality); //*rule->classDistribution->abs;
+        if ((*ei)[probVar].floatV > quality)
           x *= (1.0-quality)/(bestQuality-quality);
         x /= sqrt(quality*(1.0-quality)); // rule->classDistribution->abs*
-        futureQuality += log(1.0-max(1e-12,1.0-2*zprob(x))); */
-        float x;
-        if ((*ei)[probVar].floatV > quality)
-        {
-            x = 1.0 - ((*ei)[probVar].floatV-quality) / (bestQuality-quality);
-        }
-        else
-        {
-            x = 1.0 + quality - (*ei)[probVar].floatV;
-        }
-        futureQuality += x;
-      }
-//      futureQuality = 1.0 - exp(futureQuality);
-      futureQuality /= rule->classDistribution->atint(targetClass);
+        futureQuality += log(1.0-max(1e-12,1.0-2*zprob(x)));
+      }
+      futureQuality = 1.0 - exp(futureQuality);
     }
   }
@@ -1970,17 +1959,17 @@
 {
 	PITERATE(TIntList, ind, ruleIndices[rule_i])
-    {
-        float bestQuality = 0.0;
-        PITERATE(TIntList, fr, prefixRules) {
-            if (rules->at(*fr)->call(examples->at(*ind)) && rules->at(*fr)->quality > bestQuality) {
-                bestQuality = rules->at(*fr)->quality;
-                p[getClassIndex(rules->at(*fr))][*ind] = rules->at(*fr)->quality;
-                for (int ci=0; ci<examples->domain->classVar->noOfValues(); ci++)
-                if (ci!=getClassIndex(rules->at(*fr)))
-                    p[ci][*ind] = (1.0-rules->at(*fr)->quality)/(examples->domain->classVar->noOfValues()-1);
-                break;
-            }
-        }
-    }
+  {
+    float bestQuality = 0.0;
+		PITERATE(TIntList, fr, prefixRules) {
+			  if (rules->at(*fr)->call(examples->at(*ind)) && rules->at(*fr)->quality > bestQuality) {
+          bestQuality = rules->at(*fr)->quality;
+				  p[getClassIndex(rules->at(*fr))][*ind] = rules->at(*fr)->quality;
+				  for (int ci=0; ci<examples->domain->classVar->noOfValues(); ci++)
+					  if (ci!=getClassIndex(rules->at(*fr)))
+						  p[ci][*ind] = (1.0-rules->at(*fr)->quality)/(examples->domain->classVar->noOfValues()-1);
+				  break;
+			  }
+	  }
+  }
 }
 
@@ -2029,10 +2018,10 @@
 void TLogitClassifierState::setPrefixRule(int rule_i) //, int position)
 {
-    prefixRules->push_back(rule_i);
-    setFixed(rule_i);
-    updateFixedPs(rule_i);
-    betas[rule_i] = 0.0;
-    computeAvgProbs();
-    computePriorProbs();
+	prefixRules->push_back(rule_i);
+	setFixed(rule_i);
+	updateFixedPs(rule_i);
+	betas[rule_i] = 0.0;
+  computeAvgProbs();
+  computePriorProbs();
 }
 
@@ -2041,5 +2030,5 @@
 {}
 
-TRuleClassifier_logit::TRuleClassifier_logit(PRuleList arules, const float &minSignificance, const float &minBeta, const float &penalty, PExampleTable anexamples, const int &aweightID, const PClassifier &classifier, const PDistributionList &probList, bool setPrefixRules, bool optimizeBetasFlag)
+TRuleClassifier_logit::TRuleClassifier_logit(PRuleList arules, const float &minSignificance, const float &minBeta, PExampleTable anexamples, const int &aweightID, const PClassifier &classifier, const PDistributionList &probList, bool setPrefixRules, bool optimizeBetasFlag)
 : TRuleClassifier(arules, anexamples, aweightID),
   minSignificance(minSignificance),
@@ -2047,9 +2036,9 @@
   setPrefixRules(setPrefixRules),
   optimizeBetasFlag(optimizeBetasFlag),
-  minBeta(minBeta),
-  penalty(penalty)
+  minBeta(minBeta)
 {
   initialize(probList);
   float step = 2.0;
+  minStep = (float)0.01;
 
   // initialize prior betas
@@ -2062,10 +2051,10 @@
   if (setPrefixRules)
   {
-    bool changed = setBestPrefixRule();
-    while (changed) {
-        if (optimizeBetasFlag)
-            optimizeBetas();
-        changed = setBestPrefixRule();
-    }
+	  bool changed = setBestPrefixRule();
+	  while (changed) {
+		if (optimizeBetasFlag)
+			optimizeBetas();
+		changed = setBestPrefixRule();
+	  }
   }
 
@@ -2218,8 +2207,8 @@
   wsig = sig;
   PITERATE(TRuleList, ri, rules) {
-    float maxDiff = (*ri)->classDistribution->atint(getClassIndex(*ri))/(*ri)->classDistribution->abs;
-    maxDiff -= (*ri)->quality;
-    wsig->push_back(maxDiff);
-    float n = (*ri)->examples->numberOfExamples();
+  	float maxDiff = (*ri)->classDistribution->atint(getClassIndex(*ri))/(*ri)->classDistribution->abs;
+	  maxDiff -= (*ri)->quality;
+	  wsig->push_back(maxDiff);
+   float n = (*ri)->examples->numberOfExamples();
     float a = n*(*ri)->quality;
     float b = n*(1.0-(*ri)->quality);
@@ -2283,8 +2272,8 @@
         if ((*ri)->call(*ei)) {
           //int vv = (*ei).getClass().intV;
-          //if ((*ei).getClass().intV == getClassIndex(*ri))
-          coverages[getClassIndex(*ri)][j] += 1.0;
+		      //if ((*ei).getClass().intV == getClassIndex(*ri))
+			    coverages[getClassIndex(*ri)][j] += 1.0;
         }
-        j++;
+	      j++;
       }
       i++;
@@ -2324,15 +2313,13 @@
 
     float step = 0.1f;
+    float gamma = 0.01f;
     float error = 1e+20f;
     float old_error = 1e+21f;
 
-    int nsteps = 0;
     while (old_error > error || step > 0.00001)
     {
         // reduce step if improvement failed
-        nsteps++;
-        if (old_error < error && nsteps > 20 || nsteps > 1000)
+        if (old_error < error)
         {
-            nsteps = 0;
             step /= 10;
             finalState->copyTo(currentState);
@@ -2348,14 +2335,7 @@
 
             float der = 0.0;
-            if (currentState->avgProb->at(i) > rules->at(i)->quality)
-            {
-                der += pow(rules->at(i)->quality - currentState->avgProb->at(i),2);
-                der -= 2 * (rules->at(i)->quality - currentState->avgProb->at(i)) * currentState->betas[i];
-            }
-            else
-                der -= 2 * (rules->at(i)->quality - currentState->avgProb->at(i));
-            der += 2 * penalty * currentState->betas[i];
-//            if (currentState->avgProb->at(i) > rules->at(i)->quality)
-//                der = max(0.01f / step, der);
+            if (currentState->avgProb->at(i) < rules->at(i)->quality)
+                der -= rules->at(i)->quality - currentState->avgProb->at(i);
+            der += 2*gamma*currentState->betas[i];
             currentState->newBeta(i,max(0.0f, currentState->betas[i]-step*der));
         }
@@ -2363,10 +2343,7 @@
         error = 0;
         for (int i=0; i<rules->size(); i++) {
-//            if (currentState->avgProb->at(i) < rules->at(i)->quality)
-            if (currentState->avgProb->at(i) > rules->at(i)->quality)
-                error += pow(rules->at(i)->quality - currentState->avgProb->at(i),2) * currentState->betas[i];
-            else
-                error += pow(rules->at(i)->quality - currentState->avgProb->at(i),2);
-            error += penalty*pow(currentState->betas[i],2);
+            if (currentState->avgProb->at(i) < rules->at(i)->quality)
+                error += rules->at(i)->quality - currentState->avgProb->at(i);
+            error += gamma*pow(currentState->betas[i],2);
         }
         //printf("error = %4.4f\n", error);
@@ -2376,7 +2353,111 @@
         //printf("\n"); 
     }
-
     finalState->copyTo(currentState);
 }
+
+/*
+void TRuleClassifier_logit::updateRuleBetas2(float step_)
+{
+
+  stabilizeAndEvaluate(step_,-1);
+  PLogitClassifierState finalState, tempState;
+  currentState->copyTo(finalState);
+
+  float step = 2.0;
+  int changed;
+  float worst_underestimate, underestimate;
+  float auc = currentState->getAUC();
+  float brier = currentState->getBrierScore();
+  float temp_auc, temp_brier;
+  int worst_rule_index;
+  while (step > 0.001)
+  {
+      step /= 2;
+      changed = 0;
+      while (changed < 100)
+      {
+        changed = 0;
+        worst_underestimate = (float)0.01;
+        worst_rule_index = -1;
+        // find rule with greatest underestimate in probability
+        for (int i=0; i<rules->size(); i++) {
+            if (currentState->avgProb->at(i) >= rules->at(i)->quality)
+                continue;
+            if (skipRule[i])
+                continue;
+
+            underestimate = (rules->at(i)->quality - currentState->avgProb->at(i));//*rules->at(i)->classDistribution->abs;
+            // if under estimate error is big enough
+            if (underestimate > worst_underestimate)
+            {
+                worst_underestimate = underestimate;
+                worst_rule_index = i;
+            }
+        }
+        if (worst_rule_index > -1)
+        {
+            currentState->newBeta(worst_rule_index,currentState->betas[worst_rule_index]+step);
+            if (currentState->avgProb->at(worst_rule_index) > rules->at(worst_rule_index)->quality)
+            {
+                finalState->copyTo(currentState);
+                changed = 100;
+            }
+            else
+            {
+              stabilizeAndEvaluate(step,-1);
+              temp_auc = currentState->getAUC();
+              temp_brier = currentState->getBrierScore();
+              if (temp_auc >= auc && temp_brier < brier)
+              {
+                currentState->copyTo(finalState);
+                changed = 0;
+                auc = temp_auc;
+                brier = temp_brier;
+              }
+              else
+                changed ++;
+            }
+         // }
+        }
+        else
+        {
+          changed = 100;
+          finalState->copyTo(currentState);
+        }
+      }
+  }
+  finalState->copyTo(currentState);
+}
+*/
+
+void TRuleClassifier_logit::stabilizeAndEvaluate(float & step, int last_changed_rule_index)
+{
+    PLogitClassifierState tempState;
+    currentState->copyTo(tempState);
+    bool changed = true;
+    while (changed)
+    {
+        changed = false;
+        for (int i=0; i<rules->size(); i++)
+        {
+            if (currentState->avgProb->at(i) > (rules->at(i)->quality + 0.01) && currentState->betas[i] > 0.0 &&
+                i != last_changed_rule_index)
+            {
+                float new_beta = currentState->betas[i]-step > 0 ? currentState->betas[i]-step : 0.0;
+                currentState->newBeta(i,new_beta);
+                if (currentState->avgProb->at(i) < rules->at(i)->quality + 1e-6)
+                {
+                    tempState->copyTo(currentState);
+                }
+                else
+                {
+                    currentState->copyTo(tempState);
+                    changed = true;
+                }
+            }
+        }
+    }
+}
+
 
 void TRuleClassifier_logit::addPriorClassifier(const TExample &ex, double * priorFs) {
@@ -2435,14 +2516,14 @@
   bool foundPrefixRule = false;
   float bestQuality = 0.0;
-  PITERATE(TRuleList, rs, prefixRules) {    
-    if ((*rs)->call(ex) && (*rs)->quality > bestQuality) {
-        bestQuality = (*rs)->quality;
-        dist->setint(getClassIndex(*rs),(*rs)->quality);
-            for (int ci=0; ci<examples->domain->classVar->noOfValues(); ci++)
-            if (ci!=getClassIndex(*rs))
-                dist->setint(ci,(1.0-(*rs)->quality)/(examples->domain->classVar->noOfValues()-1));
-        foundPrefixRule = true;
-        break;
-      }
+  PITERATE(TRuleList, rs, prefixRules) {
+	  if ((*rs)->call(ex) && (*rs)->quality > bestQuality) {
+      bestQuality = (*rs)->quality;
+		  dist->setint(getClassIndex(*rs),(*rs)->quality);
+		  for (int ci=0; ci<examples->domain->classVar->noOfValues(); ci++)
+		    if (ci!=getClassIndex(*rs))
+			    dist->setint(ci,(1.0-(*rs)->quality)/(examples->domain->classVar->noOfValues()-1));
+      foundPrefixRule = true;
+      break;
+	  }
   }
   if (foundPrefixRule)
@@ -2464,7 +2545,7 @@
       if ((*r)->call(cexample)) {
         if (getClassIndex(*r) == i)
-            f += (*b);
+  		    f += (*b);
         else if (getClassIndex(*r) == res->noOfElements()-1)
-            f -= (*b);
+          f -= (*b);
       }
     dist->addint(i,exp(f));
Index: source/orange/rulelearner.hpp
===================================================================
--- source/orange/rulelearner.hpp	(revision 10517)
+++ source/orange/rulelearner.hpp	(revision 8735)
@@ -482,14 +482,12 @@
   __REGISTER_CLASS
 
-  PRuleList rules; //P
-  PExampleTable examples; //P
+  PRuleList rules;
+  PExampleTable examples;
   int weightID;
 
   float eval, **f, **p, *betas, *priorBetas;
   bool *isExampleFixed;
-  PFloatList avgProb; //P
-  PFloatList avgPriorProb; //P
-  PIntList *ruleIndices; //P
-  PIntList prefixRules; //P
+  PFloatList avgProb, avgPriorProb;
+  PIntList *ruleIndices, prefixRules;
 
   TLogitClassifierState(PRuleList, PExampleTable, const int &);
@@ -517,22 +515,18 @@
   PDomain domain; //P Domain
   PFloatList ruleBetas; //P Rule betas
+  float minStep; //P minimal step value
   float minSignificance; //P minimum requested significance for betas. 
   float minBeta; //P minimum beta by rule to be included in the model. 
-  bool setPrefixRules; //P should we order prefix rules ? 
-  bool optimizeBetasFlag; //P should we assign betas to rules ? 
-  float penalty; //P
+  bool setPrefixRules; // P should we order prefix rules ? 
+  bool optimizeBetasFlag; // P should we assign betas to rules ? 
 
   PClassifier priorClassifier; //P prior classifier used if provided
-  PLogitClassifierState currentState; //P
+  PLogitClassifierState currentState;
   bool *skipRule;
-  // standard deviations of rule quality
-  PFloatList wsd; //P
-  PFloatList wavgCov; //P
-  PFloatList wSatQ; //P
-  PFloatList wsig; //P
+  PFloatList wsd, wavgCov, wSatQ, wsig; // standard deviations of rule quality
   PRuleList prefixRules; //P rules that trigger before logit sum.
 
   TRuleClassifier_logit();
-  TRuleClassifier_logit(PRuleList rules, const float &minSignificance, const float &minBeta, const float &penalty, PExampleTable examples, const int &weightID = 0, const PClassifier &classifer = NULL, const PDistributionList &probList = NULL, bool setPrefixRules = false, bool optimizeBetasFlag = true);
+  TRuleClassifier_logit(PRuleList rules, const float &minSignificance, const float &minBeta, PExampleTable examples, const int &weightID = 0, const PClassifier &classifer = NULL, const PDistributionList &probList = NULL, bool setPrefixRules = false, bool optimizeBetasFlag = true);
 
   void initialize(const PDistributionList &);
Index: source/orangeqt/CMakeLists.txt
===================================================================
--- source/orangeqt/CMakeLists.txt	(revision 10515)
+++ source/orangeqt/CMakeLists.txt	(revision 9252)
@@ -9,5 +9,5 @@
 find_package(SIP REQUIRED)
 find_package(PythonLibrary REQUIRED)
-#find_package(OpenGL)
+find_package(OpenGL)
 find_package(Numpy)
 include(SIPMacros)
@@ -29,7 +29,7 @@
     multicurve.cpp
     plot.cpp 
-#    plot3d.cpp
-#    canvas3d.cpp
-#    glextensions.cpp
+    plot3d.cpp
+    canvas3d.cpp
+    glextensions.cpp
 )
 qt4_automoc(${orangeqt_SRCS})
@@ -51,6 +51,5 @@
 set(SIP_EXTRA_OPTIONS "-k")
 
-#set(SIP_EXTRA_LINK_LIBRARIES ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY} ${OPENGL_gl_LIBRARY})
-set(SIP_EXTRA_LINK_LIBRARIES ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
+set(SIP_EXTRA_LINK_LIBRARIES ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY} ${OPENGL_gl_LIBRARY})
 set(SIP_EXTRA_SOURCES ${orangeqt_SRCS})
 
Index: source/orangeqt/orangeqt.sip
===================================================================
--- source/orangeqt/orangeqt.sip	(revision 10515)
+++ source/orangeqt/orangeqt.sip	(revision 9057)
@@ -2,10 +2,10 @@
 
 %Import QtGui/QtGuimod.sip
-/*%Import QtOpenGL/QtOpenGLmod.sip*/
+%Import QtOpenGL/QtOpenGLmod.sip 
 
 %Include types.sip
 %Include plot.sip
-/*%Include plot3d.sip
-%Include canvas3d.sip*/
+%Include plot3d.sip
+%Include canvas3d.sip
 %Include plotitem.sip
 %Include point.sip
