Changeset 2e3e959 in sasview for src/sas/qtgui


Ignore:
Timestamp:
Jan 13, 2017 4:28:30 AM (8 years ago)
Author:
Piotr Rozyczko <rozyczko@…>
Branches:
ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
239214f
Parents:
db5cd8d
Message:

Code review issues addressed.
More unit tests for plotting.

Location:
src/sas/qtgui
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/LinearFit.py

    r87cc73a r2e3e959  
    7070        self.transform = transform 
    7171 
     72        self.setFixedSize(self.minimumSizeHint()) 
     73 
    7274        # connect Fit button 
    7375        self.cmdFit.clicked.connect(self.fit) 
     
    7981        assert(isinstance(label, basestring)) 
    8082        self.lblRange.setText(label) 
    81  
    82     def a(self): 
    83         return (float(self.txtA.text()), float(self.txtAerr.text())) 
    84  
    85     def b(self): 
    86         return (float(self.txtB.text()), float(self.txtBerr.text())) 
    87  
    88     def chi(self): 
    89         return float(self.txtChi2.text()) 
    9083 
    9184    def range(self): 
  • src/sas/qtgui/UI/LinearFitUI.ui

    r570a58f9 r2e3e959  
    77    <x>0</x> 
    88    <y>0</y> 
    9     <width>413</width> 
    10     <height>327</height> 
     9    <width>439</width> 
     10    <height>324</height> 
    1111   </rect> 
    1212  </property> 
    1313  <property name="sizePolicy"> 
    14    <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> 
     14   <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> 
    1515    <horstretch>0</horstretch> 
    1616    <verstretch>0</verstretch> 
     
    2828    <widget class="QLabel" name="label"> 
    2929     <property name="text"> 
    30       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Perform fit for &lt;span style=&quot; font-style:italic;&quot;&gt;y(x) = ax + b&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
     30      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Perform fit for &lt;span style=&quot; font-weight:600; font-style:italic;&quot;&gt;y(x) = ax + b&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
    3131     </property> 
    3232    </widget> 
    3333   </item> 
    3434   <item row="1" column="0" colspan="2"> 
     35    <widget class="QGroupBox" name="groupBox_2"> 
     36     <property name="title"> 
     37      <string>Fit ranges</string> 
     38     </property> 
     39     <layout class="QGridLayout" name="gridLayout_3"> 
     40      <item row="0" column="0"> 
     41       <layout class="QGridLayout" name="gridLayout_2"> 
     42        <item row="0" column="1"> 
     43         <widget class="QLabel" name="label_9"> 
     44          <property name="text"> 
     45           <string>Min</string> 
     46          </property> 
     47         </widget> 
     48        </item> 
     49        <item row="0" column="2"> 
     50         <widget class="QLabel" name="label_10"> 
     51          <property name="text"> 
     52           <string>Max</string> 
     53          </property> 
     54         </widget> 
     55        </item> 
     56        <item row="1" column="0"> 
     57         <widget class="QLabel" name="label_8"> 
     58          <property name="text"> 
     59           <string>Range (linear scale)</string> 
     60          </property> 
     61         </widget> 
     62        </item> 
     63        <item row="1" column="1"> 
     64         <widget class="QLineEdit" name="txtRangeMin"> 
     65          <property name="toolTip"> 
     66           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Minimum value on the x-axis for the plotted data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
     67          </property> 
     68          <property name="autoFillBackground"> 
     69           <bool>true</bool> 
     70          </property> 
     71          <property name="readOnly"> 
     72           <bool>true</bool> 
     73          </property> 
     74         </widget> 
     75        </item> 
     76        <item row="1" column="2"> 
     77         <widget class="QLineEdit" name="txtRangeMax"> 
     78          <property name="toolTip"> 
     79           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum value on the x-axis for the plotted data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
     80          </property> 
     81          <property name="autoFillBackground"> 
     82           <bool>true</bool> 
     83          </property> 
     84          <property name="readOnly"> 
     85           <bool>true</bool> 
     86          </property> 
     87         </widget> 
     88        </item> 
     89        <item row="2" column="0"> 
     90         <widget class="QLabel" name="lblRange"> 
     91          <property name="text"> 
     92           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit range&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
     93          </property> 
     94         </widget> 
     95        </item> 
     96        <item row="2" column="1"> 
     97         <widget class="QLineEdit" name="txtFitRangeMin"> 
     98          <property name="toolTip"> 
     99           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter the minimum value on the x-axis to be included in the fit.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
     100          </property> 
     101         </widget> 
     102        </item> 
     103        <item row="2" column="2"> 
     104         <widget class="QLineEdit" name="txtFitRangeMax"> 
     105          <property name="toolTip"> 
     106           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter the maximum value on the x-axis to be included in the fit.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
     107          </property> 
     108         </widget> 
     109        </item> 
     110       </layout> 
     111      </item> 
     112     </layout> 
     113    </widget> 
     114   </item> 
     115   <item row="2" column="0" colspan="2"> 
    35116    <widget class="QGroupBox" name="groupBox"> 
    36117     <property name="title"> 
     
    134215    </widget> 
    135216   </item> 
    136    <item row="2" column="0" colspan="2"> 
    137     <widget class="QGroupBox" name="groupBox_2"> 
    138      <property name="title"> 
    139       <string>Fit ranges</string> 
    140      </property> 
    141      <layout class="QGridLayout" name="gridLayout_3"> 
    142       <item row="0" column="0"> 
    143        <layout class="QGridLayout" name="gridLayout_2"> 
    144         <item row="0" column="1"> 
    145          <widget class="QLabel" name="label_9"> 
    146           <property name="text"> 
    147            <string>Min</string> 
    148           </property> 
    149          </widget> 
    150         </item> 
    151         <item row="0" column="2"> 
    152          <widget class="QLabel" name="label_10"> 
    153           <property name="text"> 
    154            <string>Max</string> 
    155           </property> 
    156          </widget> 
    157         </item> 
    158         <item row="1" column="0"> 
    159          <widget class="QLabel" name="label_8"> 
    160           <property name="text"> 
    161            <string>Range (linear scale)</string> 
    162           </property> 
    163          </widget> 
    164         </item> 
    165         <item row="1" column="1"> 
    166          <widget class="QLineEdit" name="txtRangeMin"> 
    167           <property name="toolTip"> 
    168            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Minimum value on the x-axis for the plotted data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
    169           </property> 
    170           <property name="readOnly"> 
    171            <bool>true</bool> 
    172           </property> 
    173          </widget> 
    174         </item> 
    175         <item row="1" column="2"> 
    176          <widget class="QLineEdit" name="txtRangeMax"> 
    177           <property name="toolTip"> 
    178            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum value on the x-axis for the plotted data.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
    179           </property> 
    180           <property name="readOnly"> 
    181            <bool>true</bool> 
    182           </property> 
    183          </widget> 
    184         </item> 
    185         <item row="2" column="0"> 
    186          <widget class="QLabel" name="lblRange"> 
    187           <property name="text"> 
    188            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit range&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
    189           </property> 
    190          </widget> 
    191         </item> 
    192         <item row="2" column="1"> 
    193          <widget class="QLineEdit" name="txtFitRangeMin"> 
    194           <property name="toolTip"> 
    195            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter the minimum value on the x-axis to be included in the fit.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
    196           </property> 
    197          </widget> 
    198         </item> 
    199         <item row="2" column="2"> 
    200          <widget class="QLineEdit" name="txtFitRangeMax"> 
    201           <property name="toolTip"> 
    202            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enter the maximum value on the x-axis to be included in the fit.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
    203           </property> 
    204          </widget> 
    205         </item> 
    206        </layout> 
    207       </item> 
    208      </layout> 
    209     </widget> 
    210    </item> 
    211217   <item row="3" column="0" colspan="2"> 
    212218    <widget class="QLabel" name="label_2"> 
    213219     <property name="text"> 
    214       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;WARNING! Resolution is NOT accounted for.&lt;br/&gt;Thus slit smeared data will give very wrong answers!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
     220      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#000000;&quot;&gt;Resolution is NOT accounted for.&lt;br/&gt;Slit smeared data will give very wrong answers!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 
    215221     </property> 
    216222    </widget> 
  • src/sas/qtgui/UI/SetGraphRangeUI.ui

    rd3ca363 r2e3e959  
    1919  <property name="windowTitle"> 
    2020   <string>Set Graph Range</string> 
     21  </property> 
     22  <property name="windowIcon"> 
     23   <iconset resource="main_resources.qrc"> 
     24    <normaloff>:/res/ball.ico</normaloff>:/res/ball.ico</iconset> 
    2125  </property> 
    2226  <property name="modal"> 
     
    9397  </layout> 
    9498 </widget> 
    95  <resources/> 
     99 <resources> 
     100  <include location="main_resources.qrc"/> 
     101 </resources> 
    96102 <connections> 
    97103  <connection> 
  • src/sas/qtgui/UI/convert_all.sh

    r9290b1a r2e3e959  
    11# UI -> PY 
    22for filename in *.ui; do 
    3   pyuic.bat $filename > "`basename "$filename" .ui`.py" 
     3  pyuic4 $filename > "`basename "$filename" .ui`.py" 
    44done 
    55 
  • src/sas/qtgui/UI/convert_ui.sh

    rf51ed67 r2e3e959  
    1 pyuic.bat $1.ui > $1.py 
     1pyuic4 $1.ui > $1.py 
  • src/sas/qtgui/UnitTesting/LinearFitTest.py

    rb46f285 r2e3e959  
    44 
    55from PyQt4 import QtGui 
    6 from PyQt4 import QtCore 
    76from mock import MagicMock 
    87 
     
    109import path_prepare 
    1110 
    12 from UnitTesting.TestUtils import QtSignalSpy 
    1311from sas.sasgui.guiframe.dataFitting import Data1D 
    1412import sas.qtgui.Plotter as Plotter 
     
    6159        # Compare 
    6260        self.assertItemsEqual(return_values[0], [1.0, 3.0]) 
    63         self.assertItemsEqual(return_values[1], [10.004054329087303, 12.030439848443539]) 
     61        self.assertAlmostEqual(return_values[1][0], 10.004054329, 6) 
     62        self.assertAlmostEqual(return_values[1][1], 12.030439848, 6) 
    6463 
    6564        # Set the log scale 
     
    6968        # Compare 
    7069        self.assertItemsEqual(return_values[0], [1.0, 3.0]) 
    71         self.assertItemsEqual(return_values[1], [9.9877329376711437, 11.843650824649025]) 
     70        self.assertAlmostEqual(return_values[1][0], 9.987732937, 6) 
     71        self.assertAlmostEqual(return_values[1][1], 11.84365082, 6) 
    7272 
    7373    def testOrigData(self): 
     
    8181 
    8282        self.assertItemsEqual(x, orig_x) 
    83         self.assertItemsEqual(y, orig_y) 
    84         self.assertItemsEqual(dy, orig_dy) 
     83        self.assertEqual(y[0], orig_y[0]) 
     84        self.assertAlmostEqual(y[1], orig_y[1], 8) 
     85        self.assertAlmostEqual(y[2], orig_y[2], 8) 
     86        self.assertEqual(dy[0], orig_dy[0]) 
     87        self.assertAlmostEqual(dy[1], orig_dy[1], 8) 
     88        self.assertAlmostEqual(dy[2], orig_dy[2], 8) 
    8589 
    8690        # x, y 
     
    107111 
    108112        self.assertItemsEqual(x, orig_x) 
    109         self.assertItemsEqual(y, orig_y) 
    110         self.assertItemsEqual(dy, orig_dy) 
     113        self.assertEqual(y[0], orig_y[0]) 
     114        self.assertAlmostEqual(y[1], orig_y[1], 8) 
     115        self.assertAlmostEqual(y[2], orig_y[2], 8) 
     116        self.assertEqual(dy[0], orig_dy[0]) 
     117        self.assertAlmostEqual(dy[1], orig_dy[1], 8) 
     118        self.assertAlmostEqual(dy[2], orig_dy[2], 8) 
    111119 
    112120    def testCheckFitValues(self): 
     
    114122        # Good values 
    115123        self.assertTrue(self.widget.checkFitValues(self.widget.txtFitRangeMin)) 
    116         self.assertEqual(self.widget.txtFitRangeMin.palette().color(10).name(), "#f0f0f0") 
     124        # Colors platform dependent 
     125        #self.assertEqual(self.widget.txtFitRangeMin.palette().color(10).name(), "#f0f0f0") 
    117126        # Bad values 
    118127        self.widget.x_is_log = True 
  • src/sas/qtgui/UnitTesting/PlotterTest.py

    rdb5cd8d r2e3e959  
    1414from sas.sasgui.guiframe.dataFitting import Data2D 
    1515from UnitTesting.TestUtils import WarningTestNotImplemented 
     16from sas.qtgui.LinearFit import LinearFit 
     17from sas.qtgui.PlotProperties import PlotProperties 
    1618 
    1719# Tested module 
     
    224226    def testOnLinearFit(self): 
    225227        """ Checks the response to LinearFit call """ 
    226         WarningTestNotImplemented() 
     228        self.plotter.plot(self.data) 
     229        self.plotter.show() 
     230        QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted) 
     231 
     232        # Just this one plot 
     233        self.assertEqual(len(self.plotter.plot_dict.keys()), 1) 
     234        self.plotter.onLinearFit(1) 
     235 
     236        # Check that exec_ got called 
     237        self.assertTrue(QtGui.QDialog.exec_.called) 
    227238 
    228239    def testOnRemovePlot(self): 
    229240        """ Assure plots get removed when requested """ 
    230         WarningTestNotImplemented() 
     241        # Add two plots 
     242        self.plotter.show() 
     243        self.plotter.plot(self.data) 
     244        data2 = Data1D(x=[1.0, 2.0, 3.0], 
     245                       y=[11.0, 12.0, 13.0], 
     246                       dx=[0.1, 0.2, 0.3], 
     247                       dy=[0.1, 0.2, 0.3]) 
     248        data2.title="Test data 2" 
     249        data2.name="Test name 2" 
     250        data2.id = 2 
     251        self.plotter.plot(data2) 
     252 
     253        # Assure the plotter window is visible 
     254        self.assertTrue(self.plotter.isVisible()) 
     255 
     256        # Assure we have two sets 
     257        self.assertEqual(len(self.plotter.plot_dict.keys()), 2) 
     258 
     259        # Delete one set 
     260        self.plotter.onRemovePlot(2) 
     261        # Assure we have two sets 
     262        self.assertEqual(len(self.plotter.plot_dict.keys()), 1) 
     263 
     264        self.plotter.manager = MagicMock() 
     265 
     266        # Delete the remaining set 
     267        self.plotter.onRemovePlot(1) 
     268        # Assure we have no plots 
     269        self.assertEqual(len(self.plotter.plot_dict.keys()), 0) 
     270        # Assure the plotter window is closed 
     271        self.assertFalse(self.plotter.isVisible()) 
     272 
    231273 
    232274    def testRemovePlot(self): 
    233275        """ Test plot removal """ 
    234         WarningTestNotImplemented() 
     276        # Add two plots 
     277        self.plotter.show() 
     278        self.plotter.plot(self.data) 
     279        data2 = Data1D(x=[1.0, 2.0, 3.0], 
     280                       y=[11.0, 12.0, 13.0], 
     281                       dx=[0.1, 0.2, 0.3], 
     282                       dy=[0.1, 0.2, 0.3]) 
     283        data2.title="Test data 2" 
     284        data2.name="Test name 2" 
     285        data2.id = 2 
     286        data2._xaxis = "XAXIS" 
     287        data2._xunit = "furlong*fortnight^{-1}" 
     288        data2._yaxis = "YAXIS" 
     289        data2._yunit = "cake" 
     290        data2.hide_error = True 
     291        self.plotter.plot(data2) 
     292 
     293        # delete plot 1 
     294        self.plotter.removePlot(1) 
     295 
     296        # See that the labels didn't change 
     297        xl = self.plotter.ax.xaxis.label.get_text() 
     298        yl = self.plotter.ax.yaxis.label.get_text() 
     299        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$") 
     300        self.assertEqual(yl, "$YAXIS(cake)$") 
     301        # The hide_error flag should also remain 
     302        self.assertTrue(self.plotter.plot_dict[2].hide_error) 
    235303 
    236304    def testOnToggleHideError(self): 
    237305        """ Test the error bar toggle on plots """ 
    238         WarningTestNotImplemented() 
     306        # Add two plots 
     307        self.plotter.show() 
     308        self.plotter.plot(self.data) 
     309        data2 = Data1D(x=[1.0, 2.0, 3.0], 
     310                       y=[11.0, 12.0, 13.0], 
     311                       dx=[0.1, 0.2, 0.3], 
     312                       dy=[0.1, 0.2, 0.3]) 
     313        data2.title="Test data 2" 
     314        data2.name="Test name 2" 
     315        data2.id = 2 
     316        data2._xaxis = "XAXIS" 
     317        data2._xunit = "furlong*fortnight^{-1}" 
     318        data2._yaxis = "YAXIS" 
     319        data2._yunit = "cake" 
     320        error_status = True 
     321        data2.hide_error = error_status 
     322        self.plotter.plot(data2) 
     323 
     324        # Reverse the toggle 
     325        self.plotter.onToggleHideError(2) 
     326        # See that the labels didn't change 
     327        xl = self.plotter.ax.xaxis.label.get_text() 
     328        yl = self.plotter.ax.yaxis.label.get_text() 
     329        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$") 
     330        self.assertEqual(yl, "$YAXIS(cake)$") 
     331        # The hide_error flag should toggle 
     332        self.assertEqual(self.plotter.plot_dict[2].hide_error, not error_status) 
    239333 
    240334    def testOnFitDisplay(self): 
    241335        """ Test the fit line display on the chart """ 
    242         WarningTestNotImplemented() 
     336        self.assertIsInstance(self.plotter.fit_result, Data1D) 
     337        self.assertEqual(self.plotter.fit_result.symbol, 13) 
     338        self.assertEqual(self.plotter.fit_result.name, "Fit") 
     339 
     340        # fudge some init data 
     341        fit_data = [[0.0,0.0], [5.0,5.0]] 
     342        # Call the method 
     343        self.plotter.plot = MagicMock() 
     344        self.plotter.onFitDisplay(fit_data) 
     345        self.assertTrue(self.plotter.plot.called) 
     346        # Look at arguments passed to .plot() 
     347        self.plotter.plot.assert_called_with(data=self.plotter.fit_result, 
     348                                             hide_error=True, marker='-') 
    243349 
    244350    def testReplacePlot(self): 
    245351        """ Test the plot refresh functionality """ 
    246         WarningTestNotImplemented() 
    247  
    248     def testReplacePlot(self): 
    249         """ Test the plot refresh functionality """ 
    250         WarningTestNotImplemented(sys._getframe().f_code.co_name) 
     352        # Add original data 
     353        self.plotter.show() 
     354        self.plotter.plot(self.data) 
     355        # See the default labels 
     356        xl = self.plotter.ax.xaxis.label.get_text() 
     357        yl = self.plotter.ax.yaxis.label.get_text() 
     358        self.assertEqual(xl, "$()$") 
     359        self.assertEqual(yl, "$()$") 
     360 
     361        # Prepare new data 
     362        data2 = Data1D(x=[1.0, 2.0, 3.0], 
     363                       y=[11.0, 12.0, 13.0], 
     364                       dx=[0.1, 0.2, 0.3], 
     365                       dy=[0.1, 0.2, 0.3]) 
     366        data2.title="Test data 2" 
     367        data2.name="Test name 2" 
     368        data2.id = 2 
     369        data2._xaxis = "XAXIS" 
     370        data2._xunit = "furlong*fortnight^{-1}" 
     371        data2._yaxis = "YAXIS" 
     372        data2._yunit = "cake" 
     373        error_status = True 
     374        data2.hide_error = error_status 
     375 
     376        # Replace data in plot 
     377        self.plotter.replacePlot(1, data2) 
     378 
     379        # See that the labels changed 
     380        xl = self.plotter.ax.xaxis.label.get_text() 
     381        yl = self.plotter.ax.yaxis.label.get_text() 
     382        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$") 
     383        self.assertEqual(yl, "$YAXIS(cake)$") 
     384        # The hide_error flag should be as set 
     385        self.assertEqual(self.plotter.plot_dict[2].hide_error, error_status) 
    251386 
    252387    def testOnModifyPlot(self): 
    253388        """ Test the functionality for changing plot properties """ 
    254         WarningTestNotImplemented() 
     389        # Prepare new data 
     390        data2 = Data1D(x=[1.0, 2.0, 3.0], 
     391                       y=[11.0, 12.0, 13.0], 
     392                       dx=[0.1, 0.2, 0.3], 
     393                       dy=[0.1, 0.2, 0.3]) 
     394        data2.title="Test data 2" 
     395        data2.name="Test name 2" 
     396        data2.id = 2 
     397        data2.custom_color = None 
     398        data2.symbol = 1 
     399        data2.markersize = 11 
     400 
     401        self.plotter.plot(data2) 
     402 
     403        with patch('PlotProperties.PlotProperties') as mock: 
     404            instance = mock.return_value 
     405            QtGui.QDialog.exec_ = MagicMock(return_value=QtGui.QDialog.Accepted) 
     406            instance.symbol.return_value = 7 
     407 
     408            self.plotter.onModifyPlot(2) 
     409 
     410            #print self.plotter.plot_dict[2].symbol 
     411 
    255412 
    256413if __name__ == "__main__": 
Note: See TracChangeset for help on using the changeset viewer.